diff --git a/buildall b/buildall index 57030db..5cda4b2 100755 --- a/buildall +++ b/buildall @@ -3,13 +3,9 @@ # Not used: Target machine, used to select the right software for the SD card. # TARGET=MZ-700 # TARGET=MZ-80A +TARGET=MZ-2000 -<<<<<<< HEAD -ZPU_SHARPMZ_BUILD=1 -======= -TARGET=MZ-80A ZPU_SHARPMZ_BUILD=0 ->>>>>>> 5a59ff2f96064433b95b8489dbe7e9b175b0accc #ZPU_SHARPMZ_APPADDR=0x100000 #ZPU_SHARPMZ_APPSIZE=0x70000 #ZPU_SHARPMZ_HEAPSIZE=0x8000 @@ -26,6 +22,8 @@ ZPU_E115_APPSIZE=0x8000 ZPU_E115_HEAPSIZE=0x4000 ZPU_E115_STACKSIZE=0x3D80 +echo "Build target: ${TARGET}" + # NB: When setting this variable, see lower section creating the SD card image which uses a hard coded value and will need updating. ROOT_DIR=/dvlp/Projects/dev/github/ # NB: This clean out is intentionally hard coded as -fr is dangerous, if a variable failed to be set if could see your source base wiped out. @@ -64,13 +62,6 @@ if [ "${ZPU_E115_BUILD}x" != "x" -a ${ZPU_E115_BUILD} = 1 ]; then cp -r build/SD/* SD/Dev/ fi -<<<<<<< HEAD -echo "Building for K64F" -./build.sh -C K64F -O zos -N 0x18000 -d -T -if [ $? != 0 ]; then - echo "Error building K64F Distribution..." - exit 1 -======= if [ "${TARGET}x" != "x" -a "${TARGET}" = "MZ-80A" ]; then echo "Building for K64F on MZ-80A" ./build.sh -C K64F -O zos -N 0x10000 -d -T @@ -78,6 +69,13 @@ if [ "${TARGET}x" != "x" -a "${TARGET}" = "MZ-80A" ]; then echo "Error building K64F Distribution..." exit 1 fi +elif [ "${TARGET}x" != "x" -a "${TARGET}" = "MZ-2000" ]; then + echo "Building for K64F on MZ-2000" + ./build.sh -C K64F -O zos -N 0x10000 -d -T + if [ $? != 0 ]; then + echo "Error building K64F Distribution..." + exit 1 + fi else echo "Building for K64F" ./build.sh -C K64F -O zos -N 0x18000 -d -T @@ -85,7 +83,6 @@ else echo "Error building K64F Distribution..." exit 1 fi ->>>>>>> 5a59ff2f96064433b95b8489dbe7e9b175b0accc fi cp -r build/SD/* SD/K64F/ diff --git a/common/emumz.c b/common/emumz.c index 246a725..914cf76 100644 --- a/common/emumz.c +++ b/common/emumz.c @@ -14,6 +14,9 @@ // Copyright: (c) 2019-2021 Philip Smart // // History: v1.0 May 2021 - Initial write of the EmuMZ software. +// v1.1 Nov 2021 - Further work on Video Controller and infrastructure. +// v1.2 Nov 2021 - Adding MZ2000 logic. +// v1.3 Dec 2021 - Adding MZ800 logic. // // Notes: See Makefile to enable/disable conditional components // @@ -73,8 +76,12 @@ extern "C" { #define __EMUMZ_DEBUG__ 1 // Debug macros -#define debugf(a, ...) if(emuControl.debug) { printf("\033[1;31mSHARPMZ: " a "\033[0m\n", ##__VA_ARGS__); } -#define debugfx(a, ...) if(emuControl.debug) { printf("\033[1;32mSHARPMZ: " a "\033[0m\n", ##__VA_ARGS__); } +#define debugf(a, ...) if(emuControl.debug) { printf("\033[1;31mEMUMZ: " a "\033[0m\n", ##__VA_ARGS__); } +#define debugfx(a, ...) if(emuControl.debug) { printf("\033[1;32mEMUMZ: " a "\033[0m\n", ##__VA_ARGS__); } + +// Version data. +#define EMUMZ_VERSION 1.4 +#define EMUMZ_VERSION_DATE "22/12/2021" ////////////////////////////////////////////////////////////// // Sharp MZ Series Emulation Service Methods // @@ -82,9 +89,10 @@ extern "C" { #ifndef __APP__ // Protected methods which should only reside in the kernel on zOS. -// Global scope variables used within the zOS kernel. +// Global scope variables used within the emuMZ core. // -static t_emuControl emuControl = { +// First the ROM based default constants. These are used in the initial startup/configuration or configuration reset. They are copied into working memory as needed. +const static t_emuControl emuControlDefault = { .active = 0, .debug = 1, .activeDialog = DIALOG_MENU, .activeMenu = { .menu[0] = MENU_DISABLED, .activeRow[0] = 0, .menuIdx = 0 @@ -94,7 +102,7 @@ static t_emuControl emuControl = { }, .menu = { .rowPixelStart = 15, .colPixelStart = 40, .padding = 2, .colPixelsEnd = 12, - .inactiveFgColour = WHITE, .inactiveBgColour = BLACK, .greyedFgColour = BLUE, .greyedBgColour = BLACK, .textFgColour = CYAN, .textBgColour = BLACK, .activeFgColour = BLUE, .activeBgColour = WHITE, + .inactiveFgColour = WHITE, .inactiveBgColour = BLACK, .greyedFgColour = BLUE, .greyedBgColour = BLACK, .textFgColour = PURPLE, .textBgColour = BLACK, .activeFgColour = BLUE, .activeBgColour = WHITE, .font = FONT_7X8, .rowFontptr = &font7x8extended, .activeRow = -1 }, @@ -106,107 +114,309 @@ static t_emuControl emuControl = { } }; -static t_emuConfig emuConfig = { - .machineModel = MZ80K_IDX, .machineChanged = 1, - .params[MZ80K_IDX] = { - .cpuSpeed = 0 , .audioSource = 0, .audioVolume = 0, .audioMute = 0, .displayType = 0, .displayOutput = 0, - .vramMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, - .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", - .cmtAsciiMapping = 3, .cmtMode = 0, - .romMonitor40 = { .romFileName = "0:\\TZFS\\sp1002.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romCG = { .romFileName = "0:\\TZFS\\mz80k_cgrom.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00000800 }, - .romKeyMap = { .romFileName = "0:\\TZFS\\mz80k_keymap.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 } +const static t_emuConfig emuConfigDefault = { + .machineModel = MZ80K, .machineGroup = GROUP_MZ80K, .machineChanged = 1, + .params[MZ80K] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_MONO, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\sp1002.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz80k_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00000800 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_80K_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00001000 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_FDC_ROM_ADDR, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } }, - .params[MZ80C_IDX] = { - .cpuSpeed = 0 , .audioSource = 0, .audioVolume = 0, .audioMute = 0, .displayType = 0, .displayOutput = 0, - .vramMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, - .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", - .cmtAsciiMapping = 3, .cmtMode = 0, - .romMonitor40 = { .romFileName = "0:\\TZFS\\sp1002.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romCG = { .romFileName = "0:\\TZFS\\mz80c_cgrom.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00000800 }, - .romKeyMap = { .romFileName = "0:\\TZFS\\mz80c_keymap.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 } + .params[MZ80C] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_MONO, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\sp1002.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz80c_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00000800 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_80C_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00001000 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_FDC_ROM_ADDR, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } }, - .params[MZ1200_IDX] = { - .cpuSpeed = 0 , .audioSource = 0, .audioVolume = 0, .audioMute = 0, .displayType = 0, .displayOutput = 0, - .vramMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, - .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", - .cmtAsciiMapping = 3, .cmtMode = 0, - .romMonitor40 = { .romFileName = "0:\\TZFS\\sp1002.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romCG = { .romFileName = "0:\\TZFS\\mz80c_cgrom.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00000800 }, - .romKeyMap = { .romFileName = "0:\\TZFS\\mz80c_keymap.rom", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 }, - .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 } + .params[MZ1200] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_MONO, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\sa1510.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz80c_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00000800 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_1200_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_FDC_ROM_ADDR, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } }, - .params[MZ80A_IDX] = { - .cpuSpeed = 0 , .audioSource = 0, .audioVolume = 0, .audioMute = 0, .displayType = 0, .displayOutput = 0, - .vramMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, - .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", - .cmtAsciiMapping = 3, .cmtMode = 0, - .romMonitor40 = { .romFileName = "0:\\TZFS\\sa1510.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romMonitor80 = { .romFileName = "0:\\TZFS\\sa1510-8.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romCG = { .romFileName = "0:\\TZFS\\mz80a_cgrom.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00000800 }, - .romKeyMap = { .romFileName = "0:\\TZFS\\mz80a_keymap.rom", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 }, - .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 } + .params[MZ80A] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_MONO, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\sa1510.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romMonitor80 = { .romFileName = "0:\\TZFS\\sa1510-8.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz80a_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00000800 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_80A_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_USER_ROM_ADDR, .loadSize = 0x00000800 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_FDC_ROM_ADDR, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } }, - .params[MZ700_IDX] = { - .cpuSpeed = 0 , .audioSource = 0, .audioVolume = 0, .audioMute = 0, .displayType = 0, .displayOutput = 0, - .vramMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, - .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", - .cmtAsciiMapping = 3, .cmtMode = 0, - .romMonitor40 = { .romFileName = "0:\\TZFS\\1z-013a.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romMonitor80 = { .romFileName = "0:\\TZFS\\1z-013a-8.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romCG = { .romFileName = "0:\\TZFS\\mz700_cgrom.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romKeyMap = { .romFileName = "0:\\TZFS\\mz700_keymap.rom", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 }, - .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 } + .params[MZ700] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_COLOUR, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\1z-013a.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romMonitor80 = { .romFileName = "0:\\TZFS\\1z-013a-8.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz700_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00001000 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_700_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00001000 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_FDC_ROM_ADDR, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } }, - .params[MZ800_IDX] = { - .cpuSpeed = 0 , .audioSource = 0, .audioVolume = 0, .audioMute = 0, .displayType = 0, .displayOutput = 0, - .vramMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, - .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", - .cmtAsciiMapping = 3, .cmtMode = 0, - .romMonitor40 = { .romFileName = "0:\\TZFS\\mz800_ipl.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00004000 }, - .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romCG = { .romFileName = "0:\\TZFS\\mz800_cgrom.rom", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romKeyMap = { .romFileName = "0:\\TZFS\\mz800_keymap.rom", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 }, - .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 } + .params[MZ800] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_COLOUR, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\mz800_ipl.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00004000 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz800_cgrom.rom", .romEnabled = 0, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00001000 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_800_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00001000 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } }, - .params[MZ80B_IDX] = { - .cpuSpeed = 0 , .audioSource = 0, .audioVolume = 0, .audioMute = 0, .displayType = 0, .displayOutput = 0, - .vramMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, - .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", - .cmtAsciiMapping = 3, .cmtMode = 0, - .romMonitor40 = { .romFileName = "0:\\TZFS\\mz80b-ipl.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romCG = { .romFileName = "0:\\TZFS\\mz80b_cgrom.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00000800 }, - .romKeyMap = { .romFileName = "0:\\TZFS\\mz80b_keymap.rom", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 }, - .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 } + .params[MZ1500] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_COLOUR, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\mz150_ipl.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00004000 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz1500_cgrom.rom", .romEnabled = 0, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00001000 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_1500_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00001000 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } }, - .params[MZ2000_IDX] = { - .cpuSpeed = 0 , .audioSource = 0, .audioVolume = 0, .audioMute = 0, .displayType = 0, .displayOutput = 0, - .vramMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, - .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", - .cmtAsciiMapping = 3, .cmtMode = 0, - .romMonitor40 = { .romFileName = "0:\\TZFS\\mz2000-ipl.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romCG = { .romFileName = "0:\\TZFS\\mz2000_cgrom.rom", .romEnabled = 1, .loadAddr = 0x00000000, .loadSize = 0x00000800 }, - .romKeyMap = { .romFileName = "0:\\TZFS\\mz2000_keymap.rom", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00001000 }, - .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 }, - .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x00000000, .loadSize = 0x00000100 } + .params[MZ80B] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_MONO, .displayOption = 2, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\mz80b_ipl.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00000800 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00000800 }, + .romCG = { .romFileName = "0:\\TZFS\\mz80b_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00000800 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_80B_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } + }, + .params[MZ2000] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_MONO, .displayOption = 4, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\mz2000_ipl.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz2000_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00000800 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_2000_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } + }, + .params[MZ2200] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_MONO, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\mz2200-ipl.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz2200_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00000800 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_2200_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } + }, + .params[MZ2500] = { + .cpuSpeed = 0 , .memSize = 1, .audioSource = 0, .audioHardware = 1, .audioVolume = 15, .audioMute = 0, .audioMix = 0, .displayType = MZ_EMU_DISPLAY_COLOUR, .displayOption = 0, .displayOutput = VMMODE_VGA_640x480, + .vramMode = 0, .vramWaitMode = 0, .gramMode = 0, .pcgMode = 0, .aspectRatio = 0, .scanDoublerFX = 0, .loadDirectFilter = 0, + .mz800Mode = 0, .mz800Printer = 0, .mz800TapeIn = 0, .queueTapeFilter = 0, .tapeAutoSave = 1, .tapeButtons = 3, .fastTapeLoad = 0, .tapeSavePath = "0:\\MZF", + .cmtAsciiMapping = 3, .cmtMode = 0, .autoStart = 0, + .romMonitor40 = { .romFileName = "0:\\TZFS\\mz2500-ipl.rom", .romEnabled = 1, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romMonitor80 = { .romFileName = "", .romEnabled = 0, .loadAddr = MZ_EMU_ROM_ADDR, .loadSize = 0x00001000 }, + .romCG = { .romFileName = "0:\\TZFS\\mz2500_cgrom.rom", .romEnabled = 1, .loadAddr = MZ_EMU_CGROM_ADDR, .loadSize = 0x00000800 }, + .romKeyMap = { .romFileName = "0:\\TZFS\\700_2500_km.rom", .romEnabled = 1, .loadAddr = MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_MAP_ADDR, .loadSize = 0x00000080 }, + .romUser = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .romFDC = { .romFileName = "", .romEnabled = 0, .loadAddr = 0x000000, .loadSize = 0x00000100 }, + .loadApp = { .appFileName = "", .appEnabled = 0, .preKeyInsertion = {}, .postKeyInsertion = {} } } }; +const static t_scanMap mapToScanCode[] = { // MZ-80K MZ-80C MZ-1200 MZ-80A MZ-700 MZ-1500 MZ-800 MZ-80B MZ-2000 MZ-2200 MZ-2500 + { 'A', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 1, 0xf7, KEY_NOCTRL_BIT }, { 1, 0xf7, KEY_NOCTRL_BIT }, { 4, 0x7f, KEY_NOCTRL_BIT }, { 4, 0x7f, KEY_NOCTRL_BIT }, { 4, 0x7f, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'B', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0xfe, KEY_NOCTRL_BIT }, { 3, 0xfe, KEY_NOCTRL_BIT }, { 4, 0xbf, KEY_NOCTRL_BIT }, { 4, 0xbf, KEY_NOCTRL_BIT }, { 4, 0xbf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'C', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0xfe, KEY_NOCTRL_BIT }, { 2, 0xfe, KEY_NOCTRL_BIT }, { 4, 0xdf, KEY_NOCTRL_BIT }, { 4, 0xdf, KEY_NOCTRL_BIT }, { 4, 0xdf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'D', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0xf7, KEY_NOCTRL_BIT }, { 2, 0xf7, KEY_NOCTRL_BIT }, { 4, 0xef, KEY_NOCTRL_BIT }, { 4, 0xef, KEY_NOCTRL_BIT }, { 4, 0xef, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'E', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0xef, KEY_NOCTRL_BIT }, { 2, 0xef, KEY_NOCTRL_BIT }, { 4, 0xf7, KEY_NOCTRL_BIT }, { 4, 0xf7, KEY_NOCTRL_BIT }, { 4, 0xf7, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'F', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0xfb, KEY_NOCTRL_BIT }, { 3, 0xfb, KEY_NOCTRL_BIT }, { 4, 0xfb, KEY_NOCTRL_BIT }, { 4, 0xfb, KEY_NOCTRL_BIT }, { 4, 0xfb, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'G', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0xf7, KEY_NOCTRL_BIT }, { 3, 0xf7, KEY_NOCTRL_BIT }, { 4, 0xfd, KEY_NOCTRL_BIT }, { 4, 0xfd, KEY_NOCTRL_BIT }, { 4, 0xfd, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'H', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0xfb, KEY_NOCTRL_BIT }, { 4, 0xfb, KEY_NOCTRL_BIT }, { 4, 0xfe, KEY_NOCTRL_BIT }, { 4, 0xfe, KEY_NOCTRL_BIT }, { 4, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'I', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0xdf, KEY_NOCTRL_BIT }, { 4, 0xdf, KEY_NOCTRL_BIT }, { 3, 0x7f, KEY_NOCTRL_BIT }, { 3, 0x7f, KEY_NOCTRL_BIT }, { 3, 0x7f, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'J', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0xf7, KEY_NOCTRL_BIT }, { 4, 0xf7, KEY_NOCTRL_BIT }, { 3, 0xbf, KEY_NOCTRL_BIT }, { 3, 0xbf, KEY_NOCTRL_BIT }, { 3, 0xbf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'K', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xfb, KEY_NOCTRL_BIT }, { 5, 0xfb, KEY_NOCTRL_BIT }, { 3, 0xdf, KEY_NOCTRL_BIT }, { 3, 0xdf, KEY_NOCTRL_BIT }, { 3, 0xdf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'L', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xf7, KEY_NOCTRL_BIT }, { 5, 0xf7, KEY_NOCTRL_BIT }, { 3, 0xef, KEY_NOCTRL_BIT }, { 3, 0xef, KEY_NOCTRL_BIT }, { 3, 0xef, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'M', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xfe, KEY_NOCTRL_BIT }, { 5, 0xfe, KEY_NOCTRL_BIT }, { 3, 0xf7, KEY_NOCTRL_BIT }, { 3, 0xf7, KEY_NOCTRL_BIT }, { 3, 0xf7, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'N', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0xfd, KEY_NOCTRL_BIT }, { 4, 0xfd, KEY_NOCTRL_BIT }, { 3, 0xfb, KEY_NOCTRL_BIT }, { 3, 0xfb, KEY_NOCTRL_BIT }, { 3, 0xfb, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'O', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 3, 0xfd, KEY_NOCTRL_BIT }, { 3, 0xfd, KEY_NOCTRL_BIT }, { 3, 0xfd, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'P', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xdf, KEY_NOCTRL_BIT }, { 5, 0xdf, KEY_NOCTRL_BIT }, { 3, 0xfe, KEY_NOCTRL_BIT }, { 3, 0xfe, KEY_NOCTRL_BIT }, { 3, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'Q', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 2, 0x7f, KEY_NOCTRL_BIT }, { 2, 0x7f, KEY_NOCTRL_BIT }, { 2, 0x7f, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'R', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0xdf, KEY_NOCTRL_BIT }, { 2, 0xdf, KEY_NOCTRL_BIT }, { 2, 0xbf, KEY_NOCTRL_BIT }, { 2, 0xbf, KEY_NOCTRL_BIT }, { 2, 0xbf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'S', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0xfb, KEY_NOCTRL_BIT }, { 2, 0xfb, KEY_NOCTRL_BIT }, { 2, 0xdf, KEY_NOCTRL_BIT }, { 2, 0xdf, KEY_NOCTRL_BIT }, { 2, 0xdf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'T', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0xef, KEY_NOCTRL_BIT }, { 3, 0xef, KEY_NOCTRL_BIT }, { 2, 0xef, KEY_NOCTRL_BIT }, { 2, 0xef, KEY_NOCTRL_BIT }, { 2, 0xef, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'U', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0xef, KEY_NOCTRL_BIT }, { 4, 0xef, KEY_NOCTRL_BIT }, { 2, 0xf7, KEY_NOCTRL_BIT }, { 2, 0xf7, KEY_NOCTRL_BIT }, { 2, 0xf7, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'V', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0xfd, KEY_NOCTRL_BIT }, { 3, 0xfd, KEY_NOCTRL_BIT }, { 2, 0xfb, KEY_NOCTRL_BIT }, { 2, 0xfb, KEY_NOCTRL_BIT }, { 2, 0xfb, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'W', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 1, 0xdf, KEY_NOCTRL_BIT }, { 1, 0xdf, KEY_NOCTRL_BIT }, { 2, 0xfd, KEY_NOCTRL_BIT }, { 2, 0xfd, KEY_NOCTRL_BIT }, { 2, 0xfd, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'X', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0xfd, KEY_NOCTRL_BIT }, { 2, 0xfd, KEY_NOCTRL_BIT }, { 2, 0xfe, KEY_NOCTRL_BIT }, { 2, 0xfe, KEY_NOCTRL_BIT }, { 2, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'Y', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0xdf, KEY_NOCTRL_BIT }, { 3, 0xdf, KEY_NOCTRL_BIT }, { 1, 0x7f, KEY_NOCTRL_BIT }, { 1, 0x7f, KEY_NOCTRL_BIT }, { 1, 0x7f, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 'Z', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 1, 0xfe, KEY_NOCTRL_BIT }, { 1, 0xfe, KEY_NOCTRL_BIT }, { 1, 0xbf, KEY_NOCTRL_BIT }, { 1, 0xbf, KEY_NOCTRL_BIT }, { 1, 0xbf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + + { '0', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0x7f, KEY_NOCTRL_BIT }, { 5, 0x7f, KEY_NOCTRL_BIT }, { 6, 0xf7, KEY_NOCTRL_BIT }, { 6, 0xf7, KEY_NOCTRL_BIT }, { 6, 0xf7, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '1', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 1, 0xbf, KEY_NOCTRL_BIT }, { 1, 0xbf, KEY_NOCTRL_BIT }, { 5, 0x7f, KEY_NOCTRL_BIT }, { 5, 0x7f, KEY_NOCTRL_BIT }, { 5, 0x7f, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '2', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 1, 0x7f, KEY_NOCTRL_BIT }, { 1, 0x7f, KEY_NOCTRL_BIT }, { 5, 0xbf, KEY_NOCTRL_BIT }, { 5, 0xbf, KEY_NOCTRL_BIT }, { 5, 0xbf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '3', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0xbf, KEY_NOCTRL_BIT }, { 2, 0xbf, KEY_NOCTRL_BIT }, { 5, 0xdf, KEY_NOCTRL_BIT }, { 5, 0xdf, KEY_NOCTRL_BIT }, { 5, 0xdf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '4', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0x7f, KEY_NOCTRL_BIT }, { 2, 0x7f, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '5', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0xbf, KEY_NOCTRL_BIT }, { 3, 0xbf, KEY_NOCTRL_BIT }, { 5, 0xf7, KEY_NOCTRL_BIT }, { 5, 0xf7, KEY_NOCTRL_BIT }, { 5, 0xf7, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '6', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0x7f, KEY_NOCTRL_BIT }, { 3, 0x7f, KEY_NOCTRL_BIT }, { 5, 0xfb, KEY_NOCTRL_BIT }, { 5, 0xfb, KEY_NOCTRL_BIT }, { 5, 0xfb, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '7', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0xbf, KEY_NOCTRL_BIT }, { 4, 0xbf, KEY_NOCTRL_BIT }, { 5, 0xfd, KEY_NOCTRL_BIT }, { 5, 0xfd, KEY_NOCTRL_BIT }, { 5, 0xfd, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '8', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0x7f, KEY_NOCTRL_BIT }, { 4, 0x7f, KEY_NOCTRL_BIT }, { 5, 0xfe, KEY_NOCTRL_BIT }, { 5, 0xfe, KEY_NOCTRL_BIT }, { 5, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '9', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xbf, KEY_NOCTRL_BIT }, { 5, 0xbf, KEY_NOCTRL_BIT }, { 6, 0xfb, KEY_NOCTRL_BIT }, { 6, 0xfb, KEY_NOCTRL_BIT }, { 6, 0xfb, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + + { '_', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0x7f, KEY_SHIFT_BIT }, { 5, 0x7f, KEY_SHIFT_BIT }, { 0, 0xdf, KEY_NOCTRL_BIT }, { 0, 0xdf, KEY_NOCTRL_BIT }, { 0, 0xdf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '!', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 1, 0xbf, KEY_SHIFT_BIT }, { 1, 0xbf, KEY_SHIFT_BIT }, { 5, 0x7f, KEY_SHIFT_BIT }, { 5, 0x7f, KEY_SHIFT_BIT }, { 5, 0x7f, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '"', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 1, 0x7f, KEY_SHIFT_BIT }, { 1, 0x7f, KEY_SHIFT_BIT }, { 5, 0xbf, KEY_SHIFT_BIT }, { 5, 0xbf, KEY_SHIFT_BIT }, { 5, 0xbf, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '#', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0xbf, KEY_SHIFT_BIT }, { 2, 0xbf, KEY_SHIFT_BIT }, { 5, 0xdf, KEY_SHIFT_BIT }, { 5, 0xdf, KEY_SHIFT_BIT }, { 5, 0xdf, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '$', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 2, 0x7f, KEY_SHIFT_BIT }, { 2, 0x7f, KEY_SHIFT_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 5, 0xef, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '%', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0xbf, KEY_SHIFT_BIT }, { 3, 0xbf, KEY_SHIFT_BIT }, { 5, 0xf7, KEY_SHIFT_BIT }, { 5, 0xf7, KEY_SHIFT_BIT }, { 5, 0xf7, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '&', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 3, 0x7f, KEY_SHIFT_BIT }, { 3, 0x7f, KEY_SHIFT_BIT }, { 5, 0xfb, KEY_NOCTRL_BIT }, { 5, 0xfb, KEY_NOCTRL_BIT }, { 5, 0xfb, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '\'', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0xbf, KEY_SHIFT_BIT }, { 4, 0xbf, KEY_SHIFT_BIT }, { 6, 0x7f, KEY_NOCTRL_BIT }, { 6, 0x7f, KEY_NOCTRL_BIT }, { 6, 0x7f, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '(', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0x7f, KEY_SHIFT_BIT }, { 4, 0x7f, KEY_SHIFT_BIT }, { 5, 0xfe, KEY_SHIFT_BIT }, { 5, 0xfe, KEY_SHIFT_BIT }, { 5, 0xfe, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { ')', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xbf, KEY_SHIFT_BIT }, { 5, 0xbf, KEY_SHIFT_BIT }, { 6, 0xfb, KEY_SHIFT_BIT }, { 6, 0xfb, KEY_SHIFT_BIT }, { 6, 0xfb, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '^', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0x7f, KEY_NOCTRL_BIT }, { 6, 0x7f, KEY_NOCTRL_BIT }, { 6, 0xbf, KEY_NOCTRL_BIT }, { 6, 0xbf, KEY_NOCTRL_BIT }, { 6, 0xbf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '~', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0x7f, KEY_SHIFT_BIT }, { 6, 0x7f, KEY_SHIFT_BIT }, { 6, 0xbf, KEY_SHIFT_BIT }, { 6, 0xbf, KEY_SHIFT_BIT }, { 6, 0xbf, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '-', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xbf, KEY_NOCTRL_BIT }, { 6, 0xbf, KEY_NOCTRL_BIT }, { 1, 0xdf, KEY_SHIFT_BIT }, { 1, 0xdf, KEY_SHIFT_BIT }, { 1, 0xdf, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '=', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xbf, KEY_SHIFT_BIT }, { 6, 0xbf, KEY_SHIFT_BIT }, { 6, 0xdf, KEY_SHIFT_BIT }, { 6, 0xdf, KEY_SHIFT_BIT }, { 6, 0xdf, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '\\', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 7, 0xbf, KEY_NOCTRL_BIT }, { 7, 0xbf, KEY_NOCTRL_BIT }, { 6, 0x7f, KEY_NOCTRL_BIT }, { 6, 0x7f, KEY_NOCTRL_BIT }, { 6, 0x7f, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '|', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 7, 0xbf, KEY_SHIFT_BIT }, { 7, 0xbf, KEY_SHIFT_BIT }, { 6, 0x7f, KEY_SHIFT_BIT }, { 6, 0x7f, KEY_SHIFT_BIT }, { 6, 0x7f, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '[', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xdf, KEY_NOCTRL_BIT }, { 6, 0xdf, KEY_NOCTRL_BIT }, { 1, 0xef, KEY_NOCTRL_BIT }, { 1, 0xef, KEY_NOCTRL_BIT }, { 1, 0xef, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '{', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xdf, KEY_SHIFT_BIT }, { 6, 0xdf, KEY_SHIFT_BIT }, { 1, 0xef, KEY_SHIFT_BIT }, { 1, 0xef, KEY_SHIFT_BIT }, { 1, 0xef, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { ']', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 7, 0xfb, KEY_NOCTRL_BIT }, { 7, 0xfb, KEY_NOCTRL_BIT }, { 1, 0xf7, KEY_NOCTRL_BIT }, { 1, 0xf7, KEY_NOCTRL_BIT }, { 1, 0xf7, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '}', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 7, 0xfb, KEY_SHIFT_BIT }, { 7, 0xfb, KEY_SHIFT_BIT }, { 1, 0xf7, KEY_SHIFT_BIT }, { 1, 0xf7, KEY_SHIFT_BIT }, { 1, 0xf7, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { ':', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xf7, KEY_NOCTRL_BIT }, { 6, 0xf7, KEY_NOCTRL_BIT }, { 0, 0xfd, KEY_NOCTRL_BIT }, { 0, 0xfd, KEY_NOCTRL_BIT }, { 0, 0xfd, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '*', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xf7, KEY_SHIFT_BIT }, { 6, 0xf7, KEY_SHIFT_BIT }, { 0, 0xfd, KEY_SHIFT_BIT }, { 0, 0xfd, KEY_SHIFT_BIT }, { 0, 0xfd, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { ';', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xfb, KEY_NOCTRL_BIT }, { 6, 0xfb, KEY_NOCTRL_BIT }, { 0, 0xfb, KEY_NOCTRL_BIT }, { 0, 0xfb, KEY_NOCTRL_BIT }, { 0, 0xfb, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '+', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xfb, KEY_SHIFT_BIT }, { 6, 0xfb, KEY_SHIFT_BIT }, { 0, 0xfb, KEY_SHIFT_BIT }, { 0, 0xfb, KEY_SHIFT_BIT }, { 0, 0xfb, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { ',', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xfd, KEY_NOCTRL_BIT }, { 5, 0xfd, KEY_NOCTRL_BIT }, { 6, 0xfd, KEY_NOCTRL_BIT }, { 6, 0xfd, KEY_NOCTRL_BIT }, { 6, 0xfd, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '<', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 5, 0xfd, KEY_SHIFT_BIT }, { 5, 0xfd, KEY_SHIFT_BIT }, { 6, 0xfd, KEY_SHIFT_BIT }, { 6, 0xfd, KEY_SHIFT_BIT }, { 6, 0xfd, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '.', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xfe, KEY_NOCTRL_BIT }, { 6, 0xfe, KEY_NOCTRL_BIT }, { 6, 0xfe, KEY_NOCTRL_BIT }, { 6, 0xfe, KEY_NOCTRL_BIT }, { 6, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '>', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xfe, KEY_SHIFT_BIT }, { 6, 0xfe, KEY_SHIFT_BIT }, { 6, 0xfe, KEY_SHIFT_BIT }, { 6, 0xfe, KEY_SHIFT_BIT }, { 6, 0xfe, KEY_SHIFT_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '/', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 6, 0xfd, KEY_NOCTRL_BIT }, { 6, 0xfd, KEY_NOCTRL_BIT }, { 7, 0xfe, KEY_NOCTRL_BIT }, { 7, 0xfe, KEY_NOCTRL_BIT }, { 7, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { '?', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 7, 0xfe, KEY_NOCTRL_BIT }, { 7, 0xfe, KEY_NOCTRL_BIT }, { 7, 0xfe, KEY_NOCTRL_BIT }, { 7, 0xfe, KEY_NOCTRL_BIT }, { 7, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 0x0d, { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 7, 0xf7, KEY_NOCTRL_BIT }, { 7, 0xf7, KEY_NOCTRL_BIT }, { 0, 0xfe, KEY_NOCTRL_BIT }, { 0, 0xfe, KEY_NOCTRL_BIT }, { 0, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { ' ', { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 4, 0xfe, KEY_NOCTRL_BIT }, { 4, 0xfe, KEY_NOCTRL_BIT }, { 6, 0xef, KEY_NOCTRL_BIT }, { 6, 0xef, KEY_NOCTRL_BIT }, { 6, 0xef, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 0xf8, { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0, 0xfe, KEY_NOCTRL_BIT }, { 0, 0xfe, KEY_NOCTRL_BIT }, { 8, 0xfe, KEY_NOCTRL_BIT }, { 8, 0xfe, KEY_NOCTRL_BIT }, { 8, 0xfe, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 0xf9, { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0, 0x7f, KEY_NOCTRL_BIT }, { 0, 0x7f, KEY_NOCTRL_BIT }, { 8, 0xbf, KEY_NOCTRL_BIT }, { 8, 0xbf, KEY_NOCTRL_BIT }, { 8, 0xbf, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + { 0xfa, { { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0, 0x7f, KEY_NOCTRL_BIT }, { 0, 0x7f, KEY_NOCTRL_BIT }, { 8, 0x7f, KEY_NOCTRL_BIT }, { 8, 0x7f, KEY_NOCTRL_BIT }, { 8, 0x7f, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT }, { 0xff, 0xff, KEY_NOCTRL_BIT } } }, + }; + +// Configuration working structures. Declared static rather than malloc'd as they are used so often and malloc doesnt offer any benefit for an integral data block. +static t_emuControl emuControl; +static t_emuConfig emuConfig; + +// Real time millisecond counter, interrupt driven. Needs to be volatile in order to prevent the compiler optimising it away. uint32_t volatile *ms = &systick_millis_count; +// Method to return the emulation control software version. +static const char version[8]; +const char *EMZGetVersion(void) +{ + sprintf(version, "v%.2f", EMUMZ_VERSION); + return(version); +} + +// Method to return the emulation control software version date. +static const char versionDate[sizeof(EMUMZ_VERSION_DATE)+1]; +const char *EMZGetVersionDate(void) +{ + sprintf(versionDate, "%s", EMUMZ_VERSION_DATE); + return(versionDate); +} + +// Method to lookup a given key for a given machine and if found return the keyboard row/col scan codes and any key modifier. +// +t_numCnv EMZMapToScanCode(enum MACHINE_HW_TYPES machine, uint8_t key) +{ + // Locals. + uint16_t idx; + uint8_t row = 0xff, shiftRow = 0xff, ctrlRow = 0xff, breakRow = 0xff; + uint8_t col = 0xff, shiftCol = 0xff, ctrlCol = 0xff, breakCol = 0xff; + uint8_t mod = 0; + t_numCnv result; + + // Loop through the lookup table, based on the host layout, and try to find a key match. + for(idx=0; idx < NUMELEM(mapToScanCode); idx++) + { + // Key matched? + if(mapToScanCode[idx].key == toupper(key)) + { + row = mapToScanCode[idx].code[machine].scanRow; + col = mapToScanCode[idx].code[machine].scanCol; + mod = mapToScanCode[idx].code[machine].scanCtrl; + } + + // Match SHIFT? + if(mapToScanCode[idx].key == 0xf8) + { + shiftRow = mapToScanCode[idx].code[machine].scanRow; + shiftCol = mapToScanCode[idx].code[machine].scanCol; + } + + // Match CTRL? + if(mapToScanCode[idx].key == 0xf9) + { + ctrlRow = mapToScanCode[idx].code[machine].scanRow; + ctrlCol = mapToScanCode[idx].code[machine].scanCol; + } + + // Match BREAK? + if(mapToScanCode[idx].key == 0xfa) + { + breakRow = mapToScanCode[idx].code[machine].scanRow; + breakCol = mapToScanCode[idx].code[machine].scanCol; + } + } + // Lower case keys arent stored in the table so update the shift modifier if lower case. + if(row != 0xff && key >= 'a' && key <= 'z') + { + mod = KEY_SHIFT_BIT; + } + + // Put data into correct part of the 32bit return word. 0 = Key Row, 1 = Key Col, 2 = Modifier Row, 3 = Modifier Col. 0xff = not valid. + result.b[0] = row; + result.b[1] = col; + result.b[2] = mod == KEY_SHIFT_BIT ? shiftRow : mod == KEY_CTRL_BIT ? ctrlRow : mod == KEY_BREAK_BIT ? breakRow : 0xff; + result.b[3] = mod == KEY_SHIFT_BIT ? shiftCol : mod == KEY_CTRL_BIT ? ctrlCol : mod == KEY_BREAK_BIT ? breakCol : 0xff; + + // Return result. + return(result); +} // Method to set the menu row padding (ie. pixel spacing above/below the characters). void EMZSetMenuRowPadding(uint8_t padding) @@ -265,25 +475,28 @@ short EMZGetMachineGroup(void) switch(emuConfig.machineModel) { // These machines currently underdevelopment, so fall through to MZ80K - case MZ80B_IDX: // MZ80B - case MZ2000_IDX: // MZ2000 - machineGroup = 2; + case MZ80B: + case MZ2000: + case MZ2200: + case MZ2500: + machineGroup = GROUP_MZ80B; break; - case MZ80K_IDX: // MZ80K - case MZ80C_IDX: // MZ80C - case MZ1200_IDX: // MZ1200 - case MZ80A_IDX: // MZ80A - machineGroup = 0; + case MZ80K: + case MZ80C: + case MZ1200: + case MZ80A: + machineGroup = GROUP_MZ80K; break; - case MZ700_IDX: // MZ700 - case MZ800_IDX: // MZ800 - machineGroup = 1; + case MZ700: + case MZ1500: + case MZ800: + machineGroup = GROUP_MZ700; break; default: - machineGroup = 0; + machineGroup = GROUP_MZ80K; break; } @@ -317,8 +530,15 @@ void EMZNextMachineModel(enum ACTIONMODE mode) if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) { - emuConfig.machineModel = (emuConfig.machineModel+1 >= MAX_MZMACHINES ? 0 : emuConfig.machineModel+1); + // Forward to next active machine - skip machines under development or not instantiated. + do { + emuConfig.machineModel = (emuConfig.machineModel+1 >= MAX_MZMACHINES ? 0 : emuConfig.machineModel+1); + emuConfig.machineGroup = EMZGetMachineGroup(); + } while(MZ_ACTIVE[emuConfig.machineModel] == 0); emuConfig.machineChanged = 1; + + // Need to rewrite the menu as the choice will affect displayed items. + EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); } return; } @@ -329,7 +549,7 @@ const char *EMZGetCPUSpeedChoice(void) // Locals. // - return(SHARPMZ_CPU_SPEED[(EMZGetMachineGroup() * 8) + emuConfig.params[emuConfig.machineModel].cpuSpeed]); + return(SHARPMZ_CPU_SPEED[emuConfig.machineGroup][emuConfig.params[emuConfig.machineModel].cpuSpeed]); } // Method to change the CPU Speed, choice based on the actual selected machine. @@ -337,17 +557,129 @@ void EMZNextCPUSpeed(enum ACTIONMODE mode) { // Locals. // - short machineGroup = EMZGetMachineGroup(); if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) { - if((machineGroup == 0 && emuConfig.params[emuConfig.machineModel].cpuSpeed > 5) || (machineGroup == 1 && emuConfig.params[emuConfig.machineModel].cpuSpeed > 4) || (machineGroup == 2 && emuConfig.params[emuConfig.machineModel].cpuSpeed > 4)) - { - emuConfig.params[emuConfig.machineModel].cpuSpeed = 0; - } else - { - emuConfig.params[emuConfig.machineModel].cpuSpeed = (emuConfig.params[emuConfig.machineModel].cpuSpeed+1 > 8 ? 0 : emuConfig.params[emuConfig.machineModel].cpuSpeed+1); - } + emuConfig.params[emuConfig.machineModel].cpuSpeed = (emuConfig.params[emuConfig.machineModel].cpuSpeed+1 >= NUMELEM(SHARPMZ_CPU_SPEED[emuConfig.machineGroup]) || SHARPMZ_CPU_SPEED[emuConfig.machineGroup][emuConfig.params[emuConfig.machineModel].cpuSpeed+1] == NULL ? 0 : emuConfig.params[emuConfig.machineModel].cpuSpeed+1); + } + return; +} + +// Method to return a char string which represents the current selected memory size. +const char *EMZGetMemSizeChoice(void) +{ + // Locals. + // + + return(SHARPMZ_MEM_SIZE[emuConfig.machineModel][emuConfig.params[emuConfig.machineModel].memSize]); +} + +// Method to change the memory size, choice based on the actual selected machine. +void EMZNextMemSize(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + // Move to the next valid entry, looping round as necessary. + do { + emuConfig.params[emuConfig.machineModel].memSize = (emuConfig.params[emuConfig.machineModel].memSize+1 >= NUMELEM(SHARPMZ_MEM_SIZE[emuConfig.machineModel]) ? 0 : emuConfig.params[emuConfig.machineModel].memSize+1); + } while(SHARPMZ_MEM_SIZE[emuConfig.machineModel][emuConfig.params[emuConfig.machineModel].memSize] == NULL); + } + return; +} + +// Method to convert the memory size into a bit value for uploading to hardware. Normally a 1:1 but allow leeway for deviations. +uint8_t EMZGetMemSizeValue(void) +{ + // Locals. + uint8_t result; + + // Decode according to machine selected. + // + switch(emuConfig.machineModel) + { + case MZ80K: + case MZ80C: + case MZ1200: + case MZ80A: + case MZ700: + case MZ1500: + case MZ800: + case MZ80B: + case MZ2000: + case MZ2200: + result = emuConfig.params[emuConfig.machineModel].memSize; + break; + + case MZ2500: + result = 0x00; + break; + + } + return(result); +} + +// Method to return a char string which represents the current selected MZ800 Mode. +const char *EMZGetMZ800ModeChoice(void) +{ + // Locals. + // + return(SHARPMZ_MZ800_MODE[emuConfig.params[emuConfig.machineModel].mz800Mode]); +} + +// Method to change the MZ800 Mode. +void EMZNextMZ800Mode(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + emuConfig.params[emuConfig.machineModel].mz800Mode = (emuConfig.params[emuConfig.machineModel].mz800Mode+1 >= NUMELEM(SHARPMZ_MZ800_MODE) ? 0 : emuConfig.params[emuConfig.machineModel].mz800Mode+1); + } + return; +} + +// Method to return a char string which represents the current selected MZ800 Printer setting. +const char *EMZGetMZ800PrinterChoice(void) +{ + // Locals. + // + return(SHARPMZ_MZ800_PRINTER[emuConfig.params[emuConfig.machineModel].mz800Printer]); +} + +// Method to change the MZ800 Printer setting. +void EMZNextMZ800Printer(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + emuConfig.params[emuConfig.machineModel].mz800Printer = (emuConfig.params[emuConfig.machineModel].mz800Printer+1 >= NUMELEM(SHARPMZ_MZ800_PRINTER) ? 0 : emuConfig.params[emuConfig.machineModel].mz800Printer+1); + } + return; +} + +// Method to return a char string which represents the current selected MZ800 Printer setting. +const char *EMZGetMZ800TapeInChoice(void) +{ + // Locals. + // + return(SHARPMZ_MZ800_TAPEIN[emuConfig.params[emuConfig.machineModel].mz800TapeIn]); +} + +// Method to change the MZ800 Tape Input setting. +void EMZNextMZ800TapeIn(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + emuConfig.params[emuConfig.machineModel].mz800TapeIn = (emuConfig.params[emuConfig.machineModel].mz800TapeIn+1 >= NUMELEM(SHARPMZ_MZ800_TAPEIN) ? 0 : emuConfig.params[emuConfig.machineModel].mz800TapeIn+1); } return; } @@ -373,6 +705,30 @@ void EMZNextAudioSource(enum ACTIONMODE mode) return; } +// Method to return a char string which represents the current selected Audio Hardware Driver. +const char *EMZGetAudioHardwareChoice(void) +{ + // Locals. + // + return(SHARPMZ_AUDIO_HARDWARE[emuConfig.params[emuConfig.machineModel].audioHardware]); +} + +// Method to change the Audio Hardware Driver, choice based on the actual selected machine. +void EMZNextAudioHardware(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + emuConfig.params[emuConfig.machineModel].audioHardware = (emuConfig.params[emuConfig.machineModel].audioHardware+1 >= NUMELEM(SHARPMZ_AUDIO_HARDWARE) ? 0 : emuConfig.params[emuConfig.machineModel].audioHardware+1); + } + + // Need to rewrite the menu as the choice will affect displayed items. + EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); + return; +} + // Method to return a char string which represents the current selected Audio Volume. const char *EMZGetAudioVolumeChoice(void) { @@ -415,12 +771,33 @@ void EMZNextAudioMute(enum ACTIONMODE mode) return; } +// Method to return a char string which represents the current selected Audio channel mix. +const char *EMZGetAudioMixChoice(void) +{ + // Locals. + // + return(SHARPMZ_AUDIO_MIX[emuConfig.params[emuConfig.machineModel].audioMix]); +} + +// Method to change the Audio channel mix, choice based on the actual selected machine. +void EMZNextAudioMix(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + emuConfig.params[emuConfig.machineModel].audioMix = (emuConfig.params[emuConfig.machineModel].audioMix+1 >= NUMELEM(SHARPMZ_AUDIO_MIX) ? 0 : emuConfig.params[emuConfig.machineModel].audioMix+1); + } + return; +} + // Method to return a char string which represents the current selected Display Type. const char *EMZGetDisplayTypeChoice(void) { // Locals. // - return(SHARPMZ_DISPLAY_TYPE[emuConfig.params[emuConfig.machineModel].displayType]); + return(SHARPMZ_DISPLAY_TYPE[emuConfig.machineModel][emuConfig.params[emuConfig.machineModel].displayType]); } // Method to change the Display Type, choice based on the actual selected machine. @@ -431,11 +808,100 @@ void EMZNextDisplayType(enum ACTIONMODE mode) if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) { - emuConfig.params[emuConfig.machineModel].displayType = (emuConfig.params[emuConfig.machineModel].displayType+1 >= NUMELEM(SHARPMZ_DISPLAY_TYPE) ? 0 : emuConfig.params[emuConfig.machineModel].displayType+1); + // Move to the next valid entry, looping round as necessary. + do { + emuConfig.params[emuConfig.machineModel].displayType = (emuConfig.params[emuConfig.machineModel].displayType+1 >= NUMELEM(SHARPMZ_DISPLAY_TYPE[emuConfig.machineModel]) ? 0 : emuConfig.params[emuConfig.machineModel].displayType+1); +printf("%d\n", emuConfig.params[emuConfig.machineModel].displayType); + } while(SHARPMZ_DISPLAY_TYPE[emuConfig.machineModel][emuConfig.params[emuConfig.machineModel].displayType] == NULL); } return; } +// Method to return a char string which represents the current selected Display Option installed. +const char *EMZGetDisplayOptionChoice(void) +{ + // Locals. + // + + return(SHARPMZ_DISPLAY_OPTION[emuConfig.machineModel][emuConfig.params[emuConfig.machineModel].displayOption]); +} + +// Method to change the installed display option, choice based on the actual selected machine. +void EMZNextDisplayOption(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + // Move to the next valid entry, looping round as necessary. + do { + emuConfig.params[emuConfig.machineModel].displayOption = (emuConfig.params[emuConfig.machineModel].displayOption+1 >= NUMELEM(SHARPMZ_DISPLAY_OPTION[emuConfig.machineModel]) ? 0 : emuConfig.params[emuConfig.machineModel].displayOption+1); + } while(SHARPMZ_DISPLAY_OPTION[emuConfig.machineModel][emuConfig.params[emuConfig.machineModel].displayOption] == NULL); + + // Need to rewrite the menu as the choice will affect displayed items. + EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); + } + return; +} + +// Method to translate the selected options into an option byte which can be written to hardware. This mechanism needs to be table driven eventually! +// +uint8_t EMZGetDisplayOptionValue(void) +{ + // Locals. + uint8_t result; + + // Decode according to machine selected. + // + switch(emuConfig.machineModel) + { + case MZ80K: + case MZ80C: + case MZ1200: + result = 0; + break; + + case MZ80A: + case MZ700: + result |= emuConfig.params[emuConfig.machineModel].displayOption == 1 ? 0x08 : 0x00; + break; + + case MZ1500: + result = 0x08; + break; + + case MZ800: + result = emuConfig.params[emuConfig.machineModel].displayOption == 1 ? 0x10 : 0x00; + break; + + case MZ80B: + result = 0x00; + result |= emuConfig.params[emuConfig.machineModel].displayOption == 1 ? 0x01 : 0x00; + result |= emuConfig.params[emuConfig.machineModel].displayOption == 2 ? 0x03 : 0x00; + printf("displayOption=%d,%d\n", emuConfig.params[emuConfig.machineModel].displayOption, result); + break; + + case MZ2000: + result = 0x00; + result |= emuConfig.params[emuConfig.machineModel].displayOption == 1 ? 0x01 : 0x00; + result |= emuConfig.params[emuConfig.machineModel].displayOption == 2 ? 0x03 : 0x00; + result |= emuConfig.params[emuConfig.machineModel].displayOption == 3 ? 0x05 : 0x00; + result |= emuConfig.params[emuConfig.machineModel].displayOption == 4 ? 0x07 : 0x00; + break; + + case MZ2200: + result = 0x07; + break; + + case MZ2500: + result = 0x00; + break; + + } + return(result); +} + // Method to return a char string which represents the current selected Display Output. const char *EMZGetDisplayOutputChoice(void) { @@ -675,7 +1141,7 @@ void EMZNextCMTMode(enum ACTIONMODE mode) return; } -// Method to enable/disable the 80char monitor ROM and select the image to be used in the ROM. +// Method to select the FPGA based CMT or the hardware CMT. // void EMZChangeCMTMode(enum ACTIONMODE mode) { @@ -692,7 +1158,8 @@ const char *EMZGetFastTapeLoadChoice(void) { // Locals. // - return(SHARPMZ_FAST_TAPE[emuConfig.params[emuConfig.machineModel].fastTapeLoad]); + + return(SHARPMZ_FAST_TAPE[emuConfig.machineGroup][emuConfig.params[emuConfig.machineModel].fastTapeLoad]); } // Method to change the Fast Tape Load mode, choice based on the actual selected machine. @@ -703,7 +1170,7 @@ void EMZNextFastTapeLoad(enum ACTIONMODE mode) if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) { - emuConfig.params[emuConfig.machineModel].fastTapeLoad = (emuConfig.params[emuConfig.machineModel].fastTapeLoad+1 >= NUMELEM(SHARPMZ_FAST_TAPE) ? 0 : emuConfig.params[emuConfig.machineModel].fastTapeLoad+1); + emuConfig.params[emuConfig.machineModel].fastTapeLoad = (emuConfig.params[emuConfig.machineModel].fastTapeLoad+1 >= NUMELEM(SHARPMZ_FAST_TAPE[emuConfig.machineGroup]) || SHARPMZ_FAST_TAPE[emuConfig.machineGroup][emuConfig.params[emuConfig.machineModel].fastTapeLoad+1] == NULL ? 0 : emuConfig.params[emuConfig.machineModel].fastTapeLoad+1); } return; } @@ -767,6 +1234,7 @@ void EMZNextMonitorROM40(enum ACTIONMODE mode) if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) { emuConfig.params[emuConfig.machineModel].romMonitor40.romEnabled = (emuConfig.params[emuConfig.machineModel].romMonitor40.romEnabled == 1 ? 0 : 1); +printf("romEnabled=%d\n", emuConfig.params[emuConfig.machineModel].romMonitor40.romEnabled ); } return; } @@ -876,10 +1344,76 @@ void EMZNextFloppyDiskROM(enum ACTIONMODE mode) return; } +// Method to return a string representation of the tape type held in the last tape accessed buffer. +const char *EMZGetTapeType(void) +{ + // Locals. + // + return(SHARPMZ_TAPE_TYPE[emuControl.tapeHeader.dataType >= NUMELEM(SHARPMZ_TAPE_TYPE) ? NUMELEM(SHARPMZ_TAPE_TYPE) - 1 : emuControl.tapeHeader.dataType]); +} + +// Method to return a char string which represents the current selected application autostart setting. +const char *EMZGetLoadApplicationChoice(void) +{ + // Locals. + // + return(emuConfig.params[emuConfig.machineModel].loadApp.appEnabled ? emuConfig.params[emuConfig.machineModel].loadApp.appFileName : "Disabled"); +} + +// Method to change the current select application autostart setting. +void EMZNextLoadApplication(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + emuConfig.params[emuConfig.machineModel].loadApp.appEnabled = (emuConfig.params[emuConfig.machineModel].loadApp.appEnabled == 1 ? 0 : 1); + } + return; +} + +// Method to return a char string which represents the current state of the autostart feature. +const char *EMZGetAutoStartChoice(void) +{ + // Locals. + // + return(SHARPMZ_AUTOSTART[emuConfig.params[emuConfig.machineModel].autoStart]); +} + +// Method to change the start of the autostart feature, choice based on the actual selected machine. +void EMZNextAutoStart(enum ACTIONMODE mode) +{ + // Locals. + // + + if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE) + { + emuConfig.params[emuConfig.machineModel].autoStart = (emuConfig.params[emuConfig.machineModel].autoStart+1 >= NUMELEM(SHARPMZ_AUTOSTART) ? 0 : emuConfig.params[emuConfig.machineModel].autoStart+1); + } + return; +} + +// Method to select the autostart mode. +// +void EMZChangeAutoStart(enum ACTIONMODE mode) +{ + if(mode == ACTION_TOGGLECHOICE) + { + // Need to change choice then rewrite the menu as the choice will affect displayed items. + EMZNextAutoStart(mode); + EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); + } +} + // Method to add a line into the displayed menu. // -void EMZAddToMenu(uint8_t row, uint8_t active, char *text, enum MENUTYPES type, enum MENUSTATE state, t_menuCallback mcb, enum MENUCALLBACK cbAction, t_choiceCallback ccb) -{ +void EMZAddToMenu(uint8_t row, uint8_t active, char *text, char hotKey, enum MENUTYPES type, enum MENUSTATE state, t_menuCallback mcb, enum MENUCALLBACK cbAction, t_choiceCallback ccb, t_viewCallback vcb) +{ + // Locals. + uint32_t textLen = strlen(text); + uint32_t idx; + // Sanity check. if(row >= MAX_MENU_ROWS) return; @@ -895,14 +1429,36 @@ void EMZAddToMenu(uint8_t row, uint8_t active, char *text, enum MENUTYPES type, debugf("Failed to allocate %d bytes on heap for menu row data %d\n", sizeof(t_menuItem), row); return; } - if(strlen(text) > 0) + idx = textLen; + if(textLen > 0) + { + // Scan the text for a hotkey, case insensitive. + for(idx=0; idx < textLen; idx++) + { + if(text[idx] == hotKey) + break; + } strcpy(emuControl.menu.data[row]->text, text); + } else + { emuControl.menu.data[row]->text[0] = 0x00; + } + // Store hotkey if given and found. + if(hotKey != 0x00 && idx < textLen) + { + // Store as upper case, even though lower case hot keys can be given, it is expected that + // the menu system doesnt contain 2 of the same upper/lower characters as hotkey. + emuControl.menu.data[row]->hotKey = hotKey; + } else + { + emuControl.menu.data[row]->hotKey = 0x00; + } emuControl.menu.data[row]->type = type; emuControl.menu.data[row]->state = state; emuControl.menu.data[row]->menuCallback = mcb; emuControl.menu.data[row]->choiceCallback = ccb; + emuControl.menu.data[row]->viewCallback = vcb; emuControl.menu.data[row]->cbAction = cbAction; if(active && state == MENUSTATE_ACTIVE) @@ -942,10 +1498,12 @@ int16_t EMZDrawMenu(int16_t activeRow, uint8_t direction, enum MENUMODE mode) uint16_t xpad = 0; uint16_t ypad = 1; uint16_t rowPixelDepth = (emuControl.menu.rowFontptr->height + emuControl.menu.rowFontptr->spacing + emuControl.menu.padding + 2*ypad); - uint16_t colPixelEnd = (uint16_t)OSDGet(ACTIVE_MAX_X) - emuControl.menu.colPixelsEnd; + uint16_t maxCol = (uint16_t)OSDGet(ACTIVE_MAX_X); + uint16_t colPixelEnd = maxCol - emuControl.menu.colPixelsEnd; uint16_t maxRow = ((uint16_t)OSDGet(ACTIVE_MAX_Y)/rowPixelDepth) + 1; uint8_t textChrX = (emuControl.menu.colPixelStart / (emuControl.menu.rowFontptr->width + emuControl.menu.rowFontptr->spacing)); char activeBuf[MENU_ROW_WIDTH]; + uint16_t attrBuf[MENU_ROW_WIDTH]; int16_t firstMenuRow; int16_t firstActiveMenuRow; int16_t lastMenuRow; @@ -954,7 +1512,7 @@ int16_t EMZDrawMenu(int16_t activeRow, uint8_t direction, enum MENUMODE mode) // Get menu boundaries. EMZGetMenuBoundaries(&firstMenuRow, &lastMenuRow, &firstActiveMenuRow, &lastActiveMenuRow, &visibleRows); -printf("first=%d, last=%d, firstactive=%d, lastactive=%d, visible=%d\n", firstMenuRow, lastMenuRow, firstActiveMenuRow, lastActiveMenuRow, visibleRows); + // Sanity check. if(firstMenuRow == -1 || lastMenuRow == -1 || firstActiveMenuRow == -1 || lastActiveMenuRow == -1 || visibleRows == 0) return(activeRow); @@ -997,11 +1555,13 @@ printf("first=%d, last=%d, firstactive=%d, lastactive=%d, visible=%d\n", firstMe continue; if(dspRow >= maxRow) continue; -printf("%d, %d, %d, %d, %d\n", activeRow, menuRow, emuControl.menu.data[menuRow], emuControl.menu.data[menuRow]->state, dspRow, maxRow); // Skip rendering blank lines! if(emuControl.menu.data[menuRow]->state != MENUSTATE_BLANK) { + // Zero out attributes buffer. + memset(attrBuf, NOATTR, MENU_ROW_WIDTH*sizeof(uint16_t)); + // For read only text, no choice or directory indicator required. if(emuControl.menu.data[menuRow]->state == MENUSTATE_TEXT) { @@ -1015,57 +1575,69 @@ printf("%d, %d, %d, %d, %d\n", activeRow, menuRow, emuControl.menu.data[menuRow] ptr=&activeBuf[strlen(activeBuf)]; sprintf(ptr, "%-*s", MENU_CHOICE_WIDTH, (emuControl.menu.data[menuRow]->type & MENUTYPE_CHOICE && emuControl.menu.data[menuRow]->choiceCallback != NULL) ? emuControl.menu.data[menuRow]->choiceCallback() : ""); sprintf(ptr+MENU_CHOICE_WIDTH, "%c", (emuControl.menu.data[menuRow]->type & MENUTYPE_SUBMENU) && !(emuControl.menu.data[menuRow]->type & MENUTYPE_ACTION) ? 0x10 : ' '); + + // Prepare any needed attributes. + for(uint16_t idx=0; idx < strlen(activeBuf); idx++) + { + // Highlight the Hot Key. + if(activeBuf[idx] == emuControl.menu.data[menuRow]->hotKey) + { + attrBuf[idx] = HILIGHT_FG_CYAN; + break; + } + } } // Output the row according to type. if(activeRow == menuRow) { - OSDWriteString(textChrX, dspRow, 0, emuControl.menu.rowPixelStart, xpad, ypad, emuControl.menu.font, NORMAL, activeBuf, emuControl.menu.activeFgColour, emuControl.menu.activeBgColour); + OSDWriteString(textChrX, dspRow, 0, emuControl.menu.rowPixelStart, xpad, ypad, emuControl.menu.font, NORMAL, activeBuf, attrBuf, emuControl.menu.activeFgColour, emuControl.menu.activeBgColour); if(activeRow != -1) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = activeRow; } else if(emuControl.menu.data[menuRow]->state == MENUSTATE_GREYED) { - OSDWriteString(textChrX, dspRow, 0, emuControl.menu.rowPixelStart, xpad, ypad, emuControl.menu.font, NORMAL, activeBuf, emuControl.menu.greyedFgColour, emuControl.menu.greyedBgColour); + OSDWriteString(textChrX, dspRow, 0, emuControl.menu.rowPixelStart, xpad, ypad, emuControl.menu.font, NORMAL, activeBuf, attrBuf, emuControl.menu.greyedFgColour, emuControl.menu.greyedBgColour); } else if(emuControl.menu.data[menuRow]->state == MENUSTATE_TEXT) { - OSDWriteString(textChrX, dspRow, 0, emuControl.menu.rowPixelStart, xpad, ypad, emuControl.menu.font, NORMAL, activeBuf, emuControl.menu.textFgColour, emuControl.menu.textBgColour); + OSDWriteString(textChrX, dspRow, 0, emuControl.menu.rowPixelStart, xpad, ypad, emuControl.menu.font, NORMAL, activeBuf, attrBuf, emuControl.menu.textFgColour, emuControl.menu.textBgColour); } else { - OSDWriteString(textChrX, dspRow, 0, emuControl.menu.rowPixelStart, xpad, ypad, emuControl.menu.font, NORMAL, activeBuf, emuControl.menu.inactiveFgColour, emuControl.menu.inactiveBgColour); + OSDWriteString(textChrX, dspRow, 0, emuControl.menu.rowPixelStart, xpad, ypad, emuControl.menu.font, NORMAL, activeBuf, attrBuf, emuControl.menu.inactiveFgColour, emuControl.menu.inactiveBgColour); + } + // Once the menu entry has been rendered, render view data if callback given. + if(emuControl.menu.data[menuRow]->viewCallback != NULL) + { + emuControl.menu.data[menuRow]->viewCallback(); } } dspRow++; } - + // If this is a submenu, place a back arrow to indicate you can go back. if(emuControl.activeMenu.menuIdx != 0) { - OSDWriteString(textChrX+1, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "\x1b back", CYAN, BLACK); + OSDWriteString(textChrX+1, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "\x1b back", NULL, CYAN, BLACK); } // Place scroll arrows if we span a page. if(activeRow >= maxRow && visibleRows > maxRow) { -printf("Scroll both:%d,%d,%d\n", activeRow, maxRow, visibleRows); - OSDWriteString(textChrX+71, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x17", CYAN, BLACK); + OSDWriteString(textChrX+(maxCol < 512 ? 38 : 71), 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x17", NULL, CYAN, BLACK); } else if(activeRow >= maxRow) { -printf("Scroll up:%d,%d,%d\n", activeRow, maxRow, visibleRows); - OSDWriteString(textChrX+71, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x18 ",CYAN, BLACK); + OSDWriteString(textChrX+(maxCol < 512 ? 38 : 71), 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x18 ", NULL, CYAN, BLACK); } else if(visibleRows > maxRow) { -printf("Scroll down:%d,%d,%d\n", activeRow, maxRow, visibleRows); - OSDWriteString(textChrX+71, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x19", CYAN, BLACK); + OSDWriteString(textChrX+(maxCol < 512 ? 38 : 71), 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x19", NULL, CYAN, BLACK); } else { - OSDWriteString(textChrX+71, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, " ", CYAN, BLACK); + OSDWriteString(textChrX+(maxCol < 512 ? 38 : 71), 0, 0, 4, 0, 0, FONT_5X7, NORMAL, " ", NULL, CYAN, BLACK); } -printf("RETURN ACTIVEROW=%d\n", activeRow); return(activeRow); } @@ -1093,9 +1665,9 @@ void EMZSetupMenu(char *sideTitle, char *menuTitle, enum FONTS font) // fontStruct *fontptr = OSDGetFont(font); uint16_t fontWidth = fontptr->width+fontptr->spacing; - uint16_t menuStartX = (((((uint16_t)OSDGet(ACTIVE_MAX_X) / fontWidth) - (30/fontWidth)) / 2) - strlen(menuTitle)/2) + 1; - uint16_t menuTitleLineLeft = (menuStartX * fontWidth) - 5; - uint16_t menuTitleLineRight = ((menuStartX+strlen(menuTitle))*fontWidth) + 3; + uint16_t menuStartX = (((((uint16_t)OSDGet(ACTIVE_MAX_X) / fontWidth) - (30/fontWidth)) / 2) - strlen(menuTitle)/2) + 2; + uint16_t menuTitleLineLeft = (menuStartX * fontWidth) - 3; + uint16_t menuTitleLineRight = ((menuStartX+strlen(menuTitle))*fontWidth) + 1; // Release previous memory as creation of a new menu will reallocate according to requirements. EMZReleaseMenuMemory(); @@ -1105,8 +1677,8 @@ void EMZSetupMenu(char *sideTitle, char *menuTitle, enum FONTS font) OSDClearArea(30, -1, -1, -1, BLACK); // Side and Top menu titles. - OSDWriteString(0, 0, 2, 8, 0, 0, FONT_9X16, DEG270, sideTitle, BLACK, WHITE); - OSDWriteString(menuStartX, 0, 0, 0, 0, 0, font, NORMAL, menuTitle, WHITE, BLACK); + OSDWriteString(0, 0, 2, 8, 0, 0, FONT_9X16, DEG270, sideTitle, NULL, BLACK, WHITE); + OSDWriteString(menuStartX, 0, 0, 0, 0, 0, font, NORMAL, menuTitle, NULL, WHITE, BLACK); // Top line indenting menu title. OSDDrawLine( 0, 0, menuTitleLineLeft, 0, WHITE); @@ -1141,9 +1713,9 @@ void EMZSetupDirList(char *sideTitle, char *menuTitle, enum FONTS font) OSDClearArea(30, -1, -1, -1, BLACK); // Side and Top menu titles. - OSDWriteString(0, 0, 8, 8, 0, 0, FONT_9X16, DEG270, sideTitle, BLUE, WHITE); + OSDWriteString(0, 0, 8, 8, 0, 0, FONT_9X16, DEG270, sideTitle, NULL, BLUE, WHITE); // Adjust the title start location when it is larger than the display area. - OSDWriteString(menuStartX, 0, 0, 0, 0, 0, font, NORMAL, (strlen(menuTitle) >= menuTitleWidth - 2) ? &menuTitle[menuTitleWidth - strlen(menuTitle) - 2] : menuTitle, WHITE, BLACK); + OSDWriteString(menuStartX, 0, 0, 0, 0, 0, font, NORMAL, (strlen(menuTitle) >= menuTitleWidth - 2) ? &menuTitle[menuTitleWidth - strlen(menuTitle) - 2] : menuTitle, NULL, WHITE, BLACK); // Top line indenting menu title. OSDDrawLine( 0, 0, menuTitleLineLeft, 0, WHITE); @@ -1162,6 +1734,38 @@ void EMZSetupDirList(char *sideTitle, char *menuTitle, enum FONTS font) // void EMZProcessMenuKey(uint8_t data, uint8_t ctrl) { + // Locals. + uint16_t menuRow = MAX_MENU_ROWS; +printf("ProcessMenuKey:%02x,%02x\n", data,ctrl); + // Does the key match a hotkey? If it does, modify active row and action. + for(menuRow=0; menuRow < MAX_MENU_ROWS; menuRow++) + { + // Skip inactive or hidden rows. + if(emuControl.menu.data[menuRow] == NULL) + continue; + if(emuControl.menu.data[menuRow]->state != MENUSTATE_ACTIVE) + continue; + // Key match? + if(toupper(emuControl.menu.data[menuRow]->hotKey) == toupper(data)) + break; + } + + // If key matched with a hotkey then modify action according to row type. + if(menuRow != MAX_MENU_ROWS) + { + // Update the active row to the matched hotkey row. + emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = menuRow; + + // Update the action. + if(emuControl.menu.data[menuRow]->type & MENUTYPE_ACTION) + data = 0x0D; + else if(emuControl.menu.data[menuRow]->type & MENUTYPE_CHOICE) + data = ' '; + else if(emuControl.menu.data[menuRow]->type & MENUTYPE_SUBMENU) + data = 0xA3; + } + + // Process the data received. switch(data) { // Up key. @@ -1177,20 +1781,15 @@ void EMZProcessMenuKey(uint8_t data, uint8_t ctrl) case 0xA1: if(emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx]] != NULL) { -printf("Calling down\n"); emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = EMZDrawMenu(++emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx], 1, MENU_WRAP); -printf("Calling Refresh\n"); OSDRefreshScreen(); -printf("Calling done\n"); } break; // Left key. case 0xA4: -printf("HERE 1:%d\n", emuControl.activeMenu.menuIdx); if(emuControl.activeMenu.menuIdx != 0) { -printf("HERE 2\n"); emuControl.activeMenu.menuIdx = emuControl.activeMenu.menuIdx-1; EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); } @@ -1214,18 +1813,15 @@ printf("HERE 2\n"); case 0xA3: if(emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx]] != NULL && emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx]]->type & MENUTYPE_SUBMENU && emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx]]->menuCallback != NULL) { -printf("HERE 4:%d\n", emuControl.activeMenu.menuIdx); emuControl.activeMenu.menuIdx = emuControl.activeMenu.menuIdx >= MAX_MENU_DEPTH - 1 ? MAX_MENU_DEPTH - 1 : emuControl.activeMenu.menuIdx+1; emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx-1]]->menuCallback(ACTION_SELECT); } else if(data == 0x0D && emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx]] != NULL) { -printf("HERE 5:%d\n", emuControl.activeMenu.menuIdx); if(emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx]]->menuCallback != NULL) emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx]]->menuCallback(ACTION_SELECT); if(emuControl.menu.data[emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx]]->cbAction == MENUCB_REFRESH) { -printf("HERE 5 DM:%d\n", emuControl.activeMenu.menuIdx); EMZDrawMenu(emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx], 0, MENU_WRAP); OSDRefreshScreen(); } @@ -1289,7 +1885,7 @@ uint8_t EMZReadDirectory(const char *path, const char *filter) // Filter out files not relevant to the caller based on the provided filter. const char *ext = strrchr(fno.fname, '.'); const char *filterExt = strrchr(filter, '.'); - +//FIX ME: Doesnt process wildcard filename // Is a File Is not a Wildcard Filter doesnt match the extension if(!(fno.fattrib & AM_DIR) && !(filterExt != NULL && strcmp(filterExt, "\*") == 0) && (ext == NULL || strcasecmp(++ext, (filterExt == NULL ? filter : ++filterExt)) != 0)) continue; @@ -1378,7 +1974,8 @@ int16_t EMZDrawFileList(int16_t activeRow, uint8_t direction) uint8_t xpad = 0; uint8_t ypad = 1; uint16_t rowPixelDepth = (emuControl.fileList.rowFontptr->height + emuControl.fileList.rowFontptr->spacing + emuControl.fileList.padding + 2*ypad); - uint16_t colPixelEnd = (uint16_t)OSDGet(ACTIVE_MAX_X) - emuControl.fileList.colPixelsEnd; + uint16_t maxCol = (uint16_t)OSDGet(ACTIVE_MAX_X); + uint16_t colPixelEnd = maxCol - emuControl.fileList.colPixelsEnd; uint16_t maxRow = ((uint16_t)OSDGet(ACTIVE_MAX_Y)/rowPixelDepth) + 1; uint8_t textChrX = (emuControl.fileList.colPixelStart / (emuControl.fileList.rowFontptr->width + emuControl.fileList.rowFontptr->spacing)); char activeBuf[MENU_ROW_WIDTH]; @@ -1395,26 +1992,25 @@ int16_t EMZDrawFileList(int16_t activeRow, uint8_t direction) // If this is a sub directory, place a back arrow to indicate you can go back. if(emuControl.activeDir.dirIdx != 0) { - OSDWriteString(textChrX, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "\x1b back", CYAN, BLACK); + OSDWriteString(textChrX, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "\x1b back", NULL, CYAN, BLACK); } // Place scroll arrows if we span a page. if(activeRow >= maxRow && visibleRows > maxRow) { - OSDWriteString(textChrX+70, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x17", CYAN, BLACK); + OSDWriteString(textChrX+(maxCol < 512 ? 38 : 70), 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x17", NULL, CYAN, BLACK); } else if(activeRow >= maxRow) { - OSDWriteString(textChrX+70, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x18 ",CYAN, BLACK); + OSDWriteString(textChrX+(maxCol < 512 ? 38 : 70), 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x18 ",NULL, CYAN, BLACK); } else if(visibleRows > maxRow) { - OSDWriteString(textChrX+70, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x19", CYAN, BLACK); + OSDWriteString(textChrX+(maxCol < 512 ? 38 : 70), 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "scroll \x19", NULL, CYAN, BLACK); } else { - OSDWriteString(textChrX+70, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, " ", CYAN, BLACK); + OSDWriteString(textChrX+(maxCol < 512 ? 38 : 70), 0, 0, 4, 0, 0, FONT_5X7, NORMAL, " ", NULL, CYAN, BLACK); } -printf("first=%d, last=%d, visible=%d\n", firstFileListRow, lastFileListRow, visibleRows); // Sanity check, no files or parameters out of range just exit as though the directory is empty. if(firstFileListRow == -1 || lastFileListRow == -1 || visibleRows == 0) return(activeRow); @@ -1450,7 +2046,6 @@ printf("first=%d, last=%d, visible=%d\n", firstFileListRow, lastFileListRow, vis continue; if(dspRow >= maxRow) continue; -printf("%d, %d, %d, %d, %d\n", activeRow, fileRow, emuControl.fileList.dirEntries[fileRow].name, emuControl.fileList.dirEntries[fileRow].isDir, dspRow, maxRow); // Format the data into a single buffer for output. uint16_t selectionWidth = EMZGetFileListColumnWidth() - 9; @@ -1460,13 +2055,13 @@ printf("%d, %d, %d, %d, %d\n", activeRow, fileRow, emuControl.fileList.dirEntrie // Finall output the row according to selection. if(activeRow == fileRow) { - OSDWriteString(textChrX, dspRow, 0, emuControl.fileList.rowPixelStart, xpad, ypad, emuControl.fileList.font, NORMAL, activeBuf, emuControl.fileList.activeFgColour, emuControl.fileList.activeBgColour); + OSDWriteString(textChrX, dspRow, 0, emuControl.fileList.rowPixelStart, xpad, ypad, emuControl.fileList.font, NORMAL, activeBuf, NULL, emuControl.fileList.activeFgColour, emuControl.fileList.activeBgColour); if(activeRow != -1) emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] = activeRow; } else { - OSDWriteString(textChrX, dspRow, 0, emuControl.fileList.rowPixelStart, xpad, ypad, emuControl.fileList.font, NORMAL, activeBuf, emuControl.fileList.inactiveFgColour, emuControl.fileList.inactiveBgColour); + OSDWriteString(textChrX, dspRow, 0, emuControl.fileList.rowPixelStart, xpad, ypad, emuControl.fileList.font, NORMAL, activeBuf, NULL, emuControl.fileList.inactiveFgColour, emuControl.fileList.inactiveBgColour); } dspRow++; } @@ -1482,7 +2077,7 @@ void EMZGetFile(void) // Method to process a key event according to current state. If displaying a list of files for selection then this method is called to allow user interaction with the file // list and ultimate selection. // -void processFileListKey(uint8_t data, uint8_t ctrl) +void EMZProcessFileListKey(uint8_t data, uint8_t ctrl) { // Locals. // @@ -1496,7 +2091,6 @@ void processFileListKey(uint8_t data, uint8_t ctrl) // If the break key is pressed, this is equivalent to escape so exit file list selection. if(ctrl & KEY_BREAK_BIT) { -printf("BREAK pressed\n"); // Just switch back to active menu dont activate the callback for storing a selection. EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); } else @@ -1533,7 +2127,6 @@ printf("BREAK pressed\n"); emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] = emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] - maxRow -1 > 0 ? emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] - maxRow -1 : 0; } emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] = EMZDrawFileList(--emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx], 0); - printf("ACTIVE ROW:%d\n", emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] ); OSDRefreshScreen(); break; @@ -1544,19 +2137,14 @@ printf("BREAK pressed\n"); { emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] = emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] + maxRow -1 > 0 ? emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] + maxRow -1 : MAX_DIRENTRY-1; } - printf("BEFORE:%d\n", emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx]); emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] = EMZDrawFileList(++emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx], 1); - printf("AFTER:%d\n", emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx]); - printf("ACTIVE ROW:%d\n", emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx] ); OSDRefreshScreen(); break; // Left key. case 0xA4: - printf("HERE 1:%d\n", emuControl.activeDir.dirIdx); if(emuControl.activeDir.dirIdx != 0) { - printf("HERE 2\n"); emuControl.activeDir.dirIdx = emuControl.activeDir.dirIdx-1; EMZSetupDirList("Select File", emuControl.activeDir.dir[emuControl.activeDir.dirIdx], FONT_7X8); @@ -1591,12 +2179,10 @@ printf("BREAK pressed\n"); } if(emuControl.activeDir.dirIdx == 1) { - printf("ACTIVE ROW=%d,%s\n", emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx],emuControl.fileList.dirEntries[emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx-1]].name ); sprintf(tmpbuf, "0:\\%s", emuControl.fileList.dirEntries[emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx-1]].name); } else { - printf("ACTIVE ROW=%d\n", emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx],emuControl.fileList.dirEntries[emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx-1]].name ); sprintf(tmpbuf, "%s\\%s", emuControl.activeDir.dir[emuControl.activeDir.dirIdx-1], emuControl.fileList.dirEntries[emuControl.activeDir.activeRow[emuControl.activeDir.dirIdx-1]].name); } if((emuControl.activeDir.dir[emuControl.activeDir.dirIdx] = (char *)malloc(strlen(tmpbuf)+1)) == NULL) @@ -1605,7 +2191,6 @@ printf("BREAK pressed\n"); return; } strcpy(emuControl.activeDir.dir[emuControl.activeDir.dirIdx], tmpbuf); - printf("DATA:%d,%s,%s\n", emuControl.activeDir.dirIdx, tmpbuf, emuControl.activeDir.dir[emuControl.activeDir.dirIdx]); // Bring up the OSD. EMZSetupDirList("Select File", emuControl.activeDir.dir[emuControl.activeDir.dirIdx], FONT_7X8); @@ -1690,11 +2275,84 @@ void EMZLoadDirectToRAM(enum ACTIONMODE mode) return; } +// Method to print out the details of the last processed tape. +// +void EMZPrintTapeDetails(short errCode) +{ + // Locals. + // + uint8_t textChrX = (emuControl.menu.colPixelStart / (emuControl.menu.rowFontptr->width + emuControl.menu.rowFontptr->spacing)); + char strBuf[MENU_ROW_WIDTH]; + + // Use the menu framework to draw the borders and title but write the details directly. + // + if(errCode) + EMZSetupMenu(EMZGetMachineTitle(), "Tape Error", FONT_7X8); + else + EMZSetupMenu(EMZGetMachineTitle(), "Tape Details", FONT_7X8); + + sprintf(strBuf, "File Size: %04x", emuControl.tapeHeader.fileSize); + OSDWriteString(18, 4, 0, 2, 0, 0, FONT_7X8, NORMAL, strBuf, NULL, WHITE, BLACK); + sprintf(strBuf, "File Type: %s", EMZGetTapeType()); + OSDWriteString(18, 5, 0, 2, 0, 0, FONT_7X8, NORMAL, strBuf, NULL, WHITE, BLACK); + sprintf(strBuf, "File Name: %s", emuControl.tapeHeader.fileName); + OSDWriteString(18, 6, 0, 2, 0, 0, FONT_7X8, NORMAL, strBuf, NULL, WHITE, BLACK); + sprintf(strBuf, "Load Addr: %04x", emuControl.tapeHeader.loadAddress); + OSDWriteString(18, 7, 0, 2, 0, 0, FONT_7X8, NORMAL, strBuf, NULL, WHITE, BLACK); + sprintf(strBuf, "Exec Addr: %04x", emuControl.tapeHeader.execAddress); + OSDWriteString(18, 8, 0, 2, 0, 0, FONT_7X8, NORMAL, strBuf, NULL, WHITE, BLACK); + + if(errCode > 0 && errCode < 0x20) + { + sprintf(strBuf, "FAT FileSystem error code: %02x", errCode); + } + else if(errCode == 0x20) + { + sprintf(strBuf, "File header contains insufficient bytes."); + } + else if(errCode == 0x21) + { + sprintf(strBuf, "Tape Data Type is invalid: %02x", emuControl.tapeHeader.dataType); + } + else if(errCode == 0x22) + { + sprintf(strBuf, "Tape is not machine code, cannot load to RAM directly."); + } + else if(errCode == 0x23 || errCode == 0x24) + { + sprintf(strBuf, "File read error. directly."); + } + else + { + sprintf(strBuf, "Unknown error (%02x) processing tape file.", errCode); + } + if(errCode > 0) + { + OSDWriteString(((VC_MENU_MAX_X_PIXELS/7) - 4 - strlen(strBuf))/2, 12, 0, 2, 0, 0, FONT_7X8, NORMAL, strBuf, NULL, RED, BLACK); + } + EMZRefreshMenu(); + + return; +} + // Secondary method called after a file has been chosen. // -void EMZLoadDirectToRAMSet(char *param) +void EMZLoadDirectToRAMSet(char *fileName) { - printf("IVE GOT A FILE:%s\n", param); + // Locals. + // + short errCode; + + // Simply call tape load with the RAM option to complete request. + errCode = EMZLoadTapeToRAM(fileName, 0); + + // Print out the tape details. + EMZPrintTapeDetails(errCode); + + // Slight delay to give user chance to see the details. + delay(8000); + + return; } // Method to push a tape filename onto the queue. @@ -1815,10 +2473,12 @@ char *EMZNextTapeQueueFilename(char reset) // Method to clear the queued tape list. // -void EMZClearTapeQueue(void) +uint16_t EMZClearTapeQueue(void) { // Locals. + uint16_t entries = emuControl.tapeQueue.elements; + // Clear the queue through iteration, freeing allocated memory per entry. if(emuControl.tapeQueue.elements > 0) { for(int i=0; i < MAX_TAPE_QUEUE; i++) @@ -1830,9 +2490,13 @@ void EMZClearTapeQueue(void) emuControl.tapeQueue.queue[i] = NULL; } } + // Reset control variables. emuControl.tapeQueue.elements = 0; emuControl.tapeQueue.tapePos = 0; emuControl.tapeQueue.fileName[0] = 0; + + // Finally, return number of entries in the queue which have been cleared out. + return(entries); } // Method to select a tape file which is added to the tape queue. The tape queue is a virtual tape where @@ -1871,7 +2535,11 @@ void EMZQueueClear(enum ACTIONMODE mode) { if(mode == ACTION_DEFAULT || mode == ACTION_SELECT) { - EMZClearTapeQueue(); + uint16_t deletedEntries = EMZClearTapeQueue(); + + // Update the active row to account for number of entries deleted. + if(emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] - deletedEntries > 0) + emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] -= deletedEntries; // Need to redraw the menu as read only text has changed. EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); @@ -1883,7 +2551,7 @@ void EMZTapeSave(enum ACTIONMODE mode) { if(mode == ACTION_DEFAULT || mode == ACTION_SELECT) { - // Test to see if a recording is in the tape buffer, if it is then save to the name given in the MZF header + // Prompt to enter the path in which incoming files will be saved. EMZSetupDirList("Select Path", emuControl.activeDir.dir[emuControl.activeDir.dirIdx], FONT_7X8); strcpy(emuControl.fileList.fileFilter, "."); emuControl.fileList.selectDir = 1; @@ -1905,8 +2573,18 @@ void EMZTapeSaveSet(char *param) emuControl.fileList.selectDir = 0; } -void EMZReset(unsigned long preResetSleep, unsigned long postResetSleep) +void EMZReset(void) { + // Initiate a machine RESET via the control registers. + // + emuConfig.emuRegisters[MZ_EMU_REG_CTRL] |= 0x01; + + // Write the control register to initiate RESET command. + writeZ80Array(MZ_EMU_ADDR_REG_MODEL+emuConfig.emuRegisters[MZ_EMU_REG_CTRL], &emuConfig.emuRegisters[emuConfig.emuRegisters[MZ_EMU_REG_CTRL]], 1, FPGA); + + // Clear any reset command from the internal register copy so the command isnt accidentally sent again. + emuConfig.emuRegisters[MZ_EMU_REG_CTRL] &= 0xFE; + } // Method to reset the machine. This can be done via the hardware, load up the configuration and include the machine definition and the hardware will force a reset. @@ -1917,9 +2595,56 @@ void EMZResetMachine(enum ACTIONMODE mode) { // Force a reload of the machine ROM's and reset. EMZSwitchToMachine(emuConfig.machineModel, 1); + + // Refresh menu to update cursor. + EMZRefreshMenu(); } } +// Method to read in the header of an MZF file and populate the tapeHeader structure. +// +short EMZReadTapeDetails(const char *tapeFile) +{ + // Locals. + // + char loadName[MAX_FILENAME_LEN+1]; + uint32_t actualReadSize; + FIL fileDesc; + FRESULT result; + + // If a relative path has been given we need to expand it into an absolute path. + if(tapeFile[0] != '/' && tapeFile[0] != '\\' && (tapeFile[0] < 0x30 || tapeFile[0] > 0x32)) + { + sprintf(loadName, "%s\%s", TOPLEVEL_DIR, tapeFile); + } else + { + strcpy(loadName, tapeFile); + } + + // Attempt to open the file for reading. + result = f_open(&fileDesc, loadName, FA_OPEN_EXISTING | FA_READ); + if(result) + { + debugf("EMZReadTapeDetails(open) File:%s, error: %d.\n", loadName, fileDesc); + return(result); + } + + // Read in the tape header, this indicates crucial data such as data type, size, exec address, load address etc. + // + result = f_read(&fileDesc, &emuControl.tapeHeader, MZF_HEADER_SIZE, &actualReadSize); + if(actualReadSize != 128) + { + debugf("Only read:%d bytes of header, aborting.\n", actualReadSize); + f_close(&fileDesc); + return(0x20); + } + + // Close the open file to complete, details stored in the tapeHeader structure. + f_close(&fileDesc); + + return result; +} + // Method to load a tape (MZF) file directly into RAM. // This involves reading the tape header, extracting the size and destination and loading // the header and program into emulator ram. @@ -1936,7 +2661,6 @@ short EMZLoadTapeToRAM(const char *tapeFile, unsigned char dstCMT) uint32_t readSize; char loadName[MAX_FILENAME_LEN+1]; char sectorBuffer[512]; - t_tapeHeader tapeHeader; #if defined __EMUMZ_DEBUG__ char fileName[17]; @@ -1963,86 +2687,86 @@ short EMZLoadTapeToRAM(const char *tapeFile, unsigned char dstCMT) // Read in the tape header, this indicates crucial data such as data type, size, exec address, load address etc. // - result = f_read(&fileDesc, &tapeHeader, MZF_HEADER_SIZE, &actualReadSize); + result = f_read(&fileDesc, &emuControl.tapeHeader, MZF_HEADER_SIZE, &actualReadSize); if(actualReadSize != 128) { debugf("Only read:%d bytes of header, aborting.\n", actualReadSize); f_close(&fileDesc); - return(2); + return(0x20); } // Some sanity checks. // - if(tapeHeader.dataType == 0 || tapeHeader.dataType > 5) return(4); + if(emuControl.tapeHeader.dataType == 0 || emuControl.tapeHeader.dataType > 5) return(0x21); #if defined __EMUMZ_DEBUG__ for(int i=0; i < 17; i++) { - fileName[i] = tapeHeader.fileName[i] == 0x0d ? 0x00 : tapeHeader.fileName[i]; + fileName[i] = emuControl.tapeHeader.fileName[i] == 0x0d ? 0x00 : emuControl.tapeHeader.fileName[i]; } // Debug output to indicate the file loaded and information about the tape image. // - switch(tapeHeader.dataType) + switch(emuControl.tapeHeader.dataType) { case 0x01: - debugf("Binary File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + debugf("Binary File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", emuControl.tapeHeader.loadAddress, emuControl.tapeHeader.fileSize, emuControl.tapeHeader.execAddress, fileName); break; case 0x02: - debugf("MZ-80 Basic Program(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + debugf("MZ-80 Basic Program(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", emuControl.tapeHeader.loadAddress, emuControl.tapeHeader.fileSize, emuControl.tapeHeader.execAddress, fileName); break; case 0x03: - debugf("MZ-80 Data File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + debugf("MZ-80 Data File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", emuControl.tapeHeader.loadAddress, emuControl.tapeHeader.fileSize, emuControl.tapeHeader.execAddress, fileName); break; case 0x04: - debugf("MZ-700 Data File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + debugf("MZ-700 Data File(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", emuControl.tapeHeader.loadAddress, emuControl.tapeHeader.fileSize, emuControl.tapeHeader.execAddress, fileName); break; case 0x05: - debugf("MZ-700 Basic Program(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + debugf("MZ-700 Basic Program(Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", emuControl.tapeHeader.loadAddress, emuControl.tapeHeader.fileSize, emuControl.tapeHeader.execAddress, fileName); break; default: - debugf("Unknown tape type(Type=%02x, Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", tapeHeader.dataType, tapeHeader.loadAddress, tapeHeader.fileSize, tapeHeader.execAddress, fileName); + debugf("Unknown tape type(Type=%02x, Load Addr=%04x, Size=%04x, Exec Addr=%04x, FileName=%s)\n", emuControl.tapeHeader.dataType, emuControl.tapeHeader.loadAddress, emuControl.tapeHeader.fileSize, emuControl.tapeHeader.execAddress, fileName); break; } #endif // Check the data type, only load machine code directly to RAM. // - if(dstCMT == 0 && tapeHeader.dataType != CMT_TYPE_OBJCD) + if(dstCMT == 0 && emuControl.tapeHeader.dataType != CMT_TYPE_OBJCD) { f_close(&fileDesc); - return(3); + return(0x22); } // Reset Emulator if loading direct to RAM. This clears out memory, resets monitor and places it in a known state. // if(dstCMT == 0) - EMZReset(10, 50000); + EMZReset(); // Load the data from tape to RAM. // if(dstCMT == 0) // Load to emulators RAM { - loadAddress = MZ_EMU_RAM_ADDR + tapeHeader.loadAddress; + loadAddress = MZ_EMU_RAM_ADDR + emuControl.tapeHeader.loadAddress; } else { loadAddress = MZ_EMU_CMT_DATA_ADDR; } - for (unsigned short i = 0; i < tapeHeader.fileSize && actualReadSize > 0; i += actualReadSize) + for (unsigned short i = 0; i < emuControl.tapeHeader.fileSize && actualReadSize > 0; i += actualReadSize) { result = f_read(&fileDesc, sectorBuffer, 512, &actualReadSize); if(result) { debugf("Failed to read data from file:%s @ addr:%08lx, aborting.\n", loadName, loadAddress); f_close(&fileDesc); - return(4); + return(0x23); } - debugf("Bytes to read, actual:%d, index:%d, sizeHeader:%d, load:%08lx", actualReadSize, i, tapeHeader.fileSize, loadAddress); + debugf("Bytes to read, actual:%d, index:%d, sizeHeader:%d, load:%08lx", actualReadSize, i, emuControl.tapeHeader.fileSize, loadAddress); if(actualReadSize > 0) { @@ -2051,14 +2775,14 @@ short EMZLoadTapeToRAM(const char *tapeFile, unsigned char dstCMT) loadAddress += actualReadSize; } else { - debugf("Bad tape or corruption, should never be 0, actual:%d, index:%d, sizeHeader:%d", actualReadSize, i, tapeHeader.fileSize); - return(4); + debugf("Bad tape or corruption, should never be 0, actual:%d, index:%d, sizeHeader:%d", actualReadSize, i, emuControl.tapeHeader.fileSize); + return(0x24); } } // Now load header - this is done last because the emulator monitor wipes the stack area on reset. // - writeZ80Array(MZ_EMU_CMT_HDR_ADDR, &tapeHeader, MZF_HEADER_SIZE, FPGA); + writeZ80Array(MZ_EMU_CMT_HDR_ADDR, &emuControl.tapeHeader, MZF_HEADER_SIZE, FPGA); #ifdef __EMUMZ_DEBUG__ time = *ms - time; @@ -2072,7 +2796,7 @@ short EMZLoadTapeToRAM(const char *tapeFile, unsigned char dstCMT) // for(int i=0; i < 17; i++) { - if(tapeHeader.fileName[i] == 0x0d) tapeHeader.fileName[i] = 0x00; + if(emuControl.tapeHeader.fileName[i] == 0x0d) emuControl.tapeHeader.fileName[i] = 0x00; } // Success. @@ -2095,7 +2819,6 @@ short EMZSaveTapeFromCMT(const char *tapeFile) FRESULT result; uint32_t time = *ms; char sectorBuffer[512]; - t_tapeHeader tapeHeader; // Read the header, then data, but limit data size to the 'file size' stored in the header. // @@ -2109,10 +2832,10 @@ short EMZSaveTapeFromCMT(const char *tapeFile) readAddress = MZ_EMU_CMT_HDR_ADDR; } else { - dataSize = tapeHeader.fileSize; - readAddress = MZ_EMU_CMT_DATA_ADDR + tapeHeader.loadAddress; + dataSize = emuControl.tapeHeader.fileSize; + readAddress = MZ_EMU_CMT_DATA_ADDR + emuControl.tapeHeader.loadAddress; + debugf("mb=%d, tapesize=%04x\n", mb, emuControl.tapeHeader.fileSize); } - debugf("mb=%d, tapesize=%04x\n", mb, tapeHeader.fileSize); for (; dataSize > 0; dataSize -= actualWriteSize) { debugf("mb=%d, dataSize=%04x, writeSize=%04x\n", mb, dataSize, writeSize); @@ -2129,7 +2852,7 @@ short EMZSaveTapeFromCMT(const char *tapeFile) if(mb == 0) { - memcpy(&tapeHeader, §orBuffer, MZF_HEADER_SIZE); + memcpy(&emuControl.tapeHeader, §orBuffer, MZF_HEADER_SIZE); // Now open the file for writing. If no name provided, use the one stored in the header. // @@ -2137,10 +2860,10 @@ short EMZSaveTapeFromCMT(const char *tapeFile) { for(int i=0; i < 17; i++) { - fileName[i] = tapeHeader.fileName[i] == 0x0d ? 0x00 : tapeHeader.fileName[i]; + fileName[i] = emuControl.tapeHeader.fileName[i] == 0x0d ? 0x00 : emuControl.tapeHeader.fileName[i]; } strcat(fileName, ".mzf"); - debugf("File from tape:%s (%02x,%04x,%04x,%04x)\n", fileName, tapeHeader.dataType, tapeHeader.fileSize, tapeHeader.loadAddress, tapeHeader.execAddress); + debugf("File from tape:%s (%02x,%04x,%04x,%04x)\n", fileName, emuControl.tapeHeader.dataType, emuControl.tapeHeader.fileSize, emuControl.tapeHeader.loadAddress, emuControl.tapeHeader.execAddress); } else { strcpy(fileName, tapeFile); @@ -2386,6 +3109,83 @@ void EMZFloppyDiskROMSet(char *param) } } +// Method to enable/disable the cold boot application load and select the image to be loaded. +// +void EMZLoadApplication(enum ACTIONMODE mode) +{ + if(mode == ACTION_TOGGLECHOICE) + { + EMZNextLoadApplication(mode); + EMZRefreshMenu(); + } else + if(mode == ACTION_DEFAULT || mode == ACTION_SELECT) + { + EMZSetupDirList("Select File", emuControl.activeDir.dir[emuControl.activeDir.dirIdx], FONT_7X8); + strcpy(emuControl.fileList.fileFilter, "*.MZF"); + emuControl.fileList.selectDir = 0; + EMZReadDirectory(emuControl.activeDir.dir[emuControl.activeDir.dirIdx], emuControl.fileList.fileFilter); + EMZRefreshFileList(); + + // Switch to the File List Dialog mode setting the return Callback which will be activated after a file has been chosen. + // + emuControl.activeDialog = DIALOG_FILELIST; + emuControl.fileList.returnCallback = EMZLoadApplicationSet; + } +} + +// Method to store the selected file name. +void EMZLoadApplicationSet(char *param) +{ + // Locals. + uint8_t tmpbuf[20]; + + // If a file has been selected, store it within the config and also extract the load address from the file to be used as the + // default Post load key injection sequence. + if(strlen(param) < MAX_FILENAME_LEN) + { + strcpy(emuConfig.params[emuConfig.machineModel].loadApp.appFileName, param); + emuConfig.params[emuConfig.machineModel].loadApp.appEnabled = 1; + + // Try read the tape, set tapeHeader structure to tape details. + if(EMZReadTapeDetails(emuConfig.params[emuConfig.machineModel].loadApp.appFileName) == 0) + { + // Clear out existing key entries. + for(uint16_t idx=0; idx < MAX_KEY_INS_BUFFER; idx++) { if(emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx].i == 0) { emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx].i = 0xffffffff; } } + + // First key injection is a pause, a delay needed for the monitor BIOS to startup and present the entry prompt. + emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[0].b[0] = 0x00; + emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[0].b[1] = 0x00; + emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[0].b[2] = 0x7f; + emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[0].b[3] = 0x82; + + // Default command based on target machine. + // + switch(emuConfig.machineModel) + { + case MZ80K: + case MZ80C: + sprintf(tmpbuf, "GOTO$%04x\r", emuControl.tapeHeader.execAddress); + break; + + default: + sprintf(tmpbuf, "J%04x\r", emuControl.tapeHeader.execAddress); + break; + } + + for(uint16_t idx=0; idx < strlen(tmpbuf); idx++) + { + // Map the ASCII key and insert into the key injection buffer. + t_numCnv map = EMZMapToScanCode(emuControl.hostMachine, tmpbuf[idx]); + emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx+1].b[0] = map.b[0]; + emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx+1].b[1] = map.b[1]; + emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx+1].b[2] = 0x7f; + emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx+1].b[3] = 0x7f; + + } + } + } +} + void EMZMainMenu(void) { // Locals. @@ -2397,16 +3197,16 @@ void EMZMainMenu(void) emuControl.activeDialog = DIALOG_MENU; EMZSetupMenu(EMZGetMachineTitle(), "Main Menu", FONT_7X8); - EMZAddToMenu(row++, 0, "Tape Storage", MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZTapeStorageMenu, MENUCB_REFRESH, NULL ); - EMZAddToMenu(row++, 0, "Machine", MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZMachineMenu, MENUCB_REFRESH, NULL ); - EMZAddToMenu(row++, 0, "Display", MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZDisplayMenu, MENUCB_REFRESH, NULL ); - EMZAddToMenu(row++, 0, "System", MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZSystemMenu, MENUCB_REFRESH, NULL ); - EMZAddToMenu(row++, 0, "", MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "", MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "Reset", MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZResetMachine, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "Reload config", MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZReadConfig, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "Save config", MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZWriteConfig, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "Reset config", MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZResetConfig, MENUCB_DONOTHING, NULL ); + EMZAddToMenu(row++, 0, "Tape Storage", 'T', MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZTapeStorageMenu, MENUCB_REFRESH, NULL, NULL ); + EMZAddToMenu(row++, 0, "Floppy Storage", 'F', MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZFloppyStorageMenu, MENUCB_REFRESH, NULL, NULL ); + EMZAddToMenu(row++, 0, "Machine", 'M', MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZMachineMenu, MENUCB_REFRESH, NULL, NULL ); + EMZAddToMenu(row++, 0, "Display", 'D', MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZDisplayMenu, MENUCB_REFRESH, NULL, NULL ); + EMZAddToMenu(row++, 0, "Audio", 'A', MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZAudioMenu, MENUCB_REFRESH, NULL, NULL ); + EMZAddToMenu(row++, 0, "System", 'S', MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZSystemMenu, MENUCB_REFRESH, NULL, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "Reset Machine", 'R', MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZResetMachine, MENUCB_DONOTHING, NULL, NULL ); EMZRefreshMenu(); } @@ -2419,14 +3219,14 @@ void EMZTapeStorageMenu(enum ACTIONMODE mode) char lineBuf[MENU_ROW_WIDTH+1]; // Set active menu for the case when this method is invoked as a menu callback. - emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_STORAGE; + emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_TAPE_STORAGE; emuControl.activeDialog = DIALOG_MENU; EMZSetupMenu(EMZGetMachineTitle(), "Tape Storage Menu", FONT_7X8); - EMZAddToMenu(row++, 0, "CMT Hardware", MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZChangeCMTMode, MENUCB_REFRESH, EMZGetCMTModeChoice ); - EMZAddToMenu(row++, 0, "Load tape direct to RAM", MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZLoadDirectToRAM, MENUCB_DONOTHING, EMZGetLoadDirectFileFilterChoice ); - EMZAddToMenu(row++, 0, "", MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "Queue Tape", MENUTYPE_ACTION | MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZQueueTape, MENUCB_DONOTHING, EMZGetQueueTapeFileFilterChoice ); + EMZAddToMenu(row++, 0, "CMT Hardware", 'C', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZChangeCMTMode, MENUCB_REFRESH, EMZGetCMTModeChoice, NULL ); + EMZAddToMenu(row++, 0, "Load tape to RAM", 'L', MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZLoadDirectToRAM, MENUCB_DONOTHING, EMZGetLoadDirectFileFilterChoice, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "Queue Tape", 'Q', MENUTYPE_ACTION | MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZQueueTape, MENUCB_DONOTHING, EMZGetQueueTapeFileFilterChoice, NULL ); // List out the current tape queue. if(!emuConfig.params[emuConfig.machineModel].cmtMode) @@ -2440,17 +3240,35 @@ void EMZTapeStorageMenu(enum ACTIONMODE mode) sprintf(lineBuf, " >%d %.50s", fileCount++, fileName); else sprintf(lineBuf, " %d %.50s", fileCount++, fileName); - EMZAddToMenu(row++, 0, lineBuf, MENUTYPE_TEXT, MENUSTATE_TEXT, NULL, MENUCB_DONOTHING, NULL ); + EMZAddToMenu(row++, 0, lineBuf, 0x00, MENUTYPE_TEXT, MENUSTATE_TEXT, NULL, MENUCB_DONOTHING, NULL, NULL ); } } - EMZAddToMenu(row++, 0, "Clear Queue", MENUTYPE_ACTION, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZQueueClear, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "Save Tape Directory", MENUTYPE_ACTION | MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZTapeSave, MENUCB_DONOTHING, EMZGetTapeSaveFilePathChoice ); - EMZAddToMenu(row++, 0, "Auto Save Tape", MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZNextTapeAutoSave, MENUCB_REFRESH, EMZGetTapeAutoSaveChoice ); - EMZAddToMenu(row++, 0, "", MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "File Name Ascii Mapping", MENUTYPE_ACTION | MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZNextCMTAsciiMapping, MENUCB_REFRESH, EMZGetCMTAsciiMappingChoice ); - EMZAddToMenu(row++, 0, "Tape Buttons", MENUTYPE_ACTION | MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZNextTapeButtons, MENUCB_REFRESH, EMZGetTapeButtonsChoice ); - EMZAddToMenu(row++, 0, "Fast Tape Load", MENUTYPE_ACTION | MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZNextFastTapeLoad, MENUCB_REFRESH, EMZGetFastTapeLoadChoice ); + EMZAddToMenu(row++, 0, "Clear Queue", 'e', MENUTYPE_ACTION, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZQueueClear, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "Save Tape Directory", 'T', MENUTYPE_ACTION | MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZTapeSave, MENUCB_DONOTHING, EMZGetTapeSaveFilePathChoice, NULL ); + EMZAddToMenu(row++, 0, "Auto Save Tape", 'A', MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZNextTapeAutoSave, MENUCB_REFRESH, EMZGetTapeAutoSaveChoice, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "File Name Map Ascii", 'F', MENUTYPE_ACTION | MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZNextCMTAsciiMapping, MENUCB_REFRESH, EMZGetCMTAsciiMappingChoice, NULL ); + EMZAddToMenu(row++, 0, "Tape Buttons", 'B', MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZNextTapeButtons, MENUCB_REFRESH, EMZGetTapeButtonsChoice, NULL ); + EMZAddToMenu(row++, 0, "Fast Tape Load", 'd', MENUTYPE_CHOICE, !emuConfig.params[emuConfig.machineModel].cmtMode ? MENUSTATE_ACTIVE : MENUSTATE_HIDDEN, EMZNextFastTapeLoad, MENUCB_REFRESH, EMZGetFastTapeLoadChoice, NULL ); + // When called as a select callback then the menus are moving forward so start the active row at the top. + if(mode == ACTION_SELECT) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = 0; + EMZRefreshMenu(); +} + +void EMZFloppyStorageMenu(enum ACTIONMODE mode) +{ + // Locals. + // + uint8_t row = 0; + char *fileName; + char lineBuf[MENU_ROW_WIDTH+1]; + + // Set active menu for the case when this method is invoked as a menu callback. + emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_FLOPPY_STORAGE; + emuControl.activeDialog = DIALOG_MENU; + + EMZSetupMenu(EMZGetMachineTitle(), "Floppy Storage Menu", FONT_7X8); // When called as a select callback then the menus are moving forward so start the active row at the top. if(mode == ACTION_SELECT) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = 0; EMZRefreshMenu(); @@ -2467,14 +3285,18 @@ void EMZMachineMenu(enum ACTIONMODE mode) emuControl.activeDialog = DIALOG_MENU; EMZSetupMenu(EMZGetMachineTitle(), "Machine Menu", FONT_7X8); - EMZAddToMenu(row++, 0, "Machine Model", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextMachineModel, MENUCB_REFRESH, EMZGetMachineModelChoice ); - EMZAddToMenu(row++, 0, "CPU Speed", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextCPUSpeed, MENUCB_REFRESH, EMZGetCPUSpeedChoice ); - EMZAddToMenu(row++, 0, "", MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "Audio Source", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAudioSource, MENUCB_REFRESH, EMZGetAudioSourceChoice ); - EMZAddToMenu(row++, 0, "Audio Volume", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAudioVolume, MENUCB_REFRESH, EMZGetAudioVolumeChoice ); - EMZAddToMenu(row++, 0, "Audio Mute", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAudioMute, MENUCB_REFRESH, EMZGetAudioMuteChoice ); - EMZAddToMenu(row++, 0, "", MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL ); - EMZAddToMenu(row++, 0, "Rom Management", MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZRomManagementMenu, MENUCB_REFRESH, NULL ); + EMZAddToMenu(row++, 0, "Machine Model", 'M', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextMachineModel, MENUCB_REFRESH, EMZGetMachineModelChoice, NULL ); + EMZAddToMenu(row++, 0, "CPU Speed", 'C', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextCPUSpeed, MENUCB_REFRESH, EMZGetCPUSpeedChoice, NULL ); + EMZAddToMenu(row++, 0, "Memory Size", 'S', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextMemSize, MENUCB_REFRESH, EMZGetMemSizeChoice, NULL ); + if(emuConfig.machineModel == MZ800) + { + EMZAddToMenu(row++, 0, "Mode", 'o', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextMZ800Mode, MENUCB_REFRESH, EMZGetMZ800ModeChoice, NULL ); + EMZAddToMenu(row++, 0, "Printer", 'r', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextMZ800Printer, MENUCB_REFRESH, EMZGetMZ800PrinterChoice, NULL ); + EMZAddToMenu(row++, 0, "Tape In", 'a', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextMZ800TapeIn, MENUCB_REFRESH, EMZGetMZ800TapeInChoice, NULL ); + } + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "Rom Management", 'R', MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZRomManagementMenu, MENUCB_REFRESH, NULL, NULL ); + EMZAddToMenu(row++, 0, "AutoStart Application", 'u', MENUTYPE_SUBMENU, MENUSTATE_ACTIVE, EMZAutoStartApplicationMenu, MENUCB_REFRESH, NULL, NULL ); // When called as a select callback then the menus are moving forward so start the active row at the top. if(mode == ACTION_SELECT) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = 0; EMZRefreshMenu(); @@ -2491,14 +3313,87 @@ void EMZDisplayMenu(enum ACTIONMODE mode) emuControl.activeDialog = DIALOG_MENU; EMZSetupMenu(EMZGetMachineTitle(), "Display Menu", FONT_7X8); - EMZAddToMenu(row++, 0, "Display Type", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextDisplayType, MENUCB_REFRESH, EMZGetDisplayTypeChoice ); - EMZAddToMenu(row++, 0, "Display Output", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextDisplayOutput, MENUCB_REFRESH, EMZGetDisplayOutputChoice ); - EMZAddToMenu(row++, 0, "Video", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextVRAMMode, MENUCB_REFRESH, EMZGetVRAMModeChoice ); - EMZAddToMenu(row++, 0, "Graphics", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextGRAMMode, MENUCB_REFRESH, EMZGetGRAMModeChoice ); - EMZAddToMenu(row++, 0, "VRAM CPU Wait", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextVRAMWaitMode, MENUCB_REFRESH, EMZGetVRAMWaitModeChoice ); - EMZAddToMenu(row++, 0, "PCG Mode", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextPCGMode, MENUCB_REFRESH, EMZGetPCGModeChoice ); - EMZAddToMenu(row++, 0, "Aspect Ratio", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAspectRatio, MENUCB_REFRESH, EMZGetAspectRatioChoice ); - EMZAddToMenu(row++, 0, "Scandoubler", MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextScanDoublerFX, MENUCB_REFRESH, EMZGetScanDoublerFXChoice ); + switch(emuConfig.machineModel) + { + case MZ80K: + case MZ80C: + case MZ1200: + case MZ80A: + case MZ700: + case MZ1500: + EMZAddToMenu(row++, 0, "Display Type", 'T', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextDisplayType, MENUCB_REFRESH, EMZGetDisplayTypeChoice, NULL ); + break; + + default: + break; + } + switch(emuConfig.machineModel) + { + case MZ80A: + case MZ700: + case MZ800: + case MZ1500: + case MZ80B: + case MZ2000: + case MZ2200: + case MZ2500: + EMZAddToMenu(row++, 0, "Display Option", 'D', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextDisplayOption, MENUCB_REFRESH, EMZGetDisplayOptionChoice, NULL ); + break; + + default: + break; + } + EMZAddToMenu(row++, 0, "Display Output", 'O', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextDisplayOutput, MENUCB_REFRESH, EMZGetDisplayOutputChoice, NULL ); + EMZAddToMenu(row++, 0, "Video", 'V', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextVRAMMode, MENUCB_REFRESH, EMZGetVRAMModeChoice, NULL ); + switch(emuConfig.machineModel) + { + case MZ800: + case MZ80B: + case MZ2000: + case MZ2200: + case MZ2500: + EMZAddToMenu(row++, 0, "Graphics", 'G', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextGRAMMode, MENUCB_REFRESH, EMZGetGRAMModeChoice, NULL ); + break; + + default: + break; + } + if(emuConfig.machineModel == MZ80A) + { + EMZAddToMenu(row++, 0, "VRAM CPU Wait", 'W', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextVRAMWaitMode, MENUCB_REFRESH, EMZGetVRAMWaitModeChoice, NULL ); + } + if(strcmp(EMZGetDisplayOptionChoice(), "PCG") == 0) + { + EMZAddToMenu(row++, 0, "PCG Mode", 'P', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextPCGMode, MENUCB_REFRESH, EMZGetPCGModeChoice, NULL ); + } + //EMZAddToMenu(row++, 0, "Aspect Ratio", 'R', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAspectRatio, MENUCB_REFRESH, EMZGetAspectRatioChoice, NULL ); + //EMZAddToMenu(row++, 0, "Scandoubler", 'S', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextScanDoublerFX, MENUCB_REFRESH, EMZGetScanDoublerFXChoice, NULL ); + // When called as a select callback then the menus are moving forward so start the active row at the top. + if(mode == ACTION_SELECT) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = 0; + EMZRefreshMenu(); +} + +void EMZAudioMenu(enum ACTIONMODE mode) +{ + // Locals. + // + uint8_t row = 0; + + // Set active menu for the case when this method is invoked as a menu callback. + emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_AUDIO; + emuControl.activeDialog = DIALOG_MENU; + + EMZSetupMenu(EMZGetMachineTitle(), "Audio Menu", FONT_7X8); + EMZAddToMenu(row++, 0, "Source", 'S', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAudioSource, MENUCB_REFRESH, EMZGetAudioSourceChoice, NULL ); + EMZAddToMenu(row++, 0, "Hardware", 'H', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAudioHardware, MENUCB_REFRESH, EMZGetAudioHardwareChoice, NULL ); + // If FPGA sound hardware is selected show configuration options. + if(emuConfig.params[emuConfig.machineModel].audioHardware != 0) + { + EMZAddToMenu(row++, 0, "Volume", 'V', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAudioVolume, MENUCB_REFRESH, EMZGetAudioVolumeChoice, NULL ); + EMZAddToMenu(row++, 0, "Mute", 'M', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAudioMute, MENUCB_REFRESH, EMZGetAudioMuteChoice, NULL ); + EMZAddToMenu(row++, 0, "Channel Mix", 'C', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZNextAudioMix, MENUCB_REFRESH, EMZGetAudioMixChoice, NULL ); + } + // When called as a select callback then the menus are moving forward so start the active row at the top. if(mode == ACTION_SELECT) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = 0; EMZRefreshMenu(); @@ -2515,7 +3410,10 @@ void EMZSystemMenu(enum ACTIONMODE mode) emuControl.activeDialog = DIALOG_MENU; EMZSetupMenu(EMZGetMachineTitle(), "System Menu", FONT_7X8); - EMZAddToMenu(row++, 0, "About", MENUTYPE_SUBMENU | MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZAbout, MENUCB_REFRESH, NULL ); + EMZAddToMenu(row++, 0, "Reload config", 'R', MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZReadConfig, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "Save config", 'S', MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZWriteConfig, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "Reset config", 'e', MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZResetConfig, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "About", 'A', MENUTYPE_SUBMENU | MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZAbout, MENUCB_REFRESH, NULL, NULL ); // When called as a select callback then the menus are moving forward so start the active row at the top. if(mode == ACTION_SELECT) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = 0; EMZRefreshMenu(); @@ -2525,16 +3423,17 @@ void EMZAbout(enum ACTIONMODE mode) { // Locals. // - uint8_t textChrX = (emuControl.menu.colPixelStart / (emuControl.menu.rowFontptr->width + emuControl.menu.rowFontptr->spacing)); + uint16_t maxX = OSDGet(ACTIVE_MAX_X); + uint8_t textChrX = (emuControl.menu.colPixelStart / (emuControl.menu.rowFontptr->width + emuControl.menu.rowFontptr->spacing)); // Use the menu framework to draw the borders and title but write a bitmap and text directly. // EMZSetupMenu(EMZGetMachineTitle(), "About", FONT_7X8); - OSDWriteBitmap(48, 15, BITMAP_ARGO_MEDIUM, RED, BLACK); - OSDWriteString(22, 9, 0, 2, 0, 0, FONT_7X8, NORMAL, "Sharp MZ Series v2.0", CYAN, BLACK); - OSDWriteString(19, 10, 0, 2, 0, 0, FONT_7X8, NORMAL, "(C) Philip Smart, 2018-2021", CYAN, BLACK); - OSDWriteString(21, 11, 0, 2, 0, 0, FONT_7X8, NORMAL, "MZ-700 Embedded Version", CYAN, BLACK); - OSDWriteString(textChrX+1, 0, 0, 4, 0, 0, FONT_5X7, NORMAL, "\x1b back", CYAN, BLACK); + OSDWriteBitmap(48, 15, BITMAP_ARGO_MEDIUM, RED, BLACK); + OSDWriteString(22, 9, 0, 2, 0, 0, (maxX < 512 ? FONT_5X7 : FONT_7X8), NORMAL, "Sharp MZ Series v2.01", NULL, CYAN, BLACK); + OSDWriteString(19, 10, 0, 2, 0, 0, (maxX < 512 ? FONT_5X7 : FONT_7X8), NORMAL, "(C) Philip Smart, 2018-2021", NULL, CYAN, BLACK); + OSDWriteString(21, 11, 0, 2, 0, 0, (maxX < 512 ? FONT_5X7 : FONT_7X8), NORMAL, "MZ-700 Embedded Version", NULL, CYAN, BLACK); + OSDWriteString(textChrX+1, 0, 0, 4, 0, 0, (maxX < 512 ? FONT_5X7 : FONT_5X7), NORMAL, "\x1b back", NULL, CYAN, BLACK); EMZRefreshMenu(); } @@ -2550,17 +3449,328 @@ void EMZRomManagementMenu(enum ACTIONMODE mode) EMZSetupMenu(EMZGetMachineTitle(), "Rom Management Menu", FONT_7X8); - EMZAddToMenu(row++, 0, "Monitor ROM (40x25)", MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZMonitorROM40, MENUCB_DONOTHING, EMZGetMonitorROM40Choice ); - EMZAddToMenu(row++, 0, "Monitor ROM (80x25)", MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZMonitorROM80, MENUCB_DONOTHING, EMZGetMonitorROM80Choice ); - EMZAddToMenu(row++, 0, "Character Generator ROM", MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZCGROM, MENUCB_DONOTHING, EMZGetCGROMChoice ); - EMZAddToMenu(row++, 0, "Key Mapping ROM", MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZKeyMappingROM, MENUCB_DONOTHING, EMZGetKeyMappingROMChoice ); - EMZAddToMenu(row++, 0, "User ROM", MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZUserROM, MENUCB_DONOTHING, EMZGetUserROMChoice ); - EMZAddToMenu(row++, 0, "Floppy Disk ROM", MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZFloppyDiskROM, MENUCB_DONOTHING, EMZGetFloppyDiskROMChoice ); + EMZAddToMenu(row++, 0, "Monitor ROM (40x25)", '4', MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZMonitorROM40, MENUCB_DONOTHING, EMZGetMonitorROM40Choice, NULL ); + EMZAddToMenu(row++, 0, "Monitor ROM (80x25)", '8', MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZMonitorROM80, MENUCB_DONOTHING, EMZGetMonitorROM80Choice, NULL ); + EMZAddToMenu(row++, 0, "Char Generator ROM", 'G', MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZCGROM, MENUCB_DONOTHING, EMZGetCGROMChoice, NULL ); + EMZAddToMenu(row++, 0, "Key Mapping ROM", 'K', MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZKeyMappingROM, MENUCB_DONOTHING, EMZGetKeyMappingROMChoice, NULL ); + EMZAddToMenu(row++, 0, "User ROM", 'U', MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZUserROM, MENUCB_DONOTHING, EMZGetUserROMChoice, NULL ); + EMZAddToMenu(row++, 0, "Floppy Disk ROM", 'F', MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZFloppyDiskROM, MENUCB_DONOTHING, EMZGetFloppyDiskROMChoice, NULL ); // When called as a select callback then the menus are moving forward so start the active row at the top. if(mode == ACTION_SELECT) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = 0; EMZRefreshMenu(); } +void EMZAutoStartApplicationMenu(enum ACTIONMODE mode) +{ + // Locals. + // + uint8_t row = 0; + char lineBuf[MENU_ROW_WIDTH+1]; + + // Set active menu for the case when this method is invoked as a menu callback. + emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_AUTOSTART; + emuControl.activeDialog = DIALOG_MENU; + + EMZSetupMenu(EMZGetMachineTitle(), "AutoStart Menu", FONT_7X8); + + EMZAddToMenu(row++, 0, "Enable AutoStart", 'E', MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZChangeAutoStart, MENUCB_DONOTHING, EMZGetAutoStartChoice, NULL ); + if(emuConfig.params[emuConfig.machineModel].autoStart) + { + EMZAddToMenu(row++, 0, "Application to Load", 'A', MENUTYPE_ACTION | MENUTYPE_CHOICE, MENUSTATE_ACTIVE, EMZLoadApplication, MENUCB_DONOTHING, EMZGetLoadApplicationChoice, NULL ); + EMZAddToMenu(row++, 0, "Pre-load key injection", 'r', MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZPreKeyEntry, MENUCB_DONOTHING, NULL, EMZRenderPreKeyViewTop ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + + EMZAddToMenu(row++, 0, "Post-load key injection",'o', MENUTYPE_ACTION, MENUSTATE_ACTIVE, EMZPostKeyEntry, MENUCB_DONOTHING, NULL, EMZRenderPostKeyViewTop ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + EMZAddToMenu(row++, 0, "", 0x00, MENUTYPE_BLANK, MENUSTATE_BLANK , NULL, MENUCB_DONOTHING, NULL, NULL ); + } + + // When called as a select callback then the menus are moving forward so start the active row at the top. + if(mode == ACTION_SELECT) emuControl.activeMenu.activeRow[emuControl.activeMenu.menuIdx] = 0; + EMZRefreshMenu(); +} + +void EMZRenderPreKeyViewTop(void) +{ + EMZRenderPreKeyView(0); +} +void EMZRenderPreKeyView(uint16_t startpos) +{ + // Locals. + // + uint16_t maxX = OSDGet(ACTIVE_MAX_X); + char lineBuf[MAX_INJEDIT_COLS*KEY_INJEDIT_NIBBLES+MENU_ROW_WIDTH+1]; + + // Adjust start position to get 4 view rows. + startpos=startpos > KEY_INJEDIT_ROWS-MAX_INJEDIT_ROWS ? (KEY_INJEDIT_ROWS-MAX_INJEDIT_ROWS)*MAX_INJEDIT_COLS : startpos*MAX_INJEDIT_COLS; + + // Now add in the key entry text in a smaller font. + for(uint16_t idx=startpos; idx < startpos+(MAX_INJEDIT_ROWS*MAX_INJEDIT_COLS); idx+=MAX_INJEDIT_COLS) + { + lineBuf[0] = 0x00; + for(uint16_t idx2=0; idx2 < MAX_INJEDIT_COLS && idx+idx2 < MAX_KEY_INS_BUFFER; idx2++) + { + sprintf(&lineBuf[strlen(lineBuf)], "%s%02x%02x%02x%02x", idx2 == 0 ? "" : " ", + (emuConfig.params[emuConfig.machineModel].loadApp.preKeyInsertion[idx+idx2].b[0]), + (emuConfig.params[emuConfig.machineModel].loadApp.preKeyInsertion[idx+idx2].b[1]), + (emuConfig.params[emuConfig.machineModel].loadApp.preKeyInsertion[idx+idx2].b[2]), + (emuConfig.params[emuConfig.machineModel].loadApp.preKeyInsertion[idx+idx2].b[3])); + } + OSDWriteString(10 - (maxX < 512 ? 2 : 0), 6+((idx-startpos)/MAX_INJEDIT_COLS)+(maxX < 512 ? 1 : 0), 0, 0, 0, 0, maxX < 512 ? FONT_3X6 : FONT_5X7, NORMAL, lineBuf, NULL, PURPLE, BLACK); + } +} +void EMZRenderPostKeyViewTop(void) +{ + EMZRenderPostKeyView(0); +} +void EMZRenderPostKeyView(uint16_t startpos) +{ + // Locals. + // + uint16_t maxX = OSDGet(ACTIVE_MAX_X); + char lineBuf[MAX_INJEDIT_COLS*KEY_INJEDIT_NIBBLES+MENU_ROW_WIDTH+1]; + + // Adjust start position to get 4 view rows. + startpos=startpos > KEY_INJEDIT_ROWS-MAX_INJEDIT_ROWS ? (KEY_INJEDIT_ROWS-MAX_INJEDIT_ROWS)*MAX_INJEDIT_COLS : startpos*MAX_INJEDIT_COLS; + + for(uint16_t idx=startpos; idx < startpos+(MAX_INJEDIT_ROWS*MAX_INJEDIT_COLS); idx+=MAX_INJEDIT_COLS) + { + lineBuf[0] = 0x00; + for(uint16_t idx2=0; idx2 < MAX_INJEDIT_COLS && idx+idx2 < MAX_KEY_INS_BUFFER; idx2++) + { + sprintf(&lineBuf[strlen(lineBuf)], "%s%02x%02x%02x%02x", idx2 == 0 ? "" : " ", + (emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx+idx2].b[0]), + (emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx+idx2].b[1]), + (emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx+idx2].b[2]), + (emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[idx+idx2].b[3])); + } + OSDWriteString(10 - (maxX < 512 ? 2 : 0), 11+((idx-startpos)/MAX_INJEDIT_COLS)+(maxX < 512 ? 1 : 0), 0, 4, 0, 0, maxX < 512 ? FONT_3X6 : FONT_5X7, NORMAL, lineBuf, NULL, GREEN, BLACK); + } +} + +void EMZPreKeyEntry(void) +{ + // Locals. + uint16_t maxX = OSDGet(ACTIVE_MAX_X); + uint8_t lineBuf[10]; + + // Setup the control structure to be used by the key call back eventhandler to correctly update the displayed and stored buffer. + emuControl.keyInjEdit.bufptr = emuConfig.params[emuConfig.machineModel].loadApp.preKeyInsertion; + emuControl.keyInjEdit.editptr = 0; + emuControl.keyInjEdit.cursorAttr = HILIGHT_BG_WHITE; + emuControl.keyInjEdit.fg = PURPLE; + emuControl.keyInjEdit.bg = BLACK; + emuControl.keyInjEdit.font = maxX < 512 ? FONT_3X6 : FONT_5X7; + emuControl.keyInjEdit.startRow = 6+(maxX < 512 ? 1 : 0); + emuControl.keyInjEdit.startCol = 10 - (maxX < 512 ? 2 : 0); + emuControl.keyInjEdit.offsetRow = 0; + emuControl.keyInjEdit.offsetCol = 0; + emuControl.keyInjEdit.cursorFlashRate = 250; + emuControl.keyInjEdit.curView = 0; + emuControl.keyInjEdit.render = EMZRenderPreKeyView; + + // Setup cursor on the first nibble in buffer. + sprintf(lineBuf, "%01x", (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0]>>4)); + OSDSetCursorFlash(emuControl.keyInjEdit.startCol, emuControl.keyInjEdit.startRow, emuControl.keyInjEdit.offsetCol, emuControl.keyInjEdit.offsetRow, emuControl.keyInjEdit.font, lineBuf[0], emuControl.keyInjEdit.fg, emuControl.keyInjEdit.bg, emuControl.keyInjEdit.cursorAttr, emuControl.keyInjEdit.cursorFlashRate); + + // Setup to use the key injection editor event handler so all keys entered are redirected into this handler. + emuControl.activeDialog = DIALOG_KEYENTRY; + + return; +} + +void EMZPostKeyEntry(void) +{ + // Locals. + uint16_t maxX = OSDGet(ACTIVE_MAX_X); + uint8_t lineBuf[10]; + + // Setup the control structure to be used by the key call back eventhandler to correctly update the displayed and stored buffer. + emuControl.keyInjEdit.bufptr = emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion; + emuControl.keyInjEdit.editptr = 0; + emuControl.keyInjEdit.cursorAttr = HILIGHT_BG_WHITE; + emuControl.keyInjEdit.fg = GREEN; + emuControl.keyInjEdit.bg = BLACK; + emuControl.keyInjEdit.font = maxX < 512 ? FONT_3X6 : FONT_5X7; + emuControl.keyInjEdit.startRow = 11 +(maxX < 512 ? 1 : 0); + emuControl.keyInjEdit.startCol = 10 - (maxX < 512 ? 2 : 0); + emuControl.keyInjEdit.offsetRow = 4; + emuControl.keyInjEdit.offsetCol = 0; + emuControl.keyInjEdit.cursorFlashRate = 250; + emuControl.keyInjEdit.curView = 0; + emuControl.keyInjEdit.render = EMZRenderPostKeyView; + + // Setup cursor on the first nibble in buffer. + sprintf(lineBuf, "%01x", (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0]>>4)); + OSDSetCursorFlash(emuControl.keyInjEdit.startCol, emuControl.keyInjEdit.startRow, emuControl.keyInjEdit.offsetCol, emuControl.keyInjEdit.offsetRow, emuControl.keyInjEdit.font, lineBuf[0], emuControl.keyInjEdit.fg, emuControl.keyInjEdit.bg, emuControl.keyInjEdit.cursorAttr, emuControl.keyInjEdit.cursorFlashRate); + + // Setup to use the key injection editor event handler so all keys entered are redirected into this handler. + emuControl.activeDialog = DIALOG_KEYENTRY; + + return; +} +void EMZKeyInjectionEdit(uint8_t data, uint8_t ctrl) +{ + // Locals. + // + uint8_t lineBuf[10]; + uint8_t row; + uint8_t col; + uint8_t key; + + char tmpbuf[MAX_FILENAME_LEN+1]; + uint16_t rowPixelDepth = (emuControl.fileList.rowFontptr->height + emuControl.fileList.rowFontptr->spacing + emuControl.fileList.padding + 2); + uint16_t maxRow = ((uint16_t)OSDGet(ACTIVE_MAX_Y)/rowPixelDepth) + 1; + + // data = ascii code/ctrl code for key pressed. + // ctrl = KEY_BREAK & KEY_CTRL & KEY_SHIFT & "000" & KEY_DOWN & KEY_UP + + // If the break key is pressed, this is equivalent to escape, ie. exit edit mode. + if(ctrl & KEY_BREAK_BIT) + { + // Disable the cursor. + OSDClearCursorFlash(); + + // Just switch back to active menu dont activate the callback for storing a selection. + EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); + } else + { + // Process according to pressed key. + // + switch(data) + { + // Up key. + case 0xA0: + if(emuControl.keyInjEdit.editptr >= KEY_INJEDIT_NIBBLES_PER_ROW) + { + emuControl.keyInjEdit.editptr-=KEY_INJEDIT_NIBBLES_PER_ROW; + } + break; + + // Down key. + case 0xA1: + if(emuControl.keyInjEdit.editptr < ((MAX_KEY_INS_BUFFER*KEY_INJEDIT_NIBBLES)-KEY_INJEDIT_NIBBLES_PER_ROW)) + { + emuControl.keyInjEdit.editptr+=KEY_INJEDIT_NIBBLES_PER_ROW; + } + break; + + // Left key. + case 0xA4: + if(ctrl & KEY_SHIFT_BIT) + { + if(emuControl.keyInjEdit.editptr > 1) + { + emuControl.keyInjEdit.editptr = emuControl.keyInjEdit.editptr >= KEY_INJEDIT_NIBBLES ? ((emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES)-1)*KEY_INJEDIT_NIBBLES : 0; + } + } + else + { + if(emuControl.keyInjEdit.editptr > 0) + { + emuControl.keyInjEdit.editptr--; + } + } + break; + + case 0xA3: // Right Key + if(ctrl & KEY_SHIFT_BIT) + { + if(emuControl.keyInjEdit.editptr < ((MAX_KEY_INS_BUFFER*KEY_INJEDIT_NIBBLES)-KEY_INJEDIT_NIBBLES)) + { + emuControl.keyInjEdit.editptr = ((emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES)+1)*KEY_INJEDIT_NIBBLES; + } + } + else + { + if(emuControl.keyInjEdit.editptr < (MAX_KEY_INS_BUFFER*KEY_INJEDIT_NIBBLES)-1) + { + emuControl.keyInjEdit.editptr++; + } + } + break; + + // All other keys are processed as data. + case 'a' ... 'z': + case 'A' ... 'Z': + case '0' ... '9': + default: + // When CTRL is pressed we insert a nibble based on the key pressed. + if(ctrl & KEY_CTRL_BIT) + { + key = toupper(data); + if(key >= '0' && key <= '9') + key -= '0'; + else if(key >= 'A' && key <= 'F') + key = key - 'A' + 10; + else + // Npt a hex value. + break; + + // Update the nibble according to edit pointer. + if(emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 0) emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0] = emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0] & 0x0f | key << 4; + if(emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 1) emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0] = emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0] & 0xf0 | key; + if(emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 2) emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[1] = emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[1] & 0x0f | key << 4; + if(emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 3) emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[1] = emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[1] & 0xf0 | key; + if(emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 4) emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[2] = emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[2] & 0x0f | key << 4; + if(emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 5) emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[2] = emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[2] & 0xf0 | key; + if(emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 6) emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[3] = emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[3] & 0x0f | key << 4; + if(emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 7) emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[3] = emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[3] & 0xf0 | key; + + // Move onto next nibble. + emuControl.keyInjEdit.editptr += emuControl.keyInjEdit.editptr < (MAX_KEY_INS_BUFFER*KEY_INJEDIT_NIBBLES)-1 ? 1 : 0; + } else + { + emuControl.keyInjEdit.editptr = (emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES) * KEY_INJEDIT_NIBBLES; + t_numCnv map = EMZMapToScanCode(emuControl.hostMachine, data); + + // If a modifier key is required, it must be inserted first with 0 delay in the down/up pause timers. To avoid clash with other valid combinations, + // the delay is set to 0ms down key, 0S up key (stipulated with bit 7 set for seconds). + if(map.b[2] != 0xff && map.b[3] != 0xff) + { + emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0] = map.b[2]; + emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[1] = map.b[3]; + emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[2] = 0x00; + emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[3] = 0x80; + emuControl.keyInjEdit.editptr += emuControl.keyInjEdit.editptr < (MAX_KEY_INS_BUFFER-1)*KEY_INJEDIT_NIBBLES ? KEY_INJEDIT_NIBBLES : 0; + } + // Now insert the actual key. If the buffer is full we overwrite the last position. + if(map.b[0] != 0xff && map.b[1] != 0xff) + { + emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0] = map.b[0]; + emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[1] = map.b[1]; + emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[2] = 0x7f; + emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[3] = 0x7f; + emuControl.keyInjEdit.editptr += emuControl.keyInjEdit.editptr < (MAX_KEY_INS_BUFFER-1)*KEY_INJEDIT_NIBBLES ? KEY_INJEDIT_NIBBLES : 0; + } + } + break; + } + + // Set the view portal (to allow for bigger key buffers than the display allows) according to position of edit pointer. + emuControl.keyInjEdit.curView = (emuControl.keyInjEdit.editptr / KEY_INJEDIT_NIBBLES_PER_ROW) > MAX_INJEDIT_ROWS-1 ? (emuControl.keyInjEdit.editptr / KEY_INJEDIT_NIBBLES_PER_ROW) - MAX_INJEDIT_ROWS +1 : 0; + + col = ((emuControl.keyInjEdit.editptr) % KEY_INJEDIT_NIBBLES_PER_ROW) + ((emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES) % MAX_INJEDIT_COLS); + row = emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES_PER_ROW > MAX_INJEDIT_ROWS-1 ? MAX_INJEDIT_ROWS-1 : emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES_PER_ROW; + + sprintf(lineBuf, "%01x", emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 0 ? (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0]&0xf0)>>4 : + emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 1 ? (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[0]&0x0f) : + emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 2 ? (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[1]&0xf0)>>4 : + emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 3 ? (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[1]&0x0f) : + emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 4 ? (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[2]&0xf0)>>4 : + emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 5 ? (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[2]&0x0f) : + emuControl.keyInjEdit.editptr % KEY_INJEDIT_NIBBLES == 6 ? (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[3]&0xf0)>>4 : (emuControl.keyInjEdit.bufptr[emuControl.keyInjEdit.editptr/KEY_INJEDIT_NIBBLES].b[3]&0x0f) ); + + OSDSetCursorFlash(emuControl.keyInjEdit.startCol+col, emuControl.keyInjEdit.startRow+row, emuControl.keyInjEdit.offsetCol, emuControl.keyInjEdit.offsetRow, emuControl.keyInjEdit.font, lineBuf[0], emuControl.keyInjEdit.fg, emuControl.keyInjEdit.bg, emuControl.keyInjEdit.cursorAttr, emuControl.keyInjEdit.cursorFlashRate); + if(emuControl.keyInjEdit.render != NULL) + emuControl.keyInjEdit.render(emuControl.keyInjEdit.curView); + } + return; +} + // Method to switch to a menu given its integer Id. // void EMZSwitchToMenu(int8_t menu) @@ -2571,7 +3781,11 @@ void EMZSwitchToMenu(int8_t menu) EMZMainMenu(); break; - case MENU_STORAGE: + case MENU_TAPE_STORAGE: + EMZTapeStorageMenu(ACTION_DEFAULT); + break; + + case MENU_FLOPPY_STORAGE: EMZTapeStorageMenu(ACTION_DEFAULT); break; @@ -2583,6 +3797,10 @@ void EMZSwitchToMenu(int8_t menu) EMZDisplayMenu(ACTION_DEFAULT); break; + case MENU_AUDIO: + EMZAudioMenu(ACTION_DEFAULT); + break; + case MENU_SYSTEM: EMZSystemMenu(ACTION_DEFAULT); break; @@ -2591,6 +3809,10 @@ void EMZSwitchToMenu(int8_t menu) EMZRomManagementMenu(ACTION_DEFAULT); break; + case MENU_AUTOSTART: + EMZAutoStartApplicationMenu(ACTION_DEFAULT); + break; + default: break; } @@ -2691,6 +3913,7 @@ void EMZReadConfig(enum ACTIONMODE mode) EMZLoadConfig(); // Setup the hardware with the config values. + EMZSwitchToMachine(emuConfig.machineModel, 0); // Recreate the menu with the new config values. EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); @@ -2710,6 +3933,9 @@ void EMZWriteConfig(enum ACTIONMODE mode) // Load config, if the load fails then we remain with the current config. // EMZSaveConfig(); + + // Refresh menu to update cursor. + EMZRefreshMenu(); } return; } @@ -2724,9 +3950,12 @@ void EMZResetConfig(enum ACTIONMODE mode) if(mode == ACTION_DEFAULT || mode == ACTION_SELECT) { // Restore the reset parameters into the working set. - memcpy(emuConfig.params, emuConfig.resetParams, sizeof(emuConfig.params)); + memcpy(emuConfig.params, emuConfigDefault.params, sizeof(emuConfig.params)); + for(uint16_t idx=0; idx < MAX_MZMACHINES; idx++) { for(uint16_t idx2=0; idx2 < MAX_KEY_INS_BUFFER; idx2++) { if(emuConfig.params[idx].loadApp.preKeyInsertion[idx2].i == 0) { emuConfig.params[idx].loadApp.preKeyInsertion[idx2].i = 0xffffffff; } } } + for(uint16_t idx=0; idx < MAX_MZMACHINES; idx++) { for(uint16_t idx2=0; idx2 < MAX_KEY_INS_BUFFER; idx2++) { if(emuConfig.params[idx].loadApp.postKeyInsertion[idx2].i == 0) { emuConfig.params[idx].loadApp.postKeyInsertion[idx2].i = 0xffffffff; } } } // Setup the hardware with the config values. + EMZSwitchToMachine(emuConfig.machineModel, 0); // Recreate the menu with the new config values. EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); @@ -2739,7 +3968,7 @@ void EMZResetConfig(enum ACTIONMODE mode) // void EMZLoadConfig(void) { - if(!EMZFileLoad(CONFIG_FILENAME, emuConfig.params, sizeof(emuConfig.params))) + if(EMZFileLoad(CONFIG_FILENAME, &emuConfig.params, sizeof(emuConfig.params))) { debugf("EMZLoadConfig error reading: %s.\n", CONFIG_FILENAME); } @@ -2749,7 +3978,7 @@ void EMZLoadConfig(void) // void EMZSaveConfig(void) { - if(!EMZFileSave(CONFIG_FILENAME, emuConfig.params, sizeof(emuConfig.params))) + if(EMZFileSave(CONFIG_FILENAME, emuConfig.params, sizeof(emuConfig.params))) { debugf("EMZSaveConfig error writing: %s.\n", CONFIG_FILENAME); } @@ -2761,25 +3990,30 @@ void EMZSwitchToMachine(uint8_t machineModel, uint8_t forceROMLoad) { // Locals. // - uint8_t result; + uint8_t result = 0; -printf("Machine model:%d, old:%d, change:%d, force:%d\n", machineModel, emuConfig.machineModel, emuConfig.machineChanged, forceROMLoad); +printf("Machine model:%d, old:%d, change:%d, force:%d, memory:%d\n", machineModel, emuConfig.machineModel, emuConfig.machineChanged, forceROMLoad, emuConfig.params[machineModel].memSize); // Go through the active configuration, convert to register values and upload the register values into the FPGA. // - emuConfig.emuRegisters[MZ_EMU_REG_MODEL] = (emuConfig.emuRegisters[MZ_EMU_REG_MODEL] & 0xF0) | machineModel; + //emuConfig.emuRegisters[MZ_EMU_REG_MODEL] = (emuConfig.emuRegisters[MZ_EMU_REG_MODEL] & 0xF0) | emuConfig.params[machineModel].vramMode << 4 | machineModel; + emuConfig.emuRegisters[MZ_EMU_REG_MODEL] = (EMZGetMemSizeValue() << 4) | (machineModel&0x0f); +printf("DisplayType:%02x, VRAM:%d, GRAM:%d, WAIT:%d, PCG:%d\n", emuConfig.params[machineModel].displayType, emuConfig.params[machineModel].vramMode, emuConfig.params[machineModel].gramMode, emuConfig.params[machineModel].vramWaitMode, emuConfig.params[machineModel].pcgMode); emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY] = emuConfig.params[machineModel].pcgMode << 7 | emuConfig.params[machineModel].vramWaitMode << 6 | emuConfig.params[machineModel].gramMode << 5 | emuConfig.params[machineModel].vramMode << 4 | (emuConfig.params[machineModel].displayType & 0x0f); - emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] = (emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] & 0xF8) | emuConfig.params[machineModel].displayOutput; - // No current changes to display register 3, just a place holder until needed. - emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY3] = emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY3]; + // Display register 2 configures the output type and run time options such as Wait states. +printf("DisplayOutput:%02x,%02x\n", emuConfig.params[machineModel].displayOutput, emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2]); + emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] = (emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] & 0xF0) | emuConfig.params[machineModel].displayOutput; + + // Display register 3 configures the graphics options such as GRAM/PCG. + emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY3] = EMZGetDisplayOptionValue(); emuConfig.emuRegisters[MZ_EMU_REG_CPU] = (emuConfig.emuRegisters[MZ_EMU_REG_CPU] & 0xF8) | emuConfig.params[machineModel].cpuSpeed; - emuConfig.emuRegisters[MZ_EMU_REG_AUDIO] = (emuConfig.emuRegisters[MZ_EMU_REG_AUDIO] & 0xFE) | emuConfig.params[machineModel].audioSource; + emuConfig.emuRegisters[MZ_EMU_REG_AUDIO] = emuConfig.params[machineModel].audioHardware << 7 | emuConfig.params[machineModel].audioMix << 5 | (emuConfig.params[machineModel].audioMute == 1 ? 0 : emuConfig.params[machineModel].audioVolume << 1) | emuConfig.params[machineModel].audioSource; emuConfig.emuRegisters[MZ_EMU_REG_CMT] = emuConfig.params[machineModel].cmtMode << 7 | (emuConfig.params[machineModel].cmtAsciiMapping & 0x03) << 5 | emuConfig.params[machineModel].tapeButtons << 3 | @@ -2787,89 +4021,69 @@ printf("Machine model:%d, old:%d, change:%d, force:%d\n", machineModel, emuConfi // No current changes to CMT register 2, just a place holder until needed. emuConfig.emuRegisters[MZ_EMU_REG_CMT2] = emuConfig.emuRegisters[MZ_EMU_REG_CMT2]; - // Set the model according to parameter provided. - emuConfig.machineModel = machineModel; - - printf("Reg: "); - for(uint8_t idx=0; idx < 16; idx++) + // Setup the hardware switches. + if(machineModel == MZ800) { - printf("%02x,", emuConfig.emuRegisters[idx]); + emuConfig.emuRegisters[MZ_EMU_REG_SWITCHES] = 0x0 << 4 | emuConfig.params[machineModel].mz800TapeIn << 3 | emuConfig.params[machineModel].mz800Printer << 2 | emuConfig.params[machineModel].mz800Printer << 1 | emuConfig.params[machineModel].mz800Mode; + } else + { + emuConfig.emuRegisters[MZ_EMU_REG_SWITCHES] = 0x00; } - printf("\n"); - + + // Set the model and group according to parameter provided. + emuConfig.machineModel = machineModel; + emuConfig.machineGroup = EMZGetMachineGroup(); + // Based on the machine, upload the required ROMS into the emulator. Although the logic is the same for many machines it is seperated below in case specific implementations/configurations are needed. // - if(emuConfig.machineChanged) + if(emuConfig.machineChanged || forceROMLoad) { - switch(machineModel) - { - case MZ80K: -printf("MZ80K load\n"); - result=loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, MZ_EMU_ROM_ADDR+emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); - break; - - case MZ80C: -printf("MZ80C load\n"); - result=loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, MZ_EMU_ROM_ADDR+emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); - break; - - case MZ1200: -printf("MZ1200 load\n"); - result=loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, MZ_EMU_ROM_ADDR+emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); - break; - - case MZ700: -printf("MZ700 load\n"); - result=loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, MZ_EMU_ROM_ADDR+emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); - break; - - case MZ800: -printf("MZ800 load\n"); - result=loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, MZ_EMU_ROM_ADDR+emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); - break; - - case MZ80B: -printf("MZ80B load\n"); - result=loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, MZ_EMU_ROM_ADDR+emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); - break; - - case MZ2000: -printf("MZ2000 load\n"); - result=loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, MZ_EMU_ROM_ADDR+emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); - break; - - case MZ80A: - default: -printf("MZ80A load\n"); - result=loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, MZ_EMU_ROM_ADDR+emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); - break; - } +printf("%s load\n", MZMACHINES[machineModel]); + if(emuConfig.params[machineModel].romMonitor40.romEnabled == 1 && strlen((char *)emuConfig.params[machineModel].romMonitor40.romFileName) > 0 && (emuConfig.params[machineModel].displayType == MZ_EMU_DISPLAY_MONO || emuConfig.params[machineModel].displayType == MZ_EMU_DISPLAY_COLOUR)) + result |= loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor40.romFileName, 0, emuConfig.params[machineModel].romMonitor40.loadAddr, emuConfig.params[machineModel].romMonitor40.loadSize, 0, FPGA, 1); + if(emuConfig.params[machineModel].romMonitor80.romEnabled == 1 && strlen((char *)emuConfig.params[machineModel].romMonitor80.romFileName) > 0 && (emuConfig.params[machineModel].displayType == MZ_EMU_DISPLAY_MONO80 || emuConfig.params[machineModel].displayType == MZ_EMU_DISPLAY_COLOUR80)) + result |= loadZ80Memory((char *)emuConfig.params[machineModel].romMonitor80.romFileName, 0, emuConfig.params[machineModel].romMonitor80.loadAddr, emuConfig.params[machineModel].romMonitor80.loadSize, 0, FPGA, 1); + if(emuConfig.params[machineModel].romCG.romEnabled == 1 && strlen((char *)emuConfig.params[machineModel].romCG.romFileName) > 0) + result |= loadZ80Memory((char *)emuConfig.params[machineModel].romCG.romFileName, 0, emuConfig.params[machineModel].romCG.loadAddr, emuConfig.params[machineModel].romCG.loadSize, 0, FPGA, 1); + if(emuConfig.params[machineModel].romKeyMap.romEnabled == 1 && strlen((char *)emuConfig.params[machineModel].romKeyMap.romFileName) > 0) + result |= loadZ80Memory((char *)emuConfig.params[machineModel].romKeyMap.romFileName, 0, emuConfig.params[machineModel].romKeyMap.loadAddr, emuConfig.params[machineModel].romKeyMap.loadSize, 0, FPGA, 1); + if(machineModel == MZ80A && emuConfig.params[machineModel].romUser.romEnabled == 1 && strlen((char *)emuConfig.params[machineModel].romUser.romFileName) > 0) + result |= loadZ80Memory((char *)emuConfig.params[machineModel].romUser.romFileName, 0, emuConfig.params[machineModel].romUser.loadAddr, emuConfig.params[machineModel].romUser.loadSize, 0, FPGA, 1); + if(emuConfig.params[machineModel].romFDC.romEnabled == 1 && strlen((char *)emuConfig.params[machineModel].romFDC.romFileName) > 0) + result |= loadZ80Memory((char *)emuConfig.params[machineModel].romFDC.romFileName, 0, emuConfig.params[machineModel].romFDC.loadAddr, emuConfig.params[machineModel].romFDC.loadSize, 0, FPGA, 1); if(result) { - printf("Error: Failed to load BIOS ROM into Sharp MZ Series Emulation ROM memory.\n"); + printf("Error: Failed to load a ROM into the Sharp MZ Series Emulation ROM memory.\n"); } + // As the machine changed force a machine reset. + // + emuConfig.emuRegisters[MZ_EMU_REG_CTRL] |= 0x01; + // Next invocation we wont load the roms unless machine changes again. emuConfig.machineChanged = 0; - // Write the updated registers into the emulator to configure it, including the machine mode as this will cause a reset prior to run mode. + // Write the updated registers into the emulator to configure it. writeZ80Array(MZ_EMU_ADDR_REG_MODEL, emuConfig.emuRegisters, MZ_EMU_MAX_REGISTERS, FPGA); + + // Clear any reset command. + emuConfig.emuRegisters[MZ_EMU_REG_CTRL] &= 0xFE; } else { - // Write the updated registers into the emulator to configure it ready for run mode. - writeZ80Array(MZ_EMU_ADDR_REG_MODEL+1, &emuConfig.emuRegisters[1], MZ_EMU_MAX_REGISTERS-1, FPGA); + // Write the updated registers into the emulator to configure it. + writeZ80Array(MZ_EMU_ADDR_REG_MODEL, emuConfig.emuRegisters, MZ_EMU_MAX_REGISTERS, FPGA); } + printf("WriteReg: "); for(uint8_t idx=0; idx < 16; idx++) { printf("%02x,", emuConfig.emuRegisters[idx]); } printf("\n"); readZ80Array(MZ_EMU_ADDR_REG_MODEL, emuConfig.emuRegisters, MZ_EMU_MAX_REGISTERS, FPGA); - printf("ReadBack Reg: "); - for(uint8_t idx=0; idx < 16; idx++) - { - printf("%02x,", emuConfig.emuRegisters[idx]); - } - printf("\n"); + printf("ReadReg: "); for(uint8_t idx=0; idx < 16; idx++) { printf("%02x,", emuConfig.emuRegisters[idx]); } printf("\n"); return; } +// Method to handle and process the tape unit, loading files as requested from the queue, saving recorded files to disk and implementing the APSS +// tape drive mechanisms. +// This method is called by interrupt (cmt status change) and periodically (process tape queue). +// void EMZProcessTapeQueue(void) { // Locals. @@ -2879,117 +4093,94 @@ void EMZProcessTapeQueue(void) // Get elapsed time since last service poll. timeElapsed = *ms - time; + + // If the elapsed time is too short, ie. because a manual call and a scheduled call occur almost simultaneously, exit as it is not needed. + if(timeElapsed < 1000) + return; - // Every 2 seconds (READY signal takes 1 second to become active after previous load) to see if the tape buffer is empty. + // MZ80B APSS functionality. // - if(timeElapsed > 1000) + if(emuConfig.machineGroup == GROUP_MZ80B) { - // Take snapshot of registers. + // If Eject set, clear queue then issue CMT Register Clear. // - readZ80Array(MZ_EMU_ADDR_REG_MODEL, emuConfig.emuRegisters, MZ_EMU_MAX_REGISTERS, FPGA); - - printf("Poll Reg: "); - for(uint8_t idx=0; idx < 16; idx++) - { - printf("%02x,", emuConfig.emuRegisters[idx]); - } - printf("\n"); - - // When debugging output register change as text message. - debugf("CMT/CMT2 (%s%s%s%s%s%s%s:%s%s%s%s%s).", emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_PLAY_READY ? "PLAY_READY," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_PLAYING ? "PLAYING," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_RECORD_READY ? "RECORD_READY,": "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_RECORDING ? "RECORDING," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_ACTIVE ? "ACTIVE," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_SENSE ? "SENSE," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_WRITEBIT ? "WRITEBIT," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_APSS ? "APSS," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_DIRECTION ? "DIRECTION," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_EJECT ? "EJECT," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_PLAY ? "PLAY," : "", - emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_STOP ? "STOP" : ""); - - // MZ80B APSS functionality. - // - if(EMZGetMachineGroup() == 2) + if(emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_EJECT ) { - // If Eject set, clear queue then issue CMT Register Clear. - // - if(emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_EJECT ) - { - debugf("APSS Eject Cassette (%02x:%02x).", emuConfig.emuRegisters[MZ_EMU_REG_CMT2], MZ_EMU_CMT2_EJECT); - EMZClearTapeQueue(); - } else - - // If APSS set, rotate queue forward (DIRECTION = 1) or backward (DIRECTION = 0). - // - if(emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_APSS ) - { - debugf("APSS Search %s (%02x:%02x).", emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_DIRECTION ? "Forward" : "Reverse", emuConfig.emuRegisters[MZ_EMU_REG_CMT2], MZ_EMU_CMT2_APSS ); - EMZTapeQueueAPSSSearch(emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_DIRECTION ? 1 : 0); - } - - // If Play is active, the cache is empty and we are not recording, load into cache the next tape image. - // - if((emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_PLAY) && !(emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_PLAY_READY) && !(emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_RECORDING) ) - { - // Check the tape queue, if items available, read oldest,upload and rotate. - // - if(emuControl.tapeQueue.elements > 0) - { - // Get the filename from the queue but dont pop it. - fileName = EMZTapeQueueAPSSSearch(1); - - // If a file was found, upload it into the CMT buffer. - if(fileName != 0) - { - debugf("APSS Play %s, Rotate Queue Forward.", fileName); - debugf("Loading tape: %s\n", fileName); - EMZLoadTapeToRAM(fileName, 1); - - // Need to redraw the menu as the tape queue has changed. - EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); - } - } - } + debugf("APSS Eject Cassette (%02x:%02x).", emuConfig.emuRegisters[MZ_EMU_REG_CMT2], MZ_EMU_CMT2_EJECT); + EMZClearTapeQueue(); } else - { - // Check to see if the Tape READY signal is inactive, if it is and we have items in the queue, load up the next - // tape file and send it. - // - if((emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_SENSE) && !(emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_PLAY_READY) ) - { -debugf("Tape drive ready to load\n"); - // Check the tape queue, if items available, pop oldest and upload. - // - if(emuControl.tapeQueue.elements > 0) - { - // Get the filename from the queue. - fileName = EMZTapeQueuePopFile(); - - // If a file was found, upload it into the CMT buffer. - if(fileName != 0) - { - debugf("Loading tape: %s\n", fileName); - EMZLoadTapeToRAM(fileName, 1); - // Need to redraw the menu as the tape queue has changed. + // If APSS set, rotate queue forward (DIRECTION = 1) or backward (DIRECTION = 0). + // + if(emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_APSS ) + { + debugf("APSS Search %s (%02x:%02x).", emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_DIRECTION ? "Forward" : "Reverse", emuConfig.emuRegisters[MZ_EMU_REG_CMT2], MZ_EMU_CMT2_APSS ); + EMZTapeQueueAPSSSearch(emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_DIRECTION ? 1 : 0); + } + + // If Play is active, the cache is empty and we are not recording, load into cache the next tape image. + // + if((emuConfig.emuRegisters[MZ_EMU_REG_CMT2] & MZ_EMU_CMT2_PLAY) && !(emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_PLAY_READY) && !(emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_RECORDING) ) + { + // Check the tape queue, if items available, read oldest,upload and rotate. + // + if(emuControl.tapeQueue.elements > 0) + { + // Get the filename from the queue but dont pop it. + fileName = EMZTapeQueueAPSSSearch(1); + + // If a file was found, upload it into the CMT buffer. + if(fileName != 0) + { + debugf("APSS Play %s, Rotate Queue Forward.", fileName); + debugf("Loading tape: %s\n", fileName); + EMZLoadTapeToRAM(fileName, 1); + + // Need to redraw the menu as the tape queue has changed. + if(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] == MENU_TAPE_STORAGE) + { EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); } } } } - - // Check to see if the RECORD_READY flag is set. - if( (emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_RECORD_READY) ) - { - EMZSaveTapeFromCMT((const char *)0); - } + } else - // Reset the timer. - time = *ms; + // Standard Tape Deck functionality. + { + // Check to see if the Tape READY signal is inactive, if it is and we have items in the queue, load up the next + // tape file and send it. + // + if((emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_SENSE) && !(emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_PLAY_READY)) + { + // Check the tape queue, if items available, pop oldest and upload. + // + if(emuControl.tapeQueue.elements > 0) + { + // Get the filename from the queue. + fileName = EMZTapeQueuePopFile(); + + // If a file was found, upload it into the CMT buffer. + if(fileName != 0) + { + debugf("Loading tape: %s\n", fileName); + EMZLoadTapeToRAM(fileName, 1); + + // Need to redraw the menu as the tape queue has changed. + EMZSwitchToMenu(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx]); + } + } + } } + // Check to see if the RECORD_READY flag is set. + if( (emuConfig.emuRegisters[MZ_EMU_REG_CMT3] & MZ_EMU_CMT_RECORD_READY) ) + { + EMZSaveTapeFromCMT((const char *)0); + } + + // Reset the timer. + time = *ms; } // Method to invoke necessary services for the Sharp MZ Series emulations, ie. User OSD Menu, Tape Queuing, Floppy Disk loading etc. @@ -3000,84 +4191,108 @@ void EMZservice(uint8_t interrupt) // Locals. static uint32_t entryScreenTimer = 0xFFFFFFFF; uint8_t result; + uint8_t emuISRReason[MZ_EMU_INTR_MAX_REGISTERS]; uint8_t emuInData[256]; uint8_t emuOutData[256]; // Has an interrupt been generated by the emulator support hardware? if(interrupt) { - printf("Interrupt received.\n"); - // Read the reason code register. // - result=readZ80Array(MZ_EMU_REG_INTR_ADDR, emuInData, MZ_EMU_INTR_MAX_REGISTERS, FPGA); + result=readZ80Array(MZ_EMU_REG_INTR_ADDR, emuISRReason, MZ_EMU_INTR_MAX_REGISTERS, FPGA); +printf("IntrReg:"); for(uint16_t idx=0; idx < MZ_EMU_INTR_MAX_REGISTERS; idx++) { printf("%02x ", emuISRReason[idx]); } printf("\n"); if(!result) { - printf("Reason code:%02x\n", emuInData[MZ_EMU_INTR_ISR]); // Keyboard interrupt? - if(emuInData[0] & 0x01) + if(emuISRReason[MZ_EMU_INTR_REG_ISR] & MZ_EMU_INTR_SRC_KEYB) { // Read the key pressed. - result=readZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuInData[MZ_EMU_KEYB_CTRL_REG], 5, FPGA); + result=readZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuInData[MZ_EMU_KEYB_CTRL_REG], MZ_EMU_KEYB_MAX_REGISTERS, FPGA); +printf("KeyReg:"); for(uint16_t idx=MZ_EMU_KEYB_CTRL_REG; idx < MZ_EMU_KEYB_CTRL_REG+MZ_EMU_KEYB_MAX_REGISTERS; idx++) { printf("%02x ", emuInData[idx]); } printf("\n"); if(!result) { - printf("Received key:%02x, %02x, %d, %d\n", emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG], emuInData[MZ_EMU_KEYB_KEY_POS_REG], emuInData[MZ_EMU_KEYB_KEY_POS_LAST_REG]); + printf("Received key:%02x, %02x, %d, %d (%d,%d)\n", emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG], emuInData[MZ_EMU_KEYB_KEY_POS_REG], emuInData[MZ_EMU_KEYB_KEY_POS_LAST_REG], emuInData[MZ_EMU_KEYB_FIFO_WR_ADDR], emuInData[MZ_EMU_KEYB_FIFO_RD_ADDR]); - // First time the menu key has been pressed, pop up the menu and redirect all key input to the I/O processor. - if(emuControl.activeMenu.menu[0] == MENU_DISABLED && emuInData[MZ_EMU_KEYB_KEYD_REG] == 0xFE) + // Not interested in up key events or control events except for CTRL+BREAK, discard. + if(emuInData[MZ_EMU_KEYB_KEYC_REG] & KEY_DOWN_BIT) { - // Disable keyboard scan being sent to emulation, enable interrupts on each key press. - emuOutData[MZ_EMU_KEYB_CTRL_REG] = MZ_EMU_KEYB_DISABLE_EMU | MZ_EMU_KEYB_ENABLE_INTR; - writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuOutData[MZ_EMU_KEYB_CTRL_REG], 1, FPGA); - emuControl.activeMenu.menuIdx = 0; - emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_MAIN; - - // Draw the initial main menu. - EMZMainMenu(); - OSDRefreshScreen(); - - // Enable the OSD. - emuOutData[0] = 0x1; - writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY3, emuOutData, 1, FPGA); - - // Menu active and user has requested to return to emulation? - } - else if(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] != MENU_DISABLED && emuInData[MZ_EMU_KEYB_KEYD_REG] == 0xFE) - { - // Enable keyboard scan being sent to emulation, disable interrupts on each key press. - emuOutData[MZ_EMU_KEYB_CTRL_REG] = 0; - writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuOutData[MZ_EMU_KEYB_CTRL_REG], 1, FPGA); - emuControl.activeMenu.menuIdx = 0; - emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_DISABLED; - - // Release any allocated menu or file list memory as next invocation restarts at the main menu. - EMZReleaseDirMemory(); - EMZReleaseMenuMemory(); - - // Disable the OSD, this is done by updating the local register copy as the final act is to upload the latest configuration, OSD mode included. - emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY3] = emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY3] & 0xfe; - //emuOutData[0] = 0x0; - //writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY3, emuOutData, 1, FPGA); - - // Switch to the requested machine if changed, update the configuration in the FPGA. - // - EMZSwitchToMachine(emuConfig.machineModel, 0); - - // Direct key intercept, process according to state. - } else - { - // Event driven key processing - switch(emuControl.activeDialog) + // First time the menu key has been pressed, pop up the menu and redirect all key input to the I/O processor. + if(emuControl.activeMenu.menu[0] == MENU_DISABLED && emuInData[MZ_EMU_KEYB_KEYD_REG] == 0xFE) { - case DIALOG_FILELIST: - processFileListKey(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]); - break; + // Recheck OSD parameters - the running machine may change resolution which in turn changes the OSD settings. + OSDUpdateScreenSize(); - case DIALOG_MENU: - default: - EMZProcessMenuKey(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]); - //EMZProcessMenuKeyDebug(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]); - break; + // Setup Menu Font according to available X pixels. Original screen formats only have 320 pixel width. + if((uint16_t)OSDGet(ACTIVE_MAX_X) < 512) + { + EMZSetMenuFont(FONT_5X7); + } else + { + EMZSetMenuFont(FONT_7X8); + } + + // Disable keyboard scan being sent to emulation, enable interrupts on each key press. + emuOutData[MZ_EMU_KEYB_CTRL_REG] = MZ_EMU_KEYB_DISABLE_EMU | MZ_EMU_KEYB_ENABLE_INTR; + writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuOutData[MZ_EMU_KEYB_CTRL_REG], 1, FPGA); + emuControl.activeMenu.menuIdx = 0; + emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_MAIN; + + // Draw the initial main menu. + EMZMainMenu(); + OSDRefreshScreen(); + + // Enable the OSD. + emuOutData[0] = 0x40 | emuConfig.params[emuConfig.machineModel].displayOutput; + emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] = emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] | 0x40; + writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY2, emuOutData, 1, FPGA); + + // Menu active and user has requested to return to emulation? + } + else if(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] != MENU_DISABLED && emuInData[MZ_EMU_KEYB_KEYD_REG] == 0xFE) + { + // Enable keyboard scan being sent to emulation, disable interrupts on each key press. + emuOutData[MZ_EMU_KEYB_CTRL_REG] = 0; + writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuOutData[MZ_EMU_KEYB_CTRL_REG], 1, FPGA); + emuControl.activeMenu.menuIdx = 0; + emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_DISABLED; + + // Release any allocated menu or file list memory as next invocation restarts at the main menu. + EMZReleaseDirMemory(); + EMZReleaseMenuMemory(); + + // Disable the OSD cursor. + OSDClearCursorFlash(); + + // Disable the OSD, this is done by updating the local register copy as the final act is to upload the latest configuration, OSD mode included. + emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] = emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] & 0xbf; + //emuOutData[0] = 0x0; + //writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY3, emuOutData, 1, FPGA); + + // Switch to the requested machine if changed, update the configuration in the FPGA. + // + EMZSwitchToMachine(emuConfig.machineModel, 0); + + // Direct key intercept, process according to state. + } else + { + // Event driven key processing + switch(emuControl.activeDialog) + { + case DIALOG_FILELIST: + EMZProcessFileListKey(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]); + break; + + case DIALOG_KEYENTRY: + EMZKeyInjectionEdit(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]); + break; + + case DIALOG_MENU: + default: + EMZProcessMenuKey(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]); + //EMZProcessMenuKeyDebug(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]); + break; + } } } } else @@ -3085,6 +4300,44 @@ void EMZservice(uint8_t interrupt) printf("Key retrieval error.\n"); } } + + // CMT generated an interrupt? + if(emuISRReason[MZ_EMU_INTR_REG_ISR] & MZ_EMU_INTR_SRC_CMT) + { + // Read the cmt status directly. This data can also be ready from the Master Control register of the emulator. + result=readZ80Array(MZ_EMU_CMT_REG_ADDR, emuInData, MZ_EMU_CMT_MAX_REGISTERS, FPGA); + + // Update the local copy. + emuConfig.emuRegisters[MZ_EMU_REG_CMT3] = emuInData[MZ_EMU_CMT_STATUS_INTR_REG]; + emuConfig.emuRegisters[MZ_EMU_REG_CMT2] = emuInData[MZ_EMU_CMT_STATUS2_INTR_REG]; + + // When debugging output register change as text message. + debugf("CMT/CMT2 (%s%s%s%s%s%s:%s%s%s%s%s).", emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_PLAY_READY ? "PLAY_READY," : "", + emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_PLAYING ? "PLAYING," : "", + emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_RECORD_READY ? "RECORD_READY,": "", + emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_RECORDING ? "RECORDING," : "", + emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_ACTIVE ? "ACTIVE," : "", + emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_SENSE ? "SENSE," : "", + emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_APSS ? "APSS," : "", + emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_DIRECTION ? "DIRECTION," : "", + emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_EJECT ? "EJECT," : "", + emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_PLAY ? "PLAY," : "", + emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_STOP ? "STOP" : ""); + debugf("CMT/CMT2i(%s%s%s%s%s%s:%s%s%s%s%s).", emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_PLAY_READY ? "PLAY_READY," : "", + emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_PLAYING ? "PLAYING," : "", + emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_RECORD_READY ? "RECORD_READY,": "", + emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_RECORDING ? "RECORDING," : "", + emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_ACTIVE ? "ACTIVE," : "", + emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_SENSE ? "SENSE," : "", + emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_APSS ? "APSS," : "", + emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_DIRECTION ? "DIRECTION," : "", + emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_EJECT ? "EJECT," : "", + emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_PLAY ? "PLAY," : "", + emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_STOP ? "STOP" : ""); + + // Process the tape queue according to signals received from the hardware. + EMZProcessTapeQueue(); + } } else { printf("Interrupt reason retrieval error.\n"); @@ -3099,23 +4352,23 @@ void EMZservice(uint8_t interrupt) { OSDClearScreen(BLACK); OSDWriteBitmap(128,0,BITMAP_ARGO, RED, BLACK); - OSDWriteString(31, 6, 0, 10, 0, 0, FONT_9X16, NORMAL, "Sharp MZ Series", BLUE, BLACK); + OSDWriteString(31, 6, 0, 10, 0, 0, FONT_9X16, NORMAL, "Sharp MZ Series", NULL, BLUE, BLACK); OSDRefreshScreen(); - entryScreenTimer = 0x01FFFFF; + entryScreenTimer = 0x00FFFFF; // Enable the OSD. - emuOutData[0] = 0x1; - writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY3, emuOutData, 1, FPGA); + emuOutData[0] = 0x40 | emuConfig.params[emuConfig.machineModel].displayOutput; + writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY2, emuOutData, 1, FPGA); } else if(entryScreenTimer != 0xFFFFFFFF && entryScreenTimer > 0) { switch(--entryScreenTimer) { // Quick wording change... - case 0x80000: + case 0x40000: OSDClearScreen(BLACK); OSDWriteBitmap(128,0,BITMAP_ARGO, RED, BLACK); - OSDWriteString(31, 6, 0, 10, 0, 0, FONT_9X16, NORMAL, "Argo Inside", BLUE, BLACK); + OSDWriteString(31, 6, 0, 10, 0, 0, FONT_9X16, NORMAL, "Argo Inside", NULL, BLUE, BLACK); OSDRefreshScreen(); break; @@ -3126,8 +4379,8 @@ void EMZservice(uint8_t interrupt) // Disable the OSD. // - emuOutData[0] = 0x0; - writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY3, emuOutData, 1, FPGA); + emuOutData[0] = 0x00 | emuConfig.params[emuConfig.machineModel].displayOutput; + writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY2, emuOutData, 1, FPGA); break; default: @@ -3138,7 +4391,11 @@ void EMZservice(uint8_t interrupt) // When the startup banner has been displayed, normal operations can commence as this module has been initialised. else if(entryScreenTimer == 0x00000000) { - // Process the tape queue according to signals received from the hardware. + // Call the OSD service scheduling routine to allow any OSD updates to take plave. + OSDService(); + + // Process the tape queue periodically, this is generally only needed for uploading a new file from the queue, all other actions are serviced + // via interrupt. EMZProcessTapeQueue(); } } @@ -3149,17 +4406,27 @@ void EMZservice(uint8_t interrupt) // Initialise the EmuMZ subsystem. This method is called at startup to intialise control structures and hardware settings. // -uint8_t EMZInit(uint8_t machineModel) +uint8_t EMZInit(enum MACHINE_HW_TYPES hostMachine) { // Locals. // uint8_t result = 0; + // On initialisation, copy the default configuration into the working data structures and if an SD configuration is found, overwrite as necessary. + memcpy(&emuControl, &emuControlDefault, sizeof(t_emuControl)); + memcpy(&emuConfig, &emuConfigDefault, sizeof(t_emuConfig)); + for(uint16_t idx=0; idx < MAX_MZMACHINES; idx++) { for(uint16_t idx2=0; idx2 < MAX_KEY_INS_BUFFER; idx2++) { if(emuConfig.params[idx].loadApp.preKeyInsertion[idx2].i == 0) { emuConfig.params[idx].loadApp.preKeyInsertion[idx2].i = 0xffffffff; } } } + for(uint16_t idx=0; idx < MAX_MZMACHINES; idx++) { for(uint16_t idx2=0; idx2 < MAX_KEY_INS_BUFFER; idx2++) { if(emuConfig.params[idx].loadApp.postKeyInsertion[idx2].i == 0) { emuConfig.params[idx].loadApp.postKeyInsertion[idx2].i = 0xffffffff; } } } + // Initialise the on screen display. if(!(result=OSDInit(MENU))) { + // Store the host machine under which the emulation is running, needed for features such as keyboard scan code mapping. + emuControl.hostMachine = hostMachine; + // Allocate first file list top level directory buffer. emuControl.activeDir.dirIdx = 0; + if((emuControl.activeDir.dir[emuControl.activeDir.dirIdx] = (char *)malloc(strlen(TOPLEVEL_DIR)+1)) == NULL) { printf("Memory exhausted during init of directory cache, aborting!\n"); @@ -3168,17 +4435,6 @@ uint8_t EMZInit(uint8_t machineModel) strcpy(emuControl.activeDir.dir[emuControl.activeDir.dirIdx], TOPLEVEL_DIR); } - // Allocate a block of memory to store the config reset parameters. - // - if((emuConfig.resetParams = (t_emuMachineConfig*)malloc(sizeof(emuConfig.params))) == NULL) - { - printf("Memory exhausted during init of parameter reset config, aborting!\n"); - } else - { - // Backup the default parameter values as the reset parameters. - memcpy(emuConfig.resetParams, emuConfig.params, sizeof(emuConfig.params)); - } - // Initialise tape queue. // for(int i=0; i < MAX_TAPE_QUEUE; i++) @@ -3198,15 +4454,55 @@ uint8_t EMZInit(uint8_t machineModel) { printf("Failed to read initial emulator register configuration.\n"); } - - // Switch to the requested machine and upload the configuration to the FPGA. - // - EMZSwitchToMachine(machineModel, 0); } return(result); } +// Once the tranZPUter has been engaged and configured, start the emulation with the required machine. +// +void EMZRun(uint8_t machineModel) +{ + // Locals. + uint8_t errCode; + uint8_t keyCnt; + + // Switch to the requested machine and upload the configuration to the FPGA. + // + EMZSwitchToMachine(machineModel, 1); + + // If startup application is enabled and pre key insertion keys given, send them to the emulation keyboard module. This functionality works without + // an actual application for load being specified and these keys can also be used to interact with the I/O processor menu, ie. to set a CPU speed. + if(emuConfig.params[emuConfig.machineModel].loadApp.appEnabled && emuConfig.params[emuConfig.machineModel].loadApp.preKeyInsertion[0].i != 0xffffffff) + { + // Count the number of keys for insertion. + for(keyCnt=0; keyCnt < MAX_KEY_INS_BUFFER; keyCnt++) { if(emuConfig.params[emuConfig.machineModel].loadApp.preKeyInsertion[keyCnt].i == 0xffffffff) break; } + + } + + // If a startup application is specified, load it direct to RAM. + // + if(emuConfig.params[emuConfig.machineModel].loadApp.appEnabled && strlen(emuConfig.params[emuConfig.machineModel].loadApp.appFileName) > 0) + { + // Use the tape method for loading direct to memory. Currently startup applications limited to tape but this will change as the project progresses. + errCode = EMZLoadTapeToRAM(emuConfig.params[emuConfig.machineModel].loadApp.appFileName, 0); + if(errCode != 0) + { + debugf("Failed to load startup application:%s to memory.", emuConfig.params[emuConfig.machineModel].loadApp.appFileName); + } + } + + // If a startup application is enabled and there are post keys to be injected into the keyboard module, send them. + // + if(emuConfig.params[emuConfig.machineModel].loadApp.appEnabled && emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[0].i != 0xffffffff) + { + // Count the number of keys for insertion. + for(keyCnt=0; keyCnt < MAX_KEY_INS_BUFFER; keyCnt++) { if(emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion[keyCnt].i == 0xffffffff) break; } +printf("KeyCnt:%d, addr=%08lx, mem=%08lx\n", keyCnt, MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_FIFO_ADDR, (uint8_t *)&emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion); + writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_FIFO_ADDR, (uint8_t *)&emuConfig.params[emuConfig.machineModel].loadApp.postKeyInsertion, keyCnt*4, FPGA); + } +} + void EMZProcessMenuKeyDebug(uint8_t data, uint8_t ctrl) { // Locals. @@ -3342,12 +4638,12 @@ void EMZProcessMenuKeyDebug(uint8_t data, uint8_t ctrl) } else if(data == 'E') { OSDClearScreen(BLACK); - OSDWriteString(0, 0, 0, 0, 0, 0, FONT_5X7, NORMAL, "Sharp MZ Series Emulator", fg, bg); + OSDWriteString(0, 0, 0, 0, 0, 0, FONT_5X7, NORMAL, "Sharp MZ Series Emulator", NULL, fg, bg); OSDRefreshScreen(); } else if(data == 'F') { OSDClearScreen(BLACK); - OSDWriteString(0, 0, 0, 0, 0, 0, FONT_5X7, DEG270, "Sharp MZ Series Emulator", fg, bg); + OSDWriteString(0, 0, 0, 0, 0, 0, FONT_5X7, DEG270, "Sharp MZ Series Emulator", NULL, fg, bg); OSDRefreshScreen(); } else if(data == 'G') { diff --git a/common/osd.c b/common/osd.c index d3260ab..a379ff3 100644 --- a/common/osd.c +++ b/common/osd.c @@ -69,11 +69,23 @@ extern "C" { #include #include +// Debug macros +#define debugf(a, ...) if(osdWindow.debug) { printf("\033[1;31mOSD: " a "\033[0m\n", ##__VA_ARGS__); } +#define debugfx(a, ...) if(osdWindow.debug) { printf("\033[1;32mOSD: " a "\033[0m\n", ##__VA_ARGS__); } + #ifndef __APP__ // Protected methods which should only reside in the kernel on zOS. -static t_OSDWindow osdWindow = {.mode=MENU, .params={ {.attr=0, .row=0, .col=0, .maxCol=0, .maxRow=0, .lineWrap=1, .maxX=VC_STATUS_MAX_X_PIXELS, .maxY=VC_STATUS_MAX_Y_PIXELS}, - {.attr=0, .row=0, .col=0, .maxCol=0, .maxRow=0, .lineWrap=1, .maxX=VC_MENU_MAX_X_PIXELS, .maxY=VC_MENU_MAX_Y_PIXELS} }, +static t_OSDWindow osdWindow = {.mode=MENU, .params={ {.attr=0, .row=0, .col=0, .maxCol=0, .maxRow=0, .lineWrap=1, .maxX=VC_STATUS_MAX_X_PIXELS, .maxY=VC_STATUS_MAX_Y_PIXELS, + .cursor={.flashing=0, .enabled=0} + }, + {.attr=0, .row=0, .col=0, .maxCol=0, .maxRow=0, .lineWrap=1, .maxX=VC_MENU_MAX_X_PIXELS, .maxY=VC_MENU_MAX_Y_PIXELS, + .cursor={.flashing=0, .enabled=0} + } + }, .debug=0, .inDebug=0, .display=NULL}; +// Real time millisecond counter, interrupt driven. Needs to be volatile in order to prevent the compiler optimising it away. +uint32_t volatile *msecs = &systick_millis_count; + // Method to get internal public member values. This module ideally should be written in C++ but with the limitations of the GNU C Compiler for the ZPU (v3.4.2) and the performance penalty on // an embedded processor, it was decided to write it in C but the methodology and naming conventions (ie. OSDDrawLine = OSD.DrawLine, OSDInit = OSD::OSD constructor) are kept loosly // associated with C++. Ideally for this getter method function overloading is required! @@ -234,7 +246,7 @@ void OSDChangePixelColour(uint16_t x, uint16_t y, enum COLOUR fg, enum COLOUR bg // Internal method to write a single character into the status/menu framebuffer. The X/Y location is specified in font units, also the orientation, // colour and required font. // -void _OSDwrite(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uint8_t ypad, enum ORIENTATION orientation, uint8_t chr, enum COLOUR fg, enum COLOUR bg, fontStruct *font) +void _OSDwrite(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uint8_t ypad, enum ORIENTATION orientation, uint8_t chr, uint16_t attr, enum COLOUR fg, enum COLOUR bg, fontStruct *font) { // Locals. uint16_t startX; @@ -254,8 +266,7 @@ void _OSDwrite(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uin // Check bounds of character. if(chr < font->start || chr > font->end) { - // if(osdWindow.debug) - printf("Character out of bounds:%02x(%d,%d)\n", chr, font->start, font->end); + debugf("Character out of bounds:%02x(%d,%d)\n", chr, font->start, font->end); return; } @@ -299,8 +310,7 @@ void _OSDwrite(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uin // Cant write if out of bounds. if(startX > osdWindow.params[osdWindow.mode].maxX || startY > osdWindow.params[osdWindow.mode].maxY || startX+width > osdWindow.params[osdWindow.mode].maxX || startY+height > osdWindow.params[osdWindow.mode].maxY) { - // if(osdWindow.debug) - printf("Position out of bounds:%d,%d(%d,%d)\n", startX, startY, x, y); + debugf("Position out of bounds:%d,%d(%d,%d). Max:%d,%d\n", startX, startY, x, y, osdWindow.params[osdWindow.mode].maxX, osdWindow.params[osdWindow.mode].maxY); return; } @@ -334,12 +344,13 @@ void _OSDwrite(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uin // Test to see if a foreground or background pixel is set and update the framebuffer accordingly. if(vChrRow & 0x80 >> bitPos) { - if(fg & (1 << colourMode)) + if(((attr & HILIGHT_FG_ACTIVE) && ((attr&~HILIGHT_FG_ACTIVE) & (1 << colourMode))) || (!(attr & HILIGHT_FG_ACTIVE) && (fg & (1 << colourMode)))) osdWindow.display[colourMode][addr] |= 0x80 >> bitOffset; else osdWindow.display[colourMode][addr] &= ~(0x80 >> bitOffset); if(osdWindow.debug && colourMode == 0) { printf("*"); } - } else if(bg & (1 << colourMode)) + } + else if(((attr & HILIGHT_BG_ACTIVE) && ((attr&~HILIGHT_BG_ACTIVE) & (1 << colourMode))) || (!(attr & HILIGHT_BG_ACTIVE) && (bg & (1 << colourMode)))) { osdWindow.display[colourMode][addr] |= 0x80 >> bitOffset; if(osdWindow.debug && colourMode == 0) { printf(" "); } @@ -379,13 +390,13 @@ void _OSDwrite(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uin if(vChrRow & 0x80 >> bitPos) { - if(fg & (1 << colourMode)) + if(((attr & HILIGHT_FG_ACTIVE) && ((attr&~HILIGHT_FG_ACTIVE) & (1 << colourMode))) || (!(attr & HILIGHT_FG_ACTIVE) && (fg & (1 << colourMode)))) osdWindow.display[colourMode][addr] |= 1 << bitOffset; else osdWindow.display[colourMode][addr] &= ~(1 << bitOffset); if(osdWindow.debug && colourMode == 0) { printf("*"); } - } - else if(bg & (1 << colourMode)) + } + else if(((attr & HILIGHT_BG_ACTIVE) && ((attr&~HILIGHT_BG_ACTIVE) & (1 << colourMode))) || (!(attr & HILIGHT_BG_ACTIVE) && (bg & (1 << colourMode)))) { osdWindow.display[colourMode][addr] |= 1 << bitOffset; if(osdWindow.debug && colourMode == 0) { printf(" "); } @@ -428,13 +439,13 @@ void _OSDwrite(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uin // Test to see if a pixel is set and update the framebuffer accordingly. if(vChrRow & 1 << bitPos) { - if(fg & (1 << colourMode)) + if(((attr & HILIGHT_FG_ACTIVE) && ((attr&~HILIGHT_FG_ACTIVE) & (1 << colourMode))) || (!(attr & HILIGHT_FG_ACTIVE) && (fg & (1 << colourMode)))) osdWindow.display[colourMode][addr] |= 0x80 >> bitOffset; else osdWindow.display[colourMode][addr] &= ~(0x80 >> bitOffset); if(osdWindow.debug && colourMode == 0) { printf("*"); } - } - else if(bg & (1 << colourMode)) + } + else if(((attr & HILIGHT_BG_ACTIVE) && ((attr&~HILIGHT_BG_ACTIVE) & (1 << colourMode))) || (!(attr & HILIGHT_BG_ACTIVE) && (bg & (1 << colourMode)))) { osdWindow.display[colourMode][addr] |= 0x80 >> bitOffset; if(osdWindow.debug && colourMode == 0) { printf(" "); } @@ -475,13 +486,13 @@ void _OSDwrite(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uin if(vChrRow & (1 << (row % 8))) { - if(fg & (1 << colourMode)) + if(((attr & HILIGHT_FG_ACTIVE) && ((attr&~HILIGHT_FG_ACTIVE) & (1 << colourMode))) || (!(attr & HILIGHT_FG_ACTIVE) && (fg & (1 << colourMode)))) osdWindow.display[colourMode][addr] |= 0x80 >> bitOffset; else osdWindow.display[colourMode][addr] &= ~(0x80 >> bitOffset); if(osdWindow.debug && colourMode == 0) { printf("*"); } - } - else if(bg & (1 << colourMode)) + } + else if(((attr & HILIGHT_BG_ACTIVE) && ((attr&~HILIGHT_BG_ACTIVE) & (1 << colourMode))) || (!(attr & HILIGHT_BG_ACTIVE) && (bg & (1 << colourMode)))) { osdWindow.display[colourMode][addr] |= 0x80 >> bitOffset; if(osdWindow.debug && colourMode == 0) { printf(" "); } @@ -517,8 +528,7 @@ void OSDWriteBitmap(uint16_t x, uint16_t y, enum BITMAPS bitmap, enum COLOUR fg, // Check parameters. if(x >= osdWindow.params[osdWindow.mode].maxX || y >= osdWindow.params[osdWindow.mode].maxY) { - if(osdWindow.debug) - printf("Bitmap coordinates out of range:(%d,%d)\n", x, y); + debugf("Bitmap coordinates out of range:(%d,%d)\n", x, y); return; } @@ -579,14 +589,14 @@ void OSDWriteChar(uint8_t x, uint8_t y, uint8_t xoff, uint8_t yoff, uint8_t xpad // Locals. // - _OSDwrite(x, y, xoff, yoff, xpad, ypad, orientation, chr, fg, bg, OSDGetFont(font)); + _OSDwrite(x, y, xoff, yoff, xpad, ypad, orientation, chr, NOATTR, fg, bg, OSDGetFont(font)); return; } // Method to write a string to the required framebuffer. The X/Y co-ordinates are relative to the orientation, ie. start - NORMAL=0/0, DEG90 = maxX-font width/0, // DEG180 = maxX-font width/maxY-font height, DEG270 = 0/maxY-font height. // -void OSDWriteString(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uint8_t ypad, enum FONTS font, enum ORIENTATION orientation, char *str, enum COLOUR fg, enum COLOUR bg) +void OSDWriteString(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad, uint8_t ypad, enum FONTS font, enum ORIENTATION orientation, char *str, uint16_t *attr, enum COLOUR fg, enum COLOUR bg) { // Locals. // @@ -597,6 +607,8 @@ void OSDWriteString(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad uint8_t maxY; uint8_t xpos = x; uint8_t ypos = y; + uint8_t *ptr; + uint16_t *aptr; // Obtain the font structure based on the provided type. fontptr = OSDGetFont(font); @@ -635,9 +647,9 @@ void OSDWriteString(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad } // Output the string. - for(uint8_t *ptr=str; *ptr != 0x00; ptr++) + for(ptr=str,aptr=attr; *ptr != 0x00; ptr++, aptr++) { - _OSDwrite(xpos++, ypos, xoff, yoff, xpad, ypad, orientation, (*ptr), fg, bg, fontptr); + _OSDwrite(xpos++, ypos, xoff, yoff, xpad, ypad, orientation, (*ptr), (attr != NULL ? (*aptr) : NOATTR), fg, bg, fontptr); if(xpos > maxX) { @@ -654,6 +666,28 @@ void OSDWriteString(uint8_t x, uint8_t y, int8_t xoff, int8_t yoff, uint8_t xpad return; } +// Method to refresh the OSD size parameters from the hardware. This is required should the screen resolution change which may change +// OSD size. +void OSDUpdateScreenSize(void) +{ + // Locals. + uint8_t result; + uint8_t osdInData[8]; + + // Read the OSD Size parameters. These represent the X and Y size once multiplied by 8 (8 being the minimum size, ie. block size). + // + result=readZ80Array(VCADDR_8BIT_OSDMNU_SZX, osdInData, 6, FPGA); + if(!result) + { + osdWindow.params[STATUS].maxX = (uint16_t)(osdInData[2] * 8); + osdWindow.params[STATUS].maxY = (uint16_t)(osdInData[3] * 8) + (uint16_t)(osdInData[5] * 8); + osdWindow.params[MENU].maxX = (uint16_t)(osdInData[0] * 8); + osdWindow.params[MENU].maxY = (uint16_t)(osdInData[1] * 8); + } + + return; +} + // Method to refresh the active screen from the buffer contents. void OSDRefreshScreen(void) { @@ -734,7 +768,7 @@ void OSDDrawLine(int16_t startX, int16_t startY, int16_t endX, int16_t endY, enu int err = dx + dy, e2; /* error value e_xy */ int16_t x = sx; int16_t y = sy; - + // Sanity check. if(sx < 0 || ex >= osdWindow.params[osdWindow.mode].maxX || sx > ex || ey < 0 || ey >= osdWindow.params[osdWindow.mode].maxY || sy > ey) return; @@ -863,6 +897,101 @@ void OSDSetActiveWindow(enum WINDOWS window) return; } + +// Method to setup the data structures and enable flashing of a cursor at a given point, in a given font wth necessary attributes. +// This mechanism is used for data entry where the next character typically appears at the flashing curspr. +void OSDSetCursorFlash(uint8_t col, uint8_t row, uint8_t offsetCol, uint8_t offsetRow, enum FONTS font, uint8_t dispChar, enum COLOUR fg, enum COLOUR bg, uint16_t attr, unsigned long speed) +{ + // Disable any active cursor. + if(osdWindow.params[osdWindow.mode].cursor.enabled) + OSDClearCursorFlash(); + + // Store the given cursor data. + osdWindow.params[osdWindow.mode].cursor.row = row; + osdWindow.params[osdWindow.mode].cursor.col = col; + osdWindow.params[osdWindow.mode].cursor.ofrow = offsetRow; + osdWindow.params[osdWindow.mode].cursor.ofcol = offsetCol; + osdWindow.params[osdWindow.mode].cursor.font = font; + osdWindow.params[osdWindow.mode].cursor.dispChar = dispChar; + osdWindow.params[osdWindow.mode].cursor.attr = attr; + osdWindow.params[osdWindow.mode].cursor.fg = fg; + osdWindow.params[osdWindow.mode].cursor.bg = bg; + osdWindow.params[osdWindow.mode].cursor.speed = speed; + + // Enable the cursor. + osdWindow.params[osdWindow.mode].cursor.enabled = 1; + osdWindow.params[osdWindow.mode].cursor.flashing = 0; + + return; +} + +// Method to clear any running cursor and restore the character under the cursor. +// +void OSDClearCursorFlash(void) +{ + // Locals. + char lineBuf[2]; + + // Verify there is an active cursor. + if(osdWindow.params[osdWindow.mode].cursor.enabled) + { + // Restore the character under the cursor to original value. + lineBuf[0] = osdWindow.params[osdWindow.mode].cursor.dispChar; + lineBuf[1] = 0x00; + OSDWriteString(osdWindow.params[osdWindow.mode].cursor.col, osdWindow.params[osdWindow.mode].cursor.row, osdWindow.params[osdWindow.mode].cursor.ofcol, osdWindow.params[osdWindow.mode].cursor.ofrow, 0, 0, osdWindow.params[osdWindow.mode].cursor.font, NORMAL, lineBuf, NULL, osdWindow.params[osdWindow.mode].cursor.fg, osdWindow.params[osdWindow.mode].cursor.bg); + OSDRefreshScreen(); + + // Disable the cursor flashing. + osdWindow.params[osdWindow.mode].cursor.enabled = 0; + osdWindow.params[osdWindow.mode].cursor.flashing = 0; + } + return; +} + +// Method to flash a cursor. This is based on a timer and using the hilight properties of text write, rewrites the character at the position where the cursor should +// appear in the correct format. +void OSDCursorFlash(void) +{ + // Locals. + static unsigned long time = 0; + char lineBuf[2]; + uint16_t attrBuf[2]; + uint32_t timeElapsed; + + // Get elapsed time since last service poll. + timeElapsed = *msecs - time; + + // If the elapsed time is greater than the flash speed, toggle the flash state. + if(osdWindow.params[osdWindow.mode].cursor.enabled == 1 && timeElapsed > osdWindow.params[osdWindow.mode].cursor.speed) + { + + lineBuf[0] = osdWindow.params[osdWindow.mode].cursor.dispChar; + lineBuf[1] = 0x00; + attrBuf[0] = osdWindow.params[osdWindow.mode].cursor.attr; + attrBuf[1] = 0x0000; + OSDWriteString(osdWindow.params[osdWindow.mode].cursor.col, osdWindow.params[osdWindow.mode].cursor.row, osdWindow.params[osdWindow.mode].cursor.ofcol, osdWindow.params[osdWindow.mode].cursor.ofrow, 0, 0, osdWindow.params[osdWindow.mode].cursor.font, NORMAL, lineBuf, osdWindow.params[osdWindow.mode].cursor.flashing == 0 ? NULL : attrBuf, osdWindow.params[osdWindow.mode].cursor.fg, osdWindow.params[osdWindow.mode].cursor.bg); + OSDRefreshScreen(); + + // Set to next flash state. + osdWindow.params[osdWindow.mode].cursor.flashing = osdWindow.params[osdWindow.mode].cursor.flashing == 0 ? 1 : 0; + + // Reset the timer. + time = *msecs; + } + return; +} + +// Method to allow for OSD periodic updates as needed. +// +void OSDService(void) +{ + // Call the cursor flash routine to allow an interactive flashing cursor if enabled. + // + OSDCursorFlash(); + + return; +} + // Initialise the OSD subsystem. This method only needs to be called once, calling subsequent times will free and reallocate memory. // uint8_t OSDInit(enum WINDOWS window) @@ -874,8 +1003,7 @@ uint8_t OSDInit(enum WINDOWS window) // Allocate heap for the OSD display buffers. The size is set to the maximum required buffer. if(osdWindow.display != NULL) { - if(osdWindow.debug) - printf("Freeing OSD display framebuffer:%08lx\n", osdWindow.display); + debugf("Freeing OSD display framebuffer:%08lx\n", osdWindow.display); free(osdWindow.display); } else { @@ -888,8 +1016,7 @@ uint8_t OSDInit(enum WINDOWS window) result = 1; } else { - if(osdWindow.debug) - printf("OSD window framebuffer allocated: %dBytes@%08lx\n", VC_MENU_RGB_BITS * VC_MENU_BUFFER_SIZE > VC_STATUS_RGB_BITS * VC_STATUS_BUFFER_SIZE ? VC_MENU_RGB_BITS * VC_MENU_BUFFER_SIZE : VC_STATUS_RGB_BITS * VC_STATUS_BUFFER_SIZE, osdWindow.display); + debugf("OSD window framebuffer allocated: %dBytes@%08lx\n", VC_MENU_RGB_BITS * VC_MENU_BUFFER_SIZE > VC_STATUS_RGB_BITS * VC_STATUS_BUFFER_SIZE ? VC_MENU_RGB_BITS * VC_MENU_BUFFER_SIZE : VC_STATUS_RGB_BITS * VC_STATUS_BUFFER_SIZE, osdWindow.display); } } diff --git a/common/sharpmz.c b/common/sharpmz.c index 645c254..e3b095d 100644 --- a/common/sharpmz.c +++ b/common/sharpmz.c @@ -952,14 +952,14 @@ void mzClearLine(int row, int colStart, int colEnd, uint8_t updPos) uint8_t mzSetVGABorder(uint8_t vborder) { // Locals. - uint8_t mode = (uint8_t)*(volatile uint32_t *)(VCADDR_32BIT_VMBORDER) & VMBORDER_MASK; + 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_VMBORDER) = mode | vborder; + *(volatile uint8_t *)(VCADDR_8BIT_VMVGATTR) = mode | vborder; return(0); } @@ -968,27 +968,27 @@ uint8_t mzSetVGABorder(uint8_t vborder) uint8_t mzSetVGAMode(uint8_t vgamode) { // Locals. - uint8_t mode = (uint8_t)*(volatile uint32_t *)(VCADDR_32BIT_VMCTRL) & VMMODE_VGA_MASK; + 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_1024x768 && vgamode != VMMODE_VGA_800x600) + if(vgamode != VMMODE_VGA_OFF && vgamode != VMMODE_VGA_640x480 && vgamode != VMMODE_VGA_800x600) return(1); // Set the VGA mode. - *(volatile uint8_t *)(VCADDR_8BIT_VMCTRL) = mode | vgamode; + *(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 hwmode) +uint8_t mzSetMachineVideoMode(uint8_t vmode) { // Locals. uint8_t mode = (uint8_t)*(volatile uint32_t *)(VCADDR_32BIT_VMCTRL) & VMMODE_MASK; // Sanity check parameters. - if(hwmode != VMMODE_MZ80K && hwmode != VMMODE_MZ80C && hwmode != VMMODE_MZ1200 && hwmode != VMMODE_MZ80A && hwmode != VMMODE_MZ700 && hwmode != VMMODE_MZ800 && hwmode != VMMODE_MZ80B && hwmode != VMMODE_MZ2000) + 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. diff --git a/common/tranzputer.c b/common/tranzputer.c index 8a12ecb..84808bd 100644 --- a/common/tranzputer.c +++ b/common/tranzputer.c @@ -62,6 +62,12 @@ // and threads. // v1.7 May 2021 - Changes to use 512K-1Mbyte Z80 Static RAM, build time configurable. // Added memory test routines to validate tranZPUter memory. +// v1.8 Oct 2021 - Major changes as the Sharp MZ Series FPGA Emulation is incorporated +// within the tranZPUter. CPLD's are now coded on a 1:1 with a host +// and support to allow CPLD emulation of a different host removed +// as this is catered for by the Sharp MZ Series. +// MZ-2000 support added as the tranZPUter SW-700 now functions +// on the MZ-2000 host hardware. // // Notes: See Makefile to enable/disable conditional components // @@ -112,9 +118,12 @@ extern "C" { #include "utils.h" #include #include -#include #include +// Bring in public declarations from emuMZ module (pseudo class). +#define EMUMZ_H +#include + #ifndef __APP__ // Protected methods which should only reside in the kernel. // Global scope variables used within the zOS kernel. @@ -146,6 +155,137 @@ static t_asciiMap asciiMap[] = { { 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 +}; + // Dummy method for the interrupt Service Routines when disabled by current mode. // @@ -269,7 +409,7 @@ static void setupIRQ(void) switch(z80Control.hostType) { // For the MZ700 we need to enable IORQ to process the OUT statements the Z80 generates for memory mode selection. - case MZ700: + case HW_MZ700: // Install the dummy method to be called when PortE triggers. _VectorsRam[IRQ_PORTE + 16] = irqPortE; @@ -294,7 +434,7 @@ static void setupIRQ(void) break; // The MZ800 we setup for RESET and SVCREQ handling, everything else ignored. - case MZ800: + case HW_MZ800: // Install the dummy method to be called when PortE triggers. _VectorsRam[IRQ_PORTE + 16] = irqPortE; @@ -317,7 +457,7 @@ static void setupIRQ(void) // For the MZ80B we need to enable IORQ to process the OUT statements the Z80 generates for memory mode selection and I/O. - case MZ80B: + case HW_MZ80B: // Install the dummy method to be called when PortE triggers. _VectorsRam[IRQ_PORTE + 16] = irqPortE_dummy; @@ -338,10 +478,10 @@ static void setupIRQ(void) NVIC_SET_PRIORITY(IRQ_PORTE, 16); break; - // For the MZ2000 we need to enable IORQ to process the OUT statements the Z80 generates for memory mode selection and I/O. - case MZ2000: + // The MZ2000 we setup for RESET and SVCREQ handling, everything else ignored. + case HW_MZ2000: // Install the dummy method to be called when PortE triggers. - _VectorsRam[IRQ_PORTE + 16] = irqPortE_dummy; + _VectorsRam[IRQ_PORTE + 16] = irqPortE; // Install the method to be called when PortD triggers. _VectorsRam[IRQ_PORTD + 16] = irqPortD; @@ -361,7 +501,7 @@ static void setupIRQ(void) break; // If the tranZPUter is running as a Sharp MZ-80A then we dont need a complicated ISR, just enable the detection of IO requests on Port E. - case MZ80A: + case HW_MZ80A: default: // Install the method to be called when PortE triggers. _VectorsRam[IRQ_PORTE + 16] = irqPortE; @@ -419,7 +559,7 @@ static void restoreIRQ(void) switch(z80Control.hostType) { // For the MZ700 we need to enable IORQ to process the OUT statements the Z80 generates for memory mode selection. - case MZ700: + case HW_MZ700: // Setup the IRQ for Z80_IORQ. //installIRQ(Z80_IORQ, IRQ_MASK_FALLING); @@ -431,7 +571,7 @@ static void restoreIRQ(void) break; // The MZ800 just needs to enable IORQ to process the OUT statements the Z80 generates for memory mode selection. - case MZ800: + case HW_MZ800: // Setup the IRQ for CTL_SVCREQ. installIRQ(CTL_SVCREQ, IRQ_MASK_LOW); @@ -440,7 +580,7 @@ static void restoreIRQ(void) break; // For the MZ80B we need to enable IORQ to process the OUT statements the Z80 generates for memory mode selection and I/O. - case MZ80B: + case HW_MZ80B: // Setup the IRQ for CTL_SVCREQ. installIRQ(CTL_SVCREQ, IRQ_MASK_LOW); @@ -448,8 +588,8 @@ static void restoreIRQ(void) installIRQ(Z80_RESET, IRQ_MASK_FALLING); break; - // For the MZ2000 we need to enable IORQ to process the OUT statements the Z80 generates for memory mode selection and I/O. - case MZ2000: + // The MZ2000 just re-enable the service request and reset interrupts. + case HW_MZ2000: // Setup the IRQ for CTL_SVCREQ. installIRQ(CTL_SVCREQ, IRQ_MASK_LOW); @@ -458,7 +598,7 @@ static void restoreIRQ(void) break; // If the tranZPUter is running as a Sharp MZ-80A then we dont need a complicated ISR, just enable the detection of IO requests on Port E. - case MZ80A: + case HW_MZ80A: default: // Setup the IRQ for CTL_SVCREQ. installIRQ(CTL_SVCREQ, IRQ_MASK_LOW); @@ -579,15 +719,18 @@ void setupZ80Pins(uint8_t initK64F, volatile uint32_t *millisecondTick) } // Initialise control structure. - z80Control.svcControlAddr = getServiceAddr(); - z80Control.refreshAddr = 0x00; - z80Control.disableRefresh = 0; - z80Control.runCtrlLatch = readCtrlLatch(); - z80Control.holdZ80 = 0; - z80Control.ctrlMode = Z80_RUN; - z80Control.busDir = TRISTATE; - z80Control.hostType = MZ80A; - z80Control.machineMode = MZ80A; + z80Control.svcControlAddr = getServiceAddr(); + z80Control.refreshAddr = 0x00; + z80Control.disableRefresh = 0; + z80Control.runCtrlLatch = readCtrlLatch(); + z80Control.holdZ80 = 0; + z80Control.iplMode = 1; + z80Control.blockResetActions = 0; + z80Control.ctrlMode = Z80_RUN; + z80Control.busDir = TRISTATE; + z80Control.hostType = HW_MZ80A; +// z80Control.machineMode = MZ80A; + z80Control.cpldVersion = 1; // Final part of first call initialisation, now that the pins are configured, setup the interrupts. // @@ -638,19 +781,37 @@ void resetZ80(uint8_t memoryMode) { // The first output is a dummy write which removes the original host configuration set when the CPLD cold starts. This is necessary to keep the machine original if // the K64F isnt present or autoboot is disabled. The second output ensures the memory management is set to the default state for an MZ-800. - writeZ80IO(IO_TZ_CPLDCFG, MODE_MZ800 | MODE_VIDEO_MODULE_DISABLED | MODE_PRESERVE_CONFIG, TRANZPUTER); + writeZ80IO(IO_TZ_CPLDCFG, HWMODE_MZ800 | MODE_VIDEO_MODULE_DISABLED | MODE_PRESERVE_CONFIG, TRANZPUTER); writeZ80IO(IO_TZ_MMIO4, 0, MAINBOARD); } - // Simply change the Z80_RESET pin to an output, assert low, reset high and reset to input to create the hardware reset event. On the original hardware the - // reset pulse width is 90uS, the ms timer is only accurate to 100uS so we apply a 100uS pulse. + // On MZ-2000 hosts the RESET is controlled by a gate array so we cannot assert our output. In order to reset we must use the 8255 output to force the gate array to + // reset as it controls many signal states as well as the system reset signal. // - __disable_irq(); - pinOutputSet(Z80_RESET, LOW); - for(volatile uint32_t pulseWidth=0; pulseWidth < DEFAULT_RESET_PULSE_WIDTH; pulseWidth++); - pinHigh(Z80_RESET); - pinInput(Z80_RESET); - __enable_irq(); + if(z80Control.hostType == HW_MZ2000) + { + //writeZ80IO(IO_TZ_PPICTL, 0x06, MAINBOARD); + writeZ80IO(IO_TZ_CPLDCMD, CPLD_RESET_HOST, MAINBOARD); + } + // Unknown boards do nothing as we dont know the underlying hardware configuration. + else if(z80Control.hostType == HW_UNKNOWN) + { + } + else + { + // Simply change the Z80_RESET pin to an output, assert low, reset high and reset to input to create the hardware reset event. On the original hardware the + // reset pulse width is 90uS, the ms timer is only accurate to 100uS so we apply a 100uS pulse. + // + if(z80Control.hostType != HW_MZ2000 && z80Control.hostType != HW_UNKNOWN) + { + __disable_irq(); + pinOutputSet(Z80_RESET, LOW); + for(volatile uint32_t pulseWidth=0; pulseWidth < DEFAULT_RESET_PULSE_WIDTH; pulseWidth++); + pinHigh(Z80_RESET); + pinInput(Z80_RESET); + __enable_irq(); + } + } // Set the memory mode to the one provided. // @@ -898,7 +1059,9 @@ uint8_t writeZ80Memory(uint32_t addr, uint8_t data, enum TARGETS target) // will translate it into a correct write signal. if(target == FPGA) { - // Allow time for the address and data to settle then pulse the WR line low. + // Allow time for the address and data to settle then pulse the MREQ and WR line low. + for(volatile uint32_t pulseWidth = 0; pulseWidth < 3; pulseWidth++); + pinLow(Z80_MREQ); for(volatile uint32_t pulseWidth = 0; pulseWidth < 5; pulseWidth++); pinLow(Z80_WR); for(volatile uint32_t pulseWidth = 0; pulseWidth < 5; pulseWidth++); @@ -937,12 +1100,12 @@ uint8_t writeZ80Memory(uint32_t addr, uint8_t data, enum TARGETS target) // With the tranZPUter SW v2 boards, need to increase the write pulse width, alternatively wait until a positive edge on the CPU clock. for(volatile uint32_t pulseWidth=0; pulseWidth < 3; pulseWidth++); } - - // Complete the write cycle. - // - pinHigh(Z80_WR); - pinHigh(Z80_MREQ); } + + // Complete the write cycle. + // + pinHigh(Z80_WR); + pinHigh(Z80_MREQ); return(0); } @@ -1018,7 +1181,7 @@ uint8_t writeZ80Array(uint32_t addr, uint8_t *data, uint32_t size, enum TARGETS // Locals. uint32_t nxtAddr = addr; uint8_t *ptr = data; -printf("WZA: %08lx, %08lx\n", addr, data); +//printf("WZA: %08lx, %08lx\n", addr, data); // If the Z80 is in RUN mode, request the bus. // This mechanism allows for the Z80 BUS to remain under the tranZPUter control for multiple transactions. // @@ -1146,7 +1309,16 @@ uint8_t outZ80IO(uint32_t addr, uint8_t data) pinLow(Z80_WR); // On a K64F running at 120MHz this delay gives a pulsewidth of 760nS. - for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); + switch(z80Control.hostType) + { + case HW_MZ2000: + for(volatile uint32_t pulseWidth=0; pulseWidth < 16; pulseWidth++); + break; + + default: + for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); + break; + } // Another wait loop check as the Z80 can assert wait at the time of Write or anytime before it is deasserted. while((*ms - startTime) < 200 && pinGet(Z80_WAIT) == 0); @@ -1190,7 +1362,16 @@ uint8_t inZ80IO(uint32_t addr) { // On a K64F running at 120MHz this delay gives a pulsewidth of 760nS. This gives time for the addressed device to present the data // on the data bus. - for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); + switch(z80Control.hostType) + { + case HW_MZ2000: + for(volatile uint32_t pulseWidth=0; pulseWidth < 16; pulseWidth++); + break; + + default: + for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); + break; + } // A wait loop check as the Z80 can assert wait during the Read operation to request more time. Set a timeout in case of hardware lockup. while((*ms - startTime) < 100 && pinGet(Z80_WAIT) == 0); @@ -2327,7 +2508,7 @@ FRESULT loadZ80Memory(const char *src, uint32_t fileOffset, uint32_t addr, uint3 // if(!fr0) fr0 = f_lseek(&File, fileOffset); - +printf("Loading file(%s,%08lx,%08lx)\n", src, addr, size); // If no errors in opening the file, proceed with reading and loading into memory. if(!fr0) { @@ -2371,12 +2552,12 @@ FRESULT loadZ80Memory(const char *src, uint32_t fileOffset, uint32_t addr, uint3 { // If the host hardware is an MZ-700/MZ-800 and we are loading into main memory, issue memory management commands to page in all the DRAM. // - if(target == MAINBOARD && addr <= 0x1000 && (z80Control.hostType == MZ700 || z80Control.hostType == MZ800)) + if(target == MAINBOARD && addr <= 0x1000 && (z80Control.hostType == HW_MZ700 || z80Control.hostType == HW_MZ800)) { // Then page in the lower DRAM bank. outZ80IO(IO_TZ_MMIO0, 0); } - if(target == MAINBOARD && (addr >= 0xD000 || addr+size >= 0xD000) && (z80Control.hostType == MZ700 || z80Control.hostType == MZ800)) + if(target == MAINBOARD && (addr >= 0xD000 || addr+size >= 0xD000) && (z80Control.hostType == HW_MZ700 || z80Control.hostType == HW_MZ800)) { // Then page in the upper DRAM bank. outZ80IO(IO_TZ_MMIO1, 0); @@ -2412,12 +2593,12 @@ FRESULT loadZ80Memory(const char *src, uint32_t fileOffset, uint32_t addr, uint3 // Reset the memory management for MZ-700/MZ-800. // - if(target == MAINBOARD && addr <= 0x1000 && (z80Control.hostType == MZ700 || z80Control.hostType == MZ800)) + if(target == MAINBOARD && addr <= 0x1000 && (z80Control.hostType == HW_MZ700 || z80Control.hostType == HW_MZ800)) { // Restore lower memory bank to BIOS. outZ80IO(IO_TZ_MMIO2, 0); } - if(target == MAINBOARD && (addr >= 0xD000 || addr+size >= 0xD000) && (z80Control.hostType == MZ700 || z80Control.hostType == MZ800)) + if(target == MAINBOARD && (addr >= 0xD000 || addr+size >= 0xD000) && (z80Control.hostType == HW_MZ700 || z80Control.hostType == HW_MZ800)) { // Restore upper memory bank to VRAM etc. outZ80IO(IO_TZ_MMIO3, 0); @@ -2464,6 +2645,7 @@ FRESULT loadMZFZ80Memory(const char *src, uint32_t addr, uint32_t *bytesRead, ui FIL File; unsigned int readSize; uint32_t addrOffset = SRAM_BANK0_ADDR; + uint32_t cmtHdrAddr = MZ_CMT_ADDR; t_svcDirEnt mzfHeader; FRESULT fr0; @@ -2490,18 +2672,25 @@ FRESULT loadMZFZ80Memory(const char *src, uint32_t addr, uint32_t *bytesRead, ui // Setup bank in which to load the header/data. Default is bank 0, different host hardware uses different banks. // - if(target == TRANZPUTER && z80Control.hostType == MZ800) + if(target == TRANZPUTER && z80Control.hostType == HW_MZ800) { addrOffset = SRAM_BANK6_ADDR; } + else if(target == TRANZPUTER && z80Control.hostType == HW_MZ2000) + { + addrOffset = SRAM_BANK6_ADDR; + } // Save the header into the CMT area for reference, some applications expect it. If the load address is below 1200H this could be wiped out, the code below stores a copy // in the service record sector on exit for this purpose. The caller needs to check the service record and if the Load Address is below >= 1200H use the CMT header else // use the service sector. // - // NB: This assumes TZFS is running and made this call. + // NB: This assumes TZFS is running and made this call. Ignore for MZ2000 when in IPL mode as the header isnt needed. // - copyToZ80(addrOffset+MZ_CMT_ADDR, (uint8_t *)&mzfHeader, MZF_HEADER_SIZE, target); + if(z80Control.hostType != HW_MZ2000 || (z80Control.hostType == HW_MZ2000 && z80Control.iplMode == 0)) + { + copyToZ80(addrOffset+cmtHdrAddr, (uint8_t *)&mzfHeader, MZF_HEADER_SIZE, target); + } if(hdrOnly == 0) { @@ -2739,7 +2928,7 @@ int memoryDumpZ80(uint32_t memaddr, uint32_t memsize, uint32_t dispaddr, uint8_t // If the host hardware is an MZ-700/MZ-800 and memCtrl has been set then we need to issue memory management commands to page in all the DRAM. // - if(target == MAINBOARD && memCtrl == 1 && (z80Control.hostType == MZ700 || z80Control.hostType == MZ800)) + if(target == MAINBOARD && memCtrl == 1 && (z80Control.hostType == HW_MZ700 || z80Control.hostType == HW_MZ800)) { // First reset memory map. outZ80IO(IO_TZ_MMIO4, 0); @@ -2821,7 +3010,7 @@ int memoryDumpZ80(uint32_t memaddr, uint32_t memsize, uint32_t dispaddr, uint8_t // Reset the memory management for MZ-700/MZ-800. // - if(target == MAINBOARD && memCtrl == 1 && (z80Control.hostType == MZ700 || z80Control.hostType == MZ800)) + if(target == MAINBOARD && memCtrl == 1 && (z80Control.hostType == HW_MZ700 || z80Control.hostType == HW_MZ800)) { // Bring back the monitor ROM. outZ80IO(IO_TZ_MMIO2, 0); @@ -2843,6 +3032,88 @@ int memoryDumpZ80(uint32_t memaddr, uint32_t memsize, uint32_t dispaddr, uint8_t return(keyIn == 0x1b ? 0 : -1); } +// Method to clear the host video display. To cater for differences in architecture, the machine model is given and processed accordingly. +// +void clsHost(void) +{ + switch(z80Control.hostType) + { + case HW_MZ2000: + writeZ80IO(IO_TZ_PIOA, 0xD3, MAINBOARD); + fillZ80Memory(MZ_VID_RAM_ADDR, MZ_VID_RAM_SIZE, 0x00, MAINBOARD); + writeZ80IO(IO_TZ_PIOA, 0x13, MAINBOARD); + break; + + case HW_MZ700: + fillZ80Memory(MZ_VID_RAM_ADDR, MZ_VID_RAM_SIZE, 0x00, MAINBOARD); + fillZ80Memory(MZ_ATTR_RAM_ADDR, MZ_ATTR_RAM_SIZE, VMATTR_FG_WHITE|VMATTR_BG_BLUE, MAINBOARD); + break; + + case HW_MZ80A: + default: + fillZ80Memory(MZ_VID_RAM_ADDR, MZ_VID_RAM_SIZE, 0x00, MAINBOARD); + break; + } + return; +} + +// Method to print to the host display. +// +void printfHost(uint8_t x, uint8_t y, char *format, ...) +{ + // Locals. + // + va_list args; + uint8_t tmpbuf[1024]; + uint32_t tmpbuflen; + uint32_t addr; + + // Sanity check. + if(x > MZ_VID_MAX_COL || y > MZ_VID_MAX_ROW) + return; + + // Setup variable arguments. + va_start(args, format); + + // Expand the given string into a physical byte buffer. + vsprintf(tmpbuf, format, args); + + // Store length as Sharp code uses 0x00 as SPACE character so strlen isnt useful when converting. + tmpbuflen = strlen(tmpbuf); + + // Process any machine specific differences in display addressing. + switch(z80Control.hostType) + { + case HW_MZ2000: + addr = MZ_VID_RAM_ADDR + (y * MZ_VID_MAX_COL) + x; + writeZ80IO(IO_TZ_PIOA, 0xD3, MAINBOARD); + copyToZ80(addr, &tmpbuf, tmpbuflen, MAINBOARD); + writeZ80IO(IO_TZ_PIOA, 0x13, MAINBOARD); + break; + + case HW_MZ80A: + case HW_MZ700: + case HW_MZ800: + // Translate ASCII to Sharp ASCII. + for(uint32_t idx=0; idx < tmpbuflen; idx++) + { + tmpbuf[idx] = dispCodeMap[tmpbuf[idx]].dispCode; + } + addr = MZ_VID_RAM_ADDR + (y * MZ_VID_MAX_COL) + x; + copyToZ80(addr, &tmpbuf, tmpbuflen, MAINBOARD); + break; + + default: + addr = MZ_VID_RAM_ADDR + (y * MZ_VID_MAX_COL) + x; + copyToZ80(addr, &tmpbuf, tmpbuflen, MAINBOARD); + break; + } + + // End variable argument processing. + va_end(args); + return; +} + /////////////////////////////////////////////////////// // Getter/Setter methods to keep z80Control private. // /////////////////////////////////////////////////////// @@ -2939,7 +3210,8 @@ void convertToFAT32FileNameFormat(char *dst) // Method to load a BIOS into the tranZPUter and configure for a particular host type. // -uint8_t loadBIOS(const char *biosFileName, uint8_t machineMode, uint32_t loadAddr) +//uint8_t loadBIOS(const char *biosFileName, uint8_t machineMode, uint32_t loadAddr) +uint8_t loadBIOS(const char *biosFileName, uint32_t loadAddr) { // Locals. uint8_t result = FR_OK; @@ -2954,7 +3226,7 @@ uint8_t loadBIOS(const char *biosFileName, uint8_t machineMode, uint32_t loadAdd setZ80CPUFrequency(0, 4); // Set the machine mode according to BIOS loaded. - z80Control.machineMode = machineMode; + // z80Control.machineMode = machineMode; // setup the IRQ's according to this machine. setupIRQ(); @@ -2969,20 +3241,64 @@ void hardResetTranZPUter(void) { // Locals. uint8_t cpuConfig; - - // Firstly, ascertain what CPU we are using, soft or hard. +printf("Hard Z80 Reset\n"); + // Firstly, ascertain what CPU we are using, soft or hard. If the read value is illegal default to Z80. // - cpuConfig = readZ80IO(IO_TZ_CPUCFG, TRANZPUTER) & CPUMODE_IS_SOFT_MASK; - - // Load up the default ROMS. - loadTranZPUterDefaultROMS(cpuConfig); + cpuConfig = readZ80IO(IO_TZ_CPUCFG, TRANZPUTER); + if(cpuConfig == 0xff) cpuConfig = CPUMODE_IS_Z80; + cpuConfig &= CPUMODE_IS_SOFT_MASK; + + // If this host is an MZ-2000 with distinct boot and run modes, query the hardware to find the current mode as a reset in run mode doesnt require a hard reset. + if(z80Control.hostType == HW_MZ2000) + { + z80Control.iplMode = readZ80IO(IO_TZ_CPLDSTATUS, TRANZPUTER) & 0x01; +printf("IPL Mode:%d\n", z80Control.iplMode); + } + + // Load up the default ROMS in IPL mode (normal mode for all MZ's except MZ-80B/2000/2200/2500). + if(z80Control.iplMode && !z80Control.blockResetActions) + loadTranZPUterDefaultROMS(cpuConfig); // Setup the Interrupts for IORQ and MREQ. setupIRQ(); + // Reset any block action request. + z80Control.blockResetActions = 0; + return; } +// Method to load TZFS with an optional BIOS. +// +//FRESULT loadTZFS(char *biosFile, uint8_t machineMode, uint32_t loadAddr) +FRESULT loadTZFS(char *biosFile, uint32_t loadAddr) +{ + // Locals. + FRESULT result = 0; + + if(biosFile) + { + result = loadBIOS(biosFile, loadAddr); + } + if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0, MZ_UROM_ADDR, 0x1800, 0, TRANZPUTER, 1) != FR_OK)) + { + printf("Error: Failed to load bank 1 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); + } + if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x1800, MZ_BANKRAM_ADDR+0x10000, 0x1000, 0, TRANZPUTER, 1) != FR_OK)) + { + printf("Error: Failed to load page 2 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); + } + if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x2800, MZ_BANKRAM_ADDR+0x20000, 0x1000, 0, TRANZPUTER, 1) != FR_OK)) + { + printf("Error: Failed to load page 3 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); + } + if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x3800, MZ_BANKRAM_ADDR+0x30000, 0x1000, 0, TRANZPUTER, 1) != FR_OK)) + { + printf("Error: Failed to load page 4 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); + } + return(result); +} + // Method to load the default ROMS into the tranZPUter RAM ready for start. // If the autoboot flag is set, perform autoboot by wiping the STACK area // of the SA1510 - this has the effect of JP 00000H. @@ -2991,11 +3307,10 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) { // Locals. FRESULT result = 0; - const char *biosFile; // Set CPU and hold soft CPU clock if configured. writeZ80IO(IO_TZ_CPUCFG, cpuConfig & CPUMODE_IS_SOFT_MASK, TRANZPUTER); - +printf("CPUCONFIG=%02x\n", cpuConfig); // Processing according to CPU. EVO needs its own zOS loading. switch(cpuConfig) { @@ -3005,22 +3320,23 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) // Now load the default BIOS into memory for the host type. switch(z80Control.hostType) { - case MZ700: - result = loadBIOS(MZ_ROM_1Z_013A_40C, MZ700, MZ_MROM_ADDR); + case HW_MZ700: + result = loadTZFS(MZ_ROM_1Z_013A_40C, MZ_MROM_ADDR); break; - case MZ800: + case HW_MZ800: // The MZ-800 uses a composite ROM containing the modified BIOS of the MZ-700 (1Z_013B), the IPL of the MZ-800 (9Z_504M), the CGROM for video text output // and the BASIC IOCS, a common code area for BASIC, // // First we load the MZ-700 compatible BIOS in page 0 to support TZFS when activated. - result = loadBIOS(MZ_ROM_1Z_013A_40C, MZ700, MZ_MROM_ADDR); + result = loadTZFS(MZ_ROM_1Z_013A_40C, MZ_MROM_ADDR); // Next we load the MZ-800 BIOS in page 7. if(!result) { printf("Loading 1Z_013B\n"); - result = loadBIOS(MZ_ROM_1Z_013B, MZ800, MZ_800_MROM_ADDR); + //result = loadBIOS(MZ_ROM_1Z_013B, MZ800, MZ_800_MROM_ADDR); + result = loadBIOS(MZ_ROM_1Z_013B, MZ_800_MROM_ADDR); } // Load up the CGROM into RAM. @@ -3031,46 +3347,61 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) if(!result) { printf("Loading 9Z_504M\n"); - result = loadBIOS(MZ_ROM_9Z_504M, MZ800, MZ_800_IPL_ADDR); + //result = loadBIOS(MZ_ROM_9Z_504M, MZ800, MZ_800_IPL_ADDR); + result = loadBIOS(MZ_ROM_9Z_504M, MZ_800_IPL_ADDR); } // Finally we load the common IOCS. if(!result) { printf("Loading BASIC IOCS\n"); - result = loadBIOS(MZ_ROM_800_IOCS, MZ800, MZ_800_IOCS_ADDR); + //result = loadBIOS(MZ_ROM_800_IOCS, MZ800, MZ_800_IOCS_ADDR); + result = loadBIOS(MZ_ROM_800_IOCS, MZ_800_IOCS_ADDR); } break; - case MZ80B: - result = loadBIOS(MZ_ROM_MZ80B_IPL, MZ80B, MZ_MROM_ADDR); + case HW_MZ80B: + //result = loadBIOS(MZ_ROM_MZ80B_IPL, MZ80B, MZ_MROM_ADDR); + result = loadBIOS(MZ_ROM_MZ80B_IPL, MZ_MROM_ADDR); break; - case MZ2000: - result = loadBIOS(MZ_ROM_MZ2000_IPL, MZ2000, MZ_MROM_ADDR); + case HW_MZ2000: + // Load up the IPL BIOS at least try even if the CGROM failed. + printf("Loading IPL\n"); + //result = loadBIOS(MZ_ROM_MZ2000_IPL_TZPU, MZ2000, MZ_MROM_ADDR); + result = loadBIOS(MZ_ROM_MZ2000_IPL_TZPU, MZ_MROM_ADDR); + if(result != FR_OK) + { + printf("Error: Failed to load IPL ROM %s into tranZPUter memory.\n", MZ_ROM_MZ2000_IPL_TZPU); + } else + { + // Load up the MZ2000 CGROM into the FPGA. + printf("Loading CGROM\n"); + + // Enable the FPGA. + writeZ80IO(IO_TZ_CPLDCFG, 0x80 | MODE_VIDEO_MODULE_ENABLED | HWMODE_MZ2000, TRANZPUTER); + + // Update the CGROM + result=loadZ80Memory((const char *)MZ_ROM_MZ2000_CGROM, 0, MZ_VID_CGROM_ADDR, 0x0800, 0, FPGA, 1); + if(result != FR_OK) + { + printf("Error: Failed to load CGROM %s into FPGA video memory.\n", MZ_ROM_MZ2000_CGROM); + } + + // Disable the FPGA. + writeZ80IO(IO_TZ_CPLDCFG, 0x80 | HWMODE_MZ2000, TRANZPUTER); + + // Make sure the video mode in the FPGA is correct (defaults to MZ700). + writeZ80IO(IO_TZ_VMCTRL, VMMODE_MZ2000, TRANZPUTER); + } break; - case MZ80A: + case HW_MZ80A: + case HW_UNKNOWN: default: - result = loadBIOS(MZ_ROM_SA1510_40C, MZ80A, MZ_MROM_ADDR); + result = loadTZFS(MZ_ROM_SA1510_40C, MZ_MROM_ADDR); break; } - if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0, MZ_UROM_ADDR, 0x1800, 0, TRANZPUTER, 1) != FR_OK)) - { - printf("Error: Failed to load bank 1 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); - } - if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x1800, MZ_BANKRAM_ADDR+0x10000, 0x1000, 0, TRANZPUTER, 1) != FR_OK)) - { - printf("Error: Failed to load page 2 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); - } - if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x2800, MZ_BANKRAM_ADDR+0x20000, 0x1000, 0, TRANZPUTER, 1) != FR_OK)) - { - printf("Error: Failed to load page 3 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); - } - if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x3800, MZ_BANKRAM_ADDR+0x30000, 0x1000, 0, TRANZPUTER, 1) != FR_OK)) - { - printf("Error: Failed to load page 4 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); - } break; case CPUMODE_IS_ZPU_EVO: @@ -3085,6 +3416,9 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) case CPUMODE_IS_EMU_MZ: printf("Sharp MZ Series Emulation Active\n"); + + // Start the emulation. + EMZRun((uint8_t)(svcControl.cmd - TZSVC_CMD_EMU_SETMZ80K)); break; } @@ -3102,15 +3436,21 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) // If autoboot flag set, force a restart to the ROM which will call User ROM startup code. if(osControl.tzAutoBoot) { - if(z80Control.hostType != MZ800) - { - // Set the memory model to BOOT so we can bootstrap TZFS. - resetZ80(TZMM_BOOT); - } else + if(z80Control.hostType == HW_MZ800) { // On the MZ-800, once all firmware loaded, set the memory mode to MZ-800 and reset to enable processing on the tranZPUter memory rather than host memory. resetZ80(TZMM_MZ800); } + // MZ-2000 stays in original mode, user will start TZFS via key press in modified IPL bios. + else if(z80Control.hostType == HW_MZ2000) + { + resetZ80(TZMM_MZ2000); + } + else + { + // Set the memory model to BOOT so we can bootstrap TZFS. + resetZ80(TZMM_BOOT); + } } else { setCtrlLatch(TZMM_ORIG); @@ -3134,6 +3474,7 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) writeZ80IO(IO_TZ_CPUCFG, cpuConfig | CPUMODE_CLK_EN | CPUMODE_RESET_CPU, TRANZPUTER); } else { +printf("HERE 10\n"); // Set the memory model to BOOT so we can bootstrap TZFS. resetZ80(TZMM_ORIG); } @@ -4329,10 +4670,14 @@ uint8_t svcSaveFile(enum FILE_TYPE type) { // Setup bank in which to load the header/data. Default is bank 0, different host hardware uses different banks. // - if(svcControl.memTarget == 0 && z80Control.hostType == MZ800) + if(svcControl.memTarget == 0 && z80Control.hostType == HW_MZ800) { addrOffset = SRAM_BANK6_ADDR; } + else if(svcControl.memTarget == 0 && z80Control.hostType == HW_MZ2000) + { + addrOffset = SRAM_BANK6_ADDR; + } // Get the MZF header which contains the details of the file to save. copyFromZ80((uint8_t *)&mzfHeader, addrOffset + MZ_CMT_ADDR, MZF_HEADER_SIZE, TRANZPUTER); @@ -4370,7 +4715,6 @@ uint8_t svcSaveFile(enum FILE_TYPE type) return(result == FR_OK ? TZSVC_STATUS_OK : TZSVC_STATUS_FILE_ERROR); } - // Method to erase a file on the SD card. // uint8_t svcEraseFile(enum FILE_TYPE type) @@ -4662,12 +5006,26 @@ uint32_t getServiceAddr(void) // If in MZ700 mode then set the service address accordingly. if(memoryMode == TZMM_MZ700_0 || memoryMode == TZMM_MZ700_2 || memoryMode == TZMM_MZ700_3 || memoryMode == TZMM_MZ700_4) addr = TZSVC_CMD_STRUCT_ADDR_MZ700; + + // If in MZ2000 mode then the service address differs according to boot state. + if(memoryMode == TZMM_MZ2000) + { + // Get the machine state and set the service address accordingly. + if(z80Control.iplMode) + { + addr = TZSVC_CMD_STRUCT_ADDR_MZ2000_IPL; + } + else + { + addr = TZSVC_CMD_STRUCT_ADDR_MZ2000_NST; + } + } } else { // zOS addr = TZSVC_CMD_STRUCT_ADDR_ZOS; } -//printf("getServiceAddr:%02x,%02x,%02x,%01x,%08lx,%02x\n", z80Control.runCtrlLatch, z80Control.curCtrlLatch, memoryMode, cpuConfig, addr, svcControl.cmd); +printf("getServiceAddr:%02x,%02x,%02x,%01x,%08lx,%02x\n", z80Control.runCtrlLatch, z80Control.curCtrlLatch, memoryMode, cpuConfig, addr, svcControl.cmd); return(addr); } @@ -4696,6 +5054,12 @@ void processServiceRequest(void) { z80Control.holdZ80 = 1; + // If this host is an MZ-2000 with distinct boot and run modes, query the hardware to find the current mode. + if(z80Control.hostType == HW_MZ2000) + { + z80Control.iplMode = readZ80IO(IO_TZ_CPLDSTATUS, TRANZPUTER) & 0x01; + } + // Update the service control record address according to memory mode. // z80Control.svcControlAddr = getServiceAddr(); @@ -4784,10 +5148,11 @@ void processServiceRequest(void) // Load the 40 column version of the default host bios into memory. case TZSVC_CMD_LOAD40ABIOS: - loadBIOS(MZ_ROM_SA1510_40C, MZ80A, MZ_MROM_ADDR); + //loadBIOS(MZ_ROM_SA1510_40C, MZ80A, MZ_MROM_ADDR); + loadBIOS(MZ_ROM_SA1510_40C, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. - if(z80Control.hostType != MZ80A) + if(z80Control.hostType != HW_MZ80A) { // Change frequency to match Sharp MZ-80A setZ80CPUFrequency(MZ_80A_CPU_FREQ, 1); @@ -4796,10 +5161,11 @@ void processServiceRequest(void) // Load the 80 column version of the default host bios into memory. case TZSVC_CMD_LOAD80ABIOS: - loadBIOS(MZ_ROM_SA1510_80C, MZ80A, MZ_MROM_ADDR); + //loadBIOS(MZ_ROM_SA1510_80C, MZ80A, MZ_MROM_ADDR); + loadBIOS(MZ_ROM_SA1510_80C, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. - if(z80Control.hostType != MZ80A) + if(z80Control.hostType != HW_MZ80A) { // Change frequency to match Sharp MZ-80A setZ80CPUFrequency(MZ_80A_CPU_FREQ, 1); @@ -4808,10 +5174,11 @@ void processServiceRequest(void) // Load the 40 column MZ700 1Z-013A bios into memory for compatibility switch. case TZSVC_CMD_LOAD700BIOS40: - loadBIOS(MZ_ROM_1Z_013A_40C, MZ700, MZ_MROM_ADDR); + //loadBIOS(MZ_ROM_1Z_013A_40C, MZ700, MZ_MROM_ADDR); + loadBIOS(MZ_ROM_1Z_013A_40C, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. - if(z80Control.hostType != MZ700) + if(z80Control.hostType != HW_MZ700) { // Change frequency to match Sharp MZ-700 setZ80CPUFrequency(MZ_700_CPU_FREQ, 1); @@ -4820,10 +5187,11 @@ void processServiceRequest(void) // Load the 80 column MZ700 1Z-013A bios into memory for compatibility switch. case TZSVC_CMD_LOAD700BIOS80: - loadBIOS(MZ_ROM_1Z_013A_80C, MZ700, MZ_MROM_ADDR); + //loadBIOS(MZ_ROM_1Z_013A_80C, MZ700, MZ_MROM_ADDR); + loadBIOS(MZ_ROM_1Z_013A_80C, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. - if(z80Control.hostType != MZ700) + if(z80Control.hostType != HW_MZ700) { // Change frequency to match Sharp MZ-700 setZ80CPUFrequency(MZ_700_CPU_FREQ, 1); @@ -4832,10 +5200,11 @@ void processServiceRequest(void) // Load the MZ800 9Z-504M bios into memory for compatibility switch. case TZSVC_CMD_LOAD800BIOS: - loadBIOS(MZ_ROM_9Z_504M, MZ800, MZ_MROM_ADDR); + //loadBIOS(MZ_ROM_9Z_504M, MZ800, MZ_MROM_ADDR); + loadBIOS(MZ_ROM_9Z_504M, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. - if(z80Control.hostType != MZ800) + if(z80Control.hostType != HW_MZ800) { // Change frequency to match Sharp MZ-800 setZ80CPUFrequency(MZ_800_CPU_FREQ, 1); @@ -4844,10 +5213,11 @@ void processServiceRequest(void) // Load the MZ-80B IPL ROM into memory for compatibility switch. case TZSVC_CMD_LOAD80BIPL: - loadBIOS(MZ_ROM_MZ80B_IPL, MZ80B, MZ_MROM_ADDR); + //loadBIOS(MZ_ROM_MZ80B_IPL, MZ80B, MZ_MROM_ADDR); + loadBIOS(MZ_ROM_MZ80B_IPL, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. - if(z80Control.hostType != MZ80B) + if(z80Control.hostType != HW_MZ80B) { // Change frequency to match Sharp MZ-80B setZ80CPUFrequency(MZ_80B_CPU_FREQ, 1); @@ -4856,16 +5226,40 @@ void processServiceRequest(void) // Load the MZ-2000 IPL ROM into memory for compatibility switch. case TZSVC_CMD_LOAD2000IPL: - loadBIOS(MZ_ROM_MZ2000_IPL, MZ2000, MZ_MROM_ADDR); + //loadBIOS(MZ_ROM_MZ2000_IPL, MZ2000, MZ_MROM_ADDR); + loadBIOS(MZ_ROM_MZ2000_IPL, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. - if(z80Control.hostType != MZ2000) + if(z80Control.hostType != HW_MZ2000) { // Change frequency to match Sharp MZ-80B setZ80CPUFrequency(MZ_2000_CPU_FREQ, 1); } break; + // Load TZFS upon request. This service is for the MZ-80B/MZ-2000 which dont have a monitor BIOS installed and TZFS isnt loaded upon reset but rather through user request. + case TZSVC_CMD_LOADTZFS: + switch(z80Control.hostType) + { + case HW_MZ80B: + break; + + case HW_MZ2000: + // Load TZFS and a modified 1Z-013A MZ700 Monitor to provide an interactive TZFS session during IPL mode. + if(loadTZFS(MZ_ROM_1Z_013A_2000, MZ_MROM_ADDR) == FR_OK) + { + // Request a cold IPL start with no ROM load, this will invoke the loaded TZFS as the BOOT IPL. + z80Control.blockResetActions = 1; + writeZ80IO(IO_TZ_PPICTL, 0x06, MAINBOARD); + } + break; + + // Default, ie. not a valid host, is to do nothing. + default: + break; + } + break; + // Load the CPM CCP+BDOS from file into the address given. case TZSVC_CMD_LOADBDOS: if((status=loadZ80Memory((const char *)osControl.lastFile, MZF_HEADER_SIZE, svcControl.loadAddr+0x40000, svcControl.loadSize, 0, TRANZPUTER, 1)) != FR_OK) @@ -4920,7 +5314,7 @@ void processServiceRequest(void) writeZ80IO(IO_TZ_CPUCFG, CPUMODE_SET_Z80, TRANZPUTER); // Ensure the video is returned to default. - writeZ80IO(IO_TZ_CPLDCFG, VMMODE_MZ700, TRANZPUTER); + writeZ80IO(IO_TZ_VMCTRL, VMMODE_MZ700, TRANZPUTER); // Set a reset event so that the ROMS are reloaded and the Z80 set. z80Control.resetEvent = 1; @@ -4955,19 +5349,18 @@ void processServiceRequest(void) case TZSVC_CMD_EMU_SETMZ1200: case TZSVC_CMD_EMU_SETMZ80A: case TZSVC_CMD_EMU_SETMZ700: + case TZSVC_CMD_EMU_SETMZ1500: case TZSVC_CMD_EMU_SETMZ800: case TZSVC_CMD_EMU_SETMZ80B: case TZSVC_CMD_EMU_SETMZ2000: - // Initialise the on screen display. - if(!EMZInit((uint8_t)(svcControl.cmd - TZSVC_CMD_EMU_SETMZ80K))) + case TZSVC_CMD_EMU_SETMZ2200: + case TZSVC_CMD_EMU_SETMZ2500: + // Initialise the emulation and OSD. + if(!EMZInit(z80Control.hostType)) { // Switch to the emulation CPU (T80). writeZ80IO(IO_TZ_CPUCFG, CPUMODE_SET_EMU_MZ, TRANZPUTER); - // Should be safe so long as the enumerated types arent changed. - z80Control.machineMode = (uint8_t)(svcControl.cmd - TZSVC_CMD_EMU_SETMZ80K); -printf("Machine mode:%d\n", z80Control.machineMode); - // Enable the emulator service methods to handle User OSD Menu, tape/floppy loading etc. z80Control.emuMZactive = 1; @@ -5099,12 +5492,13 @@ uint8_t testTZFSAutoBoot(void) } // Method to identify the type of host the tranZPUter SW is running on. Originally it was only the MZ80A but the scope has expanded -// to the MZ-700, MZ-80B, MZ-800 and potentially a plethora of other machines in the future. +// to the MZ-700, MZ-80B, MZ-800, MZ-2000 and potentially a plethora of other machines in the future. // -void setHost(void) +void setHost(uint8_t printInfo) { // Locals. uint8_t cpldInfo; + uint8_t cpuInfo; // If the Z80 is in RUN mode, request the bus. // This mechanism allows for the load command to leave the BUS under the tranZPUter control for multiple transactions. @@ -5133,6 +5527,10 @@ void setHost(void) // Copy the ID value from the CPLD information register so that we can identify the host type. // cpldInfo = inZ80IO(IO_TZ_CPLDINFO); + + // Copy the ID value from the CPU information register to identify FPGA capabilities. + // + cpuInfo = inZ80IO(IO_TZ_CPUINFO); // Release the bus if it is not being held for further transations. // @@ -5144,78 +5542,208 @@ void setHost(void) } } else { - printf("Failed to access tranZPUter bus to read CPLDINFO, defaulting to MZ80A\n"); - cpldInfo = MZ80A; + if(printInfo) printf("Failed to access tranZPUter bus to read CPLDINFO, setting to UNKNOWN\n"); + cpldInfo = 0xFF; } // Setup the control variable to indicate type of host. This will affect processing of interrupts, BIOS loads etc. // - switch(cpldInfo & 0x07) + switch(cpldInfo & 0x17) { - case MZ700: - z80Control.hostType = MZ700; - z80Control.machineMode = MZ700; - printf("Host Type: MZ-700\n"); + case HW_MZ700: + if(!printInfo) + { + z80Control.hostType = HW_MZ700; + // z80Control.machineMode = MZ700; + } else + printf("Host Type: MZ-700\n"); break; - case MZ800: - z80Control.hostType = MZ800; - z80Control.machineMode = MZ800; - printf("Host Type: MZ-800\n"); + case HW_MZ800: + if(!printInfo) + { + z80Control.hostType = HW_MZ800; + // z80Control.machineMode = MZ800; + } else + printf("Host Type: MZ-800\n"); break; - case MZ80B: - z80Control.hostType = MZ80B; - z80Control.machineMode = MZ80B; - printf("Host Type: MZ-80B\n"); + case HW_MZ80B: + if(!printInfo) + { + z80Control.hostType = HW_MZ80B; + // z80Control.machineMode = MZ80B; + } else + printf("Host Type: MZ-80B\n"); break; - case MZ2000: - z80Control.hostType = MZ2000; - z80Control.machineMode = MZ2000; - printf("Host Type: MZ-2000\n"); + case HW_MZ2000: + if(!printInfo) + { + z80Control.hostType = HW_MZ2000; + // z80Control.machineMode = MZ2000; + } else + printf("Host Type: MZ-2000\n"); + break; + + case HW_MZ80A: + case HW_MZ80K: + case HW_MZ80C: + case HW_MZ1200: + if(!printInfo) + { + z80Control.hostType = HW_MZ80A; + // z80Control.machineMode = MZ80A; + } else + printf("Host Type: MZ-80A\n"); break; - case MZ80A: - case MZ80K: - case MZ80C: - case MZ1200: default: - z80Control.hostType = MZ80A; - z80Control.machineMode = MZ80A; - printf("Host Type: MZ-80A\n"); + z80Control.hostType = HW_UNKNOWN; + // z80Control.machineMode = UNKNOWN; break; } + // Extract the CPLD version for any programming nuances required in older versions. + z80Control.cpldVersion = (cpldInfo & CPLD_VERSION) >> 5; + // Report on video hardware. // if(cpldInfo & VIDEO_FPGA) { - printf("FPGA video hardware detected.\n"); + if(printInfo) + printf("FPGA video hardware detected.\n"); + } + + // Store and report on CPU hardware. + // + if(cpuInfo & CPUMODE_IS_SOFT_AVAIL) + { + z80Control.softcpuInfo = cpuInfo & CPUMODE_IS_SOFT_MASK; + + if(printInfo) + { + if(z80Control.softcpuInfo == CPUMODE_IS_Z80) + printf("No soft CPU hardware, hard Z80 only.\n"); + if(z80Control.softcpuInfo & CPUMODE_IS_T80) + printf("Soft T80 available.\n"); + if(z80Control.softcpuInfo & CPUMODE_IS_ZPU_EVO) + printf("Soft ZPU available.\n"); + if(z80Control.softcpuInfo & CPUMODE_IS_EMU_MZ) + printf("Sharp MZ Series FPGA Emulation available.\n"); + if(z80Control.softcpuInfo & CPUMODE_IS_BBB) + printf("Unspecified soft BBB CPU available.\n"); + if(z80Control.softcpuInfo & CPUMODE_IS_CCC) + printf("Unspecified soft CCC CPU available.\n"); + if(z80Control.softcpuInfo & CPUMODE_IS_DDD) + printf("Unspecified soft DDD CPU available.\n"); + } } // Report on CPLD version. // - printf("CPLD Version: %d\n", (cpldInfo & CPLD_VERSION) >> 5); + if(printInfo) + printf("CPLD Version: %d\n", z80Control.cpldVersion); return; } // Method to configure the hardware and events to operate the tranZPUter SW upgrade. // -void setupTranZPUter(void) +void setupTranZPUter(uint8_t stage, char *VERSION, char *VERSION_DATE) { - // Setup the pins to default mode and configure IRQ's. - setupZ80Pins(0, &systick_millis_count); + // Functionality can be split according to boot up stage of the processor using the 'stage' variable. + // + if(stage == 0) + { + // Setup the pins to default mode and configure IRQ's. + setupZ80Pins(0, &systick_millis_count); + + // Check to see which host the tranZPUter is installed in. + setHost(0); - // Check to see which monitor is installed to determine the host type. - setHost(); + // Once the external Z80 interface has been enabled, make machine dependent interactions whilst we are initialising. + switch(z80Control.hostType) + { + case HW_MZ2000: + // Initialise the hardware and present a sign on message while the tranZPUter initialises. + writeZ80IO(IO_TZ_PPICTL, 0x82, MAINBOARD); + writeZ80IO(IO_TZ_PPIC, 0x58, MAINBOARD); + writeZ80IO(IO_TZ_PPIA, 0xF7, MAINBOARD); + writeZ80IO(IO_TZ_PPIA, 0xFF, MAINBOARD); + writeZ80IO(IO_TZ_PIOCTLA, 0x0F, MAINBOARD); + writeZ80IO(IO_TZ_PIOCTLB, 0xCF, MAINBOARD); + writeZ80IO(IO_TZ_PIOCTLB, 0xFF, MAINBOARD); - // Reset the interrupts so they take into account the current host rather than the default. - setupIRQ(); + // Sign on message whilst we initialise tranZPUter hardware. + clsHost(); + printfHost(4, 4, "tranZPUter SW-700 v1.3"); + printfHost(4, 7, "CPLD fw: v%d", z80Control.cpldVersion); + printfHost(4, 7, "zOS: %s (%s)", VERSION, VERSION_DATE); + if(z80Control.softcpuInfo & CPUMODE_IS_EMU_MZ) + printfHost(4, 8, "emuMZ: %s (%s)", EMZGetVersion(), EMZGetVersionDate()); + break; - // Start off by clearing active memory banks, the AS6C4008 chip holds random values at power on. - fillZ80Memory(0x000000, TZ_MAX_Z80_MEM, 0x00, TRANZPUTER); + case HW_MZ700: + // Sign on message whilst we initialise tranZPUter hardware. + clsHost(); + printfHost(4, 4, "tranZPUter SW-700 v1.3"); + printfHost(4, 6, "CPLD fw: v%d", z80Control.cpldVersion); + printfHost(4, 7, "zOS: %s (%s)", VERSION, VERSION_DATE); + if(z80Control.softcpuInfo & CPUMODE_IS_EMU_MZ) + printfHost(4, 8, "emuMZ: %s (%s)", EMZGetVersion(), EMZGetVersionDate()); + break; + + default: + break; + } + + // Reset the interrupts so they take into account the current host rather than the default. + setupIRQ(); + + // Start off by clearing active memory banks, the AS6C4008 chip holds random values at power on. + fillZ80Memory(0x000000, TZ_MAX_Z80_MEM, 0x00, TRANZPUTER); + } + else if(stage == 1) + { + // Release the bus to start loaded ROM. + writeZ80IO(IO_TZ_CPLDCMD, CPLD_RELEASE_HOST_BUS, MAINBOARD); + } + else if(stage == 8) + { + // Make any final machine specific configurations prior to setup end. + switch(z80Control.hostType) + { + case HW_MZ2000: + // writeZ80IO(IO_TZ_PPICTL, 0x06, MAINBOARD); + break; + + default: + break; + } + + // Print out host information. + setHost(1); + } + // No SD found, so run with original ROM. + else if(stage == 9) + { + // Set to original mode so the onboard ROM can be executed. + // + writeZ80IO(IO_TZ_CTRLLATCH, TZMM_ORIG, MAINBOARD); + + // Release the bus to start the code in the onboard ROM. + writeZ80IO(IO_TZ_CPLDCMD, CPLD_RELEASE_HOST_BUS, MAINBOARD); + } + + // Release Z80 if it is being held. + if(z80Control.holdZ80 != 0) + { + z80Control.holdZ80 = 0; + releaseZ80(); + } + + return; } // 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. @@ -5381,4 +5909,4 @@ void displaySignals(void) #ifdef __cplusplus } - #endif +#endif diff --git a/include/emumz.h b/include/emumz.h index 2ba7b72..30a904e 100755 --- a/include/emumz.h +++ b/include/emumz.h @@ -36,7 +36,7 @@ #ifdef __cplusplus extern "C" { #endif - + // Macros. // #define NUMELEM(a) (sizeof(a)/sizeof(a[0])) @@ -50,33 +50,31 @@ #define MAX_MACHINE_TITLE_LEN 15 // Maximum length of the side bar machine name title. #define MAX_DIRENTRY 512 // Maximum number of read and stored directory entries from the SD card per directory. #define MAX_DIR_DEPTH 4 // Maximum depth of sub-directories to enter. -#define MAX_FILENAME_LEN 256 // Maximum supported length of a filename. +#define MAX_FILENAME_LEN 64 // Maximum supported length of a filename. #define MAX_FILTER_LEN 8 // Maximum length of a file filter. #define TOPLEVEL_DIR "0:\\" // Top level directory for file list and select. #define MAX_TAPE_QUEUE 5 // Maximum number of files which can be queued in the virtual tape drive. #define CONFIG_FILENAME "0:\\EMZ.CFG" // Configuration file for persisting the configuration. #define MAX_EMU_REGISTERS 16 // Number of programmable registers in the emulator. +#define MAX_KEY_INS_BUFFER 64 // Maximum number of key sequences in a FIFO which can be inserted into the emulation keyboard. +#define MAX_INJEDIT_ROWS 4 // Maximum number of rows in the key injection editor. +#define MAX_INJEDIT_COLS 8 // Maximum number of columns in the key injection editor. + +// Keyboard key-injection constants. +#define KEY_INJEDIT_NIBBLES 8 // Number of nibbles in an injected key word. +#define KEY_INJEDIT_ROWS (MAX_KEY_INS_BUFFER/MAX_INJEDIT_COLS) +#define KEY_INJEDIT_NIBBLES_PER_ROW (MAX_INJEDIT_COLS*KEY_INJEDIT_NIBBLES) // Maximum number of machines currently supported by the emulation. // -#define MAX_MZMACHINES 8 - -// Numeric index of each machine. -// -#define MZ80K_IDX 0 // 000 -#define MZ80C_IDX 1 // 001 -#define MZ1200_IDX 2 // 010 -#define MZ80A_IDX 3 // 011 -#define MZ700_IDX 4 // 100 -#define MZ800_IDX 5 // 101 -#define MZ80B_IDX 6 // 110 -#define MZ2000_IDX 7 // 111 +#define MAX_MZMACHINES 11 // Keyboard control bits. // #define KEY_BREAK_BIT 0x80 // Break key is being pressed when set to 1 #define KEY_CTRL_BIT 0x40 // CTRL key is being pressed when set to 1 #define KEY_SHIFT_BIT 0x20 // SHIFT key is being pressed when set to 1 +#define KEY_NOCTRL_BIT 0x00 // No key control overrides. #define KEY_DOWN_BIT 0x02 // DATA key has been pressed when set to 1 #define KEY_UP_BIT 0x01 // DATA key has been released when set to 1 @@ -84,12 +82,21 @@ // #define MZ_EMU_ROM_ADDR 0x100000 // Sharp MZ Series Emulation ROM address. #define MZ_EMU_RAM_ADDR 0x120000 // Sharp MZ Series Emulation RAM address. +#define MZ_EMU_CGROM_ADDR 0x220000 // VideoController CGROM address. +#define MZ_EMU_USER_ROM_ADDR 0x12E800 // Sharp MZ Series Emulation USER ROM address. +#define MZ_EMU_FDC_ROM_ADDR 0x12F000 // Sharp MZ Series Emulation FDC ROM address. #define MZ_EMU_REG_BASE_ADDR 0x300000 // Base address, in the FPGA address domain, of the emulator registers. #define MZ_EMU_REG_INTR_ADDR 0x300020 // Base address of the interrupt generator. -#define MZ_EMU_REG_KEYB_ADDR 0x300200 // Base address of the keyboard register and map table. +#define MZ_EMU_REG_SND_ADDR 0x300200 // Base address of the sound generator. +#define MZ_EMU_REG_KEYB_ADDR 0x301000 // Base address of the keyboard register and map table. #define MZ_EMU_CMT_HDR_ADDR 0x340000 // Header RAM - 128 bytes 0x340000:0x34FFFF #define MZ_EMU_CMT_DATA_ADDR 0x350000 // Data RAM - 64KBytes. 0x350000:0x35FFFF #define MZ_EMU_CMT_MAP_ADDR 0x360000 // ASCII MAP RAM - 512 bytes 0x360000:0x36FFFF +#define MZ_EMU_CMT_REG_ADDR 0x360200 // CMT Registers. + +// Registers within the Machine Control module. Some of the data provided within these registers +// is also available directly from the hardware modules. +#define MZ_EMU_MAX_REGISTERS 16 // Maximum number of registers on the emulator. #define MZ_EMU_REG_MODEL 0 // Machine MODEL configuration register. #define MZ_EMU_REG_DISPLAY 1 // DISPLAY configuration register 1. #define MZ_EMU_REG_DISPLAY2 2 // DISPLAY configuration register 2. @@ -101,8 +108,11 @@ #define MZ_EMU_REG_CMT3 8 // CMT (tape drive) status register. #define MZ_EMU_REG_USERROM 9 // USER ROM selection register (not currently used.) #define MZ_EMU_REG_FDCROM 10 // Floppy Disk ROM selection register. +#define MZ_EMU_REG_SWITCHES 11 // Hardware switches, MZ800 = 3:0 #define MZ_EMU_REG_SETUP 13 // Emulator current setup (configuration) register. -#define MZ_EMU_MAX_REGISTERS 16 // Maximum number of registers on the emulator. +#define MZ_EMU_REG_CTRL 15 // Emulator control register. + +// Physical address of the registers within the Machine Control module. #define MZ_EMU_ADDR_REG_MODEL MZ_EMU_REG_BASE_ADDR + 0 // Address of the machine MODEL configuration register. #define MZ_EMU_ADDR_REG_DISPLAY MZ_EMU_REG_BASE_ADDR + 1 // Address of the DISPLAY configuration register 1. #define MZ_EMU_ADDR_REG_DISPLAY2 MZ_EMU_REG_BASE_ADDR + 2 // Address of the DISPLAY configuration register 2. @@ -115,20 +125,44 @@ #define MZ_EMU_ADDR_REG_USERROM MZ_EMU_REG_BASE_ADDR + 9 // Address of the USER ROM selection register (not currently used.). #define MZ_EMU_ADDR_REG_FDCROM MZ_EMU_REG_BASE_ADDR + 10 // Address of the Floppy Disk ROM selection register. #define MZ_EMU_ADDR_REG_SETUP MZ_EMU_REG_BASE_ADDR + 13 // Address of the emulator current setup (configuration) register. -#define MZ_EMU_INTR_ISR 0x00 // Interupt service reason register, define what caused the interupt. +#define MZ_EMU_ADDR_REG_CTRL MZ_EMU_REG_BASE_ADDR + 15 // Address of the Control reigster. + +// Interrupt generator control and status registers. #define MZ_EMU_INTR_MAX_REGISTERS 1 // Maximum number of registers in the interrupt generator. -#define MZ_EMU_KEYB_MAX_REGISTERS 37 // Maximum number of registers in the keyboard interface. -#define MZ_EMU_KEYB_KEY_MATRIX 0x00 // Key matrix array current scan. -#define MZ_EMU_KEYB_KEY_MATRIX_LAST 0x10 // Key matrix array previous scan. -#define MZ_EMU_KEYB_CTRL_REG 0x20 // Keyboard control register. -#define MZ_EMU_KEYB_KEYD_REG 0x21 // Keyboard key data register. -#define MZ_EMU_KEYB_KEYC_REG 0x22 // Keyboard control data register. -#define MZ_EMU_KEYB_KEY_POS_REG 0x23 // Keyboard mapped character mapping position. -#define MZ_EMU_KEYB_KEY_POS_LAST_REG 0x24 // Keyboard mapped character previous mapping position. -#define MZ_EMU_KEYB_MAP_ADDR 0x100 // Address offset to the scan code:key map array. +#define MZ_EMU_INTR_REG_ISR 0x00 // Interupt service reason register, define what caused the interupt. +#define MZ_EMU_INTR_SRC_KEYB 0x01 // Interrupt source = Keyboard. +#define MZ_EMU_INTR_SRC_CMT 0x02 // Interrupt source = CMT. + +// Cassette module control and status registers. +#define MZ_EMU_CMT_MAX_REGISTERS 0x04 // Maximum number of registers in the cmt interface. +#define MZ_EMU_CMT_STATUS_REG 0x00 // CMT status register. +#define MZ_EMU_CMT_STATUS2_REG 0x01 // CMT2 status register (APSS). +#define MZ_EMU_CMT_STATUS_INTR_REG 0x02 // CMT interrupt status trigger. +#define MZ_EMU_CMT_STATUS2_INTR_REG 0x03 // CMT2 interrupt status trigger. + +// Keyboard control and status registers, mapping tables and cache. +#define MZ_EMU_KEYB_MAX_REGISTERS 8 // Maximum number of status and control registers in the keyboard interface, excludes debug registers. +#define MZ_EMU_KEYB_CTRL_REG 0x00 // Keyboard control register. +#define MZ_EMU_KEYB_FIFO_REG 0x01 // Key insertion FIFO control register. +#define MZ_EMU_KEYB_FIFO_WR_ADDR 0x02 // FIFO write pointer value. +#define MZ_EMU_KEYB_FIFO_RD_ADDR 0x03 // FIFO read pointer value. +#define MZ_EMU_KEYB_KEYC_REG 0x04 // Keyboard control data register. +#define MZ_EMU_KEYB_KEYD_REG 0x05 // Keyboard key data register. +#define MZ_EMU_KEYB_KEY_POS_REG 0x06 // Keyboard mapped character mapping position. +#define MZ_EMU_KEYB_KEY_POS_LAST_REG 0x07 // Keyboard mapped character previous mapping position. +#define MZ_EMU_KEYB_KEY_MATRIX 0x10 // Key matrix array current scan. +#define MZ_EMU_KEYB_KEY_MATRIX_LAST 0x20 // Key matrix array previous scan. +#define MZ_EMU_KEYB_FIFO_SIZE 0x40 // Size of the key insertion FIFO. +#define MZ_EMU_KEYB_FIFO_ADDR 0x0100 // Key insertion FIFO. +#define MZ_EMU_KEYB_MAP_ADDR 0x0800 // Address of the emulation keyboard mapping table. +#define MZ_EMU_KEYB_IOP_MAP_ADDR 0x0900 // Address offset to the scan code:key map array for the I/O processor keys. #define MZ_EMU_KEYB_DISABLE_EMU 0x01 // Disable keyboard scan codes being sent to the emulation. #define MZ_EMU_KEYB_ENABLE_INTR 0x02 // Enable interrupt on every key press. +#define MZ_EMU_KEYB_SEND_KEY_EVENTS 0x04 // Send keyboard up and down interrupt events. +#define MZ_EMU_KEYB_FIFO_FULL 0x01 // Bit in FIFO Status register to indicate the FIFO is full. +#define MZ_EMU_KEYB_FIFO_WORD_RST 0x80 // Reset keyboard key insertion word pointer, 4 bytes are needed per word and this resets to the 1st byte in the word. +// Display control values. #define MZ_EMU_DISPLAY_MONO 0x00 // Monochrome display. #define MZ_EMU_DISPLAY_MONO80 0x01 // Monochrome 80 column display. #define MZ_EMU_DISPLAY_COLOUR 0x02 // Colour display. @@ -146,12 +180,12 @@ #define MZ_EMU_B_CPU_SPEED_16M 0x02 // CPU Freq for the MZ80B group machines. #define MZ_EMU_B_CPU_SPEED_32M 0x03 // CPU Freq for the MZ80B group machines. #define MZ_EMU_B_CPU_SPEED_64M 0x04 // CPU Freq for the MZ80B group machines. -#define MZ_EMU_C_CPU_SPEED_2M 0x00 // CPU Freq for the MZ80C group machines. -#define MZ_EMU_C_CPU_SPEED_4M 0x01 // CPU Freq for the MZ80C group machines. -#define MZ_EMU_C_CPU_SPEED_8M 0x02 // CPU Freq for the MZ80C group machines. -#define MZ_EMU_C_CPU_SPEED_16M 0x03 // CPU Freq for the MZ80C group machines. -#define MZ_EMU_C_CPU_SPEED_32M 0x04 // CPU Freq for the MZ80C group machines. -#define MZ_EMU_C_CPU_SPEED_64M 0x05 // CPU Freq for the MZ80C group machines. +#define MZ_EMU_C_CPU_SPEED_2M 0x00 // CPU Freq for the MZ80K group machines. +#define MZ_EMU_C_CPU_SPEED_4M 0x01 // CPU Freq for the MZ80K group machines. +#define MZ_EMU_C_CPU_SPEED_8M 0x02 // CPU Freq for the MZ80K group machines. +#define MZ_EMU_C_CPU_SPEED_16M 0x03 // CPU Freq for the MZ80K group machines. +#define MZ_EMU_C_CPU_SPEED_32M 0x04 // CPU Freq for the MZ80K group machines. +#define MZ_EMU_C_CPU_SPEED_64M 0x05 // CPU Freq for the MZ80K group machines. #define MZ_EMU_78_CPU_SPEED_3M5 0x00 // CPU Freq for the MZ80/700/800 group machines. #define MZ_EMU_78_CPU_SPEED_7M 0x01 // CPU Freq for the MZ80/700/800 group machines. #define MZ_EMU_78_CPU_SPEED_14M 0x02 // CPU Freq for the MZ80/700/800 group machines. @@ -215,11 +249,14 @@ enum MENUMODE { enum MENUACTIVE { MENU_DISABLED = 0x00, // Menu is disabled and not being displayed. MENU_MAIN = 0x01, // Main menu is active. - MENU_STORAGE = 0x02, // Storage menu is active. - MENU_MACHINE = 0x03, // Machine menu is active. - MENU_DISPLAY = 0x04, // Display menu is active. - MENU_SYSTEM = 0x05, // System menu is active. - MENU_ROMMANAGEMENT = 0x06 // Rom Management menu is active. + MENU_TAPE_STORAGE = 0x02, // Tape Storage menu is active. + MENU_FLOPPY_STORAGE = 0x03, // Floppy Storage menu is active. + MENU_MACHINE = 0x04, // Machine menu is active. + MENU_DISPLAY = 0x05, // Display menu is active. + MENU_AUDIO = 0x06, // Audio menu is active. + MENU_SYSTEM = 0x07, // System menu is active. + MENU_ROMMANAGEMENT = 0x08, // Rom Management menu is active. + MENU_AUTOSTART = 0x09 // Autostart Application menu is active. }; enum MENUCALLBACK { @@ -230,6 +267,7 @@ enum MENUCALLBACK { enum DIALOGTYPE { DIALOG_MENU = 0x00, // OSD is displaying the Menu system. DIALOG_FILELIST = 0x01, // OSD is displaying a file list selection screen. + DIALOG_KEYENTRY = 0x02, // OSD is updating the key injection values. }; enum ACTIONMODE { @@ -245,17 +283,45 @@ typedef void (*t_menuCallback)(uint8_t); // Declare the choice callback as a type. This callback is used when rendering the menu and the choice value needs to be realised from the config settings. typedef const char * (*t_choiceCallback)(void); +// Declare the data view callback as a type. This callback is used when rendering the menu and non menu data requires rendering as read only. +typedef void (*t_viewCallback)(void); +// Ditto but for in function rendering. +typedef void (*t_renderCallback)(uint16_t); + // Declare the return from dialog callback which is required to process data from a non-menu dialog such as a file list. typedef void (*t_dialogCallback)(char *param); + +// Structure to map an ascii key into a row and column scan code. +typedef struct { + uint8_t scanRow; // Emulation scan row. + uint8_t scanCol; // Emulation scan column. + uint8_t scanCtrl; // Emulation control key overrides for the row/col combination. +} t_scanCode; + +// Structure to map an ascii key into a row and column scan code. +typedef struct { + uint8_t key; // Ascii key for lookup. + t_scanCode code[MAX_MZMACHINES]; // Scan code per machine. +} t_scanMap; + +// Type translation union. +typedef union { + uint32_t i; + uint8_t b[sizeof (float)]; + float f; +} t_numCnv; + // Structure to contain a menu item and its properties. // typedef struct { char text[MENU_ROW_WIDTH]; // Buffers to store menu item text. + char hotKey; // Shortcut key to activate selection, NULL = disabled. enum MENUTYPES type; // Type of menu option, sub-menu select or choice. enum MENUSTATE state; // State of the menu item, ie. hidden, greyed, active. t_menuCallback menuCallback; // Function to call when a line is activated, by CR or toggle. t_choiceCallback choiceCallback; // Function to call when a choice value is required. + t_viewCallback viewCallback; // Function to call when non-menu data requires rendering within the menu. enum MENUCALLBACK cbAction; // Action to take after callback completed. } t_menuItem; @@ -317,20 +383,30 @@ typedef struct uint32_t loadSize; } romData_t; +// Structure to store the cold boot application details which gets loaded on machine instantiation. +// +typedef struct +{ + char appFileName[MAX_FILENAME_LEN]; + uint8_t appEnabled; + t_numCnv preKeyInsertion[MAX_KEY_INS_BUFFER]; + t_numCnv postKeyInsertion[MAX_KEY_INS_BUFFER]; +} appData_t; + // MZ Series Tape header structure - 128 bytes. // typedef struct { - unsigned char dataType; // 01 = machine code program. - // 02 MZ-80 Basic program. - // 03 MZ-80 data file. - // 04 MZ-700 data file. - // 05 MZ-700 Basic program. - char fileName[17]; // File name. - unsigned short fileSize; // Size of data partition. - unsigned short loadAddress; // Load address of the program/data. - unsigned short execAddress; // Execution address of program. - unsigned char comment[104]; // Free text or code area. + unsigned char dataType; // 01 = machine code program. + // 02 MZ-80 Basic program. + // 03 MZ-80 data file. + // 04 MZ-700 data file. + // 05 MZ-700 Basic program. + char fileName[17]; // File name. + unsigned short fileSize; // Size of data partition. + unsigned short loadAddress; // Load address of the program/data. + unsigned short execAddress; // Execution address of program. + unsigned char comment[104]; // Free text or code area. } t_tapeHeader; // Structures to store the tape file queue. @@ -343,13 +419,55 @@ typedef struct uint16_t elements; } t_tapeQueue; +// Structure to store the parameters for key insertion editting. +// +typedef struct +{ + // Pointer into the key buffer. This pointer points to the start of the buffer. + t_numCnv *bufptr; + + // Pointer to the key being editted. This is nibble level, so 2 nibbles per byte. + uint16_t editptr; + + // Cursor attribute for cursor highlighting. + uint16_t cursorAttr; + + // Colour of the dislayed character, + enum COLOUR fg; + enum COLOUR bg; + + // Location in the framebuffer where the character buffer commences. + uint8_t startRow; + uint8_t startCol; + + // Screen offsets to adjust for mixed fonts. + uint8_t offsetRow; + uint8_t offsetCol; + + // Flash speed of the cursor in ms. + unsigned long cursorFlashRate; + + // Font used for the underlying character. + enum FONTS font; + + // Current view portal. Key buffer greater than 12x4 needs to be scrolled to access the entire buffer. + uint16_t curView; + + // Function to render the buffer for updates etc. + t_renderCallback render; +} t_keyInjectionEdit; + // Structure to maintain individual emulation configuration parameters. typedef struct { - uint8_t cpuSpeed; - uint8_t audioSource; - uint8_t audioVolume; - uint8_t audioMute; + uint8_t cpuSpeed; // Select the CPU speed, original or multiples. + uint8_t memSize; // Select the memory size to match original machine. + uint8_t audioSource; // Select the audio source. Not used on the MZ-700 + uint8_t audioHardware; // Select the audio hardware. Either driver the underlying host hardware directly or enable the FPGA sound hardware. + uint8_t audioVolume; // Set audio output volume. + uint8_t audioMute; // Mute audio output. + uint8_t audioMix; // Channel mix, blend left/right channel sound. uint8_t displayType; + uint8_t displayOption; uint8_t displayOutput; uint8_t vramMode; uint8_t gramMode; @@ -364,6 +482,10 @@ typedef struct { uint8_t tapeButtons; uint8_t fastTapeLoad; uint8_t cmtAsciiMapping; // Enable Sharp<->ASCII name conversion during Record/Play operations. + uint8_t mz800Mode; // MZ-800 Mode setting switch. + uint8_t mz800Printer; // MZ-800 Printer setting switch. + uint8_t mz800TapeIn; // MZ-800 Tape Input setting switch. + uint8_t autoStart; // Application autostart on machine instantiation. char tapeSavePath[MAX_FILENAME_LEN]; // Path where saved files should be stored. romData_t romMonitor40; // Details of 40x25 rom monitor image to upload. romData_t romMonitor80; // Details of 80x25 rom monitor image to upload. @@ -371,13 +493,15 @@ typedef struct { romData_t romKeyMap; // Details of rom Key mapping images to upload. romData_t romUser; // Details of User ROM images to upload. romData_t romFDC; // Details of FDC ROM images to upload. + appData_t loadApp; // Details of an application to load on machine instantiation. } t_emuMachineConfig; // Structure to maintain the emulator configuration which is intended to mirror the physical hardware configuration. typedef struct { - uint8_t machineModel; // Current emulated model. + enum MACHINE_TYPES machineModel; // Current emulated model. + enum MACHINE_GROUP machineGroup; // Group to which the current emulated model belongs. uint8_t machineChanged; // Flag to indicate the base machine has changed. - t_emuMachineConfig *resetParams; // Copy of the default parameters. + // t_emuMachineConfig *resetParams; // Copy of the default parameters. t_emuMachineConfig params[MAX_MZMACHINES]; // Working set of parameters. uint8_t emuRegisters[MZ_EMU_MAX_REGISTERS]; // Mirror of the emulator register contents for local manipulation prior to sync. } t_emuConfig; @@ -405,8 +529,11 @@ typedef struct { t_activeDir activeDir; // Active directory tree. uint8_t debug; // Debug the emuMZ module by outputting log information if set. t_menu menu; // Menu control and data. + enum MACHINE_HW_TYPES hostMachine; // Host hardware emulation being hosted on. t_fileList fileList; // List of files for perusal and selection during OSD interaction. + t_tapeHeader tapeHeader; // Last processed tape details. t_tapeQueue tapeQueue; // Linked list of files which together form a virtual tape. + t_keyInjectionEdit keyInjEdit; // Control structure for event callback editting of the key injection array. } t_emuControl; // Application execution constants. @@ -414,57 +541,83 @@ typedef struct { // Lookup tables for menu entries. // -const char *MZMACHINES[MAX_MZMACHINES] = { "MZ-80K", "MZ-80C", "MZ1200", "MZ-80A", "MZ-700", "MZ-800", "MZ-80B", "MZ2000" }; -const char *SHARPMZ_FAST_TAPE[] = { "Off", "2x", "4x", "8x", "16x", "32x", "Off", "Off", - "Off", "2x", "4x", "8x", "16x", "32x", "Off", "Off", - "Off", "2x", "4x", "8x", "16x", "Off", "Off", "Off" +const uint8_t MZ_ACTIVE[MAX_MZMACHINES] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }; +const char *MZMACHINES[MAX_MZMACHINES] = { "MZ-80K", "MZ-80C", "MZ1200", "MZ-80A", "MZ-700", "MZ-800", "MZ1500", "MZ-80B", "MZ2000", "MZ2200", "MZ2500" }; +const char *SHARPMZ_FAST_TAPE[][6] = { { "Off", "2x", "4x", "8x", "16x", "32x" }, // Group MZ80K + { "Off", "2x", "4x", "8x", "16x", "32x" }, // Group MZ700 + { "Off", "2x", "4x", "8x", "16x", NULL } // Group MZ80B }; -const char *SHARPMZ_CPU_SPEED[] = { "2MHz", "4MHz", "8MHz", "16MHz", "32MHz", "64MHz", "2MHz", "2MHz", - "3.5MHz", "7MHz", "14MHz", "28MHz", "56MHz", "3.5MHz", "3.5MHz", "3.5MHz", - "4MHz", "8MHz", "16MHz", "32MHz", "64MHz", "4MHz", "4MHz", "4MHz" +const char *SHARPMZ_CPU_SPEED[][7] = { { "2MHz", "4MHz", "8MHz", "16MHz", "32MHz", "64MHz", NULL }, // Group MZ80K + { "3.5MHz", "7MHz", "14MHz", "28MHz", "56MHz", NULL, NULL }, // Group MZ700 + { "4MHz", "8MHz", "16MHz", "32MHz", "64MHz", NULL, NULL } // Group MZ80B }; -const char *SHARPMZ_TAPE_MODE[] = { "FPGA", "MZ-700" }; +const char *SHARPMZ_MEM_SIZE[][3] = { { "32K", "48K", NULL }, // 80K + { "32K", "48K", NULL }, // 80C + { "32K", "48K", NULL }, // 1200 + { "32K", "48K", NULL }, // 80A + { NULL, "64K", NULL }, // 700 + { NULL, "64K", NULL }, // 800 + { NULL, "64K", NULL }, // 1500 + { "32K", "64K", NULL }, // 80B + { NULL, "64K", NULL }, // 2000 + { NULL, "64K", NULL }, // 2200 + { "64K", "128K", "256K" } // 2500 + }; +const char *SHARPMZ_TAPE_MODE[] = { "FPGA", "MZ CMT" }; const char *SHARPMZ_TAPE_BUTTONS[] = { "Off", "Play", "Record", "Auto" }; const char *SHARPMZ_ASCII_MAPPING[] = { "Off", "Record", "Play", "Both" }; const char *SHARPMZ_AUDIO_SOURCE[] = { "Sound", "Tape" }; -const char *SHARPMZ_AUDIO_VOLUME[] = { "Max", "14", "13", "12", "11", "10", "9", "8", "7", "6", "5", "4", "3", "2", "1", "Min" }; +const char *SHARPMZ_AUDIO_HARDWARE[] = { "Host", "FPGA" }; +const char *SHARPMZ_AUDIO_VOLUME[] = { "Off", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "Max" }; const char *SHARPMZ_AUDIO_MUTE[] = { "Off", "Mute" }; +const char *SHARPMZ_AUDIO_MIX [] = { "Off", "25%", "50%", "Mono" }; const char *SHARPMZ_USERROM_ENABLED[] = { "Disabled", "Enabled" }; const char *SHARPMZ_FDCROM_ENABLED[] = { "Disabled", "Enabled" }; const char *SHARPMZ_ROM_ENABLED[] = { "Disabled", "Enabled" }; -const char *SHARPMZ_DISPLAY_TYPE[] = { "Mono 40x25", "Mono 80x25 ", "Colour 40x25", "Colour 80x25" }; -const char *SHARPMZ_DISPLAY_OUTPUT[] = { "Original", "640x480@60Hz", "1024x768@60Hz", "800x600@60Hz" }; +const char *SHARPMZ_DISPLAY_TYPE[][4] = { + { "Mono 40x25", "Mono 80x25 ", NULL, NULL }, // 80K + { "Mono 40x25", "Mono 80x25 ", NULL, NULL }, // 80C + { "Mono 40x25", "Mono 80x25 ", NULL, NULL }, // 1200 + { "Mono 40x25", "Mono 80x25 ", "Colour 40x25", "Colour 80x25" }, // 80A + { NULL, NULL, "Colour 40x25", "Colour 80x25" }, // 700 + { NULL, NULL, "Colour", NULL }, // 800 + { NULL, NULL, "Colour 40x25", "Colour 80x25" }, // 1500 + { NULL, NULL, NULL, NULL }, // 80B + { NULL, NULL, NULL, NULL }, // 2000 + { NULL, NULL, NULL, NULL }, // 2200 + { NULL, NULL, NULL, NULL } // 2500 + }; +const char *SHARPMZ_DISPLAY_OPTION[][5] = { { "None", NULL, NULL, NULL, NULL }, // 80K + { "None", NULL, NULL, NULL, NULL }, // 80C + { "None", NULL, NULL, NULL, NULL }, // 1200 + { "None", "PCG", NULL, NULL, NULL }, // 80A + { "None", "PCG", NULL, NULL, NULL }, // 700 + { "None", "MZ-1R25", NULL, NULL, NULL }, // 800 + { NULL, "PCG", NULL, NULL, NULL }, // 1500 + { "None", "GRAMI", "GRAMI/II", NULL, NULL }, // 80B + { "None", "GRAMB", "GRAMB/R", " GRAMB/G", "GRAMB/R/G" }, // 2000 + { NULL, NULL, NULL, NULL, "GRAMB/R/G" }, // 2200 + { "None", NULL, NULL, NULL, NULL } // 2500 + }; +const char *SHARPMZ_DISPLAY_OUTPUT[] = { "Original", "Original 50Hz", "640x480@60Hz", "800x600@60Hz" }; const char *SHARPMZ_ASPECT_RATIO[] = { "4:3", "16:9" }; const char *SHARPMZ_SCANDOUBLER_FX[] = { "None", "HQ2x", "CRT 25%", "CRT 50%", "CRT 75%" }; const char *SHARPMZ_VRAMWAIT_MODE[] = { "Off", "On" }; const char *SHARPMZ_VRAMDISABLE_MODE[] = { "Enabled", "Disabled" }; const char *SHARPMZ_GRAMDISABLE_MODE[] = { "Enabled", "Disabled" }; -const char *SHARPMZ_GRAM_BASEADDR[] = { "0x00", "0x08", "0x10", "0x18", "0x20", "0x28", "0x30", "0x38", "0x40", "0x48", "0x50", "0x58", "0x60", "0x68", "0x70", "0x78", - "0x80", "0x88", "0x90", "0x98", "0xA0", "0xA8", "0xB0", "0xB8", "0xC0", "0xC8", "0xD0", "0xD8", "0xE0", "0xE8", "0xF0", "0xF8" }; -const char *SHARPMZ_PCG_MODE[] = { "Off", "ROM", "RAM" }; +//const char *SHARPMZ_GRAM_BASEADDR[] = { "0x00", "0x08", "0x10", "0x18", "0x20", "0x28", "0x30", "0x38", "0x40", "0x48", "0x50", "0x58", "0x70", "0x78", +// "0x80", "0x88", "0x90", "0x98" }; +const char *SHARPMZ_PCG_MODE[] = { "ROM", "RAM" }; const char *SHARPMZ_TAPE_AUTO_SAVE[] = { "Disabled", "Enabled" }; -const char *SHARPMZ_DEBUG_ENABLE[] = { "Off", "On" }; -const char *SHARPMZ_DEBUG_LEDS[] = { "Off", "On" }; -const char *SHARPMZ_DEBUG_LEDS_BANK[] = { "T80", "I/O", "IOCTL", "Config", "MZ80C I", "MZ80C II", "MZ80B I", "MZ80B II" }; -const char *SHARPMZ_DEBUG_LEDS_SUBBANK[] = { "Auto", "A7-0", "A15-8", "DI", "Signals", "", "", "", - "Auto", "Video", "PS2Key", "Signals", "CMT 1", "CMT 2", "CMT 3", "CMT 4", - "Auto", "A23-16", "A15-8", "A7-0", "Signals", "", "", "", - "Auto", "Config 1", "Config 2", "Config 3", "Config 4", "Config 5", "", "", - "Auto", "CS 1", "CS 2", "CS 3", "INT/RE", "Clk", "", "", - "Auto", "", "", "", "", "", "", "", - "Auto", "CS 1", "CS 2", "MEM EN", "INT", "KEYB", "PPIA", "PPIB", - "Auto", "PPIC", "", "", "", "", "", "", - }; -const char *SHARPMZ_DEBUG_CPUFREQ[] = { "Normal", "1MHz", "100KHz", "10KHz", "5KHz", "1KHz", "500Hz", "100Hz", "50Hz", "10Hz", "5Hz", "2Hz", "1Hz", "0.5Hz", "0.2Hz", "0.1Hz" }; -const char *SHARPMZ_DEBUG_LEDS_SMPFREQ[] = { "CPU", "1MHz", "100KHz", "10KHz", "5KHz", "1KHz", "500Hz", "100Hz", "50Hz", "10Hz", "5Hz", "2Hz", "1Hz", "0.5Hz", "0.2Hz", "0.1Hz" }; +const char *SHARPMZ_AUTOSTART[] = { "Disabled", "Enabled" }; const char *SHARPMZ_MEMORY_BANK[] = { "SysROM", "SysRAM", "KeyMap", "VRAM", "CMTHDR", "CMTDATA", "CGROM", "CGRAM", "All" }; -const char *SHARPMZ_MEMORY_BANK_FILE[] = { "sysrom.dump", "sysram.dump", "keymap.dump", "vram.dump", "cmt_hdr.dump", "cmt_data.dump", "cgrom.dump", "cgram.dump", "all_memory.dump" }; -const char *SHARPMZ_TAPE_TYPE[] = { "N/A", "M/code", "MZ80 Basic", "MZ80 Data", "MZ700 Data", "MZ700 Basic", "N/A" }; -const char *SHARPMZ_HELPTEXT[] = { "Welcome to the Sharp MZ Series! Use the cursor keys to navigate the menus. Use space bar or enter to select an item. Press Esc or F12 to exit the menus. ", - 0 - }; +//const char *SHARPMZ_MEMORY_BANK_FILE[] = { "sysrom.dump", "sysram.dump", "keymap.dump", "vram.dump", "cmt_hdr.dump", "cmt_data.dump", "cgrom.dump", "cgram.dump", "all_memory.dump" }; +const char *SHARPMZ_TAPE_TYPE[] = { "N/A", "M/code", "MZ80 Basic", "MZ80 Data", "MZ700 Data", "MZ700 Basic", "Unknown" }; const char *SHARPMZ_FILE_FILTERS[] = { "*.MZF", "*.MTI", "*.MZT", "*.*" }; +const char *SHARPMZ_MZ800_MODE[] = { "MZ-800", "MZ-700" }; +const char *SHARPMZ_MZ800_PRINTER[] = { "MZ", "Centronics" }; +const char *SHARPMZ_MZ800_TAPEIN[] = { "External", "Internal" }; // Prototypes. @@ -473,17 +626,26 @@ void EMZReleaseMenuMemory(void); void EMZReleaseDirMemory(void); void EMZSetupMenu(char *, char *, enum FONTS); void EMZSetupDirList(char *, char *, enum FONTS); -void EMZAddToMenu(uint8_t, uint8_t, char *, enum MENUTYPES, enum MENUSTATE, t_menuCallback, enum MENUCALLBACK, t_choiceCallback); +void EMZAddToMenu(uint8_t, uint8_t, char *, char, enum MENUTYPES, enum MENUSTATE, t_menuCallback, enum MENUCALLBACK, t_choiceCallback, t_viewCallback); int16_t EMZDrawMenu(int16_t, uint8_t, enum MENUMODE); void EMZRefreshMenu(void); void EMZRefreshFileList(void); void EMZMainMenu(void); void EMZTapeStorageMenu(enum ACTIONMODE); +void EMZFloppyStorageMenu(enum ACTIONMODE); void EMZMachineMenu(enum ACTIONMODE); void EMZDisplayMenu(enum ACTIONMODE); +void EMZAudioMenu(enum ACTIONMODE); void EMZSystemMenu(enum ACTIONMODE); void EMZAbout(enum ACTIONMODE); void EMZRomManagementMenu(enum ACTIONMODE); +void EMZAutoStartApplicationMenu(enum ACTIONMODE); +void EMZRenderPreKeyViewTop(void); +void EMZRenderPreKeyView(uint16_t); +void EMZRenderPostKeyViewTop(void); +void EMZRenderPostKeyView(uint16_t); +void EMZPreKeyEntry(void); +void EMZPostKeyEntry(void); void EMZSwitchToMenu(int8_t); void EMZProcessMenuKey(uint8_t, uint8_t); void EMZservice(uint8_t); @@ -500,9 +662,9 @@ uint16_t EMZGetFileListColumnWidth(void); int16_t EMZDrawFileList(int16_t, uint8_t); uint8_t EMZReadDirectory(const char *, const char *); void EMZGetFile(void); -void EMZReset(unsigned long, unsigned long); -uint8_t EMZInit(uint8_t); +void EMZReset(void); +void EMZPrintTapeDetails(short); void EMZLoadDirectToRAM(enum ACTIONMODE); void EMZLoadDirectToRAMSet(char *); void EMZQueueTape(enum ACTIONMODE); @@ -521,22 +683,29 @@ void EMZUserROM(enum ACTIONMODE); void EMZUserROMSet(char *); void EMZFloppyDiskROM(enum ACTIONMODE); void EMZFloppyDiskROMSet(char *); +void EMZLoadApplication(enum ACTIONMODE); +void EMZLoadApplicationSet(char *); +void EMZChangeLoadApplication(enum ACTIONMODE); void EMZTapeQueuePushFile(char *); char *EMZTapeQueuePopFile(void); char *EMZTapeQueueAPSSSearch(char); char *EMZNextTapeQueueFilename(char); -void EMZClearTapeQueue(void); +uint16_t EMZClearTapeQueue(void); void EMZChangeCMTMode(enum ACTIONMODE); +short EMZReadTapeDetails(const char *); short EMZLoadTapeToRAM(const char *, unsigned char); short EMZSaveTapeFromCMT(const char *); // Menu choice helper functions, increment to next choice. void EMZNextMachineModel(enum ACTIONMODE); void EMZNextCPUSpeed(enum ACTIONMODE); +void EMZNextMemSize(enum ACTIONMODE mode); void EMZNextAudioSource(enum ACTIONMODE); +void EMZNextAudioHardware(enum ACTIONMODE); void EMZNextAudioVolume(enum ACTIONMODE); void EMZNextAudioMute(enum ACTIONMODE); +void EMZNextAudioMix(enum ACTIONMODE); // Getter/Setter methods! void EMZSetMenuRowPadding(uint8_t); @@ -548,13 +717,16 @@ uint16_t EMZGetMenuColumnWidth(void); const char *EMZGetMachineModelChoice(void); char *EMZGetMachineTitle(void); short EMZGetMachineGroup(void); -const char *EMZGetMachineModelChoice(void); const char *EMZGetCPUSpeedChoice(void); +const char *EMZGetMemSizeChoice(void); const char *EMZGetAudioSourceChoice(void); +const char *EMZGetAudioHardwareChoice(void); const char *EMZGetAudioVolumeChoice(void); const char *EMZGetAudioMuteChoice(void); +const char *EMZGetAudioMixChoice(void); const char *EMZGetCMTModeChoice(void); const char *EMZGetDisplayTypeChoice(void); +const char *EMZGetDisplayOptionChoice(void); const char *EMZGetDisplayOutputChoice(void); const char *EMZGetVRAMModeChoice(void); const char *EMZGetGRAMModeChoice(void); @@ -572,9 +744,18 @@ const char *EMZGetCGROMChoice(void); const char *EMZGetKeyMappingROMChoice(void); const char *EMZGetUserROMChoice(void); const char *EMZGetFloppyDiskROMChoice(void); +const char *EMZGetTapeType(void); +const char *EMZGetLoadApplicationChoice(void); +const char *EMZGetAutoStartChoice(void); +const char *EMZGetMZ800ModeChoice(void); +const char *EMZGetMZ800PrinterChoice(void); +const char *EMZGetMZ800TapeInChoice(void); void EMZNextCMTMode(enum ACTIONMODE); void EMZNextDisplayType(enum ACTIONMODE); +void EMZNextDisplayOption(enum ACTIONMODE); +uint8_t EMZGetDisplayOptionValue(void); +uint8_t EMZGetMemSizeValue(void); void EMZNextDisplayOutput(enum ACTIONMODE); void EMZNextVRAMMode(enum ACTIONMODE); void EMZNextGRAMMode(enum ACTIONMODE); @@ -591,11 +772,27 @@ void EMZNextCGROM(enum ACTIONMODE); void EMZNextKeyMappingROM(enum ACTIONMODE); void EMZNextUserROM(enum ACTIONMODE); void EMZNextFloppyDiskROM(enum ACTIONMODE); - - +void EMZNextLoadApplication(enum ACTIONMODE); +void EMZNextMZ800Mode(enum ACTIONMODE mode); +void EMZNextMZ800Printer(enum ACTIONMODE mode); +void EMZNextMZ800TapeIn(enum ACTIONMODE mode); #ifdef __cplusplus } #endif #endif // EMUMZ_H + +// Pseudo 'public' method prototypes. +#ifdef __cplusplus + extern "C" { +#endif + +uint8_t EMZInit(enum MACHINE_HW_TYPES hostMachine); +void EMZRun(uint8_t); +const char *EMZGetVersion(void); +const char *EMZGetVersionDate(void); + +#ifdef __cplusplus +} +#endif diff --git a/include/osd.h b/include/osd.h index a3d4638..7afd5b5 100755 --- a/include/osd.h +++ b/include/osd.h @@ -68,31 +68,38 @@ #define VC_8BIT_BASE_ADDR VIDEO_BASE_ADDR + 0x000000 #define VC_32BIT_BASE_ADDR VIDEO_BASE_ADDR + 0x000000 // 8 Bit access addresses - used for writing, read can only be on a 32bit boundary with lower address lines set to 00. Writing can write upto 4 consecutive addresses if desired. -#define VCADDR_8BIT_PALSLCTOFF VC_8BIT_BASE_ADDR + 0xD3 // Set the palette slot Off position to be adjusted. -#define VCADDR_8BIT_PALSLCTON VC_8BIT_BASE_ADDR + 0xD4 // Set the palette slot On position to be adjusted. -#define VCADDR_8BIT_PALSETRED VC_8BIT_BASE_ADDR + 0xD5 // Set the red palette value according to the PALETTE_PARAM_SEL address. -#define VCADDR_8BIT_PALSETGREEN VC_8BIT_BASE_ADDR + 0xD6 // Set the green palette value according to the PALETTE_PARAM_SEL address. -#define VCADDR_8BIT_PALSETBLUE VC_8BIT_BASE_ADDR + 0xD7 // Set the blue palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_8BIT_PALSLCTOFF VC_8BIT_BASE_ADDR + 0xA3 // Set the palette slot Off position to be adjusted. +#define VCADDR_8BIT_PALSLCTON VC_8BIT_BASE_ADDR + 0xA4 // Set the palette slot On position to be adjusted. +#define VCADDR_8BIT_PALSETRED VC_8BIT_BASE_ADDR + 0xA5 // Set the red palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_8BIT_PALSETGREEN VC_8BIT_BASE_ADDR + 0xA6 // Set the green palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_8BIT_PALSETBLUE VC_8BIT_BASE_ADDR + 0xA7 // Set the blue palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_8BIT_OSDMNU_SZX VC_8BIT_BASE_ADDR + 0xA8 // Get OSD Menu Horizontal Size (X). +#define VCADDR_8BIT_OSDMNU_SZY VC_8BIT_BASE_ADDR + 0xA9 // Get OSD Menu Vertical Size (Y). +#define VCADDR_8BIT_OSDHDR_SZX VC_8BIT_BASE_ADDR + 0xAA // Get OSD Status Header Horizontal Size (X). +#define VCADDR_8BIT_OSDHDR_SZY VC_8BIT_BASE_ADDR + 0xAB // Get OSD Status Header Vertical Size (Y). +#define VCADDR_8BIT_OSDFTR_SZX VC_8BIT_BASE_ADDR + 0xAC // Get OSD Status Footer Horizontal Size (X). +#define VCADDR_8BIT_OSDFTR_SZY VC_8BIT_BASE_ADDR + 0xAD // Get OSD Status Footer Vertical Size (Y). +#define VCADDR_8BIT_VMPALETTE VC_8BIT_BASE_ADDR + 0xB0 // Sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. + // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. +#define VCADDR_8BIT_GPUPARAM VC_8BIT_BASE_ADDR + 0xB2 // Set parameters. Store parameters in a long word to be used by the graphics command processor. + // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. +#define VCADDR_8BIT_GPUCMD VC_8BIT_BASE_ADDR + 0xB3 // Set the graphics processor unit commands. + // Bits [5:0] - 0 = Reset parameters. + // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter +#define VCADDR_8BIT_VMCTRL VC_8BIT_BASE_ADDR + 0xB8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. +#define VCADDR_8BIT_VMGRMODE VC_8BIT_BASE_ADDR + 0xB9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). +#define VCADDR_8BIT_VMREDMASK VC_8BIT_BASE_ADDR + 0xBA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_8BIT_VMGREENMASK VC_8BIT_BASE_ADDR + 0xBB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_8BIT_VMBLUEMASK VC_8BIT_BASE_ADDR + 0xBC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_8BIT_VMPAGE VC_8BIT_BASE_ADDR + 0xBD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +#define VCADDR_8BIT_VMVGATTR VC_8BIT_BASE_ADDR + 0xBE // Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue, 4:3 = VGA Mode, 00 = Off, 01 = 640x480, 10 = 800x600, 11 = 50Hz Internal +#define VCADDR_8BIT_VMVGAMODE VC_8BIT_BASE_ADDR + 0xBF // Select VGA Output mode. [3:0] - required output resolution/frequency. #define VCADDR_8BIT_SYSCTRL VC_8BIT_BASE_ADDR + 0xF0 // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus. -#define VCADDR_8BIT_VMBORDER VC_8BIT_BASE_ADDR + 0xF3 // Select VGA Border colour attributes. Bit 2 = Red, 1 = Green, 0 = Blue. #define VCADDR_8BIT_GRAMMODE VC_8BIT_BASE_ADDR + 0xF4 // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display. #define VCADDR_8BIT_VMPALETTE VC_8BIT_BASE_ADDR + 0xF5 // Select Palette: // 0xF5 sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. - // GPU: -#define VCADDR_8BIT_GPUPARAM VC_8BIT_BASE_ADDR + 0xF6 // 0xF6 set parameters. Store parameters in a long word to be used by the graphics command processor. - // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. -#define VCADDR_8BIT_GPUCMD VC_8BIT_BASE_ADDR + 0xF7 // 0xF7 set the graphics processor unit commands. -#define VCADDR_8BIT_GPUSTATUS VC_8BIT_BASE_ADDR + 0xF7 // [7;1] - FSM state, [0] - 1 = busy, 0 = idle - // Bits [5:0] - 0 = Reset parameters. - // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter - // -#define VCADDR_8BIT_VMCTRL VC_8BIT_BASE_ADDR + 0xF8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. -#define VCADDR_8BIT_VMGRMODE VC_8BIT_BASE_ADDR + 0xF9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). -#define VCADDR_8BIT_VMREDMASK VC_8BIT_BASE_ADDR + 0xFA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_8BIT_VMGREENMASK VC_8BIT_BASE_ADDR + 0xFB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_8BIT_VMBLUEMASK VC_8BIT_BASE_ADDR + 0xFC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_8BIT_VMPAGE VC_8BIT_BASE_ADDR + 0xFD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. + #define VCADDR_8BIT_KEYPA VC_8BIT_BASE_ADDR + 0xE000 // VideoModule 8255 Port A #define VCADDR_8BIT_KEYPB VC_8BIT_BASE_ADDR + 0xE001 // VideoModule 8255 Port B #define VCADDR_8BIT_KEYPC VC_8BIT_BASE_ADDR + 0xE002 // VideoModule 8255 Port C @@ -205,20 +212,70 @@ #define IO_TZ_CLKSELRD 0x66 // Read the status of the clock select, ie. which clock is connected to the CPU. #define IO_TZ_SVCREQ 0x68 // Service request from the Z80 to be provided by the K64F. #define IO_TZ_SYSREQ 0x6A // System request from the Z80 to be provided by the K64F. +#define IO_TZ_CPLDSTATUS 0x6B // Version 2.1 CPLD status register. #define IO_TZ_CPUCFG 0x6C // Version 2.2 CPU configuration register. #define IO_TZ_CPUSTATUS 0x6C // Version 2.2 CPU runtime status register. #define IO_TZ_CPUINFO 0x6D // Version 2.2 CPU information register. #define IO_TZ_CPLDCFG 0x6E // Version 2.1 CPLD configuration register. -#define IO_TZ_CPLDSTATUS 0x6E // Version 2.1 CPLD status register. #define IO_TZ_CPLDINFO 0x6F // Version 2.1 CPLD version information register. +#define IO_TZ_CPLDINFO 0x6F // Version 2.1 CPLD version information register. +#define IO_TZ_PALSLCTOFF 0xA3 // Set the palette slot (PALETTE_PARAM_SEL) Off position to be adjusted. +#define IO_TZ_PALSLCTON 0xA4 // Set the palette slot (PALETTE_PARAM_SEL) On position to be adjusted. +#define IO_TZ_PALSETRED 0xA5 // Set the red palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_PALSETGREEN 0xA6 // Set the green palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_PALSETBLUE 0xA7 // Set the blue palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_OSDMNU_SZX 0xA8 // Get OSD Menu Horizontal Size (X). +#define IO_TZ_OSDMNU_SZY 0xA9 // Get OSD Menu Vertical Size (Y). +#define IO_TZ_OSDHDR_SZX 0xAA // Get OSD Status Header Horizontal Size (X). +#define IO_TZ_OSDHDR_SZY 0xAB // Get OSD Status Header Vertical Size (Y). +#define IO_TZ_OSDFTR_SZX 0xAC // Get OSD Status Footer Horizontal Size (X). +#define IO_TZ_OSDFTR_SZY 0xAD // Get OSD Status Footer Vertical Size (Y). +#define IO_TZ_PALETTE 0xB0 // Sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. + // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. +#define IO_TZ_GPUPARAM 0xB2 // Set parameters. Store parameters in a long word to be used by the graphics command processor. + // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. +#define IO_TZ_GPUCMD 0xB3 // Set the graphics processor unit commands. + // Bits [5:0] - 0 = Reset parameters. + // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter +#define IO_TZ_VMCTRL 0xB8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. +#define IO_TZ_VMGRMODE 0xB9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). +#define IO_TZ_VMREDMASK 0xBA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMGREENMASK 0xBB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMBLUEMASK 0xBC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMPAGE 0xBD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +#define IO_TZ_VMVGATTR 0xBE // Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue, 4:3 = VGA Mode, 00 = Off, 01 = 640x480, 10 = 800x600, 11 = 50Hz Internal +#define IO_TZ_VMVGAMODE 0xBF // Select VGA Output mode. [3:0] - required output resolution/frequency. +#define IO_TZ_GDGWF 0xCC // MZ-800 write format register +#define IO_TZ_GDGRF 0xCD // MZ-800 read format register +#define IO_TZ_GDCMD 0xCE // MZ-800 CRTC Mode register +#define IO_TZ_GDCMD 0xCF // MZ-800 CRTC control register +#define IO_TZ_MMIO0 0xE0 // MZ-700/MZ-800 Memory management selection ports. +#define IO_TZ_MMIO1 0xE1 // "" +#define IO_TZ_MMIO2 0xE2 // "" +#define IO_TZ_MMIO3 0xE3 // "" +#define IO_TZ_MMIO4 0xE4 // "" +#define IO_TZ_MMIO5 0xE5 // "" +#define IO_TZ_MMIO6 0xE6 // "" +#define IO_TZ_MMIO7 0xE7 // MZ-700/MZ-800 Memory management selection ports. +#define IO_TZ_PPIA 0xE0 // MZ80B/MZ2000 8255 PPI Port A +#define IO_TZ_PPIB 0xE1 // MZ80B/MZ2000 8255 PPI Port B +#define IO_TZ_PPIC 0xE2 // MZ80B/MZ2000 8255 PPI Port C +#define IO_TZ_PPICTL 0xE3 // MZ80B/MZ2000 8255 PPI Control Register +#define IO_TZ_PIT0 0xE4 // MZ80B/MZ2000 8253 PIT Timer 0 +#define IO_TZ_PIT1 0xE5 // MZ80B/MZ2000 8253 PIT Timer 1 +#define IO_TZ_PIT2 0xE6 // MZ80B/MZ2000 8253 PIT Timer 2 +#define IO_TZ_PITCTL 0xE7 // MZ80B/MZ2000 8253 PIT Control Register +#define IO_TZ_PIOA 0xE8 // MZ80B/MZ2000 Z80 PIO Port A +#define IO_TZ_PIOCTLA 0xE9 // MZ80B/MZ2000 Z80 PIO Port A Control Register +#define IO_TZ_PIOB 0xEA // MZ80B/MZ2000 Z80 PIO Port B +#define IO_TZ_PIOCTLB 0xEB // MZ80B/MZ2000 Z80 PIO Port B Control Register #define IO_TZ_SYSCTRL 0xF0 // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus. #define IO_TZ_GRAMMODE 0xF4 // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display. -#define IO_TZ_VMCTRL 0xF8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. -#define IO_TZ_VMGRMODE 0xF9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). -#define IO_TZ_VMREDMASK 0xFA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMGREENMASK 0xFB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMBLUEMASK 0xFC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMPAGE 0xFD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +//#define IO_TZ_GRAMOPT 0xF4 // MZ80B/MZ2000 GRAM configuration option. +#define IO_TZ_CRTGRPHPRIO 0xF5 // MZ2000 Graphics priority register, character or a graphics colour has front display priority. +#define IO_TZ_CRTGRPHSEL 0xF6 // MZ2000 Graphics output select on CRT or external CRT +#define IO_TZ_GRAMCOLRSEL 0xF7 // MZ2000 Graphics RAM colour bank select. + // IO register constants. // @@ -251,18 +308,22 @@ #define VMMODE_MZ80A 0x03 // Video mode = MZ80A #define VMMODE_MZ700 0x04 // Video mode = MZ700 #define VMMODE_MZ800 0x05 // Video mode = MZ800 -#define VMMODE_MZ80B 0x06 // Video mode = MZ80B -#define VMMODE_MZ2000 0x07 // Video mode = MZ2000 -#define VMMODE_80CHAR 0x08 // Enable 80 character display. -#define VMMODE_80CHAR_MASK 0xF7 // Mask to filter out display width control bit. -#define VMMODE_COLOUR 0x10 // Enable colour display. -#define VMMODE_COLOUR_MASK 0xEF // Mask to filter out colour control bit. -#define VMMODE_PCGRAM 0x20 // Enable PCG RAM. -#define VMMODE_VGA_MASK 0x3F // Mask to filter out the VGA mode bits. -#define VMMODE_VGA_OFF 0x00 // Set VGA mode off, external monitor is driven by standard internal signals. -#define VMMODE_VGA_640x480 0x40 // Set external monitor to VGA 640x480 @ 60Hz mode. -#define VMMODE_VGA_1024x768 0x80 // Set external monitor to VGA 1024x768 @ 60Hz mode. -#define VMMODE_VGA_800x600 0xC0 // Set external monitor to VGA 800x600 @ 60Hz mode. +#define VMMODE_MZ1500 0x06 // Video mode = MZ1500 +#define VMMODE_MZ80B 0x07 // Video mode = MZ80B +#define VMMODE_MZ2000 0x08 // Video mode = MZ2000 +#define VMMODE_MZ2200 0x09 // Video mode = MZ2200 +#define VMMODE_MZ2500 0x0A // Video mode = MZ2500 +#define VMMODE_80CHAR 0x10 // Enable 80 character display. +#define VMMODE_80CHAR_MASK 0xEF // Mask to filter out display width control bit. +#define VMMODE_COLOUR 0x20 // Enable colour display. +#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit. +#define VMMODE_PCGRAM 0x40 // Enable PCG RAM. +#define VMMODE_VGA_MASK 0xF0 // Mask to filter out the VGA output mode bits. +#define VMMODE_VGA_OFF 0x00 // Set VGA mode off, external monitor is driven by standard internal 60Hz signals. +#define VMMODE_VGA_INT 0x00 // Set VGA mode off, external monitor is driven by standard internal 60Hz signals. +#define VMMODE_VGA_INT50 0x01 // Set VGA mode off, external monitor is driven by standard internal 50Hz signals. +#define VMMODE_VGA_640x480 0x02 // Set external monitor to VGA 640x480 @ 60Hz mode. +#define VMMODE_VGA_800x600 0x03 // Set external monitor to VGA 800x600 @ 60Hz mode. // VGA mode border control constants. // @@ -464,12 +525,69 @@ enum COLOUR { WHITE = 0x07 // Green, Red and Blue pixels active. }; +// Supported attriutes/ +enum ATTRIBUTES { + NOATTR = 0x0000, // No attributes. + HILIGHT_FG_ACTIVE = 0x0008, // Highlight flag. + HILIGHT_FG_BLACK = 0x0008 + 0x00, // Highlight the character foreground in black. + HILIGHT_FG_BLUE = 0x0008 + 0x01, // Highlight "" "" "" "" blue. + HILIGHT_FG_RED = 0x0008 + 0x02, // Highlight "" "" "" "" red. + HILIGHT_FG_PURPLE = 0x0008 + 0x03, // Highlight "" "" "" "" purple. + HILIGHT_FG_GREEN = 0x0008 + 0x04, // Highlight "" "" "" "" green. + HILIGHT_FG_CYAN = 0x0008 + 0x05, // Highlight "" "" "" "" cyan. + HILIGHT_FG_YELLOW = 0x0008 + 0x06, // Highlight "" "" "" "" yellow. + HILIGHT_FG_WHITE = 0x0008 + 0x07, // Highlight "" "" "" "" white. + HILIGHT_BG_ACTIVE = 0x0010, // Highlight flag. + HILIGHT_BG_BLACK = 0x0010 + 0x00, // Highlight the character background in black. + HILIGHT_BG_BLUE = 0x0010 + 0x01, // Highlight "" "" "" "" blue. + HILIGHT_BG_RED = 0x0010 + 0x02, // Highlight "" "" "" "" red. + HILIGHT_BG_PURPLE = 0x0010 + 0x03, // Highlight "" "" "" "" purple. + HILIGHT_BG_GREEN = 0x0010 + 0x04, // Highlight "" "" "" "" green. + HILIGHT_BG_CYAN = 0x0010 + 0x05, // Highlight "" "" "" "" cyan. + HILIGHT_BG_YELLOW = 0x0010 + 0x06, // Highlight "" "" "" "" yellow. + HILIGHT_BG_WHITE = 0x0010 + 0x07 // Highlight "" "" "" "" white. +}; + // Public settings, accessed via enumerated value. enum OSDPARAMS { ACTIVE_MAX_X = 0x00, // Width in pixels of the active framebuffer. ACTIVE_MAX_Y = 0x01 // Depth in pixels of the active framebuffer. }; +// Structure to maintain data relevant to flashing a cursor at a given location. +// +typedef struct { + // Attributes to be used when cursor is showing. + uint16_t attr; + + // Colour of the character, + enum COLOUR fg; + enum COLOUR bg; + + // Location in the framebuffer where the character commences. + uint8_t row; + uint8_t col; + + // Offset in pixels to the given row/col. Allows for finer placing within mixed fonts. + uint8_t ofrow; + uint8_t ofcol; + + // Font used for the underlying character. + enum FONTS font; + + // Flash speed of the cursor in ms. + unsigned long speed; + + // Character being displayed. + uint8_t dispChar; + + // Switch to enable/disable the cursor. + uint8_t enabled; + + // Flash State. + uint8_t flashing; +} t_CursorFlash; + // Structure to maintain the OSD Menu and Status display output parameters and data. // typedef struct { @@ -488,8 +606,12 @@ typedef struct { uint8_t lineWrap; // Wrap line at status window edge (1) else stop printing at status window edge. uint16_t maxX; // Maximum X plane pixels. uint16_t maxY; // Maximum Y plane pixels. - + + // Cursor data. + t_CursorFlash cursor; // Data for enabling a flashing cursor at a given screen coordinate. } t_WindowParams; + +// Structure to maintain the OSD window data. typedef struct { // Mode in which the OSD is operating. enum WINDOWS mode; @@ -517,10 +639,11 @@ bitmapStruct *OSDGetBitmap(enum BITMAPS); void OSDSetPixel(uint16_t, uint16_t, enum COLOUR); void OSDClearPixel(uint16_t, uint16_t, enum COLOUR); void OSDChangePixelColour(uint16_t, uint16_t, enum COLOUR, enum COLOUR); -void _OSDwrite(uint8_t, uint8_t, int8_t, int8_t, uint8_t, uint8_t, enum ORIENTATION, uint8_t, enum COLOUR, enum COLOUR, fontStruct *); +void _OSDwrite(uint8_t, uint8_t, int8_t, int8_t, uint8_t, uint8_t, enum ORIENTATION, uint8_t, uint16_t, enum COLOUR, enum COLOUR, fontStruct *); void OSDWriteBitmap(uint16_t, uint16_t, enum BITMAPS, enum COLOUR, enum COLOUR); void OSDWriteChar(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, enum FONTS, enum ORIENTATION, char, enum COLOUR, enum COLOUR); -void OSDWriteString(uint8_t, uint8_t, int8_t, int8_t, uint8_t, uint8_t, enum FONTS, enum ORIENTATION, char *, enum COLOUR, enum COLOUR); +void OSDWriteString(uint8_t, uint8_t, int8_t, int8_t, uint8_t, uint8_t, enum FONTS, enum ORIENTATION, char *, uint16_t *, enum COLOUR, enum COLOUR); +void OSDUpdateScreenSize(void); void OSDRefreshScreen(void); void OSDClearScreen(enum COLOUR); void OSDClearArea(int16_t, int16_t, int16_t, int16_t, enum COLOUR); @@ -529,6 +652,10 @@ void OSDDrawCircle(int16_t, int16_t, int16_t, enum COLOUR); void OSDDrawFilledCircle(int16_t, int16_t, int16_t, enum COLOUR); void OSDDrawEllipse(int16_t, int16_t, int16_t, int16_t, enum COLOUR); void OSDSetActiveWindow(enum WINDOWS); +void OSDSetCursorFlash(uint8_t, uint8_t, uint8_t, uint8_t, enum FONTS, uint8_t, enum COLOUR, enum COLOUR, uint16_t, unsigned long); +void OSDClearCursorFlash(void); +void OSDCursorFlash(void); +void OSDService(void); uint8_t OSDInit(enum WINDOWS); // Getter/Setter methods! diff --git a/include/sharpmz.h b/include/sharpmz.h index afe526c..944d617 100755 --- a/include/sharpmz.h +++ b/include/sharpmz.h @@ -98,69 +98,88 @@ // ------------------------ // // Address A23 -A16 -// Y+0x080000 00001000 - Memory and I/O ports mapped into direct addressable memory location. +// Y+0x000000 00001000 - Memory and I/O ports mapped into direct addressable memory location. // // A15 - A8 A7 - A0 // I/O registers are mapped to the bottom 256 bytes mirroring the I/O address. -// Y+0x0800D0 00000000 11010000 - 0xD0 - Set the parameter number to update. -// 00000000 11010001 - 0xD1 - Update the lower selected parameter byte. -// 00000000 11010010 - 0xD2 - Update the upper selected parameter byte. -// 00000000 11010011 - 0xD3 - set the palette slot Off position to be adjusted. -// 00000000 11010100 - 0xD4 - set the palette slot On position to be adjusted. -// 00000000 11010101 - 0xD5 - set the red palette value according to the PALETTE_PARAM_SEL address. -// 00000000 11010110 - 0xD6 - set the green palette value according to the PALETTE_PARAM_SEL address. -// Y+0x0800D7 00000000 11010111 - 0xD7 - set the blue palette value according to the PALETTE_PARAM_SEL address. +// +// Y+0x0000A0 00000000 10100000 - 0xA0 - +// 00000000 10100001 - 0xA1 - +// 00000000 10100010 - 0xA2 - +// 00000000 10100011 - 0xA3 - set the palette slot Off position to be adjusted. +// 00000000 10100100 - 0xA4 - set the palette slot On position to be adjusted. +// 00000000 10100101 - 0xA5 - set the red palette value according to the PALETTE_PARAM_SEL address. +// 00000000 10100110 - 0xA6 - set the green palette value according to the PALETTE_PARAM_SEL address. +// Y+0x0000A7 00000000 10100111 - 0xA7 - set the blue palette value according to the PALETTE_PARAM_SEL address. +// 00000000 10101000 - 0xA8 - Get OSD Menu Horizontal Size (X). +// 00000000 10101001 - 0xA9 - Get OSD Menu Vertical Size (Y). +// 00000000 10101010 - 0xAA - Get OSD Status Header Horizontal Size (X). +// 00000000 10101011 - 0xAB - Get OSD Status Header Vertical Size (Y). +// 00000000 10101100 - 0xAC - Get OSD Status Footer Horizontal Size (X). +// 00000000 10101101 - 0xAD - Get OSD Status Footer Vertical Size (Y). +// Y+0x0000B0 00000000 10110000 - 0xB0 - sets the palette. +// 00000000 10110001 - 0xB1 - +// 00000000 10110010 - 0xB2 - set parameters. +// 00000000 10110011 - 0xB3 - set the graphics processor unit commands. +// 00000000 10111000 - 0xB8 - set the video mode. +// 00000000 10111001 - 0xB9 - set the graphics mode. +// 00000000 10111010 - 0xBA - set the Red bit mask +// 00000000 10111011 - 0xBB - set the Green bit mask +// 00000000 10111100 - 0xBC - set the Blue bit mask +// Y+0x0000BD 00000000 10111101 - 0xBD - set the Video memory page in block C000:FFFF +// Y+0x0000BE 00000000 10111110 - 0xBE - set the VGA border colour and attributes. +// Y+0x0000BF 00000000 10111111 - 0xBF - set the VGA output mode. // -// Y+0x0800E0 00000000 11100000 - 0xE0 MZ80B PPI +// Y+0x0000E0 00000000 11100000 - 0xE0 MZ80B PPI // 00000000 11100100 - 0xE4 MZ80B PIT -// Y+0x0800E8 00000000 11101000 - 0xE8 MZ80B PIO +// Y+0x0000E8 00000000 11101000 - 0xE8 MZ80B PIO // -// 00000000 11110000 - -// 00000000 11110001 - -// 00000000 11110010 - -// Y+0x0800F3 00000000 11110011 - 0xF3 set the VGA border colour. -// 00000000 11110100 - 0xF4 set the MZ80B video in/out mode. -// 00000000 11110101 - 0xF5 sets the palette. -// 00000000 11110110 - 0xF6 set parameters. -// 00000000 11110111 - 0xF7 set the graphics processor unit commands. -// 00000000 11111000 - 0xF6 set parameters. -// 00000000 11111001 - 0xF7 set the graphics processor unit commands. -// 00000000 11111010 - 0xF8 set the video mode. -// 00000000 11111011 - 0xF9 set the graphics mode. -// 00000000 11111100 - 0xFA set the Red bit mask -// 00000000 11111101 - 0xFB set the Green bit mask -// 00000000 11111110 - 0xFC set the Blue bit mask -// Y+0x0800FD 00000000 11111111 - 0xFD set the Video memory page in block C000:FFFF +// 00000000 11110000 - 0xF0 +// 00000000 11110001 - 0xF1 +// 00000000 11110010 - 0xF2 +// Y+0x0000F3 00000000 11110011 - 0xF3 +// 00000000 11110100 - 0xF4 set the MZ80B video in/out mode or MZ2000 Colour CRT Background Colour Selection. +// 00000000 11110101 - 0xF5 MZ2000 Priority, Bit 3 = 0, Character comes to foreground, = 1, Graphics comes to foreground. 2:0 = Colour +// 00000000 11110110 - 0xF6 MZ2000 Bit 4 Graphics Display on CRT (H), 2:0 colour VRAM enable to Colour CRT / CRT (if enabled). +// 00000000 11110111 - 0xF7 MZ2000 Selection of VRAM bank in memory map when enabled, 0 = None, 1 = Blue, 2 = Red, 3 = Green // // Memory registers are mapped to the E000 region as per base machines. -// Y+0x08E010 11100000 00010010 - Program Character Generator RAM. E010 - Write cycle (Read cycle = reset memory swap). +// Y+0x00E010 11100000 00010010 - Program Character Generator RAM. E010 - Write cycle (Read cycle = reset memory swap). // 11100000 00010100 - Normal display select. // 11100000 00010101 - Inverted display select. // 11100010 00000000 - Scroll display register. E200 - E2FF -// Y+0x08E2FF 11111111 +// Y+0x00E2FF 11111111 // -// Y+0x090000 00001001 - Video/Attribute RAM. 64K Window. -// Y+0x09D000 11010000 00000000 - Video RAM -// Y+0x09D7FF 11010111 11111111 -// Y+0x09D800 11011000 00000000 - Attribute RAM -// Y+0x09DFFF 11011111 11111111 +// Y+0x010000 00000001 - Video/Attribute RAM. 64K Window. +// Y+0x01D000 11010000 00000000 - Video RAM +// Y+0x01D7FF 11010111 11111111 +// Y+0x01D800 11011000 00000000 - Attribute RAM +// Y+0x01DFFF 11011111 11111111 // -// Y+0x0A0000 00001010 - Character Generator RAM 64K Window. -// Y+0x0A0000 00000000 00000000 - CGROM -// Y+0x0A0FFF 00001111 11111111 -// Y+0x0A1000 00010000 00000000 - CGRAM -// Y+0x0A1FFF 00011111 11111111 +// Y+0x020000 00000010 - Character Generator RAM 64K Window. +// Y+0x020000 00000000 00000000 - CGROM +// Y+0x020FFF 00001111 11111111 +// Y+0x021000 00010000 00000000 - CGRAM +// Y+0x021FFF 00011111 11111111 // -// Y+0x0C0000 00001100 - 128K Red framebuffer. +// Y+0x040000 00000100 - 128K Red framebuffer. // 00000000 00000000 - Red pixel addressed framebuffer. Also MZ-80B GRAM I memory in lower 8K -// Y+0x0C3FFF 00111111 11111111 -// Y+0x0D0000 00001101 - 128K Blue framebuffer. +// Y+0x043FFF 00111111 11111111 +// Y+0x050000 00000101 - 128K Blue framebuffer. // 00000000 00000000 - Blue pixel addressed framebuffer. Also MZ-80B GRAM II memory in lower 8K -// Y+0x0D3FFF 00111111 11111111 -// Y+0x0E0000 00001110 - 128K Green framebuffer. +// Y+0x053FFF 00111111 11111111 +// Y+0x060000 00000110 - 128K Green framebuffer. // 00000000 00000000 - Green pixel addressed framebuffer. -// Y+0x0E3FFF 00111111 11111111 +// Y+0x063FFF 00111111 11111111 // +// Y+0x070000 00000111 - Blue Menu/Status framebuffer. +// Y+0x071FFF 00011111 11111111 +// Y+0x080000 00001000 - Red Menu/Status framebuffer. +// Y+0x081FFF 00011111 11111111 +// Y+0x090000 00001001 - Green Menu/Status framebuffer. +// Y+0x091FFF 00011111 11111111 +// Y+0x0A0000 00001010 - Red/Green/Blue Menu/Status framebuffer write only. +// Y+0x0A1FFF 00011111 11111111 // Base addresses and sizes within the FPGA/Video Controller. #define VIDEO_BASE_ADDR 0xD00000 // Base address of the Video Controller. @@ -176,31 +195,34 @@ #define VC_8BIT_BASE_ADDR VIDEO_BASE_ADDR + 0x000000 #define VC_32BIT_BASE_ADDR VIDEO_BASE_ADDR + 0x000000 // 8 Bit access addresses - used for writing, read can only be on a 32bit boundary with lower address lines set to 00. Writing can write upto 4 consecutive addresses if desired. -#define VCADDR_8BIT_PALSLCTOFF VC_8BIT_BASE_ADDR + 0xD3 // Set the palette slot Off position to be adjusted. -#define VCADDR_8BIT_PALSLCTON VC_8BIT_BASE_ADDR + 0xD4 // Set the palette slot On position to be adjusted. -#define VCADDR_8BIT_PALSETRED VC_8BIT_BASE_ADDR + 0xD5 // Set the red palette value according to the PALETTE_PARAM_SEL address. -#define VCADDR_8BIT_PALSETGREEN VC_8BIT_BASE_ADDR + 0xD6 // Set the green palette value according to the PALETTE_PARAM_SEL address. -#define VCADDR_8BIT_PALSETBLUE VC_8BIT_BASE_ADDR + 0xD7 // Set the blue palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_8BIT_PALSLCTOFF VC_8BIT_BASE_ADDR + 0xA3 // Set the palette slot Off position to be adjusted. +#define VCADDR_8BIT_PALSLCTON VC_8BIT_BASE_ADDR + 0xA4 // Set the palette slot On position to be adjusted. +#define VCADDR_8BIT_PALSETRED VC_8BIT_BASE_ADDR + 0xA5 // Set the red palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_8BIT_PALSETGREEN VC_8BIT_BASE_ADDR + 0xA6 // Set the green palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_8BIT_PALSETBLUE VC_8BIT_BASE_ADDR + 0xA7 // Set the blue palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_8BIT_OSDMNU_SZX VC_8BIT_BASE_ADDR + 0xA8 // Get OSD Menu Horizontal Size (X). +#define VCADDR_8BIT_OSDMNU_SZY VC_8BIT_BASE_ADDR + 0xA9 // Get OSD Menu Vertical Size (Y). +#define VCADDR_8BIT_OSDHDR_SZX VC_8BIT_BASE_ADDR + 0xAA // Get OSD Status Header Horizontal Size (X). +#define VCADDR_8BIT_OSDHDR_SZY VC_8BIT_BASE_ADDR + 0xAB // Get OSD Status Header Vertical Size (Y). +#define VCADDR_8BIT_OSDFTR_SZX VC_8BIT_BASE_ADDR + 0xAC // Get OSD Status Footer Horizontal Size (X). +#define VCADDR_8BIT_OSDFTR_SZY VC_8BIT_BASE_ADDR + 0xAD // Get OSD Status Footer Vertical Size (Y). +#define VCADDR_8BIT_VMPALETTE VC_8BIT_BASE_ADDR + 0xB0 // Sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. + // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. +#define VCADDR_8BIT_GPUPARAM VC_8BIT_BASE_ADDR + 0xB2 // Set parameters. Store parameters in a long word to be used by the graphics command processor. + // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. +#define VCADDR_8BIT_GPUCMD VC_8BIT_BASE_ADDR + 0xB3 // Set the graphics processor unit commands. + // Bits [5:0] - 0 = Reset parameters. + // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter +#define VCADDR_8BIT_VMCTRL VC_8BIT_BASE_ADDR + 0xB8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. +#define VCADDR_8BIT_VMGRMODE VC_8BIT_BASE_ADDR + 0xB9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). +#define VCADDR_8BIT_VMREDMASK VC_8BIT_BASE_ADDR + 0xBA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_8BIT_VMGREENMASK VC_8BIT_BASE_ADDR + 0xBB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_8BIT_VMBLUEMASK VC_8BIT_BASE_ADDR + 0xBC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_8BIT_VMPAGE VC_8BIT_BASE_ADDR + 0xBD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +#define VCADDR_8BIT_VMVGATTR VC_8BIT_BASE_ADDR + 0xBE // Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue, 4:3 = VGA Mode, 00 = Off, 01 = 640x480, 10 = 800x600, 11 = 50Hz Internal +#define VCADDR_8BIT_VMVGAMODE VC_8BIT_BASE_ADDR + 0xBF // Select VGA Output mode. [3:0] - required output resolution/frequency. #define VCADDR_8BIT_SYSCTRL VC_8BIT_BASE_ADDR + 0xF0 // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus. -#define VCADDR_8BIT_VMBORDER VC_8BIT_BASE_ADDR + 0xF3 // Select VGA Border colour attributes. Bit 2 = Red, 1 = Green, 0 = Blue. #define VCADDR_8BIT_GRAMMODE VC_8BIT_BASE_ADDR + 0xF4 // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display. -#define VCADDR_8BIT_VMPALETTE VC_8BIT_BASE_ADDR + 0xF5 // Select Palette: - // 0xF5 sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. - // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. - // GPU: -#define VCADDR_8BIT_GPUPARAM VC_8BIT_BASE_ADDR + 0xF6 // 0xF6 set parameters. Store parameters in a long word to be used by the graphics command processor. - // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. -#define VCADDR_8BIT_GPUCMD VC_8BIT_BASE_ADDR + 0xF7 // 0xF7 set the graphics processor unit commands. -#define VCADDR_8BIT_GPUSTATUS VC_8BIT_BASE_ADDR + 0xF7 // [7;1] - FSM state, [0] - 1 = busy, 0 = idle - // Bits [5:0] - 0 = Reset parameters. - // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter - // -#define VCADDR_8BIT_VMCTRL VC_8BIT_BASE_ADDR + 0xF8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. -#define VCADDR_8BIT_VMGRMODE VC_8BIT_BASE_ADDR + 0xF9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). -#define VCADDR_8BIT_VMREDMASK VC_8BIT_BASE_ADDR + 0xFA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_8BIT_VMGREENMASK VC_8BIT_BASE_ADDR + 0xFB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_8BIT_VMBLUEMASK VC_8BIT_BASE_ADDR + 0xFC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_8BIT_VMPAGE VC_8BIT_BASE_ADDR + 0xFD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. #define VCADDR_8BIT_KEYPA VC_8BIT_BASE_ADDR + 0xE000 // VideoModule 8255 Port A #define VCADDR_8BIT_KEYPB VC_8BIT_BASE_ADDR + 0xE001 // VideoModule 8255 Port B #define VCADDR_8BIT_KEYPC VC_8BIT_BASE_ADDR + 0xE002 // VideoModule 8255 Port C @@ -221,32 +243,34 @@ #define VCADDR_8BIT_SCLBASE VC_8BIT_BASE_ADDR + 0xE2 // High byte scroll base. // 32 Bit access addresses for 8bit registers - used for reading, address is shifted right by 2 and the resulting byte read into bits 7:0, 31:8 are zero. -#define VCADDR_32BIT_PALSLCTOFF VC_32BIT_BASE_ADDR + (4*0xD3) // Set the palette slot Off position to be adjusted. -#define VCADDR_32BIT_PALSLCTON VC_32BIT_BASE_ADDR + (4*0xD4) // Set the palette slot On position to be adjusted. -#define VCADDR_32BIT_PALSETRED VC_32BIT_BASE_ADDR + (4*0xD5) // Set the red palette value according to the PALETTE_PARAM_SEL address. -#define VCADDR_32BIT_PALSETGREEN VC_32BIT_BASE_ADDR + (4*0xD6) // Set the green palette value according to the PALETTE_PARAM_SEL address. -#define VCADDR_32BIT_PALSETBLUE VC_32BIT_BASE_ADDR + (4*0xD7) // Set the blue palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_32BIT_PALSLCTOFF VC_32BIT_BASE_ADDR + (4*0xA3) // Set the palette slot Off position to be adjusted. +#define VCADDR_32BIT_PALSLCTON VC_32BIT_BASE_ADDR + (4*0xA4) // Set the palette slot On position to be adjusted. +#define VCADDR_32BIT_PALSETRED VC_32BIT_BASE_ADDR + (4*0xA5) // Set the red palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_32BIT_PALSETGREEN VC_32BIT_BASE_ADDR + (4*0xA6) // Set the green palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_32BIT_PALSETBLUE VC_32BIT_BASE_ADDR + (4*0xA7) // Set the blue palette value according to the PALETTE_PARAM_SEL address. +#define VCADDR_32BIT_OSDMNU_SZX VC_32BIT_BASE_ADDR + (4*0xA8) // Get OSD Menu Horizontal Size (X). +#define VCADDR_32BIT_OSDMNU_SZY VC_32BIT_BASE_ADDR + (4*0xA9) // Get OSD Menu Vertical Size (Y). +#define VCADDR_32BIT_OSDHDR_SZX VC_32BIT_BASE_ADDR + (4*0xAA) // Get OSD Status Header Horizontal Size (X). +#define VCADDR_32BIT_OSDHDR_SZY VC_32BIT_BASE_ADDR + (4*0xAB) // Get OSD Status Header Vertical Size (Y). +#define VCADDR_32BIT_OSDFTR_SZX VC_32BIT_BASE_ADDR + (4*0xAC) // Get OSD Status Footer Horizontal Size (X). +#define VCADDR_32BIT_OSDFTR_SZY VC_32BIT_BASE_ADDR + (4*0xAD) // Get OSD Status Footer Vertical Size (Y). +#define VCADDR_32BIT_VMPALETTE VC_32BIT_BASE_ADDR + (4*0xB0) // Sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. + // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. +#define VCADDR_32BIT_GPUPARAM VC_32BIT_BASE_ADDR + (4*0xB2) // Set parameters. Store parameters in a long word to be used by the graphics command processor. + // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. +#define VCADDR_32BIT_GPUCMD VC_32BIT_BASE_ADDR + (4*0xB3) // Set the graphics processor unit commands. + // Bits [5:0] - 0 = Reset parameters. + // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter +#define VCADDR_32BIT_VMCTRL VC_32BIT_BASE_ADDR + (4*0xB8) // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. +#define VCADDR_32BIT_VMGRMODE VC_32BIT_BASE_ADDR + (4*0xB9) // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). +#define VCADDR_32BIT_VMREDMASK VC_32BIT_BASE_ADDR + (4*0xBA) // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_32BIT_VMGREENMASK VC_32BIT_BASE_ADDR + (4*0xBB) // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_32BIT_VMBLUEMASK VC_32BIT_BASE_ADDR + (4*0xBC) // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define VCADDR_32BIT_VMPAGE VC_32BIT_BASE_ADDR + (4*0xBD) // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +#define VCADDR_32BIT_VMVGATTR VC_32BIT_BASE_ADDR + (4*0xBE) // Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue, 4:3 = VGA Mode, 00 = Off, 01 = 640x480, 10 = 800x600, 11 = 50Hz Internal +#define VCADDR_32BIT_VMVGAMODE VC_32BIT_BASE_ADDR + (4*0xBF) // Select VGA Output mode. [3:0] - required output resolution/frequency. #define VCADDR_32BIT_SYSCTRL VC_32BIT_BASE_ADDR + (4*0xF0) // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus. -#define VCADDR_32BIT_VMBORDER VC_32BIT_BASE_ADDR + (4*0xF3) // Select VGA Border colour attributes. Bit 2 = Red, 1 = Green, 0 = Blue. #define VCADDR_32BIT_GRAMMODE VC_32BIT_BASE_ADDR + (4*0xF4) // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display. -#define VCADDR_32BIT_VMPALETTE VC_32BIT_BASE_ADDR + (4*0xF5) // Select Palette: - // 0xF5 sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. - // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. - // GPU: -#define VCADDR_32BIT_GPUPARAM VC_32BIT_BASE_ADDR + (4*0xF6) // 0xF6 set parameters. Store parameters in a long word to be used by the graphics command processor. - // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. -#define VCADDR_32BIT_GPUCMD VC_32BIT_BASE_ADDR + (4*0xF7) // 0xF7 set the graphics processor unit commands. -#define VCADDR_32BIT_GPUSTATUS VC_32BIT_BASE_ADDR + (4*0xF7) // [7;1] - FSM state, [0] - 1 = busy, 0 = idle - // Bits [5:0] - 0 = Reset parameters. - // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter - // -#define VCADDR_32BIT_VMCTRL VC_32BIT_BASE_ADDR + (4*0xF8) // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. - // [4] defines the colour mode, 0 = mono, 1 = colour - ignored on certain modes. [5] defines wether PCGRAM is enabled, 0 = disabled, 1 = enabled. [7:6] define the VGA mode. -#define VCADDR_32BIT_VMGRMODE VC_32BIT_BASE_ADDR + (4*0xF9) // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). -#define VCADDR_32BIT_VMREDMASK VC_32BIT_BASE_ADDR + (4*0xFA) // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_32BIT_VMGREENMASK VC_32BIT_BASE_ADDR + (4*0xFB) // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_32BIT_VMBLUEMASK VC_32BIT_BASE_ADDR + (4*0xFC) // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define VCADDR_32BIT_VMPAGE VC_32BIT_BASE_ADDR + (4*0xFD) // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. #define VCADDR_32BIT_KEYPA VC_32BIT_BASE_ADDR + (4*0xE000) // Video Module 8255 Port A #define VCADDR_32BIT_KEYPB VC_32BIT_BASE_ADDR + (4*0xE001) // Video Module 8255 Port B #define VCADDR_32BIT_KEYPC VC_32BIT_BASE_ADDR + (4*0xE002) // Video Module 8255 Port C @@ -325,14 +349,24 @@ #define MBADDR_8BIT_IOW_CPLDCFG MB_32BIT_IO_ADDR + 0x6E // Version 2.1 CPLD configuration register. #define MBADDR_8BIT_IOW_CPLDSTATUS MB_32BIT_IO_ADDR + 0x6E // Version 2.1 CPLD status register. #define MBADDR_8BIT_IOW_CPLDINFO MB_32BIT_IO_ADDR + 0x6F // Version 2.1 CPLD version information register. + +#define MBADDR_8BIT_IOW_VMPALETTE VC_32BIT_IO_ADDR + 0xB0 // Sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. + // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. +#define MBADDR_8BIT_IOW_GPUPARAM VC_32BIT_IO_ADDR + 0xB2 // Set parameters. Store parameters in a long word to be used by the graphics command processor. + // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. +#define MBADDR_8BIT_IOW_GPUCMD VC_32BIT_IO_ADDR + 0xB3 // Set the graphics processor unit commands. + // Bits [5:0] - 0 = Reset parameters. + // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter +#define MBADDR_8BIT_IOW_VMCTRL MB_32BIT_IO_ADDR + 0xB8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. +#define MBADDR_8BIT_IOW_VMGRMODE MB_32BIT_IO_ADDR + 0xB9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). +#define MBADDR_8BIT_IOW_VMREDMASK MB_32BIT_IO_ADDR + 0xBA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define MBADDR_8BIT_IOW_VMGREENMASK MB_32BIT_IO_ADDR + 0xBB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define MBADDR_8BIT_IOW_VMBLUEMASK MB_32BIT_IO_ADDR + 0xBC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define MBADDR_8BIT_IOW_VMPAGE MB_32BIT_IO_ADDR + 0xBD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +#define MBADDR_8BIT_IOW_VMVGATTR MB_32BIT_IO_ADDR + 0xBE // Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue, 4:3 = VGA Mode, 00 = Off, 01 = 640x480, 10 = 800x600, 11 = 50Hz Internal +#define MBADDR_8BIT_IOW_VMVGAMODE MB_32BIT_IO_ADDR + 0xBF // Select VGA Output mode. [3:0] - required output resolution/frequency. #define MBADDR_8BIT_IOW_SYSCTRL MB_32BIT_IO_ADDR + 0xF0 // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus. #define MBADDR_8BIT_IOW_GRAMMODE MB_32BIT_IO_ADDR + 0xF4 // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display. -#define MBADDR_8BIT_IOW_VMCTRL MB_32BIT_IO_ADDR + 0xF8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. -#define MBADDR_8BIT_IOW_VMGRMODE MB_32BIT_IO_ADDR + 0xF9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). -#define MBADDR_8BIT_IOW_VMREDMASK MB_32BIT_IO_ADDR + 0xFA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define MBADDR_8BIT_IOW_VMGREENMASK MB_32BIT_IO_ADDR + 0xFB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define MBADDR_8BIT_IOW_VMBLUEMASK MB_32BIT_IO_ADDR + 0xFC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define MBADDR_8BIT_IOW_VMPAGE MB_32BIT_IO_ADDR + 0xFD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. #define MBADDR_32BIT_IOR_CTRLLATCH MB_32BIT_IO_ADDR + (4*0x60) // Control latch which specifies the Memory Model/mode. #define MBADDR_32BIT_IOR_SETXMHZ MB_32BIT_IO_ADDR + (4*0x62) // Switch to alternate CPU frequency provided by K64F. @@ -346,17 +380,14 @@ #define MBADDR_32BIT_IOR_CPLDCFG MB_32BIT_IO_ADDR + (4*0x6E) // Version 2.1 CPLD configuration register. #define MBADDR_32BIT_IOR_CPLDSTATUS MB_32BIT_IO_ADDR + (4*0x6E) // Version 2.1 CPLD status register. #define MBADDR_32BIT_IOR_CPLDINFO MB_32BIT_IO_ADDR + (4*0x6F) // Version 2.1 CPLD version information register. +#define MBADDR_32BIT_IOR_VMCTRL MB_32BIT_IO_ADDR + (4*0xB8) // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. +#define MBADDR_32BIT_IOR_VMGRMODE MB_32BIT_IO_ADDR + (4*0xB9) // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). +#define MBADDR_32BIT_IOR_VMREDMASK MB_32BIT_IO_ADDR + (4*0xBA) // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define MBADDR_32BIT_IOR_VMGREENMASK MB_32BIT_IO_ADDR + (4*0xBB) // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define MBADDR_32BIT_IOR_VMBLUEMASK MB_32BIT_IO_ADDR + (4*0xBC) // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define MBADDR_32BIT_IOR_VMPAGE MB_32BIT_IO_ADDR + (4*0xBD) // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. #define MBADDR_32BIT_IOR_SYSCTRL MB_32BIT_IO_ADDR + (4*0xF0) // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus. #define MBADDR_32BIT_IOR_GRAMMODE MB_32BIT_IO_ADDR + (4*0xF4) // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display. -#define MBADDR_32BIT_IOR_VMCTRL MB_32BIT_IO_ADDR + (4*0xF8) // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. -#define MBADDR_32BIT_IOR_VMGRMODE MB_32BIT_IO_ADDR + (4*0xF9) // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). -#define MBADDR_32BIT_IOR_VMREDMASK MB_32BIT_IO_ADDR + (4*0xFA) // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define MBADDR_32BIT_IOR_VMGREENMASK MB_32BIT_IO_ADDR + (4*0xFB) // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define MBADDR_32BIT_IOR_VMBLUEMASK MB_32BIT_IO_ADDR + (4*0xFC) // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define MBADDR_32BIT_IOR_VMPAGE MB_32BIT_IO_ADDR + (4*0xFD) // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. - - - // tranZPUter Memory Modes - select one of the 32 possible memory models using these constants. // @@ -392,20 +423,69 @@ #define IO_TZ_CLKSELRD 0x66 // Read the status of the clock select, ie. which clock is connected to the CPU. #define IO_TZ_SVCREQ 0x68 // Service request from the Z80 to be provided by the K64F. #define IO_TZ_SYSREQ 0x6A // System request from the Z80 to be provided by the K64F. +#define IO_TZ_CPLDSTATUS 0x6B // Version 2.1 CPLD status register. #define IO_TZ_CPUCFG 0x6C // Version 2.2 CPU configuration register. #define IO_TZ_CPUSTATUS 0x6C // Version 2.2 CPU runtime status register. #define IO_TZ_CPUINFO 0x6D // Version 2.2 CPU information register. #define IO_TZ_CPLDCFG 0x6E // Version 2.1 CPLD configuration register. -#define IO_TZ_CPLDSTATUS 0x6E // Version 2.1 CPLD status register. #define IO_TZ_CPLDINFO 0x6F // Version 2.1 CPLD version information register. + +#define IO_TZ_PALSLCTOFF 0xA3 // Set the palette slot (PALETTE_PARAM_SEL) Off position to be adjusted. +#define IO_TZ_PALSLCTON 0xA4 // Set the palette slot (PALETTE_PARAM_SEL) On position to be adjusted. +#define IO_TZ_PALSETRED 0xA5 // Set the red palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_PALSETGREEN 0xA6 // Set the green palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_PALSETBLUE 0xA7 // Set the blue palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_OSDMNU_SZX 0xA8 // Get OSD Menu Horizontal Size (X). +#define IO_TZ_OSDMNU_SZY 0xA9 // Get OSD Menu Vertical Size (Y). +#define IO_TZ_OSDHDR_SZX 0xAA // Get OSD Status Header Horizontal Size (X). +#define IO_TZ_OSDHDR_SZY 0xAB // Get OSD Status Header Vertical Size (Y). +#define IO_TZ_OSDFTR_SZX 0xAC // Get OSD Status Footer Horizontal Size (X). +#define IO_TZ_OSDFTR_SZY 0xAD // Get OSD Status Footer Vertical Size (Y). +#define IO_TZ_PALETTE 0xB0 // Sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. + // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. +#define IO_TZ_GPUPARAM 0xB2 // Set parameters. Store parameters in a long word to be used by the graphics command processor. + // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. +#define IO_TZ_GPUCMD 0xB3 // Set the graphics processor unit commands. + // Bits [5:0] - 0 = Reset parameters. + // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter +#define IO_TZ_VMCTRL 0xB8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. +#define IO_TZ_VMGRMODE 0xB9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). +#define IO_TZ_VMREDMASK 0xBA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMGREENMASK 0xBB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMBLUEMASK 0xBC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMPAGE 0xBD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +#define IO_TZ_VMVGATTR 0xBE // Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue, 4:3 = VGA Mode, 00 = Off, 01 = 640x480, 10 = 800x600, 11 = 50Hz Internal +#define IO_TZ_VMVGAMODE 0xBF // Select VGA Output mode. [3:0] - required output resolution/frequency. +#define IO_TZ_GDGWF 0xCC // MZ-800 write format register +#define IO_TZ_GDGRF 0xCD // MZ-800 read format register +#define IO_TZ_GDCMD 0xCE // MZ-800 CRTC Mode register +#define IO_TZ_GDCMD 0xCF // MZ-800 CRTC control register +#define IO_TZ_MMIO0 0xE0 // MZ-700/MZ-800 Memory management selection ports. +#define IO_TZ_MMIO1 0xE1 // "" +#define IO_TZ_MMIO2 0xE2 // "" +#define IO_TZ_MMIO3 0xE3 // "" +#define IO_TZ_MMIO4 0xE4 // "" +#define IO_TZ_MMIO5 0xE5 // "" +#define IO_TZ_MMIO6 0xE6 // "" +#define IO_TZ_MMIO7 0xE7 // MZ-700/MZ-800 Memory management selection ports. +#define IO_TZ_PPIA 0xE0 // MZ80B/MZ2000 8255 PPI Port A +#define IO_TZ_PPIB 0xE1 // MZ80B/MZ2000 8255 PPI Port B +#define IO_TZ_PPIC 0xE2 // MZ80B/MZ2000 8255 PPI Port C +#define IO_TZ_PPICTL 0xE3 // MZ80B/MZ2000 8255 PPI Control Register +#define IO_TZ_PIT0 0xE4 // MZ80B/MZ2000 8253 PIT Timer 0 +#define IO_TZ_PIT1 0xE5 // MZ80B/MZ2000 8253 PIT Timer 1 +#define IO_TZ_PIT2 0xE6 // MZ80B/MZ2000 8253 PIT Timer 2 +#define IO_TZ_PITCTL 0xE7 // MZ80B/MZ2000 8253 PIT Control Register +#define IO_TZ_PIOA 0xE8 // MZ80B/MZ2000 Z80 PIO Port A +#define IO_TZ_PIOCTLA 0xE9 // MZ80B/MZ2000 Z80 PIO Port A Control Register +#define IO_TZ_PIOB 0xEA // MZ80B/MZ2000 Z80 PIO Port B +#define IO_TZ_PIOCTLB 0xEB // MZ80B/MZ2000 Z80 PIO Port B Control Register #define IO_TZ_SYSCTRL 0xF0 // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus. #define IO_TZ_GRAMMODE 0xF4 // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display. -#define IO_TZ_VMCTRL 0xF8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. -#define IO_TZ_VMGRMODE 0xF9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). -#define IO_TZ_VMREDMASK 0xFA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMGREENMASK 0xFB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMBLUEMASK 0xFC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMPAGE 0xFD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +//#define IO_TZ_GRAMOPT 0xF4 // MZ80B/MZ2000 GRAM configuration option. +#define IO_TZ_CRTGRPHPRIO 0xF5 // MZ2000 Graphics priority register, character or a graphics colour has front display priority. +#define IO_TZ_CRTGRPHSEL 0xF6 // MZ2000 Graphics output select on CRT or external CRT +#define IO_TZ_GRAMCOLRSEL 0xF7 // MZ2000 Graphics RAM colour bank select./ // IO register constants. // @@ -438,18 +518,22 @@ #define VMMODE_MZ80A 0x03 // Video mode = MZ80A #define VMMODE_MZ700 0x04 // Video mode = MZ700 #define VMMODE_MZ800 0x05 // Video mode = MZ800 -#define VMMODE_MZ80B 0x06 // Video mode = MZ80B -#define VMMODE_MZ2000 0x07 // Video mode = MZ2000 -#define VMMODE_80CHAR 0x08 // Enable 80 character display. -#define VMMODE_80CHAR_MASK 0xF7 // Mask to filter out display width control bit. -#define VMMODE_COLOUR 0x10 // Enable colour display. -#define VMMODE_COLOUR_MASK 0xEF // Mask to filter out colour control bit. -#define VMMODE_PCGRAM 0x20 // Enable PCG RAM. -#define VMMODE_VGA_MASK 0x3F // Mask to filter out the VGA mode bits. -#define VMMODE_VGA_OFF 0x00 // Set VGA mode off, external monitor is driven by standard internal signals. -#define VMMODE_VGA_640x480 0x40 // Set external monitor to VGA 640x480 @ 60Hz mode. -#define VMMODE_VGA_1024x768 0x80 // Set external monitor to VGA 1024x768 @ 60Hz mode. -#define VMMODE_VGA_800x600 0xC0 // Set external monitor to VGA 800x600 @ 60Hz mode. +#define VMMODE_MZ1500 0x06 // Video mode = MZ1500 +#define VMMODE_MZ80B 0x07 // Video mode = MZ80B +#define VMMODE_MZ2000 0x08 // Video mode = MZ2000 +#define VMMODE_MZ2200 0x09 // Video mode = MZ2200 +#define VMMODE_MZ2500 0x0A // Video mode = MZ2500 +#define VMMODE_80CHAR 0x10 // Enable 80 character display. +#define VMMODE_80CHAR_MASK 0xEF // Mask to filter out display width control bit. +#define VMMODE_COLOUR 0x20 // Enable colour display. +#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit. +#define VMMODE_PCGRAM 0x40 // Enable PCG RAM. +#define VMMODE_VGA_MASK 0xF0 // Mask to filter out the VGA output mode bits. +#define VMMODE_VGA_OFF 0x00 // Set VGA mode off, external monitor is driven by standard internal 60Hz signals. +#define VMMODE_VGA_INT 0x00 // Set VGA mode off, external monitor is driven by standard internal 60Hz signals. +#define VMMODE_VGA_INT50 0x01 // Set VGA mode off, external monitor is driven by standard internal 50Hz signals. +#define VMMODE_VGA_640x480 0x02 // Set external monitor to VGA 640x480 @ 60Hz mode. +#define VMMODE_VGA_800x600 0x03 // Set external monitor to VGA 800x600 @ 60Hz mode. // VGA mode border control constants. // diff --git a/include/tranzputer.h b/include/tranzputer.h index 0b4145b..02b7957 100755 --- a/include/tranzputer.h +++ b/include/tranzputer.h @@ -66,6 +66,7 @@ #define TZMM_MZ700_3 0x0d // MZ700 Mode - 0000:0FFF is on the tranZPUter board in block 0, 1000:CFFF is on the tranZPUter board in block 0, D000:FFFF is inaccessible. #define TZMM_MZ700_4 0x0e // MZ700 Mode - 0000:0FFF is on the tranZPUter board in block 6, 1000:CFFF is on the tranZPUter board in block 0, D000:FFFF is inaccessible. #define TZMM_MZ800 0x0f // MZ800 Mode - Host is an MZ-800 and mode provides for MZ-700/MZ-800 decoding per original machine. +#define TZMM_MZ2000 0x10 // MZ2000 Mode - Running on MZ2000 hardware, configuration set according to runtime configuration registers. #define TZMM_FPGA 0x15 // Open up access for the K64F to the FPGA resources such as memory. All other access to RAM or mainboard is blocked. #define TZMM_TZPUM 0x16 // Everything is on mainboard, no access to tranZPUter memory. #define TZMM_TZPU 0x17 // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory. K64F drives A18-A16 allowing full access to RAM. @@ -86,12 +87,43 @@ #define IO_TZ_CLKSELRD 0x66 // Read the status of the clock select, ie. which clock is connected to the CPU. #define IO_TZ_SVCREQ 0x68 // Service request from the Z80 to be provided by the K64F. #define IO_TZ_SYSREQ 0x6A // System request from the Z80 to be provided by the K64F. +#define IO_TZ_CPLDCMD 0x6B // Version 2.1 CPLD command register. +#define IO_TZ_CPLDSTATUS 0x6B // Version 2.1 CPLD status register. #define IO_TZ_CPUCFG 0x6C // Version 2.2 CPU configuration register. #define IO_TZ_CPUSTATUS 0x6C // Version 2.2 CPU runtime status register. #define IO_TZ_CPUINFO 0x6D // Version 2.2 CPU information register. #define IO_TZ_CPLDCFG 0x6E // Version 2.1 CPLD configuration register. -#define IO_TZ_CPLDSTATUS 0x6E // Version 2.1 CPLD status register. #define IO_TZ_CPLDINFO 0x6F // Version 2.1 CPLD version information register. +#define IO_TZ_PALSLCTOFF 0xA3 // set the palette slot Off position to be adjusted. +#define IO_TZ_PALSLCTON 0xA4 // set the palette slot On position to be adjusted. +#define IO_TZ_PALSETRED 0xA5 // set the red palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_PALSETGREEN 0xA6 // set the green palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_PALSETBLUE 0xA7 // set the blue palette value according to the PALETTE_PARAM_SEL address. +#define IO_TZ_OSDMNU_SZX 0xA8 // Get OSD Menu Horizontal Size (X). +#define IO_TZ_OSDMNU_SZY 0xA9 // Get OSD Menu Vertical Size (Y). +#define IO_TZ_OSDHDR_SZX 0xAA // Get OSD Status Header Horizontal Size (X). +#define IO_TZ_OSDHDR_SZY 0xAB // Get OSD Status Header Vertical Size (Y). +#define IO_TZ_OSDFTR_SZX 0xAC // Get OSD Status Footer Horizontal Size (X). +#define IO_TZ_OSDFTR_SZY 0xAD // Get OSD Status Footer Vertical Size (Y). +#define IO_TZ_PALETTE 0xB0 // Sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output. + // Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input. +#define IO_TZ_GPUPARAM 0xB2 // Set parameters. Store parameters in a long word to be used by the graphics command processor. + // The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0. +#define IO_TZ_GPUCMD 0xB3 // Set the graphics processor unit commands. + // Bits [5:0] - 0 = Reset parameters. + // 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter +#define IO_TZ_VMCTRL 0xB8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. +#define IO_TZ_VMGRMODE 0xB9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). +#define IO_TZ_VMREDMASK 0xBA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMGREENMASK 0xBB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMBLUEMASK 0xBC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). +#define IO_TZ_VMPAGE 0xBD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +#define IO_TZ_VMVGATTR 0xBE // Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue, 4:3 = VGA Mode, 00 = Off, 01 = 640x480, 10 = 800x600, 11 = 50Hz Internal +#define IO_TZ_VMVGAMODE 0xBF // Select VGA Output mode, ie. Internal, 640x480 etc. Bits [3:0] specify required mode. Undefined default to internal standard frequency. +#define IO_TZ_GDGWF 0xCC // MZ-800 write format register +#define IO_TZ_GDGRF 0xCD // MZ-800 read format register +#define IO_TZ_GDCMD 0xCE // MZ-800 CRTC Mode register +#define IO_TZ_GDCMD 0xCF // MZ-800 CRTC control register #define IO_TZ_MMIO0 0xE0 // MZ-700/MZ-800 Memory management selection ports. #define IO_TZ_MMIO1 0xE1 // "" #define IO_TZ_MMIO2 0xE2 // "" @@ -100,14 +132,24 @@ #define IO_TZ_MMIO5 0xE5 // "" #define IO_TZ_MMIO6 0xE6 // "" #define IO_TZ_MMIO7 0xE7 // MZ-700/MZ-800 Memory management selection ports. +#define IO_TZ_PPIA 0xE0 // MZ80B/MZ2000 8255 PPI Port A +#define IO_TZ_PPIB 0xE1 // MZ80B/MZ2000 8255 PPI Port B +#define IO_TZ_PPIC 0xE2 // MZ80B/MZ2000 8255 PPI Port C +#define IO_TZ_PPICTL 0xE3 // MZ80B/MZ2000 8255 PPI Control Register +#define IO_TZ_PIT0 0xE4 // MZ80B/MZ2000 8253 PIT Timer 0 +#define IO_TZ_PIT1 0xE5 // MZ80B/MZ2000 8253 PIT Timer 1 +#define IO_TZ_PIT2 0xE6 // MZ80B/MZ2000 8253 PIT Timer 2 +#define IO_TZ_PITCTL 0xE7 // MZ80B/MZ2000 8253 PIT Control Register +#define IO_TZ_PIOA 0xE8 // MZ80B/MZ2000 Z80 PIO Port A +#define IO_TZ_PIOCTLA 0xE9 // MZ80B/MZ2000 Z80 PIO Port A Control Register +#define IO_TZ_PIOB 0xEA // MZ80B/MZ2000 Z80 PIO Port B +#define IO_TZ_PIOCTLB 0xEB // MZ80B/MZ2000 Z80 PIO Port B Control Register #define IO_TZ_SYSCTRL 0xF0 // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus. #define IO_TZ_GRAMMODE 0xF4 // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display. -#define IO_TZ_VMCTRL 0xF8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col. -#define IO_TZ_VMGRMODE 0xF9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used). -#define IO_TZ_VMREDMASK 0xFA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMGREENMASK 0xFB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMBLUEMASK 0xFC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte). -#define IO_TZ_VMPAGE 0xFD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF. +//#define IO_TZ_GRAMOPT 0xF4 // MZ80B/MZ2000 GRAM configuration option. +#define IO_TZ_CRTGRPHPRIO 0xF5 // MZ2000 Graphics priority register, character or a graphics colour has front display priority. +#define IO_TZ_CRTGRPHSEL 0xF6 // MZ2000 Graphics output select on CRT or external CRT +#define IO_TZ_GRAMCOLRSEL 0xF7 // MZ2000 Graphics RAM colour bank select. // Addresses on the tranZPUter board. // @@ -142,40 +184,50 @@ #define CPUMODE_IS_SOFT_MASK 0x03F // Mask to filter out the Soft CPU availability flags. // CPLD Configuration constants. -#define MODE_MZ80K 0x00 // Hardware mode = MZ80K -#define MODE_MZ80C 0x01 // Hardware mode = MZ80C -#define MODE_MZ1200 0x02 // Hardware mode = MZ1200 -#define MODE_MZ80A 0x03 // Hardware mode = MZ80A -#define MODE_MZ700 0x04 // Hardware mode = MZ700 -#define MODE_MZ800 0x05 // Hardware mode = MZ800 -#define MODE_MZ80B 0x06 // Hardware mode = MZ80B -#define MODE_MZ2000 0x07 // Hardware mode = MZ2000 -#define MODE_VIDEO_MODULE_DISABLED 0x08 // Hardware enable (bit 3 = 0) or disable of the Video Module. +#define HWMODE_MZ80K 0x00 // Hardware mode = MZ80K +#define HWMODE_MZ80C 0x01 // Hardware mode = MZ80C +#define HWMODE_MZ1200 0x02 // Hardware mode = MZ1200 +#define HWMODE_MZ80A 0x03 // Hardware mode = MZ80A +#define HWMODE_MZ700 0x04 // Hardware mode = MZ700 +#define HWMODE_MZ800 0x05 // Hardware mode = MZ800 +#define HWMODE_MZ80B 0x06 // Hardware mode = MZ80B +#define HWMODE_MZ2000 0x07 // Hardware mode = MZ2000 +#define MODE_VIDEO_MODULE_ENABLED 0x08 // Hardware enable (bit 3 = 1) or disable of the Video Module on the newer version, the one below will be removed. +#define MODE_VIDEO_MODULE_DISABLED 0x00 // Hardware enable (bit 3 = 0) or disable of the Video Module. #define MODE_PRESERVE_CONFIG 0x80 // Preserve hardware configuration on RESET. +// CPLD Command Instruction constants. +#define CPLD_RESET_HOST 1 // CPLD level command to reset the host system. +#define CPLD_HOLD_HOST_BUS 2 // CPLD command to hold the host bus. +#define CPLD_RELEASE_HOST_BUS 3 // CPLD command to release the host bus. + // Video Module control bits. #define SYSMODE_MZ80A 0x00 // System board mode MZ80A, 2MHz CPU/Bus. #define SYSMODE_MZ80B 0x01 // System board mode MZ80B, 4MHz CPU/Bus. #define SYSMODE_MZ700 0x02 // System board mode MZ700, 3.54MHz CPU/Bus. -#define VMMODE_MASK 0xF8 // Mask to mask out video mode. -#define VMMODE_MZ80K MODE_MZ80K // Video mode = MZ80K -#define VMMODE_MZ80C MODE_MZ80C // Video mode = MZ80C -#define VMMODE_MZ1200 MODE_MZ1200 // Video mode = MZ1200 -#define VMMODE_MZ80A MODE_MZ80A // Video mode = MZ80A -#define VMMODE_MZ700 MODE_MZ700 // Video mode = MZ700 -#define VMMODE_MZ800 MODE_MZ800 // Video mode = MZ800 -#define VMMODE_MZ80B MODE_MZ80B // Video mode = MZ80B -#define VMMODE_MZ2000 MODE_MZ2000 // Video mode = MZ2000 -#define VMMODE_80CHAR 0x08 // Enable 80 character display. -#define VMMODE_80CHAR_MASK 0xF7 // Mask to filter out display width control bit. -#define VMMODE_COLOUR 0x10 // Enable colour display. -#define VMMODE_COLOUR_MASK 0xEF // Mask to filter out colour control bit. -#define VMMODE_PCGRAM 0x20 // Enable PCG RAM. -#define VMMODE_VGA_MASK 0x3F // Mask to filter out the VGA mode bits. -#define VMMODE_VGA_OFF 0x00 // Set VGA mode off, external monitor is driven by standard internal signals. -#define VMMODE_VGA_640x480 0x40 // Set external monitor to VGA 640x480 @ 60Hz mode. -#define VMMODE_VGA_1024x768 0x80 // Set external monitor to VGA 1024x768 @ 60Hz mode. -#define VMMODE_VGA_800x600 0xC0 // Set external monitor to VGA 800x600 @ 60Hz mode. +#define VMMODE_MASK 0xF0 // Mask to mask out video mode. +#define VMMODE_MZ80K 0x00 // Video mode = MZ80K +#define VMMODE_MZ80C 0x01 // Video mode = MZ80C +#define VMMODE_MZ1200 0x02 // Video mode = MZ1200 +#define VMMODE_MZ80A 0x03 // Video mode = MZ80A +#define VMMODE_MZ700 0x04 // Video mode = MZ700 +#define VMMODE_MZ800 0x05 // Video mode = MZ800 +#define VMMODE_MZ1500 0x06 // Video mode = MZ1500 +#define VMMODE_MZ80B 0x07 // Video mode = MZ80B +#define VMMODE_MZ2000 0x08 // Video mode = MZ2000 +#define VMMODE_MZ2200 0x09 // Video mode = MZ2200 +#define VMMODE_MZ2500 0x0A // Video mode = MZ2500 +#define VMMODE_80CHAR 0x10 // Enable 80 character display. +#define VMMODE_80CHAR_MASK 0xEF // Mask to filter out display width control bit. +#define VMMODE_COLOUR 0x20 // Enable colour display. +#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit. +#define VMMODE_PCGRAM 0x40 // Enable PCG RAM. +#define VMMODE_VGA_MASK 0xF0 // Mask to filter out the VGA output mode bits. +#define VMMODE_VGA_OFF 0x00 // Set VGA mode off, external monitor is driven by standard internal 60Hz signals. +#define VMMODE_VGA_INT 0x00 // Set VGA mode off, external monitor is driven by standard internal 60Hz signals. +#define VMMODE_VGA_INT50 0x01 // Set VGA mode off, external monitor is driven by standard internal 50Hz signals. +#define VMMODE_VGA_640x480 0x02 // Set external monitor to VGA 640x480 @ 60Hz mode. +#define VMMODE_VGA_800x600 0x03 // Set external monitor to VGA 800x600 @ 60Hz mode. // VGA mode border control constants. // @@ -226,7 +278,11 @@ #define MZ_CMT_ADDR 0x010F0 // Address of the CMT (tape) header record. #define MZ_CMT_DEFAULT_LOAD_ADDR 0x01200 // The default load address for a CMT, anything below this is normally illegal. #define MZ_VID_RAM_ADDR 0x0D000 // Start of Video RAM +#define MZ_VID_CGROM_ADDR 0x220000 // Start of the CG ROM memory. +#define MZ_VID_CGRAM_ADDR 0x221000 // Start of the CG RAM memory. #define MZ_VID_RAM_SIZE 2048 // Size of Video RAM. +#define MZ_VID_MAX_COL 40 // Maximum column for the host display +#define MZ_VID_MAX_ROW 25 // Maximum row for the host display #define MZ_VID_DFLT_BYTE 0x00 // Default character (SPACE) for video RAM. #define MZ_ATTR_RAM_ADDR 0xD800 // On machines with the upgrade, the start of the Attribute RAM. #define MZ_ATTR_RAM_SIZE 2048 // Size of the attribute RAM. @@ -250,6 +306,7 @@ #define MZ_ROM_1Z_013A_80C "0:\\TZFS\\1z-013a-8.rom" // Original Monitor ROM patched for the Sharp MZ700 patched for 80 column mode. #define MZ_ROM_1Z_013A_KM_40C "0:\\TZFS\\1z-013a-km.rom" // Original 40 character Monitor ROM for the Sharp MZ700 with keyboard remapped for the MZ80A. #define MZ_ROM_1Z_013A_KM_80C "0:\\TZFS\\1z-013a-km-8.rom" // Original Monitor ROM patched for the Sharp MZ700 with keyboard remapped for the MZ80A and patched for 80 column mode. +#define MZ_ROM_1Z_013A_2000 "0:\\TZFS\\1z-013a-2000.rom" // Original 40 character Monitor ROM for the Sharp MZ700 modified to run on an MZ-2000. #define MZ_ROM_9Z_504M_COMBINED "0:\\TZFS\\mz800_ipl.rom" // Original MZ-800 BIOS which comprises the 1Z_013B BIOS, 9Z_504M IPL, CGROM and IOCS. #define MZ_ROM_9Z_504M "0:\\TZFS\\mz800_9z_504m.rom" // Modified MZ-800 9Z_504M IPL to contain a select TZFS option. #define MZ_ROM_1Z_013B "0:\\TZFS\\mz800_1z_013b.rom" // Original MZ-800 1Z_013B MZ-700 compatible BIOS. @@ -257,6 +314,8 @@ #define MZ_ROM_800_IOCS "0:\\TZFS\\mz800_iocs.rom" // Original MZ-800 common IOCS bios. #define MZ_ROM_MZ80B_IPL "0:\\TZFS\\mz80b_ipl.rom" // Original IPL ROM for the Sharp MZ-80B. #define MZ_ROM_MZ2000_IPL "0:\\TZFS\\mz2000_ipl.rom" // Original IPL ROM for the Sharp MZ-2000. +#define MZ_ROM_MZ2000_IPL_TZPU "0:\\TZFS\\mz2000_ipl_tzpu.rom" // Modified IPL ROM for the tranZPUter running on the Sharp MZ-2000. +#define MZ_ROM_MZ2000_CGROM "0:\\TZFS\\mz2000_cgrom.rom" // MZ-2000 CGROM. #define MZ_ROM_TZFS "0:\\TZFS\\tzfs.rom" // tranZPUter Filing System ROM. #define MZ_ROM_ZPU_ZOS "0:\\ZOS\\zos.rom" // zOS for the ZPU running on the tranZPUter SW-700 board. @@ -274,6 +333,8 @@ #define TZSVC_CMD_STRUCT_ADDR_CPM 0x4F560 // Address of the command structure within CP/M - exists in 64K Block 4. #define TZSVC_CMD_STRUCT_ADDR_MZ700 0x6FD80 // Address of the command structure within MZ700 compatible programs - exists in 64K Block 6. #define TZSVC_CMD_STRUCT_ADDR_ZOS 0x11FD80 // 0x7FD80 // Address of the command structure for zOS use, exists in shared memory rather than FPGA. Spans top of block 6 and all of block 7. +#define TZSVC_CMD_STRUCT_ADDR_MZ2000_NST 0x6FD80 // Address of the command structure within MZ2000 compatible programs during normal state - exists in 64K Block 1. +#define TZSVC_CMD_STRUCT_ADDR_MZ2000_IPL 0x07D80 // Address of the command structure within MZ2000 compatible programs during IPL state - exists in 64K Block 0. #define TZSVC_CMD_STRUCT_SIZE 0x280 // Size of the inter z80/K64 service command memory. #define TZSVC_CMD_SIZE (sizeof(t_svcControl)-TZSVC_SECTOR_SIZE) #define TZVC_MAX_CMPCT_DIRENT_BLOCK TZSVC_SECTOR_SIZE/TZSVC_CMPHDR_SIZE // Maximum number of directory entries per sector. @@ -299,6 +360,7 @@ #define TZSVC_CMD_LOAD80BIPL 0x24 // Service command requesting the MZ-80B IPL is loaded. #define TZSVC_CMD_LOAD800BIOS 0x25 // Service command requesting that the MZ800 9Z-504M BIOS is loaded. #define TZSVC_CMD_LOAD2000IPL 0x26 // Service command requesting the MZ-2000 IPL is loaded. +#define TZSVC_CMD_LOADTZFS 0x2F // Service command requesting the loading of TZFS. This service is for machines which normally dont have a monitor BIOS. ie. MZ-80B/MZ-2000 and manually request TZFS. #define TZSVC_CMD_LOADBDOS 0x30 // Service command to reload CPM BDOS+CCP. #define TZSVC_CMD_ADDSDDRIVE 0x31 // Service command to attach a CPM disk to a drive number. #define TZSVC_CMD_READSDDRIVE 0x32 // Service command to read an attached SD file as a CPM disk drive. @@ -315,8 +377,11 @@ #define TZSVC_CMD_EMU_SETMZ80A 0x56 // "" "" "" MZ80A. #define TZSVC_CMD_EMU_SETMZ700 0x57 // "" "" "" MZ700. #define TZSVC_CMD_EMU_SETMZ800 0x58 // "" "" "" MZ800. -#define TZSVC_CMD_EMU_SETMZ80B 0x59 // "" "" "" MZ80B. -#define TZSVC_CMD_EMU_SETMZ2000 0x5A // "" "" "" MZ2000. +#define TZSVC_CMD_EMU_SETMZ1500 0x59 // "" "" "" MZ1500. +#define TZSVC_CMD_EMU_SETMZ80B 0x5A // "" "" "" MZ80B. +#define TZSVC_CMD_EMU_SETMZ2000 0x5B // "" "" "" MZ2000. +#define TZSVC_CMD_EMU_SETMZ2200 0x5C // "" "" "" MZ2200. +#define TZSVC_CMD_EMU_SETMZ2500 0x5D // "" "" "" MZ2500. #define TZSVC_CMD_SD_DISKINIT 0x60 // Service command to initialise and provide raw access to the underlying SD card. #define TZSVC_CMD_SD_READSECTOR 0x61 // Service command to provide raw read access to the underlying SD card. #define TZSVC_CMD_SD_WRITESECTOR 0x62 // Service command to provide raw write access to the underlying SD card. @@ -602,17 +667,43 @@ enum VIDEO_FRAMES { WORKING = 1 }; -// Possible machines the tranZPUter can be hosted on and can emulate. +// Possible machine hardware types the tranZPUter is functioning within. +// +enum MACHINE_HW_TYPES { + HW_MZ80K = HWMODE_MZ80K, // Host hardware = MZ-80K. + HW_MZ80C = HWMODE_MZ80C, // Host hardware = MZ-80C. + HW_MZ1200 = HWMODE_MZ1200, // Host hardware = MZ-1200. + HW_MZ80A = HWMODE_MZ80A, // Host hardware = MZ-80A. + HW_MZ700 = HWMODE_MZ700, // Host hardware = MZ-700. + HW_MZ800 = HWMODE_MZ800, // Host hardware = MZ-800. + HW_MZ80B = HWMODE_MZ80B, // Host hardware = MZ-80B. + HW_MZ2000 = HWMODE_MZ2000, // Host hardware = MZ-2000. + HW_UNKNOWN = 0xFF // Host hardware unknown, fault or CPLD misconfiguration. +}; + +// Possible machine types the tranZPUter can select. These are on a 1:1 with the video controller types for Sharp MZ machines. // enum MACHINE_TYPES { - MZ80K = MODE_MZ80K, // Machine = MZ-80K. - MZ80C = MODE_MZ80C, // Machine = MZ-80C. - MZ1200 = MODE_MZ1200, // Machine = MZ-1200. - MZ80A = MODE_MZ80A, // Machine = MZ-80A. - MZ700 = MODE_MZ700, // Machine = MZ-700. - MZ800 = MODE_MZ800, // Machine = MZ-800. - MZ80B = MODE_MZ80B, // Machine = MZ-80B. - MZ2000 = MODE_MZ2000 // Machine = MZ-2000. + MZ80K = VMMODE_MZ80K, // Machine = MZ-80K. + MZ80C = VMMODE_MZ80C, // Machine = MZ-80C. + MZ1200 = VMMODE_MZ1200, // Machine = MZ-1200. + MZ80A = VMMODE_MZ80A, // Machine = MZ-80A. + MZ700 = VMMODE_MZ700, // Machine = MZ-700. + MZ800 = VMMODE_MZ800, // Machine = MZ-800. + MZ1500 = VMMODE_MZ1500, // Machine = MZ-1500. + MZ80B = VMMODE_MZ80B, // Machine = MZ-80B. + MZ2000 = VMMODE_MZ2000, // Machine = MZ-2000. + MZ2200 = VMMODE_MZ2200, // Machine = MZ-2200. + MZ2500 = VMMODE_MZ2500, // Machine = MZ-2500. + UNKNOWN = 0xFF // Machine unknown, fault in coding. +}; + +// Groups to which the machines belong. This is a lineage route of the Sharp machines. +// +enum MACHINE_GROUP { + GROUP_MZ80K = 0, // Machines in the MZ80K group, ie. MZ80K/C/1200/80A + GROUP_MZ700 = 1, // Machines in the MZ700 group, ie. MZ700/800/1500 + GROUP_MZ80B = 2 // Machines in the MZ80B group, ie. MZ80B/2000/2200/2500 }; // Get and Set flags within the CPLD config and status registers. @@ -726,8 +817,12 @@ typedef struct { enum CTRL_MODE ctrlMode; // Mode of control, ie normal Z80 Running, controlling mainboard, controlling tranZPUter. enum BUS_DIRECTION busDir; // Direction the bus has been configured for. - enum MACHINE_TYPES hostType; // The underlying host machine, 0 = Sharp MZ-80A, 1 = MZ-700, 2 = MZ-80B - enum MACHINE_TYPES machineMode; // Machine compatibility, 0 = Sharp MZ-80K, 1 = MZ-80C, 2 = MZ-1200, 3 = MZ-80A, 4 = MZ-700, 5 = MZ-800, 6 = MZ-80B, 7 = MZ-2000 + enum MACHINE_HW_TYPES hostType; // The underlying host machine, 0 = Sharp MZ-80A, 1 = MZ-700, 2 = MZ-80B +// enum MACHINE_TYPES machineMode; // Machine compatibility, 0 = Sharp MZ-80K, 1 = MZ-80C, 2 = MZ-1200, 3 = MZ-80A, 4 = MZ-700, 5 = MZ-800, 6 = MZ-80B, 7 = MZ-2000 + uint8_t iplMode; // Flag to indicate if the host is in IPL (boot) or run mode. Applicable on the MZ-2000/MZ-80B only. + uint8_t blockResetActions; // Flag to request reset actions are blocked on the next detected reset. This is useful on startup or when loading a monitor ROM set different to the default. + uint8_t cpldVersion; // CPLD configuration version. 1 = original tranZPUter SW, 2 = tranZPUter SW-700 v1 + uint8_t softcpuInfo; // FPGA Soft CPU capabilities. 0 = None. t_mz700 mz700; // MZ700 emulation control to detect IO commands and adjust the memory map accordingly. t_mz80b mz80b; // MZ-80B emulation control to detect IO commands and adjust the memory map and I/O forwarding accordingly. @@ -818,6 +913,12 @@ typedef struct { uint8_t asciiCode; } t_asciiMap; +// Mapping table from Ascii to Sharp MZ display code. +// +typedef struct { + uint8_t dispCode; +} t_dispCodeMap; + // Application execution constants. // @@ -873,6 +974,8 @@ char *getAttributeFrame(enum VIDEO_FRAMES); FRESULT loadZ80Memory(const char *, uint32_t, uint32_t, uint32_t, uint32_t *, enum TARGETS, uint8_t); FRESULT saveZ80Memory(const char *, uint32_t, uint32_t, t_svcDirEnt *, enum TARGETS); FRESULT loadMZFZ80Memory(const char *, uint32_t, uint32_t *, uint8_t, enum TARGETS, uint8_t); +void clsHost(void); +void printfHost(uint8_t, uint8_t, char *, ...); // Getter/Setter methods! uint8_t isZ80Reset(void); @@ -901,13 +1004,14 @@ uint8_t svcWriteCPMDrive(void); uint32_t getServiceAddr(void); void processServiceRequest(void); void TZPUservice(void); -uint8_t loadBIOS(const char *biosFileName, uint8_t machineMode, uint32_t loadAddr); +uint8_t loadBIOS(const char *, uint32_t); +FRESULT loadTZFS(char *, uint32_t); void hardResetTranZPUter(void); void loadTranZPUterDefaultROMS(uint8_t); void tranZPUterControl(void); uint8_t testTZFSAutoBoot(void); -void setHost(void); -void setupTranZPUter(void); +void setHost(uint8_t); +void setupTranZPUter(uint8_t, char *, char *); void testRoutine(void); // Sharp MZ Series emulation methods. diff --git a/libraries/lib/libimath2-k64f.a b/libraries/lib/libimath2-k64f.a index c32982d..3f12c75 100644 Binary files a/libraries/lib/libimath2-k64f.a and b/libraries/lib/libimath2-k64f.a differ diff --git a/libraries/lib/libumansi-k64f.a b/libraries/lib/libumansi-k64f.a index 3dade29..1c438ef 100644 Binary files a/libraries/lib/libumansi-k64f.a and b/libraries/lib/libumansi-k64f.a differ diff --git a/libraries/lib/libummath-k64f.a b/libraries/lib/libummath-k64f.a index 776bbe5..5bb0dad 100644 Binary files a/libraries/lib/libummath-k64f.a and b/libraries/lib/libummath-k64f.a differ diff --git a/libraries/lib/libummathf-k64f.a b/libraries/lib/libummathf-k64f.a index a548729..a1f5051 100644 Binary files a/libraries/lib/libummathf-k64f.a and b/libraries/lib/libummathf-k64f.a differ diff --git a/libraries/lib/libummisc-k64f.a b/libraries/lib/libummisc-k64f.a index ec6db4f..3fac1c4 100644 Binary files a/libraries/lib/libummisc-k64f.a and b/libraries/lib/libummisc-k64f.a differ diff --git a/libraries/lib/libumstdio-k64f.a b/libraries/lib/libumstdio-k64f.a index dd6e788..570d829 100644 Binary files a/libraries/lib/libumstdio-k64f.a and b/libraries/lib/libumstdio-k64f.a differ diff --git a/startup/zos_k64f.ld b/startup/zos_k64f.ld index 53b51cb..0a26f8b 100644 --- a/startup/zos_k64f.ld +++ b/startup/zos_k64f.ld @@ -39,7 +39,7 @@ ENTRY(_VectorsFlash) MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00080000 - RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x0002A000 + RAM (rwx) : ORIGIN = 0x2000E000, LENGTH = 0x00022000 } /* FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K @@ -124,14 +124,14 @@ SECTIONS } > RAM __heap_section_start__ = .; - .heap 0x20016000: + .heap 0x2001E000: { . = ALIGN(8); _ebss = .; /* __end__ = .; */ /* PROVIDE(end = .); */ __HeapBase = .; - . += 0x00018000; + . += 0x00010000; __HeapLimit = .; } > RAM __heap_section_end__ = .; diff --git a/zOS/src/zOS.cpp b/zOS/src/zOS.cpp index 7546fd2..c341a51 100644 --- a/zOS/src/zOS.cpp +++ b/zOS/src/zOS.cpp @@ -35,6 +35,8 @@ // which are normally the first port of call for strange behaviour // but it was seen that using them for running the tranzputer service // wasnt really needed as this could be based on a readline idle call. +// Oct 2021 - Extensions to support the MZ-2000 host and the Sharp MZ Series FPGA +// Emulation. // // Notes: See Makefile to enable/disable conditional components // USELOADB - The Byte write command is implemented in hw/sw so use it. @@ -128,8 +130,8 @@ #endif // Version info. -#define VERSION "v1.32" -#define VERSION_DATE "25/07/2021" +#define VERSION "v1.40b" +#define VERSION_DATE "28/10/2021" #define PROGRAM_NAME "zOS" // Utility functions. @@ -301,6 +303,7 @@ void tranZPUterControl(void) // if(getZ80IO(&ioAddr) == 1) { +//printf("Activity on IO:%02x\n", ioAddr); switch(ioAddr) { // Service request. Actual data about the request is stored in the Z80 memory, so read the request and process. @@ -323,6 +326,41 @@ void tranZPUterControl(void) } #endif +// Method to setup access to the SD card. +// +static uint8_t diskInitialised = 0; +static uint8_t fsInitialised = 0; +#if defined(__SD_CARD__) +int setupSDCard(void) +{ + // Local variables. + FRESULT fr = FR_INVALID_DRIVE; + char buf[120]; + + // Initialise the first disk if FS enabled as external commands depend on it. + // + fr = FR_NOT_ENABLED; + if(!disk_initialize(0, 1)) + { + sprintf(buf, "0:"); + fr = f_mount(&G.FatFs[0], buf, 0); + } + + if(fr) + { + printf("Failed to initialise sd card 0, please init manually.\n"); + } else + { + // Indicate disk and filesystem are accessible. + diskInitialised = 1; + fsInitialised = 1; + } + + // Indicate result, FR_OK = SD card setup and ready, all other values SD card not ready. + return(fr); +} +#endif + // Interactive command processor. Allow user to input a command and execute accordingly. // int cmdProcessor(void) @@ -339,8 +377,6 @@ int cmdProcessor(void) uint32_t memAddr; #if defined(__SD_CARD__) char *src1FileName; - uint8_t diskInitialised = 0; - uint8_t fsInitialised = 0; uint8_t trying = 0; uint32_t retCode = 0xffffffff; FRESULT fr; @@ -355,38 +391,6 @@ int cmdProcessor(void) // Initialise any globals in the structure used to pass working variables to apps. G.Sector = 0; - #if defined __TRANZPUTER__ - // Setup the tranZPUter hardware ready for action! - setupTranZPUter(); - #endif - - // Initialise the first disk if FS enabled as external commands depend on it. - #if defined(__SD_CARD__) - fr = FR_NOT_ENABLED; - if(!disk_initialize(0, 1)) - { - sprintf(line, "0:"); - fr = f_mount(&G.FatFs[0], line, 0); - } - - if(fr) - { - printf("Failed to initialise sd card 0, please init manually.\n"); - } else - { - diskInitialised = 1; - fsInitialised = 1; - - #if defined __TRANZPUTER__ - // Setup memory on Z80 to default. - loadTranZPUterDefaultROMS(CPUMODE_SET_Z80); - - // Cache initial directory. - svcCacheDir(TZSVC_DEFAULT_MZF_DIR, MZF, 1); - #endif - } - #endif - while(1) { // Prompt to indicate input required. @@ -917,7 +921,6 @@ int main(int argc, char **argv) // #if defined __K64F__ Serial.begin(9600); - delay(2000); // Give time for the USB Serial Port to connect. // I/O is connected in the _read and_write methods withiin startup file mx20dx128.c. setbuf(stdout, NULL); @@ -938,6 +941,11 @@ int main(int argc, char **argv) #endif + #if defined __TRANZPUTER__ + // Setup the tranZPUter hardware ready for action! + setupTranZPUter(0, VERSION, VERSION_DATE); + #endif + // Setup the configuration using the SoC configuration register if implemented otherwise the compiled internals. setupSoCConfig(); @@ -949,24 +957,50 @@ int main(int argc, char **argv) //TIMER_COUNTER(TIMER1) = 100000; // Timer is prescaled to 100KHz //enableTimer(); - // Indicate life... - // - #if !defined __SHARPMZ__ - printf("Running...\n"); - #endif - - #if !defined __SHARPMZ__ - printf("Enabling interrupts...\n"); - #endif + // Enable interrupts. SetIntHandler(interrupt_handler); + #if defined __ZPU__ //EnableInterrupt(INTR_TIMER | INTR_PS2 | INTR_IOCTL_RD | INTR_IOCTL_WR | INTR_UART0_RX | INTR_UART0_TX | INTR_UART1_RX | INTR_UART1_TX); //EnableInterrupt(INTR_UART0_RX | INTR_UART1_RX); // | INTR_TIMER); #endif - // Intro screen + #if defined(__SD_CARD__) + setupSDCard(); + #endif + + #if defined __TRANZPUTER__ + // If the SD card is present and ready, initialise the tranZPUter logic dependent upon file storage. + if(diskInitialised && fsInitialised) + { + // Setup memory on Z80 to default. + loadTranZPUterDefaultROMS(CPUMODE_SET_Z80); + + // Cache initial directory. + svcCacheDir(TZSVC_DEFAULT_MZF_DIR, MZF, 1); + + //No SD card found so setup tranZPUter accordingly. + setupTranZPUter(1, NULL, NULL); + } else + { + // No SD card found so setup tranZPUter accordingly. + setupTranZPUter(9, NULL, NULL); + } + #endif + + #if defined __K64F__ + // Give time for the USB Serial Port to connect. + delay(2000); + #endif + + // Signon with version information. printVersion(1); + #if defined __TRANZPUTER__ + // Complete tranZPUter setup. + setupTranZPUter(8, NULL, NULL); + #endif + // Command processor. If it exits, then reset the CPU. cmdProcessor();