diff --git a/.gitignore b/.gitignore index 424936d92..4408a96b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1685,4 +1685,36 @@ software/linux/project/FusionX/ software/FusionX/src/driver/MZ80A/k64fcpu.c.hld software/linux/buildroot/.config.old software/linux/kernel/scripts/kconfig/.mconf.cmd +software/FusionX/src/ttymz/.tmp_versions/ +software/FusionX/src/ttymz/.ttymzdrv.ko.cmd +software/FusionX/src/ttymz/Makefile.orig +software/FusionX/src/ttymz/Module.symvers +software/FusionX/src/ttymz/modules.order +software/FusionX/src/ttymz/ttymzdrv.ko +software/FusionX/src/ttymz/ttymzdrv.mod.c +software/FusionX/src/z80drv/.tmp_versions/ +software/FusionX/src/z80drv/.z80drv.ko.cmd +software/FusionX/src/z80drv/Kbuild.in +software/FusionX/src/z80drv/MZ80A/emumz.c +software/FusionX/src/z80drv/MZ80A/k64fcpu.c.hld +software/FusionX/src/z80drv/MZ80A/z80driver.c.bad +software/FusionX/src/z80drv/MZ80A/z80vhw_rfs.c.bad +software/FusionX/src/z80drv/Makefile.old +software/FusionX/src/z80drv/Makefile1 +software/FusionX/src/z80drv/Makefile3 +software/FusionX/src/z80drv/Module.symvers +software/FusionX/src/z80drv/Z80.c.old +software/FusionX/src/z80drv/Z80.c.old2 +software/FusionX/src/z80drv/Z80.rc.in +software/FusionX/src/z80drv/Z80.x/ +software/FusionX/src/z80drv/Zeta.test/ +software/FusionX/src/z80drv/k64fcpu +software/FusionX/src/z80drv/modules.order +software/FusionX/src/z80drv/mz700.rom +software/FusionX/src/z80drv/sa1510.orig +software/FusionX/src/z80drv/test +software/FusionX/src/z80drv/x.mzf +software/FusionX/src/z80drv/z80ctrl +software/FusionX/src/z80drv/z80drv.ko +software/FusionX/src/z80drv/z80drv.mod.c diff --git a/.gitmodules b/.gitmodules index 9e0caca0c..b5c6c614e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "software/FusionX/src/driver/Z80"] - path = software/FusionX/src/driver/Z80 + path = software/FusionX/src/z80drv/Z80 url = https://github.com/redcode/Z80.git [submodule "software/FusionX/src/driver/Zeta"] - path = software/FusionX/src/driver/Zeta + path = software/FusionX/src/z80drv/Zeta url = https://github.com/redcode/Zeta.git [submodule "software/FusionX/src/driver/6502"] - path = software/FusionX/src/driver/6502 + path = software/FusionX/src/z80drv/6502 url = https://github.com/redcode/6502.git [submodule "software/FusionX/src/driver/software/FusionX/src/driver/6502"] - path = software/FusionX/src/driver/software/FusionX/src/driver/6502 + path = software/FusionX/src/z80drv/software/FusionX/src/driver/6502 url = https://github.com/redcode/6502.git diff --git a/software/FusionX/etc/startZ80_RFS.sh b/software/FusionX/etc/startZ80_RFS.sh index de2910c49..163adb2a3 100755 --- a/software/FusionX/etc/startZ80_RFS.sh +++ b/software/FusionX/etc/startZ80_RFS.sh @@ -32,15 +32,16 @@ rmmod z80drv 2>/dev/null insmod z80drv.ko sleep 1 -# Load the original RFS ROM images. -${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/MROM_256_${SCREENWIDTH}c.bin --addr 0x000000 --type 1 -${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_256_${SCREENWIDTH}c.bin --addr 0x80000 --type 1 -${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_II_256_${SCREENWIDTH}c.bin --addr 0x100000 --type 1 -${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_III_256_${SCREENWIDTH}c.bin --addr 0x180000 --type 1 - # Add the RFS Virtual Hardware to the driver. ${FUSIONXDIR}/bin/z80ctrl --adddev --device rfs +# Load the original RFS ROM images. These are loaded by the RFS driver but here for reference or to load alternate. If +# alternate roms are loaded then ensure they are loaded prior to the start command below. +#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/MROM_256_${SCREENWIDTH}c.bin --addr 0x000000 --type 1 +#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_256_${SCREENWIDTH}c.bin --addr 0x80000 --type 1 +#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_II_256_${SCREENWIDTH}c.bin --addr 0x100000 --type 1 +#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_III_256_${SCREENWIDTH}c.bin --addr 0x180000 --type 1 + # Start the Z80 (ie. MZ-80A virtual processor). ${FUSIONXDIR/bin/z80ctrl --start diff --git a/software/FusionX/etc/startZ80_TZFS.sh b/software/FusionX/etc/startZ80_TZFS.sh index 5b13915be..9e8a42a7f 100755 --- a/software/FusionX/etc/startZ80_TZFS.sh +++ b/software/FusionX/etc/startZ80_TZFS.sh @@ -32,6 +32,12 @@ rmmod z80drv 2>/dev/null insmod z80drv.ko sleep 1 +# Add the TZPU Virtual Hardware to the driver. +${FUSIONXDIR}/bin/z80ctrl --adddev --device tzpu + +# Start the K64F Virtual CPU Emulation. +${FUSIONXDIR}/bin/k64fcpu & + # Load the original Monitor and TZFS ROM images. This is done in the K64F daemon but can be manually enabled. #${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/monitor_${SCREENWIDTH}c_sa1510.rom --addr 0x000000 --type 1 #${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/tzfs.rom --offset 0x000000 --len 0x001800 --addr 0x00E800 --type 1 @@ -39,12 +45,6 @@ sleep 1 #${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/tzfs.rom --offset 0x002800 --len 0x001000 --addr 0x02F000 --type 1 #${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/tzfs.rom --offset 0x003800 --len 0x001000 --addr 0x03F000 --type 1 -# Add the TZPU Virtual Hardware to the driver. -${FUSIONXDIR}/bin/z80ctrl --adddev --device tzpu - -# Start the K64F Virtual CPU Emulation. -${FUSIONXDIR}/bin/k64fcpu & - # Ensure the system is set for performance mode with max frequency. # NB: Enabling this prior to starting the Z80 results in a kernel error. echo performance > /sys/devices//system/cpu/cpufreq/policy0/scaling_governor diff --git a/software/FusionX/src/tty/Makefile b/software/FusionX/src/ttymz/Makefile similarity index 100% rename from software/FusionX/src/tty/Makefile rename to software/FusionX/src/ttymz/Makefile diff --git a/software/FusionX/src/tty/sharpmz.c b/software/FusionX/src/ttymz/sharpmz.c similarity index 100% rename from software/FusionX/src/tty/sharpmz.c rename to software/FusionX/src/ttymz/sharpmz.c diff --git a/software/FusionX/src/tty/sharpmz.h b/software/FusionX/src/ttymz/sharpmz.h similarity index 100% rename from software/FusionX/src/tty/sharpmz.h rename to software/FusionX/src/ttymz/sharpmz.h diff --git a/software/FusionX/src/tty/ttymz.c b/software/FusionX/src/ttymz/ttymz.c similarity index 100% rename from software/FusionX/src/tty/ttymz.c rename to software/FusionX/src/ttymz/ttymz.c diff --git a/software/FusionX/src/tty/ttymz.h b/software/FusionX/src/ttymz/ttymz.h similarity index 100% rename from software/FusionX/src/tty/ttymz.h rename to software/FusionX/src/ttymz/ttymz.h diff --git a/software/FusionX/src/driver/MZ80A/z80io.c b/software/FusionX/src/ttymz/z80io.c similarity index 100% rename from software/FusionX/src/driver/MZ80A/z80io.c rename to software/FusionX/src/ttymz/z80io.c diff --git a/software/FusionX/src/tty/z80io.h b/software/FusionX/src/ttymz/z80io.h similarity index 100% rename from software/FusionX/src/tty/z80io.h rename to software/FusionX/src/ttymz/z80io.h diff --git a/software/FusionX/src/driver/MZ2000/z80io_test.c b/software/FusionX/src/ttymz/z80io_test.c similarity index 100% rename from software/FusionX/src/driver/MZ2000/z80io_test.c rename to software/FusionX/src/ttymz/z80io_test.c diff --git a/software/FusionX/src/driver/6502 b/software/FusionX/src/z80drv/6502 similarity index 100% rename from software/FusionX/src/driver/6502 rename to software/FusionX/src/z80drv/6502 diff --git a/software/FusionX/src/driver/CMakeLists.txt b/software/FusionX/src/z80drv/CMakeLists.txt similarity index 100% rename from software/FusionX/src/driver/CMakeLists.txt rename to software/FusionX/src/z80drv/CMakeLists.txt diff --git a/software/FusionX/src/driver/MZ2000/optparse.h b/software/FusionX/src/z80drv/MZ2000/optparse.h similarity index 100% rename from software/FusionX/src/driver/MZ2000/optparse.h rename to software/FusionX/src/z80drv/MZ2000/optparse.h diff --git a/software/FusionX/src/driver/MZ2000/z80ctrl.c b/software/FusionX/src/z80drv/MZ2000/z80ctrl.c similarity index 100% rename from software/FusionX/src/driver/MZ2000/z80ctrl.c rename to software/FusionX/src/z80drv/MZ2000/z80ctrl.c diff --git a/software/FusionX/src/driver/MZ2000/z80driver.c b/software/FusionX/src/z80drv/MZ2000/z80driver.c similarity index 100% rename from software/FusionX/src/driver/MZ2000/z80driver.c rename to software/FusionX/src/z80drv/MZ2000/z80driver.c diff --git a/software/FusionX/src/driver/MZ2000/z80driver.h b/software/FusionX/src/z80drv/MZ2000/z80driver.h similarity index 100% rename from software/FusionX/src/driver/MZ2000/z80driver.h rename to software/FusionX/src/z80drv/MZ2000/z80driver.h diff --git a/software/FusionX/src/driver/MZ2000/z80io.c b/software/FusionX/src/z80drv/MZ2000/z80io.c similarity index 100% rename from software/FusionX/src/driver/MZ2000/z80io.c rename to software/FusionX/src/z80drv/MZ2000/z80io.c diff --git a/software/FusionX/src/driver/MZ2000/z80io.h b/software/FusionX/src/z80drv/MZ2000/z80io.h similarity index 100% rename from software/FusionX/src/driver/MZ2000/z80io.h rename to software/FusionX/src/z80drv/MZ2000/z80io.h diff --git a/software/FusionX/src/driver/MZ80A/z80io_test.c b/software/FusionX/src/z80drv/MZ2000/z80io_test.c similarity index 100% rename from software/FusionX/src/driver/MZ80A/z80io_test.c rename to software/FusionX/src/z80drv/MZ2000/z80io_test.c diff --git a/software/FusionX/src/driver/MZ2000/z80menu.c b/software/FusionX/src/z80drv/MZ2000/z80menu.c similarity index 100% rename from software/FusionX/src/driver/MZ2000/z80menu.c rename to software/FusionX/src/z80drv/MZ2000/z80menu.c diff --git a/software/FusionX/src/driver/MZ2000/z80menu.h b/software/FusionX/src/z80drv/MZ2000/z80menu.h similarity index 100% rename from software/FusionX/src/driver/MZ2000/z80menu.h rename to software/FusionX/src/z80drv/MZ2000/z80menu.h diff --git a/software/FusionX/src/driver/MZ700/optparse.h b/software/FusionX/src/z80drv/MZ700/optparse.h similarity index 100% rename from software/FusionX/src/driver/MZ700/optparse.h rename to software/FusionX/src/z80drv/MZ700/optparse.h diff --git a/software/FusionX/src/driver/MZ700/z80ctrl.c b/software/FusionX/src/z80drv/MZ700/z80ctrl.c similarity index 100% rename from software/FusionX/src/driver/MZ700/z80ctrl.c rename to software/FusionX/src/z80drv/MZ700/z80ctrl.c diff --git a/software/FusionX/src/driver/MZ700/z80driver.c b/software/FusionX/src/z80drv/MZ700/z80driver.c similarity index 100% rename from software/FusionX/src/driver/MZ700/z80driver.c rename to software/FusionX/src/z80drv/MZ700/z80driver.c diff --git a/software/FusionX/src/driver/MZ700/z80driver.h b/software/FusionX/src/z80drv/MZ700/z80driver.h similarity index 100% rename from software/FusionX/src/driver/MZ700/z80driver.h rename to software/FusionX/src/z80drv/MZ700/z80driver.h diff --git a/software/FusionX/src/driver/MZ700/z80io.c b/software/FusionX/src/z80drv/MZ700/z80io.c similarity index 100% rename from software/FusionX/src/driver/MZ700/z80io.c rename to software/FusionX/src/z80drv/MZ700/z80io.c diff --git a/software/FusionX/src/driver/MZ700/z80io.h b/software/FusionX/src/z80drv/MZ700/z80io.h similarity index 100% rename from software/FusionX/src/driver/MZ700/z80io.h rename to software/FusionX/src/z80drv/MZ700/z80io.h diff --git a/software/FusionX/src/driver/MZ700/z80io_test.c b/software/FusionX/src/z80drv/MZ700/z80io_test.c similarity index 100% rename from software/FusionX/src/driver/MZ700/z80io_test.c rename to software/FusionX/src/z80drv/MZ700/z80io_test.c diff --git a/software/FusionX/src/driver/MZ700/z80menu.c b/software/FusionX/src/z80drv/MZ700/z80menu.c similarity index 100% rename from software/FusionX/src/driver/MZ700/z80menu.c rename to software/FusionX/src/z80drv/MZ700/z80menu.c diff --git a/software/FusionX/src/driver/MZ700/z80menu.h b/software/FusionX/src/z80drv/MZ700/z80menu.h similarity index 100% rename from software/FusionX/src/driver/MZ700/z80menu.h rename to software/FusionX/src/z80drv/MZ700/z80menu.h diff --git a/software/FusionX/src/driver/MZ80A/k64fcpu.c b/software/FusionX/src/z80drv/MZ80A/k64fcpu.c similarity index 100% rename from software/FusionX/src/driver/MZ80A/k64fcpu.c rename to software/FusionX/src/z80drv/MZ80A/k64fcpu.c diff --git a/software/FusionX/src/driver/MZ80A/optparse.h b/software/FusionX/src/z80drv/MZ80A/optparse.h similarity index 100% rename from software/FusionX/src/driver/MZ80A/optparse.h rename to software/FusionX/src/z80drv/MZ80A/optparse.h diff --git a/software/FusionX/src/z80drv/MZ80A/sharpmz.c b/software/FusionX/src/z80drv/MZ80A/sharpmz.c new file mode 100644 index 000000000..a10b26b92 --- /dev/null +++ b/software/FusionX/src/z80drv/MZ80A/sharpmz.c @@ -0,0 +1,2375 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Name: sharpmz.c +// Created: December 2020 +// Version: v1.0 +// Author(s): Philip Smart +// Description: The Sharp MZ library. +// This file contains methods which allow the ZPU to access and control the Sharp MZ +// series computer hardware. The ZPU is instantiated within a physical Sharp MZ machine +// or an FPGA hardware emulation and provides either a host CPU running zOS or as an +// I/O processor providing services. +// +// NB. This library is NOT yet thread safe. +// Credits: +// Copyright: (c) 2019-2020 Philip Smart +// +// History: v1.0 Dec 2020 - Initial write of the Sharp MZ series hardware interface software. +// +// Notes: See Makefile to enable/disable conditional components +// +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// This source file is free software: you can redistribute it and#or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "z80io.h" +#include "z80menu.h" + +#include +#include +#include +#include +#include "osd.h" +#include "sharpmz.h" + +#ifndef __APP__ // Protected methods which should only reside in the kernel. + +// -------------------------------------------------------------------------------------------------------------- +// Static data declarations. +// -------------------------------------------------------------------------------------------------------------- + +// Global scope variables used within the zOS kernel. +// +uint32_t volatile *ms; +t_z80Control z80Control; +t_osControl osControl; +t_svcControl *svcControl = TZSVC_CMD_STRUCT_ADDR_ZOS; + +// Mapping table to map Sharp MZ80A Ascii to Standard ASCII. +// +static t_asciiMap asciiMap[] = { + { 0x00 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x00 }, { 0x20 }, { 0x20 }, // 0x0F + { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, // 0x1F + { 0x20 }, { 0x21 }, { 0x22 }, { 0x23 }, { 0x24 }, { 0x25 }, { 0x26 }, { 0x27 }, { 0x28 }, { 0x29 }, { 0x2A }, { 0x2B }, { 0x2C }, { 0x2D }, { 0x2E }, { 0x2F }, // 0x2F + { 0x30 }, { 0x31 }, { 0x32 }, { 0x33 }, { 0x34 }, { 0x35 }, { 0x36 }, { 0x37 }, { 0x38 }, { 0x39 }, { 0x3A }, { 0x3B }, { 0x3C }, { 0x3D }, { 0x3E }, { 0x3F }, // 0x3F + { 0x40 }, { 0x41 }, { 0x42 }, { 0x43 }, { 0x44 }, { 0x45 }, { 0x46 }, { 0x47 }, { 0x48 }, { 0x49 }, { 0x4A }, { 0x4B }, { 0x4C }, { 0x4D }, { 0x4E }, { 0x4F }, // 0x4F + { 0x50 }, { 0x51 }, { 0x52 }, { 0x53 }, { 0x54 }, { 0x55 }, { 0x56 }, { 0x57 }, { 0x58 }, { 0x59 }, { 0x5A }, { 0x5B }, { 0x5C }, { 0x5D }, { 0x5E }, { 0x5F }, // 0x5F + { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, // 0x6F + { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, // 0x7F + { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, // 0x8F + { 0x20 }, { 0x20 }, { 0x65 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x74 }, { 0x67 }, { 0x68 }, { 0x20 }, { 0x62 }, { 0x78 }, { 0x64 }, { 0x72 }, { 0x70 }, { 0x63 }, // 0x9F + { 0x71 }, { 0x61 }, { 0x7A }, { 0x77 }, { 0x73 }, { 0x75 }, { 0x69 }, { 0x20 }, { 0x4F }, { 0x6B }, { 0x66 }, { 0x76 }, { 0x20 }, { 0x75 }, { 0x42 }, { 0x6A }, // 0XAF + { 0x6E }, { 0x20 }, { 0x55 }, { 0x6D }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x6F }, { 0x6C }, { 0x41 }, { 0x6F }, { 0x61 }, { 0x20 }, { 0x79 }, { 0x20 }, { 0x20 }, // 0xBF + { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, // 0XCF + { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, // 0XDF + { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, // 0XEF + { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 } // 0XFF +}; +static t_dispCodeMap dispCodeMap[] = { + { 0xCC }, // NUL '\0' (null character) + { 0xE0 }, // SOH (start of heading) + { 0xF2 }, // STX (start of text) + { 0xF3 }, // ETX (end of text) + { 0xCE }, // EOT (end of transmission) + { 0xCF }, // ENQ (enquiry) + { 0xF6 }, // ACK (acknowledge) + { 0xF7 }, // BEL '\a' (bell) + { 0xF8 }, // BS '\b' (backspace) + { 0xF9 }, // HT '\t' (horizontal tab) + { 0xFA }, // LF '\n' (new line) + { 0xFB }, // VT '\v' (vertical tab) + { 0xFC }, // FF '\f' (form feed) + { 0xFD }, // CR '\r' (carriage ret) + { 0xFE }, // SO (shift out) + { 0xFF }, // SI (shift in) + { 0xE1 }, // DLE (data link escape) + { 0xC1 }, // DC1 (device control 1) + { 0xC2 }, // DC2 (device control 2) + { 0xC3 }, // DC3 (device control 3) + { 0xC4 }, // DC4 (device control 4) + { 0xC5 }, // NAK (negative ack.) + { 0xC6 }, // SYN (synchronous idle) + { 0xE2 }, // ETB (end of trans. blk) + { 0xE3 }, // CAN (cancel) + { 0xE4 }, // EM (end of medium) + { 0xE5 }, // SUB (substitute) + { 0xE6 }, // ESC (escape) + { 0xEB }, // FS (file separator) + { 0xEE }, // GS (group separator) + { 0xEF }, // RS (record separator) + { 0xF4 }, // US (unit separator) + { 0x00 }, // SPACE + { 0x61 }, // ! + { 0x62 }, // " + { 0x63 }, // # + { 0x64 }, // $ + { 0x65 }, // % + { 0x66 }, // & + { 0x67 }, // ' + { 0x68 }, // ( + { 0x69 }, // ) + { 0x6B }, // * + { 0x6A }, // + + { 0x2F }, // , + { 0x2A }, // - + { 0x2E }, // . + { 0x2D }, // / + { 0x20 }, // 0 + { 0x21 }, // 1 + { 0x22 }, // 2 + { 0x23 }, // 3 + { 0x24 }, // 4 + { 0x25 }, // 5 + { 0x26 }, // 6 + { 0x27 }, // 7 + { 0x28 }, // 8 + { 0x29 }, // 9 + { 0x4F }, // : + { 0x2C }, // ; + { 0x51 }, // < + { 0x2B }, // = + { 0x57 }, // > + { 0x49 }, // ? + { 0x55 }, // @ + { 0x01 }, // A + { 0x02 }, // B + { 0x03 }, // C + { 0x04 }, // D + { 0x05 }, // E + { 0x06 }, // F + { 0x07 }, // G + { 0x08 }, // H + { 0x09 }, // I + { 0x0A }, // J + { 0x0B }, // K + { 0x0C }, // L + { 0x0D }, // M + { 0x0E }, // N + { 0x0F }, // O + { 0x10 }, // P + { 0x11 }, // Q + { 0x12 }, // R + { 0x13 }, // S + { 0x14 }, // T + { 0x15 }, // U + { 0x16 }, // V + { 0x17 }, // W + { 0x18 }, // X + { 0x19 }, // Y + { 0x1A }, // Z + { 0x52 }, // [ + { 0x59 }, // \ '\\' + { 0x54 }, // ] + { 0xBE }, // ^ + { 0x3C }, // _ + { 0xC7 }, // ` + { 0x81 }, // a + { 0x82 }, // b + { 0x83 }, // c + { 0x84 }, // d + { 0x85 }, // e + { 0x86 }, // f + { 0x87 }, // g + { 0x88 }, // h + { 0x89 }, // i + { 0x8A }, // j + { 0x8B }, // k + { 0x8C }, // l + { 0x8D }, // m + { 0x8E }, // n + { 0x8F }, // o + { 0x90 }, // p + { 0x91 }, // q + { 0x92 }, // r + { 0x93 }, // s + { 0x94 }, // t + { 0x95 }, // u + { 0x96 }, // v + { 0x97 }, // w + { 0x98 }, // x + { 0x99 }, // y + { 0x9A }, // z + { 0xBC }, // { + { 0x80 }, // | + { 0x40 }, // } + { 0xA5 }, // ~ + { 0xC0 } // DEL +}; + +static t_scanCodeMap scanCodeMap[] = { + // NO SHIFT + { + // S0 00 - 07 + ESC , // SPARE - Allocate as Escape + GRAPHKEY , // GRAPH + '_' , // Pound/Down Arrow + ALPHAKEY , // ALPHA + NOKEY , // NO + ';' , // + + ':' , // * + CR , // CR + // S1 08 - 0F + 'y' , // y + 'z' , // z + '@' , // ` + '[' , // { + ']' , // } + NOKEY , // NULL + NOKEY , // NULL + NOKEY , // NULL + // S2 10 - 17 + 'q' , // q + 'r' , // r + 's' , // s + 't' , // t + 'u' , // u + 'v' , // v + 'w' , // w + 'x' , // x + // S3 18 - 1F + 'i' , // i + 'j' , // j + 'k' , // k + 'l' , // l + 'm' , // m + 'n' , // n + 'o' , // o + 'p' , // p + // S4 20 - 27 + 'a' , // a + 'b' , // b + 'c' , // c + 'd' , // d + 'e' , // e + 'f' , // f + 'g' , // g + 'h' , // h + // S5 28 - 2F + '1' , // 1 + '2' , // 2 + '3' , // 3 + '4' , // 4 + '5' , // 5 + '6' , // 6 + '7' , // 7 + '8' , // 8 + // S6 30 - 37 + '\\' , // Backslash + CURSUP , // + '-' , // - + ' ' , // SPACE + '0' , // 0 + '9' , // 9 + ',' , // , + '.' , // . + // S7 38 - 3F + INSERT , // INST. + DELETE , // DEL. + CURSUP , // CURSOR UP + CURSDOWN , // CURSOR DOWN + CURSRIGHT, // CURSOR RIGHT + CURSLEFT , // CURSOR LEFT + '?' , // Question Mark + '/' , // Forward Slash + // S8 40 - 47 - modifier keys. + BACKS , // BREAK - Backspace without modifiers, like standard ascii keyboards. + NOKEY , // CTRL + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , // SHIFT + // S9 48 - 4F - Function keys. + FUNC1 , // Function key F1 + FUNC2 , // Function key F2 + FUNC3 , // Function key F3 + FUNC4 , // Function key F4 + FUNC5 , // Function key F5 + NOKEY , + NOKEY , + NOKEY + }, + // CAPS LOCK + { + // S0 00 - 07 + ESC , // SPARE - Allocate as Escape + GRAPHKEY , // GRAPH + 0x58 , // + ALPHAKEY , // ALPHA + NOKEY , // NO + ':' , // ; + ';' , // : + CR , // CR + // S1 08 - 0F + 'Y' , // Y + 'Z' , // Z + '@' , // @ + '[' , // [ + ']' , // ] + NOKEY , // NULL + NOKEY , // NULL + NOKEY , // NULL + // S2 10 - 17 + 'Q' , // Q + 'R' , // R + 'S' , // S + 'T' , // T + 'U' , // U + 'V' , // V + 'W' , // W + 'X' , // X + // S3 18 - 1F + 'I' , // I + 'J' , // J + 'K' , // K + 'L' , // L + 'M' , // M + 'N' , // N + 'O' , // O + 'P' , // P + // S4 20 - 27 + 'A' , // A + 'B' , // B + 'C' , // C + 'D' , // D + 'E' , // E + 'F' , // F + 'G' , // G + 'H' , // H + // S5 28 - 2F + '1' , // 1 + '2' , // 2 + '3' , // 3 + '4' , // 4 + '5' , // 5 + '6' , // 6 + '7' , // 7 + '8' , // 8 + // S6 30 - 37 + '\\' , // Backslash + CURSUP , // + '-' , // - + ' ' , // SPACE + '0' , // 0 + '9' , // 9 + ',' , // , + '.' , // . + // S7 38 - 3F + INSERT , // INST. + DELETE , // DEL. + CURSUP , // CURSOR UP + CURSDOWN , // CURSOR DOWN + CURSRIGHT, // CURSOR RIGHT + CURSLEFT , // CURSOR LEFT + '?' , // ? + '/' , // / + // S8 40 - 47 - modifier keys. + BACKS , // BREAK - Backspace without modifiers, like standard ascii keyboards. + NOKEY , // CTRL + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , // SHIFT + // S9 48 - 4F - Function keys. + FUNC1 , // Function key F1 + FUNC2 , // Function key F2 + FUNC3 , // Function key F3 + FUNC4 , // Function key F4 + FUNC5 , // Function key F5 + NOKEY , + NOKEY , + NOKEY + }, + // SHIFT LOCK. + { + // S0 00 - 07 + ESC , // SPARE - Allocate as Escape + GRAPHKEY , // GRAPH + 0x58 , // + ALPHAKEY , // ALPHA + NOKEY , // NO + '+' , // ; + '*' , // : + CR , // CR + // S1 08 - 0F + 'Y' , // Y + 'Z' , // Z + '`' , // @ + '{' , // [ + '}' , // ] + NOKEY , // NULL + NOKEY , // NULL + NOKEY , // NULL + // S2 10 - 17 + 'Q' , // Q + 'R' , // R + 'S' , // S + 'T' , // T + 'U' , // U + 'V' , // V + 'W' , // W + 'X' , // X + // S3 18 - 1F + 'I' , // I + 'J' , // J + 'K' , // K + 'L' , // L + 'M' , // M + 'N' , // N + 'O' , // O + 'P' , // P + // S4 20 - 27 + 'A' , // A + 'B' , // B + 'C' , // C + 'D' , // D + 'E' , // E + 'F' , // F + 'G' , // G + 'H' , // H + // S5 28 - 2F + '!' , // ! + '"' , // " + '#' , // # + '$' , // $ + '%' , // % + '&' , // & + '\'' , // ' + '(' , // ( + // S6 30 - 37 + '|' , // Backslash + '~' , // POND MARK + '=' , // YEN + ' ' , // SPACE + ' ' , // ΒΆ + ')' , // ) + '<' , // < + '>' , // > + // S7 38 - 3F + CLRKEY , // CLR - END. - Clear screen. + CURHOMEKEY, // HOME. - Cursor to home. + PAGEUP , // PAGE UP - CURSOR UP + PAGEDOWN , // PAGE DOWN - CURSOR DOWN + ENDKEY , // END - CURSOR RIGHT + HOMEKEY , // HOME - CURSOR LEFT + '?' , // ? - Question Mark + '/' , // / - Forward Slash + // S8 40 - 47 - modifier keys. + BREAKKEY , // BREAK - Shift+BREAK = BREAK + NOKEY , // CTRL + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , // SHIFT + // S9 48 - 4F - Function keys. + FUNC6 , // Function key F1 + FUNC7 , // Function key F2 + FUNC8 , // Function key F3 + FUNC9 , // Function key F4 + FUNC10 , // Function key F5 + NOKEY , + NOKEY , + NOKEY + }, + // CONTROL CODE + { + // S0 00 - 07 + ESC , // SPARE - Allocate as Escape + DEBUGKEY , // GRAPH - Enable debugging output. + CTRL_CAPPA , // ^ + ANSITGLKEY, // ALPHA - Toggle Ansi terminal emulator. + NOKEY , // NO + NOKEY , // ; + NOKEY , // : + NOKEY , // CR + // S1 08 - 0F + CTRL_Y , // ^Y E3 + CTRL_Z , // ^Z E4 (CHECKER) + CTRL_AT , // ^@ + CTRL_LB , // ^[ EB/E5 + CTRL_RB , // ^] EA/E7 + NOKEY , // #NULL + NOKEY , // #NULL + NOKEY , // #NULL + // S2 10 - 17 + CTRL_Q , // ^Q + CTRL_R , // ^R + CTRL_S , // ^S + CTRL_T , // ^T + CTRL_U , // ^U + CTRL_V , // ^V + CTRL_W , // ^W E1 + CTRL_X , // ^X E2 + // S3 18 - 1F + CTRL_I , // ^I F9 + CTRL_J , // ^J FA + CTRL_K , // ^K FB + CTRL_L , // ^L FC + CTRL_M , // ^M CD + CTRL_N , // ^N FE + CTRL_O , // ^O FF + CTRL_P , // ^P E0 + // S4 20 - 27 + CTRL_A , // ^A F1 + CTRL_B , // ^B F2 + CTRL_C , // ^C F3 + CTRL_D , // ^D F4 + CTRL_E , // ^E F5 + CTRL_F , // ^F F6 + CTRL_G , // ^G F7 + CTRL_H , // ^H F8 + // S5 28 - 2F + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + // S6 30 - 37 (ERROR? 7 VALUES ONLY!!) + NOKEY , // ^YEN E6 + CTRL_CAPPA , // ^ EF + NOKEY , + NOKEY , + NOKEY , + CTRL_UNDSCR , // ^, + NOKEY , + NOKEY , + // S7 - 38 - 3F + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + CTRL_SLASH , // ^/ EE + // S8 40 - 47 - modifier keys. + NOKEY , // BREAK - CTRL+BREAK - not yet assigned + NOKEY , // CTRL + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , // SHIFT + // S9 48 - 4F - Function keys. + FUNC1 , // Function key F1 + FUNC2 , // Function key F2 + FUNC3 , // Function key F3 + FUNC4 , // Function key F4 + FUNC5 , // Function key F5 + NOKEY , + NOKEY , + NOKEY + }, + // KANA + { + // S0 00 - 07 + 0xBF , // SPARE + NOKEY , // GRAPH BUT NULL + 0xCF , // NIKO WH. + 0xC9 , // ALPHA + NOKEY , // NO + 0xB5 , // MO + 0x4D , // DAKU TEN + 0xCD , // CR + // S1 08 - 0F + 0x35 , // HA + 0x77 , // TA + 0xD7 , // WA + 0xB3 , // YO + 0xB7 , // HANDAKU + NOKEY , + NOKEY , + NOKEY , + // S2 10 - 17 + 0x7C , // KA + 0x70 , // KE + 0x41 , // SHI + 0x31 , // KO + 0x39 , // HI + 0xA6 , // TE + 0x78 , // KI + 0xDD , // CHI + // S3 18 - 1F + 0x3D , // FU + 0x5D , // MI + 0x6C , // MU + 0x56 , // ME + 0x1D , // RHI + 0x33 , // RA + 0xD5 , // HE + 0xB1 , // HO + // S4 20 - 27 + 0x46 , // SA + 0x6E , // TO + 0xD9 , // THU + 0x48 , // SU + 0x74 , // KU + 0x43 , // SE + 0x4C , // SO + 0x73 , // MA + // S5 28 - 2F + 0x3F , // A + 0x36 , // I + 0x7E , // U + 0x3B , // E + 0x7A , // O + 0x1E , // NA + 0x5F , // NI + 0xA2 , // NU + // S6 30 - 37 + 0xD3 , // YO + 0x9F , // YU + 0xD1 , // YA + 0x00 , // SPACE + 0x9D , // NO + 0xA3 , // NE + 0xD0 , // RU + 0xB9 , // RE + // S7 38 - 3F + 0xC6 , // ?CLR + 0xC5 , // ?HOME + 0xC2 , // ?CURSOR UP + 0xC1 , // ?CURSOR DOWN + 0xC3 , // ?CURSOR RIGHT + 0xC4 , // ?CURSOR LEFT + 0xBB , // DASH + 0xBE , // RO + // S8 40 - 47 - modifier keys. + NOKEY , // BREAK - GRPH+BREAK - not yet assigned + NOKEY , // CTRL + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , + NOKEY , // SHIFT + // S9 48 - 4F - Function keys. + FUNC1 , // Function key F1 + FUNC2 , // Function key F2 + FUNC3 , // Function key F3 + FUNC4 , // Function key F4 + FUNC5 , // Function key F5 + NOKEY , + NOKEY , + NOKEY + } +}; + +// Mapping table of sharp special control keys to ANSI ESCape sequences. +// +static t_ansiKeyMap ansiKeySeq[] = { + { HOMEKEY , "\x1b[1~" }, // HOME - Cursor to home. + { CURSUP , "\x1b[A" }, // CURSOR UP + { CURSDOWN , "\x1b[B" }, // CURSOR DOWN + { CURSRIGHT , "\x1b[C" }, // CURSOR RIGHT + { CURSLEFT , "\x1b[D" }, // CURSOR LEFT + { FUNC1 , "\x1b[10~" }, // Function key 1 + { FUNC2 , "\x1b[11~" }, // Function key 2 + { FUNC3 , "\x1b[12~" }, // Function key 3 + { FUNC4 , "\x1b[13~" }, // Function key 4 + { FUNC5 , "\x1b[14~" }, // Function key 5 + { FUNC6 , "\x1b[15~" }, // Function key 6 + { FUNC7 , "\x1b[17~" }, // Function key 7 + { FUNC8 , "\x1b[18~" }, // Function key 8 + { FUNC9 , "\x1b[19~" }, // Function key 9 + { FUNC10 , "\x1b[20~" }, // Function key 10 + { INSERT , "\x1b[2~" }, // Insert. + { DELETE , "\x1b[3~" }, // Delete. + { ENDKEY , "\x1b[F" }, // End Key. + { PAGEUP , "\x1b[5~" }, // Page Up. + { PAGEDOWN , "\x1b[6~" }, // Page Down. +}; + +// Static structures for controlling and managing hardware features. +// Display control structure. Used to manage the display including the Ansi Terminal. +static t_displayBuffer display = { .screenAttr = 0x71, .screenRow = 0, .displayCol = 0, .displayRow = 0, .maxScreenRow = (VC_DISPLAY_BUFFER_SIZE / VC_MAX_COLUMNS), + .maxDisplayRow = VC_MAX_ROWS, .maxScreenCol = VC_MAX_COLUMNS, .useAnsiTerm = 1, .lineWrap = 0, .debug = 0, .inDebug = 0 }; +// Keyboard control structure. Used to manage keyboard sweep, mapping and store. +static t_keyboard keyboard = { .holdTimer = 0L, .autorepeat = 0, .mode = KEYB_LOWERCASE, .cursorOn = 1, .flashTimer = 0L, .keyBuf[0] = 0x00, .keyBufPtr = 0 }; + +// AnsiTerminal control structure. Used to manage the inbuilt Ansi Terminal. +static t_AnsiTerm ansiterm = { .state = ANSITERM_ESC, .charcnt = 0, .paramcnt = 0, .setScreenMode = 0, .setExtendedMode = 0, .saveRow = 0, .saveCol = 0 }; +// Colour map for the Ansi Terminal. +const unsigned char ansiColourMap[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; + + +// -------------------------------------------------------------------------------------------------------------- +// Methods +// -------------------------------------------------------------------------------------------------------------- + +// Method to configure the motherboard hardware after a reset. +// +uint8_t mzInitMBHardware(void) +{ + // From the 1Z-013A monitor code, initialise the 8255 PIO. + // + *(volatile uint8_t *)(MBADDR_8BIT_KEYPF) = 0x8A; // 10001010 CTRL WORD MODE0 + *(volatile uint8_t *)(MBADDR_8BIT_KEYPF) = 0x07; // PC3=1 M-ON + *(volatile uint8_t *)(MBADDR_8BIT_KEYPF) = 0x05; // PC2=1 INTMSK + *(volatile uint8_t *)(MBADDR_8BIT_KEYPF) = 0x01; // TZ: Enable VGATE + + // Initialise the 8253 timer. + *(volatile uint8_t *)(MBADDR_8BIT_CONTF) = 0x74; // From monitor, according to system clock. + *(volatile uint8_t *)(MBADDR_8BIT_CONTF) = 0xB0; // + // Set timer in seconds, default to 0. + *(volatile uint8_t *)(MBADDR_8BIT_CONT2) = 0x00; // Timer 2 is the number of seconds. + *(volatile uint8_t *)(MBADDR_8BIT_CONT2) = 0x00; // + // Set timer in seconds, default to 0. + *(volatile uint8_t *)(MBADDR_8BIT_CONT1) = 0x0A; // Timer 1 is set to 640.6uS pulse into timer 2. + *(volatile uint8_t *)(MBADDR_8BIT_CONT1) = 0x00; // + // Set timer timer to run. + *(volatile uint8_t *)(MBADDR_8BIT_CONTF) = 0x80; // + + return(0); +} + +// Method to initialise the Sharp MZ extensions. +// +uint8_t mzInit(void) +{ + // Initialise Sharp MZ hardware. + mzInitMBHardware(); + + // Clear and setup the screen mode and resolution. + mzClearScreen(3, 1); + mzSetMachineVideoMode(VMMODE_MZ700); + mzSetVGAMode(VMMODE_VGA_640x480); + mzSetVGABorder(VMBORDER_BLUE); + mzSetScreenWidth(80); + + return(0); +} + +// Method to clear the screen. +// mode: 0 = clear from cursor to end of screen. +// 1 = clear from 0,0 to cursor. +// 2 = clear entire screen +// 3 = clear entire screen and reset scroll buffer. +// +void mzClearScreen(uint8_t mode, uint8_t updPos) +{ + // Locals. + uint32_t dstVRAMStartAddr; + uint32_t dstVRAMEndAddr; + uint32_t dstARAMStartAddr; + uint32_t startIdx; + uint32_t endIdx; + + // Sanity checks. + if(mode > 3) + return; + + switch(mode) + { + // Clear from cursor to end of screen. + case 0: + dstVRAMStartAddr = VIDEO_VRAM_BASE_ADDR+(display.displayRow*VC_MAX_COLUMNS)+display.displayCol; + dstVRAMEndAddr = VIDEO_VRAM_BASE_ADDR + VIDEO_VRAM_SIZE; + dstARAMStartAddr = VIDEO_ARAM_BASE_ADDR+(display.displayRow*VC_MAX_COLUMNS)+display.displayCol; + startIdx = (((display.screenRow < display.maxDisplayRow ? display.displayRow : (display.screenRow - display.maxDisplayRow + display.displayRow))) * display.maxScreenCol) + display.displayCol; + endIdx = startIdx + ((display.maxScreenCol*display.maxDisplayRow) - ((display.screenRow < display.maxDisplayRow ? display.displayRow : display.screenRow ) * display.maxScreenCol)); + break; + + // Clear from beginning of screen to cursor. + case 1: + dstVRAMStartAddr = VIDEO_VRAM_BASE_ADDR; + dstVRAMEndAddr = VIDEO_VRAM_BASE_ADDR+(display.displayRow*VC_MAX_COLUMNS)+display.displayCol; + dstARAMStartAddr = VIDEO_ARAM_BASE_ADDR; + startIdx = ((display.screenRow < display.maxDisplayRow ? display.screenRow : (display.screenRow - display.maxDisplayRow)) * display.maxScreenCol); + endIdx = ((display.screenRow < display.maxDisplayRow ? display.displayRow : (display.screenRow - display.maxDisplayRow + display.displayRow)) * display.maxScreenCol) + display.displayCol; + break; + + // Clear entire screen. + case 2: + dstVRAMStartAddr = VIDEO_VRAM_BASE_ADDR; + dstVRAMEndAddr = VIDEO_VRAM_BASE_ADDR + VIDEO_VRAM_SIZE; + dstARAMStartAddr = VIDEO_ARAM_BASE_ADDR; + startIdx = ((display.screenRow < display.maxDisplayRow ? display.screenRow : (display.screenRow - display.maxDisplayRow)) * display.maxScreenCol); + endIdx = startIdx + (display.maxScreenCol*display.maxDisplayRow); + if(updPos) + { + display.displayRow = 0; + display.displayCol = 0; + } + break; + + // Clear entire screen including scrollback buffer. + default: + dstVRAMStartAddr = VIDEO_VRAM_BASE_ADDR; + dstVRAMEndAddr = VIDEO_VRAM_BASE_ADDR+VIDEO_VRAM_SIZE; + dstARAMStartAddr = VIDEO_ARAM_BASE_ADDR; + startIdx = 0; + endIdx = VC_DISPLAY_BUFFER_SIZE; + // Reset parameters to start of screen. + if(updPos) + { + display.displayRow = 0; + display.displayCol = 0; + display.screenRow = 0; + } + break; + } + + // Clear the physical character display and attribute RAM. + // Select 32bit or 8 bit clear depending on the start/end position. + // + if((dstVRAMStartAddr&0x3) == 0 && (dstVRAMEndAddr&0x3) ==0) + { + uint32_t screenAttr = display.screenAttr << 24 | display.screenAttr << 16 | display.screenAttr << 8 | display.screenAttr; + for(uint32_t dstVRAMAddr=dstVRAMStartAddr, dstARAMAddr = dstARAMStartAddr; dstVRAMAddr < dstVRAMEndAddr; dstVRAMAddr+=4, dstARAMAddr+=4) + { + *(uint32_t *)(dstVRAMAddr) = 0x00000000; + *(uint32_t *)(dstARAMAddr) = screenAttr; + } + } else + { + for(uint32_t dstVRAMAddr=dstVRAMStartAddr, dstARAMAddr = dstARAMStartAddr; dstVRAMAddr <= dstVRAMEndAddr; dstVRAMAddr+=1, dstARAMAddr+=1) + { + *(uint8_t *)(dstVRAMAddr) = 0x00; + *(uint8_t *)(dstARAMAddr) = display.screenAttr; + } + } + // Clear the shadow display scrollback RAM. + for(uint32_t dstAddr = startIdx; dstAddr < endIdx; dstAddr++) + { + display.screenCharBuf[dstAddr] = 0x20; + display.screenAttrBuf[dstAddr] = display.screenAttr; + } + + return; +} + +// Method to clear a line, starting at a given column. +void mzClearLine(int row, int colStart, int colEnd, uint8_t updPos) +{ + // Locals. + uint8_t newRow = row; + uint8_t newColStart = colStart; + uint8_t newColEnd = colEnd; + + // Adjust the parameters, -1 indicates use current position. + if(row == -1) newRow = display.displayRow; + if(colStart == -1) newColStart = 0; + if(colEnd == -1) newColEnd = display.maxScreenCol-1; + + // Sanity checks. + if(newRow > display.maxDisplayRow || newColStart > display.maxScreenCol || newColEnd > display.maxScreenCol || newColEnd <= newColStart) + return; + + // Clear the physical character display and attribute RAM. + uint32_t screenAttr = display.screenAttr << 24 | display.screenAttr << 16 | display.screenAttr << 8 | display.screenAttr; + uint32_t dstVRAMStartAddr = VIDEO_VRAM_BASE_ADDR+(newRow*VC_MAX_COLUMNS)+newColStart; + uint32_t dstVRAMEndAddr = dstVRAMStartAddr + newColEnd; + uint32_t dstARAMStartAddr = VIDEO_ARAM_BASE_ADDR+(newRow*VC_MAX_COLUMNS)+newColStart; + + // Select 32bit or 8 bit clear depending on the start/end position. + // + if((dstVRAMStartAddr&0x3) == 0 && (dstVRAMEndAddr&0x3) ==0) + { + uint32_t screenAttr = display.screenAttr << 24 | display.screenAttr << 16 | display.screenAttr << 8 | display.screenAttr; + for(uint32_t dstVRAMAddr=dstVRAMStartAddr, dstARAMAddr = dstARAMStartAddr; dstVRAMAddr < dstVRAMEndAddr; dstVRAMAddr+=4, dstARAMAddr+=4) + { + *(uint32_t *)(dstVRAMAddr) = 0x00000000; + *(uint32_t *)(dstARAMAddr) = screenAttr; + } + } else + { + for(uint32_t dstVRAMAddr=dstVRAMStartAddr, dstARAMAddr = dstARAMStartAddr; dstVRAMAddr <= dstVRAMEndAddr; dstVRAMAddr+=1, dstARAMAddr+=1) + { + *(uint8_t *)(dstVRAMAddr) = 0x00; + *(uint8_t *)(dstARAMAddr) = display.screenAttr; + } + } + + // Clear the shadow display scrollback RAM. + uint32_t startIdx = (((display.screenRow < display.maxDisplayRow ? newRow : (display.screenRow - display.maxDisplayRow + newRow))) * display.maxScreenCol) + newColStart; + for(uint32_t dstAddr = startIdx; dstAddr <= startIdx + newColEnd; dstAddr++) + { + display.screenCharBuf[dstAddr] = 0x20; + display.screenAttrBuf[dstAddr] = display.screenAttr; + } + + // Update the screen pointer if needed. + if(updPos) + { + display.displayRow = newRow; + display.displayCol = newColEnd; + } + return; +} + +// Method to set the VGA Border colour when running in a VGA mode where the output display doesnt match the VGA display leaving blank pixels. +uint8_t mzSetVGABorder(uint8_t vborder) +{ + // Locals. + uint8_t mode = (uint8_t)*(volatile uint32_t *)(VCADDR_32BIT_VMVGATTR) & VMBORDER_MASK; + + // Sanity check parameters. + if(vborder != VMBORDER_BLACK && vborder != VMBORDER_BLUE && vborder != VMBORDER_RED && vborder != VMBORDER_PURPLE && vborder != VMBORDER_GREEN && vborder != VMBORDER_CYAN && vborder != VMBORDER_YELLOW && vborder != VMBORDER_WHITE) + return(1); + + // Set the VGA Border. + *(volatile uint8_t *)(VCADDR_8BIT_VMVGATTR) = mode | vborder; + + return(0); +} + +// Method to set the VGA mode. +uint8_t mzSetVGAMode(uint8_t vgamode) +{ + // Locals. + uint8_t mode = (uint8_t)*(volatile uint32_t *)(VCADDR_32BIT_VMVGAMODE) & VMMODE_VGA_MASK; + + // Sanity check parameters. + if(vgamode != VMMODE_VGA_OFF && vgamode != VMMODE_VGA_640x480 && vgamode != VMMODE_VGA_800x600) + return(1); + + // Set the VGA mode. + *(volatile uint8_t *)(VCADDR_8BIT_VMVGAMODE) = mode | vgamode; + + return(0); +} + +// Method to set the screen mode, ie. machine video being emulated. +// +uint8_t mzSetMachineVideoMode(uint8_t vmode) +{ + // Locals. + uint8_t mode = (uint8_t)*(volatile uint32_t *)(VCADDR_32BIT_VMCTRL) & VMMODE_MASK; + + // Sanity check parameters. + if(vmode != VMMODE_MZ80K && vmode != VMMODE_MZ80C && vmode != VMMODE_MZ1200 && vmode != VMMODE_MZ80A && vmode != VMMODE_MZ700 && vmode != VMMODE_MZ1500 && vmode != VMMODE_MZ800 && vmode != VMMODE_MZ80B && vmode != VMMODE_MZ2000 && vmode != VMMODE_MZ2200 && vmode != VMMODE_MZ2500) + return(1); + + // Set the hardware video mode. + *(volatile uint8_t *)(VCADDR_8BIT_VMCTRL) = mode | hwmode; + + return(0); +} + +// Method to return the character based screen width. +// +uint8_t mzGetScreenWidth(void) +{ + return(display.maxScreenCol); +} + +// Method to setup the character based screen width. +// +uint8_t mzSetScreenWidth(uint8_t width) +{ + // Locals. + uint8_t mode = (uint8_t)*(volatile uint32_t *)(VCADDR_32BIT_VMCTRL) & VMMODE_80CHAR_MASK; + + // Sanity check parameters. + if(width != 40 && width != 80) + return(1); + + // Toggle the 40/80 bit according to requirements. + if(width == 40) + { + *(volatile uint8_t *)(VCADDR_8BIT_VMCTRL) = mode; + display.maxScreenCol = 40; + } + else + { + *(volatile uint8_t *)(VCADDR_8BIT_VMCTRL) = mode | VMMODE_80CHAR; + display.maxScreenCol = 80; + } + + return(0); +} + +// Method to refresh the screen from the scrollback buffer contents. +void mzRefreshScreen(void) +{ + // Refresh the screen with buffer window contents + uint32_t startIdx = (display.screenRow < display.maxDisplayRow ? 0 : (display.screenRow - display.maxDisplayRow)+1) * display.maxScreenCol; + for(uint32_t srcIdx = startIdx, dstVRAMAddr = VIDEO_VRAM_BASE_ADDR, dstARAMAddr = VIDEO_ARAM_BASE_ADDR; srcIdx < startIdx+(display.maxDisplayRow*display.maxScreenCol); srcIdx++) + { + *(uint8_t *)(dstVRAMAddr++) = dispCodeMap[display.screenCharBuf[srcIdx]].dispCode; + *(uint8_t *)(dstARAMAddr++) = display.screenAttrBuf[srcIdx]; + } +} + +// Method to scroll the screen contents upwards, either because new data is being added to the bottom or for scrollback. +// +uint8_t mzScrollUp(uint8_t lines, uint8_t clear) +{ + // Sanity check. + if(lines > display.maxDisplayRow) + return(1); + + // Restore cursor character before scrolling. + mzFlashCursor(CURSOR_RESTORE); + + // Add the lines to the current row address. If the row exceeds the maximum then scroll the screen up. + display.screenRow += lines; + display.displayRow += lines; + if(display.displayRow >= display.maxDisplayRow) + { + display.displayRow = display.maxDisplayRow - 1; + } + + // At end of buffer? Shift up. + if(display.screenRow >= display.maxScreenRow) + { + uint32_t srcAddr = (lines * display.maxScreenCol); + uint32_t dstAddr = 0; + for(; srcAddr < VC_DISPLAY_BUFFER_SIZE; srcAddr++, dstAddr++) + { + display.screenCharBuf[dstAddr] = display.screenCharBuf[srcAddr]; + display.screenAttrBuf[dstAddr] = display.screenAttrBuf[srcAddr]; + } + for(; dstAddr < VC_DISPLAY_BUFFER_SIZE; dstAddr++) + { + display.screenCharBuf[dstAddr] = 0x20; + display.screenAttrBuf[dstAddr] = display.screenAttr; + } + display.screenRow = display.maxScreenRow-1; + } + // If we havent scrolled at the end of the buffer then clear the lines scrolled if requested. + else if(clear && display.displayRow == display.maxDisplayRow - 1) + { + uint32_t startIdx = (display.screenRow - lines + 1) * display.maxScreenCol; + uint32_t endIdx = startIdx + (lines * display.maxScreenCol); + + // Clear the shadow display scrollback RAM. + for(uint32_t dstAddr = startIdx; dstAddr < endIdx; dstAddr++) + { + display.screenCharBuf[dstAddr] = 0x20; + display.screenAttrBuf[dstAddr] = display.screenAttr; + } + } + + // Refresh the screen with buffer window contents + mzRefreshScreen(); + return(0); +} + +// Method to scroll the screen contents downwards for scrollback purposes. +uint8_t mzScrollDown(uint8_t lines) +{ + // Sanity check. + if(lines > display.maxDisplayRow) + return(1); + + // Restore cursor character before scrolling. + mzFlashCursor(CURSOR_RESTORE); + + // Subtract the lines from the current row address. If the row falls below zero then scroll the screen down. + if((((int)display.screenRow) - lines) < 0) { display.screenRow = 0; } + else if( display.screenRow < display.maxDisplayRow ) { display.screenRow = display.maxDisplayRow -1; } + else { display.screenRow -= lines; } + + // Same for the physical row pointer. + if((((int)display.displayRow) - lines) < 0) { display.displayRow = 0; } + else if( display.displayRow < display.maxDisplayRow ) { display.displayRow = display.maxDisplayRow -1; } + else { display.displayRow -= lines; } + + // Refresh screen. + mzRefreshScreen(); + return(0); +} + +// Method to move the cursor within the phsyical screen buffer. +// +uint8_t mzMoveCursor(enum CURSOR_POSITION pos, uint8_t cnt) +{ + // Process according to command. + // + switch(pos) + { + case CURSOR_UP: + display.displayRow = (int)(display.displayRow - cnt) < 0 ? 0 : display.displayRow-cnt; + break; + case CURSOR_DOWN: + display.displayRow = (int)(display.displayRow + cnt) >= display.maxDisplayRow ? display.maxDisplayRow -1 : display.displayRow+cnt; + break; + case CURSOR_LEFT: + display.displayCol = (int)(display.displayCol - cnt) < 0 ? 0 : display.displayCol-cnt; + break; + case CURSOR_RIGHT: + display.displayCol = (int)(display.displayCol + cnt) >= display.maxScreenCol ? display.maxScreenCol -1 : display.displayCol+cnt; + break; + case CURSOR_COLUMN: + if(cnt < display.maxScreenCol) + display.displayCol = cnt; + break; + case CURSOR_NEXT_LINE: + display.displayCol = 0; + if(display.displayRow < display.maxDisplayRow-1) + display.displayRow += 1; + break; + case CURSOR_PREV_LINE: + display.displayCol = 0; + if(display.displayRow > 0) + display.displayRow -= 1; + break; + default: + break; + } + return(0); +} + +// Method to set the physical X/Y location of the cursor. +// +uint8_t mzSetCursor(uint8_t x, uint8_t y) +{ + display.screenRow = y >= display.maxDisplayRow ? display.maxDisplayRow-1 : y; + display.displayRow = y >= display.maxDisplayRow ? display.maxDisplayRow-1 : y; + display.displayCol = x >= display.maxScreenCol ? display.maxScreenCol-1 : x; + return(0); +} + + +// Stream method to output a character to the display. +// +int mzPutChar(char c, FILE *stream) +{ + // Variables and locals. + uint8_t output = 1; + uint32_t dispMemAddr; + + // Restore character under cursor before printing. + mzFlashCursor(CURSOR_RESTORE); + + // Pre-process special characters. + switch(c) + { + // Return to start of line? + case CR: + display.displayCol = 0; + output = 0; + break; + + // New line? + case LF: + // Increment line and scroll if necessary. + mzScrollUp(1, 1); + display.displayCol = 0; + output = 0; + break; + + // Backspace. + case BACKS: + display.displayCol = display.displayCol == 0 ? 0 : display.displayCol -1; + output = 0; + break; + + // Delete. + case DELETE: + display.displayCol = display.displayCol == 0 ? 0 : display.displayCol -1; + mzPutChar(SPACE, stream); + display.displayCol = display.displayCol == 0 ? 0 : display.displayCol -1; + output = 0; + break; + + // Tab - expand by printing whitespace. + case TAB: + for(uint8_t idx=0; idx < 4; idx++) + mzPutChar(SPACE, stream); + output = 0; + break; + + // Scroll screen up. + case SCROLL: + mzScrollUp(1, 0); + output = 0; + break; + } + + // Output to screen if flag set. + if(output) + { + // Output character using default attributes. + dispMemAddr = VIDEO_VRAM_BASE_ADDR + (display.displayRow * display.maxScreenCol) + display.displayCol; + *(uint8_t *)(dispMemAddr) = (char)dispCodeMap[c].dispCode; + display.screenCharBuf[(display.screenRow * display.maxScreenCol) + display.displayCol] = c; + // + dispMemAddr = VIDEO_ARAM_BASE_ADDR + (display.displayRow * display.maxScreenCol) + display.displayCol; + *(uint8_t *)(dispMemAddr) = display.screenAttr; + display.screenAttrBuf[(display.screenRow * display.maxScreenCol) + display.displayCol] = display.screenAttr; + if(++display.displayCol >= display.maxScreenCol) + { + if(display.lineWrap) + { + // Increment line and scroll if necessary. + display.displayCol = 0; + mzScrollUp(1, 1); + } else + { + display.displayCol = display.maxScreenCol-1; + } + } + } + + if(display.debug && !display.inDebug) mzDebugOut(3, c); + return(0); +} + +// Stream method to output a character to the display. This method becomes the defacto output for system calls (ie. printf). +// +int mzPrintChar(char c, FILE *stream) +{ + // If the ansi terminal emulator is enabled, parse the character through the emulator. + if(display.useAnsiTerm) + { + mzAnsiTerm(c); + } else + { + mzPutChar(c, stream); + } + return(0); +} + +// Method to put a character onto the screen without character interpretation. +// +int mzPutRaw(char c) +{ + // Variables and locals. + uint32_t dispMemAddr; + + // Output character using default attributes. + dispMemAddr = VIDEO_VRAM_BASE_ADDR + (display.displayRow * display.maxScreenCol) + display.displayCol; + *(uint8_t *)(dispMemAddr) = (char)dispCodeMap[c].dispCode; + display.screenCharBuf[(display.screenRow * display.maxScreenCol) + display.displayCol] = c; + // + dispMemAddr = VIDEO_ARAM_BASE_ADDR + (display.displayRow * display.maxScreenCol) + display.displayCol; + *(uint8_t *)(dispMemAddr) = display.screenAttr; + display.screenAttrBuf[(display.screenRow * display.maxScreenCol) + display.displayCol] = display.screenAttr; + if(++display.displayCol >= display.maxScreenCol) + { + if(display.lineWrap) + { + // Increment line and scroll if necessary. + display.displayCol = 0; + mzScrollUp(1, 0); + } else + { + display.displayCol = display.maxScreenCol-1; + } + } + return(0); +} + +// Method to process an ANSI ESCape Set Attribute value into a Sharp MZ attribute setting. +// +uint8_t mzSetAnsiAttribute(uint8_t attr) +{ + // Process attribute command byte and set the corresponding Sharp setting. + switch(attr) + { + // Reset to default. + case 0: + display.screenAttr = VMATTR_FG_WHITE | VMATTR_BG_BLUE; + break; + + // Invert FG/BG. + case 7: + // If background goes to white with default colours, it is not so readable so change foreground colour. + if((display.screenAttr & VMATTR_FG_MASKIN) == VMATTR_FG_WHITE) + { + display.screenAttr = VMATTR_FG_WHITE | VMATTR_BG_RED; + } else + { + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKIN) >> 4 | (display.screenAttr & VMATTR_BG_MASKIN) << 4; + } + break; + + // Foreground black. + case 30: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_BLACK; + break; + + // Foreground red. + case 31: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_RED; + break; + + // Foreground green. + case 32: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_GREEN; + break; + + // Foreground yellow. + case 33: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_YELLOW; + break; + + // Foreground blue. + case 34: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_BLUE; + break; + + // Foreground magenta. + case 35: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_PURPLE; + break; + + // Foreground cyan. + case 36: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_CYAN; + break; + + // Foreground white. + case 37: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_WHITE; + break; + + // Default Foreground colour. + case 39: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_WHITE; + break; + + // Background black. + case 40: + display.screenAttr = (display.screenAttr & VMATTR_BG_MASKOUT) | VMATTR_BG_BLACK; + break; + + // Background red. + case 41: + display.screenAttr = (display.screenAttr & VMATTR_BG_MASKOUT) | VMATTR_BG_RED; + break; + + // Background green. + case 42: + display.screenAttr = (display.screenAttr & VMATTR_BG_MASKOUT) | VMATTR_BG_GREEN; + break; + + // Background yellow. + case 43: + display.screenAttr = (display.screenAttr & VMATTR_BG_MASKOUT) | VMATTR_BG_YELLOW; + break; + + // Background blue. + case 44: + display.screenAttr = (display.screenAttr & VMATTR_BG_MASKOUT) | VMATTR_BG_BLUE; + break; + + // Background magenta. + case 45: + display.screenAttr = (display.screenAttr & VMATTR_BG_MASKOUT) | VMATTR_BG_PURPLE; + break; + + // Background cyan. + case 46: + display.screenAttr = (display.screenAttr & VMATTR_BG_MASKOUT) | VMATTR_BG_CYAN; + break; + + // Background white. + case 47: + display.screenAttr = (display.screenAttr & VMATTR_BG_MASKOUT) | VMATTR_BG_WHITE; + break; + + // Default Background colour. + case 49: + display.screenAttr = (display.screenAttr & VMATTR_FG_MASKOUT) | VMATTR_FG_BLUE; + break; + + // Not supported. + default: + break; + } + return(0); +} + +// Simple Ansi Terminal escape sequence parser. This translates ANSI Escape sequences output by programs such as the Kilo Editor +// into actual display updates. +// +int mzAnsiTerm(char c) +{ + // Locals. + char *ptr; + long result; + + // State machine to process the incoming character stream. Look for ANSI escape sequences and process else display the character. + switch (ansiterm.state) + { + // Looking for an ESC character, if one is found move to the next state else just process the character for output. + case ANSITERM_ESC: + default: + switch(c) + { + // Enhanced escape sequence start. + case ESC: + ansiterm.charcnt = 0; + ansiterm.paramcnt = 0; + ansiterm.setScreenMode = 0; + ansiterm.setExtendedMode = 0; + ansiterm.state = ANSITERM_BRACKET; + break; + + // Return to start of line? + case CR: + display.displayCol = 0; + break; + + // New line? + case LF: + // Increment line and scroll if necessary. + mzScrollUp(1, 1); + display.displayCol = 0; + break; + + // Backspace. + case BACKS: + mzFlashCursor(CURSOR_RESTORE); + display.displayCol = display.displayCol == 0 ? 0 : display.displayCol -1; + break; + + // Delete. + case DELETE: + mzFlashCursor(CURSOR_RESTORE); + display.displayCol = display.displayCol == 0 ? 0 : display.displayCol -1; + mzPutRaw(SPACE); + display.displayCol = display.displayCol == 0 ? 0 : display.displayCol -1; + break; + + // Tab - expand by printing whitespace. + case TAB: + mzFlashCursor(CURSOR_RESTORE); + for(uint8_t idx=0; idx < 4; idx++) + mzPutRaw(SPACE); + break; + + default: + mzPutRaw(c); + break; + } + break; + + // Escape found, no look for next in the ESCape sequence or abort the state if a character is received which is not expected, print the character. + case ANSITERM_BRACKET: + switch(c) + { + case ESC: + break; + + case '[': + ansiterm.state = ANSITERM_PARSE; + break; + + case '7': + // Save the current cursor position. + ansiterm.saveRow = display.displayRow; + ansiterm.saveCol = display.displayCol; + ansiterm.saveScreenRow = display.screenRow; + ansiterm.state = ANSITERM_ESC; + break; + + case '8': + // Restore the current cursor position. + display.displayRow = ansiterm.saveRow; + display.displayCol = ansiterm.saveCol; + display.screenRow = ansiterm.saveScreenRow; + ansiterm.state = ANSITERM_ESC; + break; + + default: + ansiterm.state = ANSITERM_ESC; + mzPutRaw(c); + break; + } + break; + + // Parse the ESCAPE sequence. If digits come in then these are parameters so store and parse into the parameter array. When a terminating command is received, execute the desired command. + case ANSITERM_PARSE: + // Multiple Escapes, or incomplete sequences. If an escape occurs then go back to looking for a bracket or similar as we are on a + // different escape sequence. + if(c == ESC) + { + ansiterm.state = ANSITERM_BRACKET; + } + else if(isdigit(c)) + { + ansiterm.charbuf[ansiterm.charcnt++] = c; + ansiterm.charbuf[ansiterm.charcnt] = 0x00; + } + else if(c == ';') + { + ptr = (char *)&ansiterm.charbuf; + if(!xatoi(&ptr, &result)) + { + ansiterm.state = ANSITERM_ESC; + } else + { + ansiterm.param[ansiterm.paramcnt++] = (uint16_t)result; + } + ansiterm.charcnt = 0; + } + else if(c == '=') + { + ansiterm.setScreenMode = 1; + } + else if(c == '?') + { + ansiterm.setExtendedMode = 1; + } + else + { + // No semicolon so attempt to get the next parameter before processing command. + if(ansiterm.charcnt > 0) + { + ptr = (char *)&ansiterm.charbuf; + if(xatoi(&ptr, &result)) + { + ansiterm.param[ansiterm.paramcnt++] = (uint16_t)result; + } + } + + // Process the command now parameters have been retrieved. + switch(c) + { + // Position cursor. + case 'H': + // Set the cursor to given co-ordinates. + if(ansiterm.paramcnt >= 2) + { + mzSetCursor((uint8_t)ansiterm.param[1]-1, (uint8_t)ansiterm.param[0]-1); + } + // Home cursor. + else if(ansiterm.paramcnt == 0) + { + mzSetCursor(0, 0); + } + break; + + // Move cursor up. + case 'A': + if(ansiterm.paramcnt > 0) + { + mzMoveCursor(CURSOR_UP, (uint8_t)ansiterm.param[0]); + } else + { + mzMoveCursor(CURSOR_UP, 1); + } + break; + + // Move cursor down. + case 'B': + if(ansiterm.paramcnt > 0) + { + mzMoveCursor(CURSOR_DOWN, (uint8_t)ansiterm.param[0]); + } else + { + mzMoveCursor(CURSOR_DOWN, 1); + } + break; + + // Move cursor right. + case 'C': + if(ansiterm.paramcnt > 0) + { + mzMoveCursor(CURSOR_RIGHT, (uint8_t)ansiterm.param[0]); + } else + { + mzMoveCursor(CURSOR_RIGHT, 1); + } + break; + + // Move cursor left. + case 'D': + if(ansiterm.paramcnt > 0) + { + mzMoveCursor(CURSOR_LEFT, (uint8_t)ansiterm.param[0]); + } else + { + mzMoveCursor(CURSOR_LEFT, 1); + } + break; + + // Move cursor to start of next line. + case 'E': + mzMoveCursor(CURSOR_NEXT_LINE, 0); + break; + + // Move cursor to start of previous line. + case 'F': + mzMoveCursor(CURSOR_PREV_LINE, 0); + break; + + // Move cursor to absolute column position. + case 'G': + if(ansiterm.paramcnt > 0) + { + mzMoveCursor(CURSOR_COLUMN, (uint8_t)ansiterm.param[0]-1); + } else + { + mzMoveCursor(CURSOR_COLUMN, 0); + } + break; + + // Scroll up. + case 'S': + if(ansiterm.paramcnt > 0) + { + mzScrollUp((uint8_t)ansiterm.param[0], 0); + } else + { + mzScrollUp(1, 0); + } + break; + + // Scroll down. + case 'T': + if(ansiterm.paramcnt > 0) + { + mzScrollDown((uint8_t)ansiterm.param[0]); + } else + { + mzScrollDown(1); + } + break; + + case 'R': + printf("Report Cursor:"); + for(uint8_t idx=0; idx < ansiterm.paramcnt; idx++) + printf("%d,", ansiterm.param[idx]); + printf("\n"); + break; + + case 's': + // Save the current cursor position. + ansiterm.saveRow = display.displayRow; + ansiterm.saveCol = display.displayCol; + ansiterm.saveScreenRow = display.screenRow; + break; + + case 'u': + // Restore the current cursor position. + display.displayRow = ansiterm.saveRow; + display.displayCol = ansiterm.saveCol; + display.screenRow = ansiterm.saveScreenRow; + break; + + // Report data. + case 'n': { + char response[MAX_KEYB_BUFFER_SIZE]; + + // Report current cursor position? + // + if(ansiterm.paramcnt > 0 && ansiterm.param[0] == 6) + { + // Build response and push onto keyboard buffer. + sprintf(response, "%c[%d;%dR", ESC, display.displayRow+1, display.displayCol+1); + mzPushKey(response); + } + } break; + + // Clear Screen or block of screen. + case 'J': { + // Default is to clear the complete display but not scrollback buffer. + int clearMode = 2; + if(ansiterm.paramcnt > 0 && ansiterm.param[0] < 4) + { + clearMode = ansiterm.param[0]; + } + mzClearScreen(clearMode, 1); + } break; + + // Clear line. + case 'K': { + int clearRow = -1; + int clearColStart = 0; + int clearColEnd = display.maxScreenCol-1; + if(ansiterm.paramcnt > 0) + { + // 0 = clear cursor to end of line. + if(ansiterm.param[0] == 0) + { + clearColStart = display.displayCol; + } + // 1 = clear from beginning to cursor. + else if(ansiterm.param[0] == 1) + { + clearColEnd = display.displayCol; + } + // 2 = clear whole line. + } + mzClearLine(clearRow, clearColStart, clearColEnd, 0); + } break; + + // Set Display Attributes. + case 'm': + // Process all the attributes. + for(uint8_t idx=0; idx < ansiterm.paramcnt; idx++) + { + mzSetAnsiAttribute(ansiterm.param[idx]); + } + break; + + case 'h': + // Show cursor? + if(ansiterm.paramcnt > 0 && ansiterm.param[0] == 25) + { + mzFlashCursor(CURSOR_ON); + } + break; + + case 'l': + // Hide cursor? + if(ansiterm.paramcnt > 0 && ansiterm.param[0] == 25) + { + mzFlashCursor(CURSOR_OFF); + } + break; + + default: + mzPutRaw(c); + ansiterm.state = ANSITERM_ESC; + break; + } + ansiterm.state = ANSITERM_ESC; + + if(display.debug && !display.inDebug) mzDebugOut(1, c); + } + break; + } + return(0) ; +} + +// Method to output debug data to track issues with the display or ansi emulator. +// +void mzDebugOut(uint8_t set, uint8_t data1) +{ + // Save current coordinates. + uint8_t sr = display.displayRow; + uint8_t scr= display.screenRow; + uint8_t sc = display.displayCol; + uint8_t uat= display.useAnsiTerm; + + // Disable ansi terminal so we dont get recursion issues when we call printf. Disable further debug calls whilst data + // is being output. + display.useAnsiTerm = 0; + display.inDebug = 1; + + switch(set) + { + // Debug data to show the escape sequence and parameters. + case 1: { + // Set location where debug data should be displayed. + display.displayRow = 0; + display.displayCol = 40; + display.screenRow = 0; + + // Output required data. + printf("D:%d-%d-%d:%c:%d,%d,%d:", sr,sc,scr,data1,ansiterm.paramcnt, ansiterm.setScreenMode, ansiterm.setExtendedMode); + for(uint8_t idx=0; idx < ansiterm.paramcnt; idx++) + printf("%d,", ansiterm.param[idx]); + printf(" "); + + // Set a delay so that the change can be seen. + //TIMER_MILLISECONDS_UP = 0; while(TIMER_MILLISECONDS_UP < 50); + } break; + + case 2: { + // Set location where debug data should be displayed. + display.displayRow = 1; + display.displayCol = 40; + display.screenRow = 1; + + printf("K:%d:", strlen(keyboard.keyBuf)); + for(uint8_t idx=0; idx < strlen(keyboard.keyBuf); idx++) + printf("%02x,", keyboard.keyBuf[idx]); + + // Set a delay so that the change can be seen. + //TIMER_MILLISECONDS_UP = 0; while(TIMER_MILLISECONDS_UP < 100); + } break; + + case 3: { + // Set location where debug data should be displayed. + display.displayRow = 2; + display.displayCol = 40; + display.screenRow = 2; + + printf("X:%d,%d,%d,%d,%d,%d:%02x", sr, sc, scr, display.maxScreenRow, display.maxDisplayRow, display.maxScreenCol, data1); + + // Set a delay so that the change can be seen. + //TIMER_MILLISECONDS_UP = 0; while(TIMER_MILLISECONDS_UP < 1000); + } break; + + // No set defined, illegal call! + default: + break; + } + + // Restore ansi emulation mode and disable further debug calls. + display.useAnsiTerm = uat; + display.inDebug = 0; + + // Restore coordinates + display.displayRow = sr; + display.screenRow = scr; + display.displayCol = sc; + return; +} + +// Method to flash a cursor at current X/Y location on the physical screen. +uint8_t mzFlashCursor(enum CURSOR_STATES state) +{ + // Locals. + uint32_t dispMemAddr = VIDEO_VRAM_BASE_ADDR + (display.displayRow * display.maxScreenCol) + display.displayCol; + uint16_t srcIdx = (display.screenRow * display.maxScreenCol) + display.displayCol; + + // Action according to request. + switch(state) + { + // Disable the cursor flash mechanism. + case CURSOR_OFF: + default: + // Only restore character if it had been previously saved and active. + if(keyboard.cursorOn == 1 && keyboard.displayCursor == 1) + { + *(uint8_t *)(dispMemAddr) = dispCodeMap[display.screenCharBuf[srcIdx]].dispCode; + } + keyboard.cursorOn = 0; + break; + + // Enable the cursor mechanism. + case CURSOR_ON: + keyboard.cursorOn = 1; + break; + + // Restore the character under the cursor. + case CURSOR_RESTORE: + if(keyboard.displayCursor == 1) + { + *(uint8_t *)(dispMemAddr) = dispCodeMap[display.screenCharBuf[srcIdx]].dispCode; + } + break; + + // If enabled and timer expired, flash cursor. + case CURSOR_FLASH: + if(keyboard.cursorOn == 1 && (keyboard.flashTimer == 0L || keyboard.flashTimer + KEYB_FLASH_TIME < RTC_MILLISECONDS_EPOCH)) + { + keyboard.displayCursor = keyboard.displayCursor == 1 ? 0 : 1; + keyboard.flashTimer = RTC_MILLISECONDS_EPOCH; + if(keyboard.displayCursor == 1) + { + switch(keyboard.mode) + { + case KEYB_LOWERCASE: + *(uint8_t *)(dispMemAddr) = CURSOR_UNDERLINE; + break; + case KEYB_CAPSLOCK: + *(uint8_t *)(dispMemAddr) = CURSOR_BLOCK; + break; + case KEYB_SHIFTLOCK: + default: + *(uint8_t *)(dispMemAddr) = CURSOR_THICK_BLOCK; + break; + } + } else + { + *(uint8_t *)(dispMemAddr) = dispCodeMap[display.screenCharBuf[srcIdx]].dispCode; + } + } + break; + } + return(0); +} + +// A method to push keys into the keyboard buffer as though they had been pressed. This +// is necessary for the ANSI Terminal emulation but also a useful feature for applications. +// +uint8_t mzPushKey(char *keySeq) +{ + uint8_t seqSize = strlen(keySeq); + + // Sanity check, cant push more keys then the keyboard buffer will hold. + // + if((keyboard.keyBufPtr + seqSize) > MAX_KEYB_BUFFER_SIZE) + return(1); + + // Concat the key sequence into the keyboard buffer. + // + strcat(keyboard.keyBuf, keySeq); + + return(0); +} + +// Method to sweep the keyboard and store any active keys. Detect key down, key up and keys being held. +uint8_t mzSweepKeys(void) +{ + // Sequence through the strobe lines and read back the scan data into the buffer. + for(uint8_t strobe=0xF0; strobe < 0xFA; strobe++) + { + // Output the keyboard strobe. + *(volatile uint8_t *)(MBADDR_8BIT_KEYPA) = strobe; + + // Slight delay to allow for bounce. + TIMER_MILLISECONDS_UP = 0; while(TIMER_MILLISECONDS_UP < 1); + + // Read the scan lines. + keyboard.scanbuf[0][strobe-0xF0] = (uint8_t)(*(volatile uint32_t *)(MBADDR_8BIT_KEYPB)); +// keyboard.scanbuf[0][strobe-0xF0] = (uint8_t)(*(volatile uint32_t *)(MBADDR_8BIT_KEYPB)); +//printf("R%02x ", (uint8_t)(*(volatile uint32_t *)(MBADDR_8BIT_KEYPB))); + + } + + // Now look for active keys. + for(uint8_t strobeIdx=0; strobeIdx < 10; strobeIdx++) + { + // Skip over modifier keys. + //if(strobeIdx == 8) continue; + + if(keyboard.scanbuf[0][strobeIdx] != keyboard.scanbuf[1][strobeIdx]) + { + if(keyboard.scanbuf[0][strobeIdx] != 0xFF) + { + keyboard.keydown[strobeIdx] = keyboard.scanbuf[0][strobeIdx]; + } else + { + keyboard.keydown[strobeIdx] = 0xFF; + } + + if(keyboard.scanbuf[1][strobeIdx] != 0xFF) + { + keyboard.keyup[strobeIdx] = keyboard.scanbuf[1][strobeIdx]; + } else + { + keyboard.keyup[strobeIdx] = 0xFF; + } + } else + { + if(keyboard.scanbuf[0][strobeIdx] != 0xFF) + { + keyboard.keyhold[strobeIdx]++; + } else + { + keyboard.keyhold[strobeIdx] = 0; + keyboard.keydown[strobeIdx] = 0xFF; + keyboard.keyup[strobeIdx] = 0xFF; + } + } + keyboard.scanbuf[1][strobeIdx] = keyboard.scanbuf[0][strobeIdx]; + } +//printf("\n"); + + // Check for modifiers. + // + if((keyboard.scanbuf[0][8] & 0x80) == 0) + { + keyboard.breakKey = 1; + } else + { + keyboard.breakKey = 0; + } + if((keyboard.scanbuf[0][8] & 0x40) == 0) + { + keyboard.ctrlKey = 1; + } else + { + keyboard.ctrlKey = 0; + } + if((keyboard.scanbuf[0][8] & 0x01) == 0) + { + keyboard.shiftKey = 1; + } else + { + keyboard.shiftKey = 0; + } + + return(0); +} + +// Method to scan the keyboard and return any valid key presses. +// Input: mode = 0 - No blocking, standard keyboard. +// 1 - blocking, standard keyboard. +// 2 - No blocking, ansi keyboard. +// 3 - blocking, ansi keyboard. +// Return: -1 = no key pressed. +// ASCII value when key pressed. +int mzGetKey(uint8_t mode) +{ + // Locals. + int retcode = -1; + + // Return buffered key strokes first, once exhausted scan for more. + // + if(keyboard.keyBuf[keyboard.keyBufPtr] != 0x00) + { + retcode = (int)keyboard.keyBuf[keyboard.keyBufPtr++]; + } + else + { + // Loop if blocking flag set until a key is pressed else get a key if available and return. + do { + // Flash the cursor as needed. + mzFlashCursor(CURSOR_FLASH); + + // Make a sweep of the keyboard, updating the key map. + mzSweepKeys(); + + // Run through the strobe sequence and identify any pressed keys, mapping to an ASCII value for return. + for(uint8_t strobeIdx=0; strobeIdx < 10; strobeIdx++) + { + // Skip over modifier keys. + //if(strobeIdx == 8) continue; + + // If a keyboard press is released, cancel autorepeat. + if((keyboard.keydown[strobeIdx] != 0xFF && keyboard.keyhold[strobeIdx] == 0) || (keyboard.keyup[strobeIdx] != 0xFF && keyboard.keyhold[strobeIdx] > 0)) + { + keyboard.autorepeat = 0; + } else + if(keyboard.keydown[strobeIdx] != 0xFF && keyboard.keyhold[strobeIdx] == 1) + { + uint8_t keyIdx = 0; + uint8_t key = keyboard.keydown[strobeIdx]; + uint8_t modifiedMode = keyboard.ctrlKey == 1 ? KEYB_CTRL : keyboard.mode == KEYB_LOWERCASE && keyboard.shiftKey == 1 ? KEYB_SHIFTLOCK : keyboard.mode == KEYB_SHIFTLOCK && keyboard.shiftKey == 1 ? KEYB_CAPSLOCK : keyboard.mode == KEYB_CAPSLOCK && keyboard.shiftKey == 1 ? KEYB_LOWERCASE : keyboard.mode; + for(; keyIdx < 8 && key & 0x80; keyIdx++, key=key << 1); + retcode = scanCodeMap[modifiedMode].scanCode[(strobeIdx*8)+keyIdx]; + + // Setup auto repeat. + keyboard.repeatKey = retcode; + keyboard.holdTimer = RTC_MILLISECONDS_EPOCH; + } else + if(keyboard.keydown[strobeIdx] != 0xFF && keyboard.keyhold[strobeIdx] > 1 && keyboard.holdTimer + KEYB_AUTOREPEAT_INITIAL_TIME < RTC_MILLISECONDS_EPOCH) + { + keyboard.autorepeat = 1; + keyboard.holdTimer = RTC_MILLISECONDS_EPOCH; + } else + if(keyboard.keydown[strobeIdx] != 0xFF && keyboard.keyhold[strobeIdx] > 1 && keyboard.autorepeat == 1 && keyboard.holdTimer + KEYB_AUTOREPEAT_TIME < RTC_MILLISECONDS_EPOCH) + { + keyboard.holdTimer = RTC_MILLISECONDS_EPOCH; + retcode = keyboard.repeatKey; + } + } + + // Process internal keys, dont return. + // + switch(retcode) + { + // Toggle through the 3 key locks, lowercase, shiftlock, capslock. + case ALPHAKEY: + keyboard.mode = keyboard.mode == KEYB_LOWERCASE ? KEYB_SHIFTLOCK : keyboard.mode == KEYB_SHIFTLOCK ? KEYB_CAPSLOCK : KEYB_LOWERCASE; + retcode = -1; + break; + + // Switch to graphics mode character set. + case GRAPHKEY: + keyboard.mode = keyboard.mode == KEYB_GRAPHMODE ? KEYB_CAPSLOCK : KEYB_GRAPHMODE; + retcode = -1; + break; + + // If the debug key is pressed, toggle the debugging output on/off. + case DEBUGKEY: + display.debug = (display.debug == 0 ? 1 : 0); + retcode = -1; + break; + + // If the Ansi Toggle Key is pressed, toggle enabling of the Ansi Terminal Emulator (1), or raw Sharp (0). + case ANSITGLKEY: + display.useAnsiTerm = (display.useAnsiTerm == 0 ? 1 : 0); + retcode = -1; + break; + + // Send cursor to 0,0. + case CURHOMEKEY: + mzSetCursor(0,0); + retcode = -1; + break; + + // Clear screen. + case CLRKEY: + mzClearScreen(3, 1); + retcode = -1; + + // No key assigned. + case NOKEY: + retcode = -1; + + default: + break; + } + + } while(retcode == -1 && (mode == 1 || mode == 3)); + + // If we are in ANSI terminal mode, certain keys need expansion into ANSI ESCape sequences, detect the key and expand as necessary. + // + if((display.useAnsiTerm == 1 || mode == 2 || mode == 3) && retcode != -1) + { + for(uint8_t idx=0; idx < (sizeof(ansiKeySeq)/sizeof(*ansiKeySeq)); idx++) + { + // On match, copy the escape sequence into the keyboard buffer and set pointer to start of buffer+1. + if(ansiKeySeq[idx].key == retcode) + { + strcpy(keyboard.keyBuf, ansiKeySeq[idx].ansiKeySequence); + keyboard.keyBufPtr = 0; + retcode=(int)keyboard.keyBuf[keyboard.keyBufPtr++]; + break; + } + } + if(display.debug && !display.inDebug) mzDebugOut(2, retcode); + } + } + + return(retcode); +} + +// File stream method to get a key from the keyboard. +// +int mzGetChar(FILE *stream) +{ + return(mzGetKey(1)); +} + +// A helper method to wait for a change in the service request status with timeout. +int mzSDGetStatus(uint32_t timeout, uint8_t initStatus) +{ + uint32_t timeoutMS = RTC_MILLISECONDS_EPOCH; + uint8_t result; + + // Wait for the status to update, dont read status continuously as a transaction can delay the K64F from requesting the bus to make an update. + do { + for(uint32_t timeMS = RTC_MILLISECONDS_EPOCH; timeMS == RTC_MILLISECONDS_EPOCH;); + result = svcControl->result; + } while(timeoutMS + timeout > RTC_MILLISECONDS_EPOCH && initStatus == result); + + return(timeoutMS + timeout > RTC_MILLISECONDS ? (int)result : -1); +} + +// Method to make a generic service call to the K64F processor. +// +int mzServiceCall(uint8_t cmd) +{ + // Locals. + uint8_t retries; + uint8_t result = 0; + int status; + + // Place command to be executed in control structure. + svcControl->cmd = cmd; + + // Retry the command a number of times when failure occurs to allow for the I/O processor being busy. + retries = TZSVC_RETRY_COUNT; + do { + // Instigate a service request + svcControl->result = TZSVC_STATUS_REQUEST; + *(volatile uint8_t *)(MBADDR_8BIT_IOW_SVCREQ) = 0x00; + + // Error occurred? + if((status=mzSDGetStatus(TZSVC_TIMEOUT, TZSVC_STATUS_REQUEST)) != -1) + { + status=mzSDGetStatus(TZSVC_TIMEOUT, TZSVC_STATUS_PROCESSING); + } + retries--; + } while(retries > 0 && (uint8_t)status != TZSVC_STATUS_OK); + + return(retries == 0 ? -1 : status); +} + +// Method to make a service call to the K64F processor. Actual data copy in/out is made outside this method as it only takes care of actually +// making the command request and getting the status back. +// +int mzSDServiceCall(uint8_t drive, uint8_t cmd) +{ + // Locals. + int status; + + // Setup control structure to request a disk sector from the I/O processor. + svcControl->fileSector = drive; + + // Make the call. + status = mzServiceCall(cmd); + + return(status); +} + +// Method to initialise an SD card hosted on the I/O processor. This is accomplished by a service request to the I/O processor +// and it takes care of the initialisation. +// +uint8_t mzSDInit(uint8_t drive) +{ + // Locals. + uint8_t result = 0; + int status; + + // Make the initialisation service call. + status = mzSDServiceCall(drive, TZSVC_CMD_SD_DISKINIT); + + // Did we get a successful service? + if(status == -1 || (uint8_t)status != TZSVC_STATUS_OK) + { + result = 1; + } + return(result); +} + +// Method to read a sector from the SD card hosted on the I/O processor. This is accomplished by a service request to the I/O processor +// and it will read the required sector and place it into the service control record. +// +uint8_t mzSDRead(uint8_t drive, uint32_t sector, uint32_t buffer) +{ + // Locals. + uint8_t result = 0; + int status; + + // Setup control structure to request a disk sector from the I/O processor. + svcControl->sectorLBA = convBigToLittleEndian(sector); + + // Make the disk read service call. + status = mzSDServiceCall(drive, TZSVC_CMD_SD_READSECTOR); + + // Did we get a successful service? + if((uint8_t)status == TZSVC_STATUS_OK) + { + // Copy the received sector into the provided buffer. + for(uint32_t srcAddr=(uint32_t)svcControl->sector, dstAddr=buffer; dstAddr < buffer+TZSVC_SECTOR_SIZE; srcAddr++, dstAddr++) + { + *(uint8_t *)(dstAddr) = *(uint8_t *)srcAddr; + } + } else + { + result = 1; + } + return(result); +} + +// Method to write a sector to the SD card hosted on the I/O processor. This is accomplished by placing data into the service control record +// and making a service request to the I/O processor which will write the data to the required sector. +// +uint8_t mzSDWrite(uint8_t drive, uint32_t sector, uint32_t buffer) +{ + // Locals. + uint8_t result = 0; + int status; + + // Setup control structure to request writing of a sector to a disk on the I/O processor. + svcControl->sectorLBA = convBigToLittleEndian(sector); + + // Copy the provided buffer into service control record sector buffer. + for(uint32_t srcAddr=buffer, dstAddr=(uint32_t)svcControl->sector; srcAddr < buffer+TZSVC_SECTOR_SIZE; srcAddr++, dstAddr++) + { + *(uint8_t *)(dstAddr) = *(uint8_t *)srcAddr; + } + + // Make the disk write service call. + status = mzSDServiceCall(drive, TZSVC_CMD_SD_WRITESECTOR); + + // Did we get a successful service? + if((uint8_t)status != TZSVC_STATUS_OK) + { + result = 1; + } + return(result); +} + +// Method to exit from zOS/ZPU CPU and return control to the host Z80 CPU. +// +void mzSetZ80(void) +{ + // We could write direct to the CPU selection port but the host ROM may well be required as the ZPU uses it's memory. For this reason + // we make a call to the I/O processor which will load the rom, switch CPU and perform a reset. + mzServiceCall(TZSVC_CMD_CPU_SETZ80); + + // Loop forever waiting for the CPU switch or a reset. + while(1); +} + +////////////////////////////////////////////////////////////// +// End of Sharp MZ i/f methods for zOS // +////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////// +// Temporary test routines // +////////////////////////////////////////////////////////////// + +// Dummy function used for testing, it's contents change over time as tests are made on various hardware components. +int mzGetTest() +{ + uint8_t nl = 0; + while(1) + { + mzSweepKeys(); + TIMER_MILLISECONDS_UP = 0; while(TIMER_MILLISECONDS_UP < 250); + //mzSweepKeys(); + + for(uint8_t strobeIdx=0; strobeIdx < 9; strobeIdx++) + { + if(keyboard.keyup[strobeIdx] != 0xFF) + { + uint8_t keyIdx = 0; + uint8_t key = keyboard.keyup[strobeIdx]; + for(; keyIdx < 8 && key & 0x80; keyIdx++, key=key << 1); + printf("Up:%02x %02x", keyboard.keyup[strobeIdx], scanCodeMap[0].scanCode[(strobeIdx*8)+keyIdx]); + nl = 1; + } + if(keyboard.keydown[strobeIdx] != 0xFF) + { + uint8_t keyIdx = 0; + uint8_t key = keyboard.keydown[strobeIdx]; + for(; keyIdx < 8 && key & 0x80; keyIdx++, key=key << 1); + printf("Dw:%02x %02x", keyboard.keyup[strobeIdx], scanCodeMap[0].scanCode[(strobeIdx*8)+keyIdx]); + nl = 1; + } + if(keyboard.keyhold[strobeIdx] != 0) + { + printf("Hd:%02x ", keyboard.keyhold[strobeIdx]); + nl = 1; + } + if(nl == 1) + { + printf("\n"); + nl = 0; + } + } + // TIMER_MILLISECONDS_UP = 0; while(TIMER_MILLISECONDS_UP < 1000); + } + return(-1); +} + +//// Test routine. Add code here to test an item within the kernel. Anything accessing hardware generally has to call the kernel as it doesnt have real access. +// +void testRoutine(void) +{ + // Locals. + // + printf("No test defined.\n"); +} +#endif // Protected methods which reside in the kernel. + +#if defined __APP__ +#endif // __APP__ + +#ifdef __cplusplus +} +#endif diff --git a/software/FusionX/src/driver/MZ80A/tzpu.h b/software/FusionX/src/z80drv/MZ80A/tzpu.h similarity index 100% rename from software/FusionX/src/driver/MZ80A/tzpu.h rename to software/FusionX/src/z80drv/MZ80A/tzpu.h diff --git a/software/FusionX/src/driver/MZ80A/z80ctrl.c b/software/FusionX/src/z80drv/MZ80A/z80ctrl.c similarity index 97% rename from software/FusionX/src/driver/MZ80A/z80ctrl.c rename to software/FusionX/src/z80drv/MZ80A/z80ctrl.c index 5c33ada5f..6dde0c153 100644 --- a/software/FusionX/src/driver/MZ80A/z80ctrl.c +++ b/software/FusionX/src/z80drv/MZ80A/z80ctrl.c @@ -581,9 +581,13 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa break; case Z80_CMD_ADD_DEVICE: ioctlCmd.vdev.device = VIRTUAL_DEVICE_NONE; - if(strcasecmp((char *)param1, "RFS") == 0) + if(strcasecmp((char *)param1, "RFS") == 0 || strcasecmp((char *)param1, "RFS80") == 0) { - ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS; + ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80; + } + if(strcasecmp((char *)param1, "RFS40") == 0) + { + ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40; } else if(strcasecmp((char *)param1, "TZPU") == 0) { @@ -597,9 +601,13 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa break; case Z80_CMD_DEL_DEVICE: ioctlCmd.vdev.device = VIRTUAL_DEVICE_NONE; - if(strcasecmp((char *)param1, "RFS") == 0) + if(strcasecmp((char *)param1, "RFS") == 0 || strcasecmp((char *)param1, "RFS80") == 0) { - ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS; + ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80; + } + else if(strcasecmp((char *)param1, "RFS40") == 0) + { + ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40; } else if(strcasecmp((char *)param1, "TZPU") == 0) { @@ -734,8 +742,8 @@ void showArgs(char *progName, struct optparse *options) printf(" = CONTINUE # Continue Z80 execution\n"); printf(" = HOSTRAM # Use HOST DRAM\n"); printf(" = VIRTRAM # Use Virtual RAM\n"); - printf(" = ADDDEV --device # Add a virtual device into the Z80 configuration.\n"); - printf(" = DELDEV --device # Remove a virtual device from the Z80 configuration.\n"); + printf(" = ADDDEV --device # Add a virtual device into the Z80 configuration.\n"); + printf(" = DELDEV --device # Remove a virtual device from the Z80 configuration.\n"); printf(" = SPEED --mult <1, 2, 4, 8, 16, 32, 64, 128> # In Virtual RAM mode, set CPU speed to base clock x factor.\n"); printf(" = LOADMZF --file # Load MZF file into RAM.\n"); printf(" # Load contents of binary file into memory at address. default = 0x000000.\n"); diff --git a/software/FusionX/src/driver/MZ80A/z80driver.c b/software/FusionX/src/z80drv/MZ80A/z80driver.c similarity index 99% rename from software/FusionX/src/driver/MZ80A/z80driver.c rename to software/FusionX/src/z80drv/MZ80A/z80driver.c index 8af67dd0a..afcb63763 100644 --- a/software/FusionX/src/driver/MZ80A/z80driver.c +++ b/software/FusionX/src/z80drv/MZ80A/z80driver.c @@ -1629,8 +1629,10 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) } if(idx < Z80Ctrl->virtualDeviceCnt) break; + #if(TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ2000 == 1) - pr_info("RFS Board currently supported on MZ-80A Host only.\n"); + if(ioctlCmd.vdev.device & VIRTUAL_DEVICE_RFS) + pr_info("RFS Board currently supported on MZ-80A Host only.\n"); break; #endif @@ -1644,10 +1646,11 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) switch(ioctlCmd.vdev.device) { #if(TARGET_HOST_MZ80A == 1) - case VIRTUAL_DEVICE_RFS: - Z80Ctrl->virtualDevice[Z80Ctrl->virtualDeviceCnt++] = VIRTUAL_DEVICE_RFS; - Z80Ctrl->virtualDeviceBitMap |= VIRTUAL_DEVICE_RFS; - rfsInit(); + case VIRTUAL_DEVICE_RFS40: + case VIRTUAL_DEVICE_RFS80: + Z80Ctrl->virtualDevice[Z80Ctrl->virtualDeviceCnt++] = ioctlCmd.vdev.device; + Z80Ctrl->virtualDeviceBitMap |= ioctlCmd.vdev.device; + rfsInit(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_RFS40 ? 0 : 1); break; #endif @@ -1698,8 +1701,9 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) // Delete the device, removing hooks etc as required. switch(ioctlCmd.vdev.device) { - case VIRTUAL_DEVICE_RFS: - Z80Ctrl->virtualDeviceBitMap &= ~VIRTUAL_DEVICE_RFS; + case VIRTUAL_DEVICE_RFS40: + case VIRTUAL_DEVICE_RFS80: + Z80Ctrl->virtualDeviceBitMap &= ~ioctlCmd.vdev.device; break; case VIRTUAL_DEVICE_TZPU: diff --git a/software/FusionX/src/driver/MZ80A/z80driver.h b/software/FusionX/src/z80drv/MZ80A/z80driver.h similarity index 99% rename from software/FusionX/src/driver/MZ80A/z80driver.h rename to software/FusionX/src/z80drv/MZ80A/z80driver.h index 44e3abe46..0a5f1b519 100644 --- a/software/FusionX/src/driver/MZ80A/z80driver.h +++ b/software/FusionX/src/z80drv/MZ80A/z80driver.h @@ -451,8 +451,10 @@ enum Z80_MEMORY_PROFILE { }; enum VIRTUAL_DEVICE { VIRTUAL_DEVICE_NONE = 0x00000000, - VIRTUAL_DEVICE_RFS = 0x02000000, - VIRTUAL_DEVICE_TZPU = 0x01000000 + VIRTUAL_DEVICE_RFS40 = 0x01000000, + VIRTUAL_DEVICE_RFS80 = 0x02000000, + VIRTUAL_DEVICE_RFS = 0x03000000, + VIRTUAL_DEVICE_TZPU = 0x04000000 }; typedef struct { diff --git a/software/FusionX/src/tty/z80io.c b/software/FusionX/src/z80drv/MZ80A/z80io.c similarity index 100% rename from software/FusionX/src/tty/z80io.c rename to software/FusionX/src/z80drv/MZ80A/z80io.c diff --git a/software/FusionX/src/driver/MZ80A/z80io.h b/software/FusionX/src/z80drv/MZ80A/z80io.h similarity index 100% rename from software/FusionX/src/driver/MZ80A/z80io.h rename to software/FusionX/src/z80drv/MZ80A/z80io.h diff --git a/software/FusionX/src/tty/z80io_test.c b/software/FusionX/src/z80drv/MZ80A/z80io_test.c similarity index 100% rename from software/FusionX/src/tty/z80io_test.c rename to software/FusionX/src/z80drv/MZ80A/z80io_test.c diff --git a/software/FusionX/src/driver/MZ80A/z80menu.c b/software/FusionX/src/z80drv/MZ80A/z80menu.c similarity index 100% rename from software/FusionX/src/driver/MZ80A/z80menu.c rename to software/FusionX/src/z80drv/MZ80A/z80menu.c diff --git a/software/FusionX/src/driver/MZ80A/z80menu.h b/software/FusionX/src/z80drv/MZ80A/z80menu.h similarity index 100% rename from software/FusionX/src/driver/MZ80A/z80menu.h rename to software/FusionX/src/z80drv/MZ80A/z80menu.h diff --git a/software/FusionX/src/driver/MZ80A/z80vhw_rfs.c b/software/FusionX/src/z80drv/MZ80A/z80vhw_rfs.c similarity index 92% rename from software/FusionX/src/driver/MZ80A/z80vhw_rfs.c rename to software/FusionX/src/z80drv/MZ80A/z80vhw_rfs.c index 592fdb6db..9e8c522f2 100644 --- a/software/FusionX/src/driver/MZ80A/z80vhw_rfs.c +++ b/software/FusionX/src/z80drv/MZ80A/z80vhw_rfs.c @@ -86,8 +86,30 @@ #define BNKCTRLDEF BBMOSI+SDCS+BBCLK // Default on startup for the Bank Control register. +// RFS Board ROM rom filename definitions. +#define ROM_DIR "/apps/FusionX/roms/" +#define ROM_MROM_40C_FILENAME ROM_DIR "MROM_256_40c.bin" +#define ROM_USER_I_40C_FILENAME ROM_DIR "USER_ROM_256_40c.bin" +#define ROM_USER_II_40C_FILENAME ROM_DIR "USER_ROM_II_256_40c.bin" +#define ROM_USER_III_40C_FILENAME ROM_DIR "USER_ROM_III_256_40c.bin" +#define ROM_MROM_80C_FILENAME ROM_DIR "MROM_256_80c.bin" +#define ROM_USER_I_80C_FILENAME ROM_DIR "USER_ROM_256_80c.bin" +#define ROM_USER_II_80C_FILENAME ROM_DIR "USER_ROM_II_256_80c.bin" +#define ROM_USER_III_80C_FILENAME ROM_DIR "USER_ROM_III_256_80c.bin" + +// RFS Board ROM rom load and size definitions. +#define ROM_MROM_LOAD_ADDR 0x000000 +#define ROM_USER_I_LOAD_ADDR 0x080000 +#define ROM_USER_II_LOAD_ADDR 0x100000 +#define ROM_USER_III_LOAD_ADDR 0x180000 +#define ROM_MROM_SIZE 0x80000 +#define ROM_USER_I_SIZE 0x80000 +#define ROM_USER_II_SIZE 0x80000 +#define ROM_USER_III_SIZE 0x80000 + // SD Drive constants. -#define SD_CARD_FILENAME "/apps/FusionX/SD/SHARP_MZ80A_RFS_CPM_IMAGE_1.img"// SD Card Binary Image. +#define SD_DIR "/apps/FusionX/SD/" +#define SD_CARD_FILENAME SD_DIR "SHARP_MZ80A_RFS_CPM_IMAGE_1.img"// SD Card Binary Image. // MMC/SD command (SPI mode) #define CMD0 0x40 + 0 // GO_IDLE_STATE @@ -203,9 +225,45 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode) pr_info("RFS Memory Setup complete.\n"); } -// Perform any setup operations, such as variable initialisation, to enable use of this module. -void rfsInit(void) +// Method to load a ROM image into the ROM memory. +// +uint8_t loadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize) { + // Locals. + uint8_t result = 0; + long noBytes; + struct file *fp; + + fp = filp_open(romFileName, O_RDONLY, 0); + if(IS_ERR(fp)) + { + pr_info("Error opening ROM Image:%s\n:", romFileName); + result = 1; + } else + { + vfs_llseek(fp, 0, SEEK_SET); + noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->rom[loadAddr], loadSize); + if(noBytes < loadSize) + { + // pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize); + } + filp_close(fp,NULL); + } + + return(result); +} + +// Perform any setup operations, such as variable initialisation, to enable use of this module. +void rfsInit(uint8_t mode80c) +{ + // Locals. + + // Load ROMS according to the display configuration, 40 char = standard, 80 char = 40/80 board installed. + loadROM(mode80c == 0 ? ROM_MROM_40C_FILENAME : ROM_MROM_80C_FILENAME, ROM_MROM_LOAD_ADDR, ROM_MROM_SIZE); + loadROM(mode80c == 0 ? ROM_USER_I_40C_FILENAME : ROM_USER_I_80C_FILENAME, ROM_USER_I_LOAD_ADDR, ROM_MROM_SIZE); + loadROM(mode80c == 0 ? ROM_USER_II_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_II_LOAD_ADDR, ROM_MROM_SIZE); + loadROM(mode80c == 0 ? ROM_USER_III_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_III_LOAD_ADDR, ROM_MROM_SIZE); + pr_info("Enabling RFS driver.\n"); } diff --git a/software/FusionX/src/driver/MZ80A/z80vhw_tzpu.c b/software/FusionX/src/z80drv/MZ80A/z80vhw_tzpu.c similarity index 100% rename from software/FusionX/src/driver/MZ80A/z80vhw_tzpu.c rename to software/FusionX/src/z80drv/MZ80A/z80vhw_tzpu.c diff --git a/software/FusionX/src/driver/Makefile b/software/FusionX/src/z80drv/Makefile similarity index 100% rename from software/FusionX/src/driver/Makefile rename to software/FusionX/src/z80drv/Makefile diff --git a/software/FusionX/src/driver/README.txt b/software/FusionX/src/z80drv/README.txt similarity index 100% rename from software/FusionX/src/driver/README.txt rename to software/FusionX/src/z80drv/README.txt diff --git a/software/FusionX/src/driver/Z80 b/software/FusionX/src/z80drv/Z80 similarity index 100% rename from software/FusionX/src/driver/Z80 rename to software/FusionX/src/z80drv/Z80 diff --git a/software/FusionX/src/driver/Z80.c b/software/FusionX/src/z80drv/Z80.c similarity index 100% rename from software/FusionX/src/driver/Z80.c rename to software/FusionX/src/z80drv/Z80.c diff --git a/software/FusionX/src/driver/Zeta b/software/FusionX/src/z80drv/Zeta similarity index 100% rename from software/FusionX/src/driver/Zeta rename to software/FusionX/src/z80drv/Zeta diff --git a/software/FusionX/src/driver/software/FusionX/src/driver/6502 b/software/FusionX/src/z80drv/software/FusionX/src/driver/6502 similarity index 100% rename from software/FusionX/src/driver/software/FusionX/src/driver/6502 rename to software/FusionX/src/z80drv/software/FusionX/src/driver/6502