diff --git a/software/FusionX/bin/k64fcpu b/software/FusionX/bin/k64fcpu index 45e8eb4a3..7b63965d6 100755 Binary files a/software/FusionX/bin/k64fcpu and b/software/FusionX/bin/k64fcpu differ diff --git a/software/FusionX/bin/sharpbiter b/software/FusionX/bin/sharpbiter index 4b327409b..aea89db8e 100755 Binary files a/software/FusionX/bin/sharpbiter and b/software/FusionX/bin/sharpbiter differ diff --git a/software/FusionX/bin/z80ctrl b/software/FusionX/bin/z80ctrl index 8411ef107..b1018d1e9 100755 Binary files a/software/FusionX/bin/z80ctrl and b/software/FusionX/bin/z80ctrl differ diff --git a/software/FusionX/modules/ttymzdrv.ko b/software/FusionX/modules/ttymzdrv.ko index 5d601b906..3ebeb0180 100644 Binary files a/software/FusionX/modules/ttymzdrv.ko and b/software/FusionX/modules/ttymzdrv.ko differ diff --git a/software/FusionX/modules/z80drv.ko b/software/FusionX/modules/z80drv.ko index 92db948b6..585fbde04 100644 Binary files a/software/FusionX/modules/z80drv.ko and b/software/FusionX/modules/z80drv.ko differ diff --git a/software/FusionX/src/ttymz/sharpmz.c b/software/FusionX/src/ttymz/sharpmz.c index f81d46756..4f307df8e 100644 --- a/software/FusionX/src/ttymz/sharpmz.c +++ b/software/FusionX/src/ttymz/sharpmz.c @@ -14,6 +14,7 @@ // History: v1.0 Feb 2023 - Initial write of the Sharp MZ series hardware interface software. // v1.01 Mar 2023 - Bug fixes and additional ESC sequence processing. // v1.02 May 2023 - Updates to accommodate MZ-1500 host. +// v1.2 Jul 2023 - Updates to MZ-1500 to display lower case chars and bug fixes. // // Notes: See Makefile to enable/disable conditional components // @@ -2505,26 +2506,26 @@ uint8_t mzInitMBHardware(void) READ_HARDWARE_INIT(1, MBADDR_SCLDSP); // Hardware scroll needs to be reset. // Disable the hardware sound output. - WRITE_HARDWARE(0, MBADDR_SUNDG, 0x00); // Sound could be enabled on start, disable it. + WRITE_HARDWARE(1, MBADDR_SUNDG, 0x00); // Sound could be enabled on start, disable it. #if (TARGET_HOST_MZ1500 == 1) for(idx=1; idx < 4; idx++) { - WRITE_HARDWARE(0, IO_ADDR_E5, 0x00); // Select the PCG Bank. + WRITE_HARDWARE_IO(1, IO_ADDR_E5, 0x00); // Select the PCG Bank. for(idx2=0xD000; idx2 < 0xF000; idx2++) { - WRITE_HARDWARE(0, idx2, 0x00); // Zero the PCG memory in the bank. + WRITE_HARDWARE(1, idx2, 0x00); // Zero the PCG memory in the bank. } } - WRITE_HARDWARE(0, IO_ADDR_E6, 0x00); // Deselect the PCG Bank. - WRITE_HARDWARE(0, IO_PCG_PRIO, 0x00); // Set text as priority. + WRITE_HARDWARE_IO(1, IO_ADDR_E6, 0x00); // Deselect the PCG Bank. + WRITE_HARDWARE_IO(1, IO_PCG_PRIO, 0x00); // Set text as priority. for(idx=0x11; idx < 0x90; idx+=0x11) { - WRITE_HARDWARE(0, IO_PALETTE, idx); // Setup palettes. + WRITE_HARDWARE_IO(1, IO_PALETTE, idx); // Setup palettes. } - for(idx=0x9F; idx <- 0xFF; idx+=0x20) + for(idx=0x9F; idx <= 0xFF; idx+=0x20) { - WRITE_HARDWARE(0, IO_PSG_BOTH, idx); // Setup PSG. + WRITE_HARDWARE_IO(1, IO_PSG_BOTH, idx); // Setup PSG. } #endif diff --git a/software/FusionX/src/ttymz/sharpmz.h b/software/FusionX/src/ttymz/sharpmz.h index 050c96279..5ab902de5 100755 --- a/software/FusionX/src/ttymz/sharpmz.h +++ b/software/FusionX/src/ttymz/sharpmz.h @@ -14,6 +14,7 @@ // History: v1.0 Feb 2023 - Initial write of the Sharp MZ series hardware interface software. // v1.01 Mar 2023 - Bug fixes and additional ESC sequence processing. // v1.02 May 2023 - Updates to accommodate MZ-1500 host. +// v1.2 Jul 2023 - Fixed MZ-1500 ATB Display of lower case characters. // // Notes: See Makefile to enable/disable conditional components // @@ -369,6 +370,33 @@ } #define READ_KEYB_INIT() READ_HARDWARE_IO_INIT(0, MBADDR_PIOB) #define READ_KEYB() READ_HARDWARE_IO() +#elif (TARGET_HOST_MZ1500 ==1) + #define ENABLE_VIDEO() {} + #define DISABLE_VIDEO() {} + #define WRITE_VRAM_CHAR(__addr__,__data__,__xlat__) if(__xlat__ == 1)\ + {\ + if(islower(__data__))\ + {\ + WRITE_HARDWARE(0,__addr__,(dispCodeMap[(int)(__data__)].dispCode & 0x7F));\ + READ_HARDWARE_INIT(0,(__addr__+0x800));\ + WRITE_HARDWARE(0,(__addr__+0x800),(READ_HARDWARE() | 0x80));\ + } else\ + {\ + WRITE_HARDWARE(0,__addr__,dispCodeMap[(int)(__data__)].dispCode);\ + READ_HARDWARE_INIT(0,(__addr__+0x800));\ + WRITE_HARDWARE(0,(__addr__+0x800),(READ_HARDWARE() & 0x7F));\ + }\ + } else\ + {\ + WRITE_HARDWARE(0,__addr__, __data__);\ + } + #define WRITE_VRAM_ATTRIBUTE(__addr__,__data__) {\ + READ_HARDWARE_INIT(0,(__addr__));\ + WRITE_HARDWARE(0,__addr__,((READ_HARDWARE() & 0x80) | (__data__ & 0x7F)));\ + } + #define WRITE_KEYB_STROBE(__data__) WRITE_HARDWARE(0, MBADDR_KEYPA, __data__) + #define READ_KEYB_INIT() READ_HARDWARE_INIT(0, MBADDR_KEYPB) + #define READ_KEYB() READ_HARDWARE() #else #define ENABLE_VIDEO() {} #define DISABLE_VIDEO() {} diff --git a/software/FusionX/src/ttymz/ttymz.c b/software/FusionX/src/ttymz/ttymz.c index 1694b5a01..344caaf7f 100644 --- a/software/FusionX/src/ttymz/ttymz.c +++ b/software/FusionX/src/ttymz/ttymz.c @@ -19,6 +19,7 @@ // being the TTY will continue to run within the mirrored framebuffer // and when reselected, refresh the hardware screen. // Apr 2023 - v1.1 Updated to include MZ-2000 mode. +// Jul 2023 - v1.2 Updates and bug fixes. // // Notes: See Makefile to enable/disable conditional components // @@ -864,8 +865,8 @@ static int __init ttymz_init(void) mzInit(); // Sign on. - sprintf(buf, "%s %s", DRIVER_DESCRIPTION, DRIVER_VERSION); mzWriteString(0, 0, buf, -1); - sprintf(buf, "%s %s\n", DRIVER_COPYRIGHT, DRIVER_AUTHOR); mzWriteString(0, 1, buf, -1); + sprintf(buf, "%s %s", DRIVER_TITLE, DRIVER_VERSION); mzWriteString(0, 0, buf, -1); + sprintf(buf, "%s %s\n", DRIVER_COPYRIGHT, DRIVER_AUTHOR); mzWriteString(0, 1, buf, -1); pr_info(DRIVER_DESCRIPTION " " DRIVER_VERSION "\n"); diff --git a/software/FusionX/src/ttymz/ttymz.h b/software/FusionX/src/ttymz/ttymz.h index e75488aa6..b433ac60b 100644 --- a/software/FusionX/src/ttymz/ttymz.h +++ b/software/FusionX/src/ttymz/ttymz.h @@ -12,6 +12,7 @@ // // History: Feb 2023 - v1.0 Initial write of the Sharp MZ tty driver software. // Apr 2023 - v1.1 Updated to include MZ-2000 mode. +// Jul 2023 - v1.2 Updates and bug fixes. // // Notes: See Makefile to enable/disable conditional components // @@ -34,15 +35,28 @@ // Constants. #define DRIVER_LICENSE "GPL" -#define DRIVER_AUTHOR "Philip D Smart" +#define DRIVER_AUTHOR "P.D.Smart" #define DRIVER_DESCRIPTION "Sharp MZ TTY Driver" -#define DRIVER_VERSION "v1.1" -#define DRIVER_VERSION_DATE "Apr 2023" -#define DRIVER_COPYRIGHT "(C) 2018-2023" +#define DRIVER_VERSION "v1.2" +#define DRIVER_VERSION_DATE "July 2023" +#define DRIVER_COPYRIGHT "(C) 2018-23" #define DEVICE_NAME "ttymz" #define DRIVER_NAME "SharpMZ_tty" #define DEBUG_ENABLED 0 // 0 = disabled, 1 .. debug level. #define ARBITER_NAME "sharpbiter" +#if (TARGET_HOST_MZ80A == 1) + #define DRIVER_TITLE "Sharp MZ-80A TTY" +#elif (TARGET_HOST_MZ700 == 1) + #define DRIVER_TITLE "Sharp MZ-700 TTY" +#elif (TARGET_HOST_MZ1500 == 1) + #define DRIVER_TITLE "Sharp MZ-1500 TTY" +#elif (TARGET_HOST_MZ2000 == 1) + #define DRIVER_TITLE "Sharp MZ-2000 TTY" +#elif (TARGET_HOST_PCW == 1) + #define DRIVER_TITLE "Amstrad PCW-8XXX TTY" +#else + #define DRIVER_MODEL "not defined" +#endif // Fake UART values #define MCR_DTR 0x01 diff --git a/software/FusionX/src/z80drv/src/z80ctrl.c b/software/FusionX/src/z80drv/src/z80ctrl.c index 16097f023..f800fb94c 100644 --- a/software/FusionX/src/z80drv/src/z80ctrl.c +++ b/software/FusionX/src/z80drv/src/z80ctrl.c @@ -128,7 +128,7 @@ enum CTRL_COMMANDS { static t_Z80Ctrl *Z80Ctrl = NULL; static uint8_t *Z80RAM = NULL; static uint8_t *Z80ROM = NULL; -static uint32_t *Z80PAGE[MEMORY_MODES]; +static uint32_t *Z80PAGE[MEMORY_MODES+MEMORY_SUB_MODES]; static uint8_t memoryPage = 0; // Method to obtain and return the output screen width. @@ -1038,7 +1038,7 @@ int main(int argc, char *argv[]) exit(1); } // Loop through all the memory mapping pages, each page specifies a 64K mapping block, all memory accesses go through this map. - for(idx=0; idx < MEMORY_MODES; idx++) + for(idx=0; idx < MEMORY_MODES+MEMORY_SUB_MODES; idx++) { // Try and bind the page, if it doesnt exist, then the pointer will be NULL so it wont be used. Z80PAGE[idx] = (uint32_t *)mmap(0, ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + (0x1000*(idx+1))), PROT_READ | PROT_WRITE, MAP_SHARED, fdZ80, 0); diff --git a/software/FusionX/src/z80drv/src/z80driver.c b/software/FusionX/src/z80drv/src/z80driver.c index ce8245a05..c9bbe3183 100644 --- a/software/FusionX/src/z80drv/src/z80driver.c +++ b/software/FusionX/src/z80drv/src/z80driver.c @@ -40,6 +40,8 @@ // a vanilla Z80 or customisations for hosts pulled in. // Apr 2023 - v1.4.1 Completed MZ2000 mode to work with arbiter and ttymz. // May 2023 - v1.5 Added MZ1500 modes. +// Jul 2023 - v1.6 Updated MZ-700 code, adding sub-memory maps to increase page mapping +// speed specifically to enable reliable tape read/write. // // // Notes: See Makefile to enable/disable conditional components @@ -478,12 +480,12 @@ static zuint8 z80_read(void *context, zuint16 address) Z_UNUSED(context) // Only read if the address is in physical RAM. - #if(TARGET_HOST_PCW == 0) - if(isPhysical(address)) - #elif(TARGET_HOST_MZ1500 == 1) + #if(TARGET_HOST_MZ1500 == 1) // MZ-1500 take into account PCG being active, always go to hardware when active. Cannot use the map because // this can change during PCG active mode and must be reflected when PCG is deactivated. - if(isPhysicalHW(address) || (Z80Ctrl->pcgMode == 1 && address >= 0xD000)) + if(isPhysical(address) || (Z80Ctrl->pcgMode == 1 && address >= 0xD000)) + #elif(TARGET_HOST_PCW == 0) + if(isPhysical(address)) #else if(isPhysicalHW(address)) #endif @@ -863,7 +865,7 @@ static zuint8 z80_in(void *context, zuint16 port) // Finally ensure the data from the port is ready and retrieve it. while(CPLD_READY() == 0); value = z80io_PRL_Read(); - + #if (TARGET_HOST_MZ2000 == 1) // Keyport data? Store. if((port&0xff) == 0xEA) @@ -1267,10 +1269,10 @@ static int z80drv_mmap(struct file *filp, struct vm_area_struct *vma) } // Another one, as the memory bank page maps are allocated dynamically, need to send a size which indicates which memory block to map. This is done by the size of a memory map // added to it the map slot as 0x1000 per slot. - else if(size >= ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + 0x1000) && size < ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + (MEMORY_MODES * 0x1000))) + else if(size >= ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + 0x1000) && size < ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + ((MEMORY_MODES+MEMORY_SUB_MODES) * 0x1000))) { // Loop through all the memory page slots, if active and the size is in range, then map the memory to user space. - for(idx=0; idx < MEMORY_MODES; idx++) + for(idx=0; idx < MEMORY_MODES+MEMORY_SUB_MODES; idx++) { if(size >= ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + ((idx+1)*0x1000)) && size < ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + ((idx+2) * 0x1000))) { @@ -1665,6 +1667,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) case 2: Z80Ctrl->cpuGovernorDelayROM = ROM_DELAY_X2; Z80Ctrl->cpuGovernorDelayRAM = RAM_DELAY_X2; + pr_info("ROM:%d, RAM:%d\n", Z80Ctrl->cpuGovernorDelayROM, Z80Ctrl->cpuGovernorDelayRAM); break; case 4: @@ -2091,8 +2094,8 @@ static int __init ModuleInit(void) goto initExit; } // Default memory mode is 0, ie. Original. Additional modes may be used by drivers such as the tzpu driver. - Z80Ctrl->memoryMode = 0; - for(idx=0; idx < MEMORY_MODES; idx++) + Z80Ctrl->memoryMode = 0; + for(idx=0; idx < MEMORY_MODES+MEMORY_SUB_MODES; idx++) { (Z80Ctrl->page[idx]) = NULL; } @@ -2202,7 +2205,7 @@ static void __exit ModuleExit(void) } // Return the memory used for the Z80 'virtual memory' and control variables. - for(idx=0; idx < MEMORY_MODES; idx++) + for(idx=0; idx < MEMORY_MODES+MEMORY_SUB_MODES; idx++) { if(Z80Ctrl->page[idx] != NULL) { diff --git a/software/FusionX/src/z80drv/src/z80driver.h b/software/FusionX/src/z80drv/src/z80driver.h index 0051fdf42..94fa9c1aa 100644 --- a/software/FusionX/src/z80drv/src/z80driver.h +++ b/software/FusionX/src/z80drv/src/z80driver.h @@ -17,6 +17,8 @@ // Feb 2023 - v1.2 Added RFS virtual driver. // Apr 2023 - v1.4.1 Completed MZ2000 mode to work with arbiter and ttymz. // May 2023 - v1.5 Added MZ1500 modes. +// Jul 2023 - v1.6 Updated MZ-700 code, adding sub-memory maps to increase page mapping +// speed specifically to enable reliable tape read/write. // // Notes: See Makefile to enable/disable conditional components // @@ -80,8 +82,8 @@ #define DRIVER_LICENSE "GPL" #define DRIVER_AUTHOR "Philip D Smart" #define DRIVER_DESCRIPTION "Z80 CPU Emulator and Hardware Interface Driver" -#define DRIVER_VERSION "v1.5" -#define DRIVER_VERSION_DATE "May 2023" +#define DRIVER_VERSION "v1.6" +#define DRIVER_VERSION_DATE "July 2023" #define DRIVER_COPYRIGHT "(C) 2018-2023" #define Z80_VIRTUAL_ROM_SIZE (65536 * 32) // Sized to maximum Kernel contiguous allocation size, 2M which is 4x512K ROMS. #define Z80_VIRTUAL_RAM_SIZE (65536 * 32) // Sized to maximum Kernel contiguous allocation size, 2M. @@ -166,11 +168,11 @@ #define INSTRUCTION_DELAY_ROM_112MHZ 8 #define INSTRUCTION_DELAY_ROM_224MHZ 4 #define INSTRUCTION_DELAY_ROM_448MHZ 1 - #define INSTRUCTION_DELAY_RAM_3_54MHZ 253 - #define INSTRUCTION_DELAY_RAM_7MHZ 126 - #define INSTRUCTION_DELAY_RAM_14MHZ 63 - #define INSTRUCTION_DELAY_RAM_28MHZ 32 - #define INSTRUCTION_DELAY_RAM_56MHZ 16 + #define INSTRUCTION_DELAY_RAM_3_54MHZ 240 + #define INSTRUCTION_DELAY_RAM_7MHZ 120 + #define INSTRUCTION_DELAY_RAM_14MHZ 60 + #define INSTRUCTION_DELAY_RAM_28MHZ 30 + #define INSTRUCTION_DELAY_RAM_56MHZ 15 #define INSTRUCTION_DELAY_RAM_112MHZ 8 #define INSTRUCTION_DELAY_RAM_224MHZ 4 #define INSTRUCTION_DELAY_RAM_448MHZ 1 @@ -599,6 +601,7 @@ enum Z80_INSTRUCTION_DELAY { // The memory page arrays dont check for allocation due to speed, it is assumed a memory mode page has been allocated and defined prior to the memoryMode // variable being set to that page. #define MEMORY_MODES 32 // Maximum number of different memory modes. +#define MEMORY_SUB_MODES 6 // Number of possible alternate memory maps for a given memory mode. #define MEMORY_PAGE_SIZE 0x10000 // Total size of directly addressable memory. #define MEMORY_BLOCK_GRANULARITY 0x1 // Any change update MEMORY_BLOCK_SHIFT and mask in MEMORY_BLOCK_MASK #define MEMORY_BLOCK_SHIFT 0 @@ -738,10 +741,10 @@ typedef struct { // 16bit Input Address -> map -> Pointer to 24bit memory address + type flag. // -> Pointer+ to 24bit memory address + type flag. //uint32_t page[MEMORY_BLOCK_SLOTS]; - uint32_t *page[MEMORY_MODES]; + uint32_t *page[MEMORY_MODES+MEMORY_SUB_MODES]; uint32_t shadowPage[MEMORY_BLOCK_SLOTS]; // Shadow page is for manipulation and backup of an existing page. - // Current memory mode as used by active driver. + // Current memory modes as used by an active driver. uint8_t memoryMode; // I/O Page map. diff --git a/software/FusionX/src/z80drv/src/z80vhw_mz1500.c b/software/FusionX/src/z80drv/src/z80vhw_mz1500.c index 304764e47..28ddc4b0b 100644 --- a/software/FusionX/src/z80drv/src/z80vhw_mz1500.c +++ b/software/FusionX/src/z80drv/src/z80vhw_mz1500.c @@ -13,6 +13,9 @@ // Copyright: (c) 2019-2023 Philip Smart // // History: May 2023 v1.0 - Initial write based on the MZ700 module. +// Jul 2023 - v1.6 - Updated MZ-700 code, adding sub-memory maps to increase page mapping +// speed specifically to enable reliable tape read/write. Code changes +// reflected in MZ-1500 module. Addition of MZ-1R18 emulation. // // Notes: See Makefile to enable/disable conditional components // @@ -57,6 +60,10 @@ // PCW control. typedef struct { uint8_t regCtrl; // Control register. + uint8_t loDRAMen; // Lower bank 0000:0FFF DRAM enabled, else monitor. + uint8_t hiDRAMen; // Higher bank D000:FFFF DRAM enabled, else memory mapped I/O. + uint32_t *ramFileMem; // 64K RamFile memory. + uint16_t ramFileAddr; // Address pointer of the MZ-1R18 64K Ram File Board memory. } t_MZ1500Ctrl; // RFS Board control. @@ -71,10 +78,14 @@ static t_MZ1500Ctrl MZ1500Ctrl; void mz1500SetupMemory(enum Z80_MEMORY_PROFILE mode) { // Locals. + uint8_t subMode; uint32_t idx; // Setup defaults. - MZ1500Ctrl.regCtrl = 0x00; + MZ1500Ctrl.regCtrl = 0x00; + MZ1500Ctrl.loDRAMen = 0; // Default is monitor ROM is enabled. + MZ1500Ctrl.hiDRAMen = 0; // Default is memory mapped I/O enabled. + Z80Ctrl->inhibitMode = 0; // Setup default mode according to run mode, ie. Physical run or Virtual run. // @@ -146,8 +157,108 @@ void mz1500SetupMemory(enum Z80_MEMORY_PROFILE mode) } for(idx=0x0000; idx < IO_PAGE_SIZE; idx++) { - Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW; + if((idx&0x00ff) == 0xEA || (idx&0x00ff) == 0xEB) + { + Z80Ctrl->iopage[idx] = idx | IO_TYPE_VIRTUAL_HW; + } else + { + Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW; + } } + // Setup sub-memory pages to enable rapid switch according to memory bank commands. + for(subMode=0; subMode < MEMORY_SUB_MODES; subMode++) + { + if(Z80Ctrl->page[MEMORY_MODES+subMode] == NULL) + { + #if(DEBUG_ENABLED & 0x01) + if(Z80Ctrl->debug >=3) pr_info("Allocating memory sub page:%d\n", subMode); + #endif + (Z80Ctrl->page[MEMORY_MODES+subMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL); + if ((Z80Ctrl->page[MEMORY_MODES+subMode]) == NULL) + { + pr_info("z80drv: failed to allocate memory sub mapping page:%d memory!", subMode); + } + } + + // Duplicate current mode into the sub page prior to setting up specific config. + memcpy((uint8_t *)Z80Ctrl->page[MEMORY_MODES+subMode], (uint8_t *)Z80Ctrl->page[0], MEMORY_BLOCK_SLOTS*sizeof(uint32_t)); + Z80Ctrl->memoryMode = MEMORY_MODES + subMode; + + // MZ1500 memory mode switches. + // + // MZ-1500 + // |0000:0FFF|1000:CFFF|D000:FFFF + // ------------------------------ + // OUT 0xE0 = |DRAM |DRAM | + // OUT 0xE1 = | |DRAM |DRAM + // OUT 0xE2 = |MONITOR |DRAM | + // OUT 0xE3 = | |DRAM |Memory Mapped I/O + // OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O + // OUT 0xE5 = | |DRAM |PCG Enable + // OUT 0xE6 = | |DRAM |PCG Disable + // + // Sub-memory page maps: + // + // LOW BANK HIGH BANK PAGE MAP + // DRAM 0 + // DRAM MEMORY MAP 1 + // Inhibit 2 + // DRAM 3 + // MONITOR MEMORY MAP 4 + // Inhibit 5 + // + if(subMode >= 0 && subMode < 3) + { + // Enable lower 4K block as DRAM + for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); + } + } + if(subMode >= 3 && subMode < 6) + { + // Enable lower 4K block as Monitor ROM + for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); + } + } + if(subMode == 0 || subMode == 3) + { + // Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM. + for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + // MZ-700 mode we only work in first 64K block. + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); + } + } + if(subMode == 1 || subMode == 4) + { + // Enable Video RAM and Memory mapped peripherals in upper 12K block. + for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); + } + for(idx=0xE000; idx < 0xE800; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); + } + for(idx=0xE800; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); + } + } + if(subMode == 2 || subMode == 5) + { + // Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it. + for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx); + } + } + } + Z80Ctrl->memoryMode = MEMORY_MODES + 4; + // Enable refresh as using virtual RAM stops refresh of host DRAM. Z80Ctrl->refreshDRAM = 2; } @@ -195,6 +306,17 @@ void mz1500Init(uint8_t mode) // Reset memory paging to default. SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR); + #if(DEBUG_ENABLED & 0x01) + if(Z80Ctrl->debug >=3) pr_info("Allocating MZ-1R18 memory\n"); + #endif + // Allocate memory for the MZ-1R18 64K Ram File board. + MZ1500Ctrl.ramFileMem = (uint32_t *)kmalloc((65536 * sizeof(uint8_t)), GFP_KERNEL); + if(MZ1500Ctrl.ramFileMem == NULL) + { + pr_info("z80drv: failed to allocate MZ-1R18 Ram File memory!"); + } + MZ1500Ctrl.ramFileAddr = 0x0000; + // Initialise the virtual RAM from the HOST DRAM. This is to maintain compatibility as some applications (in my experience) have // bugs, which Im putting down to not initialising variables. The host DRAM is in a pattern of 0x00..0x00, 0xFF..0xFF repeating // when first powered on. @@ -248,17 +370,17 @@ void mz1500Remove(void) static inline void mz1500DecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag) { // Locals. - uint32_t idx; + //uint32_t idx; // Decoding memory address or I/O address? if(ioFlag == 0) { - // #if(DEBUG_ENABLED & 1) - // if(Z80Ctrl->debug >= 2) - // { - // pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); - // } - // #endif + #if(DEBUG_ENABLED & 1) + if(Z80Ctrl->debug >= 3) + { + pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); + } + #endif // Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map. // These updates are made whilst waiting for the CPLD to retrieve the requested byte. // @@ -285,114 +407,119 @@ static inline void mz1500DecodeMemoryMapSetup(zuint16 address, zuint8 data, uint } } else { - // #if(DEBUG_ENABLED & 1) - // if(Z80Ctrl->debug >= 2) - // { - // pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); - // } - // #endif + #if(DEBUG_ENABLED & 1) + if(Z80Ctrl->debug >= 3) + { + pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); + } + #endif - // Determine if this is a memory management port and update the memory page if required. - switch(address & 0x00FF) + // Check to see if the memory mode page has been allocated for requested mode, if it hasnt, we need to allocate and then define. + if(((address&0xFF) - 0xE0) >= 0 && ((address&0xFF) - 0xE0) < 7) { // MZ1500 memory mode switch. - // + // // MZ-1500 // |0000:0FFF|1000:CFFF|D000:FFFF // ------------------------------ - // OUT 0xE0 = |DRAM | | - // OUT 0xE1 = | | |DRAM - // OUT 0xE2 = |MONITOR | | - // OUT 0xE3 = | | |Memory Mapped I/O + // OUT 0xE0 = |DRAM |DRAM | + // OUT 0xE1 = | |DRAM |DRAM + // OUT 0xE2 = |MONITOR |DRAM | + // OUT 0xE3 = | |DRAM |Memory Mapped I/O // OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O - // OUT 0xE5 = | | |PCG Enable - // OUT 0xE6 = | | |PCG Disable - // - // = Return to the state prior to the complimentary command being invoked. - // Enable lower 4K block as DRAM - case IO_ADDR_E0: - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); - } - break; + // OUT 0xE5 = | |DRAM |PCG Enable + // OUT 0xE6 = | |DRAM |PCG Disable + // + // Sub-memory page maps: + // + // LOW BANK HIGH BANK PAGE MAP + // DRAM 0 + // DRAM MEMORY MAP 1 + // Inhibit 2 + // DRAM 3 + // MONITOR MEMORY MAP 4 + // Inhibit 5 + // + // Determine if this is a memory management port and update the memory page if required. + switch(address & 0x00FF) + { + case IO_ADDR_E0: + MZ1500Ctrl.loDRAMen = 1; + break; - // Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM. - case IO_ADDR_E1: - if(!Z80Ctrl->inhibitMode) - { - for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - // MZ-1500 mode we only work in first 64K block. - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); - } - } - break; - - // Enable MOnitor ROM in lower 4K block - case IO_ADDR_E2: - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); - } - break; - - // Enable Video RAM and Memory mapped peripherals in upper 12K block. - case IO_ADDR_E3: - if(!Z80Ctrl->inhibitMode) - { - for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); - } - for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); - } - } - break; + case IO_ADDR_E1: + MZ1500Ctrl.hiDRAMen = 1; + break; - // Reset to power on condition memory map. - case IO_ADDR_E4: - // Lower 4K set to Monitor ROM. - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); - } - if(!Z80Ctrl->inhibitMode) - { - // Upper 12K to hardware. - for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); - } - for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); - } - } - break; + case IO_ADDR_E2: + MZ1500Ctrl.loDRAMen = 0; + break; - // PCG Bank Switching. - // 7 6 5 4 3 2 1 0 - // 0 0 - CGROM - // 0 1 - PCG Blue Plane - // 1 0 - PCG Red Plane - // 1 1 - PCG Green Plane - case IO_ADDR_E5: - // Any PCG access goes to hardware, set flag and access occurs in primary read/write routines. - Z80Ctrl->pcgMode = 1; - break; + case IO_ADDR_E3: + MZ1500Ctrl.hiDRAMen = 0; + break; - // Disable PCG Bank Switching. - case IO_ADDR_E6: - // Disable PCG mode. - Z80Ctrl->pcgMode = 0; - break; + case IO_ADDR_E4: + MZ1500Ctrl.loDRAMen = 0; + MZ1500Ctrl.hiDRAMen = 0; + Z80Ctrl->inhibitMode = 0; + Z80Ctrl->pcgMode = 0; + break; - // Port is not a memory management port. - default: - break; + // PCG Bank Switching. + // 7 6 5 4 3 2 1 0 + // 0 0 - CGROM + // 0 1 - PCG Blue Plane + // 1 0 - PCG Red Plane + // 1 1 - PCG Green Plane + case IO_ADDR_E5: + // Any PCG access goes to hardware, set flag and access occurs in primary read/write routines. + Z80Ctrl->pcgMode = 1; + break; + + // Disable PCG Bank Switching. + case IO_ADDR_E6: + // Disable PCG mode. + Z80Ctrl->pcgMode = 0; + break; + + default: + break; + } + + // Setup memory mode based on flag state. + if(Z80Ctrl->inhibitMode) + { + if(MZ1500Ctrl.loDRAMen) + Z80Ctrl->memoryMode = MEMORY_MODES + 2; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 5; + } else + if(MZ1500Ctrl.loDRAMen) + { + if(MZ1500Ctrl.hiDRAMen && !Z80Ctrl->pcgMode) + Z80Ctrl->memoryMode = MEMORY_MODES + 0; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 1; + } else + { + if(MZ1500Ctrl.hiDRAMen && !Z80Ctrl->pcgMode) + Z80Ctrl->memoryMode = MEMORY_MODES + 3; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 4; + } + Z80Ctrl->governorSkip = 0; + } else + if((address&0xff) >= 0xD8 && (address&0xff) < 0xDF) + { + // Do nothing for the Disk interface. + } else + if((address&0xff) >= 0xF4 && (address&0xff) < 0xF8) + { + Z80Ctrl->governorSkip = 0; + } else + { + // Z80Ctrl->governorSkip = 0; } } } @@ -406,8 +533,18 @@ static inline uint8_t mz1500Read(zuint16 address, uint8_t ioFlag) // I/O Operation? if(ioFlag) { - switch(address) + switch((address&0xff)) { + // MZ-1R18 Ram File Data Register. + case 0xEA: + data = MZ1500Ctrl.ramFileMem[MZ1500Ctrl.ramFileAddr]; + MZ1500Ctrl.ramFileAddr++; + break; + + // MZ-1R18 Ram File Control Register. + case 0xEB: + break; + default: break; } @@ -437,8 +574,19 @@ static inline void mz1500Write(zuint16 address, zuint8 data, uint8_t ioFlag) // I/O Operation? if(ioFlag) { - switch(address) + switch((address&0xff)) { + // MZ-1R18 Ram File Data Register. + case 0xEA: + MZ1500Ctrl.ramFileMem[MZ1500Ctrl.ramFileAddr] = data; + MZ1500Ctrl.ramFileAddr++; + break; + + // MZ-1R18 Ram File Control Register. + case 0xEB: + MZ1500Ctrl.ramFileAddr = (address & 0xff00) | data; + break; + default: break; } diff --git a/software/FusionX/src/z80drv/src/z80vhw_mz700.c b/software/FusionX/src/z80drv/src/z80vhw_mz700.c index 82e385cd9..ee265b431 100644 --- a/software/FusionX/src/z80drv/src/z80vhw_mz700.c +++ b/software/FusionX/src/z80drv/src/z80vhw_mz700.c @@ -12,8 +12,11 @@ // Credits: // Copyright: (c) 2019-2023 Philip Smart // -// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module. -// Apr 2023 v1.1 - Updates from the PCW/MZ2000 changes. +// History: Mar 2023 - v1.0 - Initial write based on the RFS hardware module. +// Apr 2023 - v1.1 - Updates from the PCW/MZ2000 changes. +// Jul 2023 - v1.6 - Updated MZ-700 code, adding sub-memory maps to increase page mapping +// speed specifically to enable reliable tape read/write. Addition of +// MZ-1R18 emulation. // // Notes: See Makefile to enable/disable conditional components // @@ -58,6 +61,10 @@ // PCW control. typedef struct { uint8_t regCtrl; // Control register. + uint8_t loDRAMen; // Lower bank 0000:0FFF DRAM enabled, else monitor. + uint8_t hiDRAMen; // Higher bank D000:FFFF DRAM enabled, else memory mapped I/O. + uint32_t *ramFileMem; // 64K RamFile memory. + uint16_t ramFileAddr; // Address pointer of the MZ-1R18 64K Ram File Board memory. } t_MZ700Ctrl; // RFS Board control. @@ -72,10 +79,14 @@ static t_MZ700Ctrl MZ700Ctrl; void mz700SetupMemory(enum Z80_MEMORY_PROFILE mode) { // Locals. + uint8_t subMode; uint32_t idx; // Setup defaults. - MZ700Ctrl.regCtrl = 0x00; + MZ700Ctrl.regCtrl = 0x00; + MZ700Ctrl.loDRAMen = 0; // Default is monitor ROM is enabled. + MZ700Ctrl.hiDRAMen = 0; // Default is memory mapped I/O enabled. + Z80Ctrl->inhibitMode = 0; // Setup default mode according to run mode, ie. Physical run or Virtual run. // @@ -147,8 +158,108 @@ void mz700SetupMemory(enum Z80_MEMORY_PROFILE mode) } for(idx=0x0000; idx < IO_PAGE_SIZE; idx++) { - Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW; + if((idx&0x00ff) == 0xEA || (idx&0x00ff) == 0xEB) + { + Z80Ctrl->iopage[idx] = idx | IO_TYPE_VIRTUAL_HW; + } else + { + Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW; + } } + // Setup sub-memory pages to enable rapid switch according to memory bank commands. + for(subMode=0; subMode < MEMORY_SUB_MODES; subMode++) + { + if(Z80Ctrl->page[MEMORY_MODES+subMode] == NULL) + { + #if(DEBUG_ENABLED & 0x01) + if(Z80Ctrl->debug >=3) pr_info("Allocating memory sub page:%d\n", subMode); + #endif + (Z80Ctrl->page[MEMORY_MODES+subMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL); + if ((Z80Ctrl->page[MEMORY_MODES+subMode]) == NULL) + { + pr_info("z80drv: failed to allocate memory sub mapping page:%d memory!", subMode); + } + } + + // Duplicate current mode into the sub page prior to setting up specific config. + memcpy((uint8_t *)Z80Ctrl->page[MEMORY_MODES+subMode], (uint8_t *)Z80Ctrl->page[0], MEMORY_BLOCK_SLOTS*sizeof(uint32_t)); + Z80Ctrl->memoryMode = MEMORY_MODES + subMode; + + // MZ700 memory mode switch. + // + // MZ-700 + // |0000:0FFF|1000:CFFF|D000:FFFF + // ------------------------------ + // OUT 0xE0 = |DRAM |DRAM | + // OUT 0xE1 = | |DRAM |DRAM + // OUT 0xE2 = |MONITOR |DRAM | + // OUT 0xE3 = | |DRAM |Memory Mapped I/O + // OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O + // OUT 0xE5 = | |DRAM |Inhibit + // OUT 0xE6 = | |DRAM | + // + // Sub-memory page maps: + // + // LOW BANK HIGH BANK PAGE MAP + // DRAM 0 + // DRAM MEMORY MAP 1 + // Inhibit 2 + // DRAM 3 + // MONITOR MEMORY MAP 4 + // Inhibit 5 + // + if(subMode >= 0 && subMode < 3) + { + // Enable lower 4K block as DRAM + for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); + } + } + if(subMode >= 3 && subMode < 6) + { + // Enable lower 4K block as Monitor ROM + for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); + } + } + if(subMode == 0 || subMode == 3) + { + // Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM. + for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + // MZ-700 mode we only work in first 64K block. + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); + } + } + if(subMode == 1 || subMode == 4) + { + // Enable Video RAM and Memory mapped peripherals in upper 12K block. + for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); + } + for(idx=0xE000; idx < 0xE800; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); + } + for(idx=0xE800; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); + } + } + if(subMode == 2 || subMode == 5) + { + // Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it. + for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx); + } + } + } + Z80Ctrl->memoryMode = MEMORY_MODES + 4; + // Enable refresh as using virtual RAM stops refresh of host DRAM. Z80Ctrl->refreshDRAM = 2; } @@ -196,6 +307,17 @@ void mz700Init(uint8_t mode) // Reset memory paging to default. SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR); + #if(DEBUG_ENABLED & 0x01) + if(Z80Ctrl->debug >=3) pr_info("Allocating MZ-1R18 memory\n"); + #endif + // Allocate memory for the MZ-1R18 64K Ram File board. + MZ700Ctrl.ramFileMem = (uint32_t *)kmalloc((65536 * sizeof(uint8_t)), GFP_KERNEL); + if(MZ700Ctrl.ramFileMem == NULL) + { + pr_info("z80drv: failed to allocate MZ-1R18 Ram File memory!"); + } + MZ700Ctrl.ramFileAddr = 0x0000; + // Initialise the virtual RAM from the HOST DRAM. This is to maintain compatibility as some applications (in my experience) have // bugs, which Im putting down to not initialising variables. The host DRAM is in a pattern of 0x00..0x00, 0xFF..0xFF repeating // when first powered on. @@ -267,17 +389,17 @@ void mz700Remove(void) static inline void mz700DecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag) { // Locals. - uint32_t idx; + //uint32_t idx; // Decoding memory address or I/O address? if(ioFlag == 0) { - // #if(DEBUG_ENABLED & 1) - // if(Z80Ctrl->debug >= 2) - // { - // pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); - // } - // #endif + #if(DEBUG_ENABLED & 1) + if(Z80Ctrl->debug >= 3) + { + pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); + } + #endif // Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map. // These updates are made whilst waiting for the CPLD to retrieve the requested byte. // @@ -304,116 +426,97 @@ static inline void mz700DecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8 } } else { - // #if(DEBUG_ENABLED & 1) - // if(Z80Ctrl->debug >= 2) - // { - // pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); - // } - // #endif + #if(DEBUG_ENABLED & 1) + if(Z80Ctrl->debug >= 3) + { + pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); + } + #endif - // Determine if this is a memory management port and update the memory page if required. - switch(address & 0x00FF) + // Check to see if the memory mode page has been allocated for requested mode, if it hasnt, we need to allocate and then define. + if(((address&0xFF) - 0xE0) >= 0 && ((address&0xFF) - 0xE0) < 7) { // MZ700 memory mode switch. - // + // // MZ-700 // |0000:0FFF|1000:CFFF|D000:FFFF // ------------------------------ - // OUT 0xE0 = |DRAM | | - // OUT 0xE1 = | | |DRAM - // OUT 0xE2 = |MONITOR | | - // OUT 0xE3 = | | |Memory Mapped I/O + // OUT 0xE0 = |DRAM |DRAM | + // OUT 0xE1 = | |DRAM |DRAM + // OUT 0xE2 = |MONITOR |DRAM | + // OUT 0xE3 = | |DRAM |Memory Mapped I/O // OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O - // OUT 0xE5 = | | |Inhibit - // OUT 0xE6 = | | | - // - // = Return to the state prior to the complimentary command being invoked. - // Enable lower 4K block as DRAM - case IO_ADDR_E0: - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); - } - break; + // OUT 0xE5 = | |DRAM |Inhibit + // OUT 0xE6 = | |DRAM | + // + // Sub-memory page maps: + // + // LOW BANK HIGH BANK PAGE MAP + // DRAM 0 + // DRAM MEMORY MAP 1 + // Inhibit 2 + // DRAM 3 + // MONITOR MEMORY MAP 4 + // Inhibit 5 + // + // Determine if this is a memory management port and update the memory page if required. + switch(address & 0x00FF) + { + case IO_ADDR_E0: + MZ700Ctrl.loDRAMen = 1; + break; - // Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM. - case IO_ADDR_E1: - if(!Z80Ctrl->inhibitMode) - { - for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - // MZ-700 mode we only work in first 64K block. - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); - } - } - break; - - // Enable MOnitor ROM in lower 4K block - case IO_ADDR_E2: - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); - } - break; - - // Enable Video RAM and Memory mapped peripherals in upper 12K block. - case IO_ADDR_E3: - if(!Z80Ctrl->inhibitMode) - { - for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); - } - for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); - } - } - break; + case IO_ADDR_E1: + MZ700Ctrl.hiDRAMen = 1; + break; - // Reset to power on condition memory map. - case IO_ADDR_E4: - // Lower 4K set to Monitor ROM. - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); - } - if(!Z80Ctrl->inhibitMode) - { - // Upper 12K to hardware. - for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); - } - for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); - } - } - break; + case IO_ADDR_E2: + MZ700Ctrl.loDRAMen = 0; + break; - // Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it. - case IO_ADDR_E5: - for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - backupMemoryType(idx/MEMORY_BLOCK_GRANULARITY); - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx); - } - Z80Ctrl->inhibitMode = 1; - break; + case IO_ADDR_E3: + MZ700Ctrl.hiDRAMen = 0; + break; - // Restore D000-FFFF to its original state. - case IO_ADDR_E6: - for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - restoreMemoryType(idx/MEMORY_BLOCK_GRANULARITY); - } - Z80Ctrl->inhibitMode = 0; - break; + case IO_ADDR_E4: + MZ700Ctrl.loDRAMen = 0; + MZ700Ctrl.hiDRAMen = 0; + Z80Ctrl->inhibitMode = 0; + break; - // Port is not a memory management port. - default: - break; + case IO_ADDR_E5: + Z80Ctrl->inhibitMode = 1; + break; + + case IO_ADDR_E6: + Z80Ctrl->inhibitMode = 0; + break; + + default: + break; + } + + // Setup memory mode based on flag state. + if(Z80Ctrl->inhibitMode) + { + if(MZ700Ctrl.loDRAMen) + Z80Ctrl->memoryMode = MEMORY_MODES + 2; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 5; + } else + if(MZ700Ctrl.loDRAMen) + { + if(MZ700Ctrl.hiDRAMen) + Z80Ctrl->memoryMode = MEMORY_MODES + 0; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 1; + } else + { + if(MZ700Ctrl.hiDRAMen) + Z80Ctrl->memoryMode = MEMORY_MODES + 3; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 4; + } } } } @@ -427,8 +530,18 @@ static inline uint8_t mz700Read(zuint16 address, uint8_t ioFlag) // I/O Operation? if(ioFlag) { - switch(address) + switch((address&0xff)) { + // MZ-1R18 Ram File Data Register. + case 0xEA: + data = MZ700Ctrl.ramFileMem[MZ700Ctrl.ramFileAddr]; + MZ700Ctrl.ramFileAddr++; + break; + + // MZ-1R18 Ram File Control Register. + case 0xEB: + break; + default: break; } @@ -458,8 +571,19 @@ static inline void mz700Write(zuint16 address, zuint8 data, uint8_t ioFlag) // I/O Operation? if(ioFlag) { - switch(address) + switch((address&0xff)) { + // MZ-1R18 Ram File Data Register. + case 0xEA: + MZ700Ctrl.ramFileMem[MZ700Ctrl.ramFileAddr] = data; + MZ700Ctrl.ramFileAddr++; + break; + + // MZ-1R18 Ram File Control Register. + case 0xEB: + MZ700Ctrl.ramFileAddr = (address & 0xff00) | data; + break; + default: break; } diff --git a/software/FusionX/src/z80drv/src/z80vhw_rfs.c b/software/FusionX/src/z80drv/src/z80vhw_rfs.c index 8239e2300..7de7ad4ae 100644 --- a/software/FusionX/src/z80drv/src/z80vhw_rfs.c +++ b/software/FusionX/src/z80drv/src/z80vhw_rfs.c @@ -121,7 +121,7 @@ // SD Drive constants. #define SD_DIR "/apps/FusionX/host/MZ-80A/RFS/" -#define SD_CARD_FILENAME SD_DIR "SHARP_MZ80A_RFS_CPM_IMAGE_1.img"// SD Card Binary Image. +#define SD_CARD_FILENAME SD_DIR "SHARP_MZ80A_RFS_CPM_IMAGE_1.img" // SD Card Binary Image. // MMC/SD command (SPI mode) #define CMD0 0x40 + 0 // GO_IDLE_STATE diff --git a/software/FusionX/src/z80drv/src/z80vhw_tzpu.c b/software/FusionX/src/z80drv/src/z80vhw_tzpu.c index 490220d64..597b99ca1 100644 --- a/software/FusionX/src/z80drv/src/z80vhw_tzpu.c +++ b/software/FusionX/src/z80drv/src/z80vhw_tzpu.c @@ -16,8 +16,11 @@ // Credits: // Copyright: (c) 2019-2023 Philip Smart // -// History: Feb 2023 v1.0 - Initial write based on the tranZPUter SW hardware. -// Apr 2023 v1.1 - Updates & bug fixes. +// History: Feb 2023 - v1.0 - Initial write based on the tranZPUter SW hardware. +// Apr 2023 - v1.1 - Updates & bug fixes. +// Jul 2023 - v1.6 - Updated MZ-700 code, adding sub-memory maps to increase page mapping +// speed specifically to enable reliable tape read/write. + // // Notes: See Makefile to enable/disable conditional components // @@ -68,6 +71,8 @@ typedef struct { uint8_t regCpuInfo; // Internal FPGA CPU information register. uint8_t regCpldCfg; // Internal CPLD config register. uint8_t regCpldInfo; // Internal CPLD information register. + uint8_t loDRAMen; // Lower bank 0000:0FFF DRAM enabled, else monitor. + uint8_t hiDRAMen; // Higher bank D000:FFFF DRAM enabled, else memory mapped I/O. } t_TZPUCtrl; // TZPU Board control. @@ -147,7 +152,9 @@ void tzpuSetupMemory(enum Z80_MEMORY_PROFILE mode) #if(TARGET_HOST_MZ2000 == 1) TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ2000; #endif - TZPUCtrl.regCpldCfg = 0x00; // Not used, as no CPLD available, but need to store/return value if addressed. + TZPUCtrl.regCpldCfg = 0x00; // Not used, as no CPLD available, but need to store/return value if addressed. + TZPUCtrl.loDRAMen = 0; // Default is monitor ROM is enabled. + TZPUCtrl.hiDRAMen = 0; // Default is memory mapped I/O enabled. // Default memory mode, TZFS. Z80Ctrl->memoryMode = TZMM_TZFS; @@ -246,7 +253,7 @@ void tzpuRemove(void) uint32_t idx; // Go through and clear all memory maps, leave the original page in slot 0. - for(idx=1; idx < MEMORY_MODES; idx++) + for(idx=1; idx < MEMORY_MODES+MEMORY_SUB_MODES; idx++) { if(Z80Ctrl->page[idx] != NULL) { @@ -267,17 +274,18 @@ void tzpuRemove(void) static inline void tzpuDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag) { // Locals. - uint32_t idx; + //uint32_t idx; // I/O or Memory? if(ioFlag == 0) { - // #if(DEBUG_ENABLED & 1) - // if(Z80Ctrl->debug >= 2) - // { - // pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); - // } - // #endif + #if(DEBUG_ENABLED & 1) + if(Z80Ctrl->debug >= 3) + { + pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); + } + #endif + // Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map. // These updates are made whilst waiting for the CPLD to retrieve the requested byte. // @@ -305,116 +313,87 @@ static inline void tzpuDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_ } else // I/O Decoding. { - // #if(DEBUG_ENABLED & 1) - // if(Z80Ctrl->debug >= 2) - // { - // pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); - // } - // #endif - - // Determine if this is a memory management port and update the memory page if required. - switch(address & 0x00FF) + #if(DEBUG_ENABLED & 1) + if(Z80Ctrl->debug >= 3) + { + pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag); + } + #endif + + // Check to see if the memory mode page has been allocated for requested mode, if it hasnt, we need to allocate and then define. + if(((address&0xFF) - 0xE0) >= 0 && ((address&0xFF) - 0xE0) < MEMORY_SUB_MODES) { // MZ700 memory mode switch. - // + // // MZ-700 // |0000:0FFF|1000:CFFF|D000:FFFF // ------------------------------ - // OUT 0xE0 = |DRAM | | - // OUT 0xE1 = | | |DRAM - // OUT 0xE2 = |MONITOR | | - // OUT 0xE3 = | | |Memory Mapped I/O + // OUT 0xE0 = |DRAM |DRAM | + // OUT 0xE1 = | |DRAM |DRAM + // OUT 0xE2 = |MONITOR |DRAM | + // OUT 0xE3 = | |DRAM |Memory Mapped I/O // OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O - // OUT 0xE5 = | | |Inhibit - // OUT 0xE6 = | | | - // - // = Return to the state prior to the complimentary command being invoked. - // Enable lower 4K block as DRAM - case IO_ADDR_E0: - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); - } - break; + // OUT 0xE5 = | |DRAM |Inhibit + // OUT 0xE6 = | |DRAM | + // + // Determine if this is a memory management port and update the memory page if required. + switch(address & 0x00FF) + { + case IO_ADDR_E0: + TZPUCtrl.loDRAMen = 1; + break; - // Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM. - case IO_ADDR_E1: - if(!Z80Ctrl->inhibitMode) - { - for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - // MZ-700 mode we only work in first 64K block. - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); - } - } - break; - - // Enable MOnitor ROM in lower 4K block - case IO_ADDR_E2: - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); - } - break; - - // Enable Video RAM and Memory mapped peripherals in upper 12K block. - case IO_ADDR_E3: - if(!Z80Ctrl->inhibitMode) - { - for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); - } - for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); - } - } - break; + case IO_ADDR_E1: + TZPUCtrl.hiDRAMen = 1; + break; - // Reset to power on condition memory map. - case IO_ADDR_E4: - // Lower 4K set to Monitor ROM. - for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx); - } - if(!Z80Ctrl->inhibitMode) - { - // Upper 12K to hardware. - for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); - } - for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); - } - } - break; + case IO_ADDR_E2: + TZPUCtrl.loDRAMen = 0; + break; - // Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it. - case IO_ADDR_E5: - for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - backupMemoryType(idx/MEMORY_BLOCK_GRANULARITY); - setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx); - } - Z80Ctrl->inhibitMode = 1; - break; + case IO_ADDR_E3: + TZPUCtrl.hiDRAMen = 0; + break; - // Restore D000-FFFF to its original state. - case IO_ADDR_E6: - for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) - { - restoreMemoryType(idx/MEMORY_BLOCK_GRANULARITY); - } - Z80Ctrl->inhibitMode = 0; - break; + case IO_ADDR_E4: + TZPUCtrl.loDRAMen = 0; + TZPUCtrl.hiDRAMen = 0; + Z80Ctrl->inhibitMode = 0; + break; - // Port is not a memory management port. - default: - break; + case IO_ADDR_E5: + Z80Ctrl->inhibitMode = 1; + break; + + case IO_ADDR_E6: + Z80Ctrl->inhibitMode = 0; + break; + + default: + break; + } + + // Setup memory mode based on flag state. + if(Z80Ctrl->inhibitMode) + { + if(TZPUCtrl.loDRAMen) + Z80Ctrl->memoryMode = MEMORY_MODES + 2; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 5; + } else + if(TZPUCtrl.loDRAMen) + { + if(TZPUCtrl.hiDRAMen) + Z80Ctrl->memoryMode = MEMORY_MODES + 0; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 1; + } else + { + if(TZPUCtrl.hiDRAMen) + Z80Ctrl->memoryMode = MEMORY_MODES + 3; + else + Z80Ctrl->memoryMode = MEMORY_MODES + 4; + } } } } @@ -493,6 +472,7 @@ static inline uint8_t tzpuRead(zuint16 address, uint8_t ioFlag) static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag) { // Locals + uint8_t subMode; uint32_t idx; // The tranZPUter board, in order to autoboot and use valuable space for variables, allows writing into the User ROM @@ -925,6 +905,95 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag) } } // Memory map now created/switched. + + // Allocate/populate the sub-memory maps for this mode. TZFS currently uses sub-memory modes for MZ-700 page banking. + if(Z80Ctrl->memoryMode == TZMM_TZFS) + { + for(subMode=0; subMode < MEMORY_SUB_MODES; subMode++) + { + if(Z80Ctrl->page[MEMORY_MODES+subMode] == NULL) + { + #if(DEBUG_ENABLED & 0x01) + if(Z80Ctrl->debug >=3) pr_info("Allocating memory sub page:%d\n", subMode); + #endif +pr_info("Allocating memory sub page:%d,%d\n", subMode, (MEMORY_BLOCK_SLOTS*sizeof(uint32_t))); + (Z80Ctrl->page[MEMORY_MODES+subMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL); + if ((Z80Ctrl->page[MEMORY_MODES+subMode]) == NULL) + { + pr_info("z80drv: failed to allocate memory sub mapping page:%d memory!", subMode); + } + } + + // Duplicate current mode into the sub page prior to setting up specific config. + memcpy((uint8_t *)Z80Ctrl->page[MEMORY_MODES+subMode], (uint8_t *)Z80Ctrl->page[(data & (MEMORY_MODES - 1))], MEMORY_BLOCK_SLOTS*sizeof(uint32_t)); + Z80Ctrl->memoryMode = MEMORY_MODES + subMode; + TZPUCtrl.loDRAMen = 0; + TZPUCtrl.hiDRAMen = 0; + Z80Ctrl->inhibitMode = 0; + + // MZ700 memory mode switch. + // + // MZ-700 + // |0000:0FFF|1000:CFFF|D000:FFFF + // ------------------------------ + // OUT 0xE0 = |DRAM |DRAM | + // OUT 0xE1 = | |DRAM |DRAM + // OUT 0xE2 = |MONITOR |DRAM | + // OUT 0xE3 = | |DRAM |Memory Mapped I/O + // OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O + // OUT 0xE5 = | |DRAM |Inhibit + // OUT 0xE6 = | |DRAM | + // + // Sub-memory page maps: + // + // LOW BANK HIGH BANK PAGE MAP + // DRAM 0 + // DRAM MEMORY MAP 1 + // Inhibit 2 + // DRAM 3 + // MONITOR MEMORY MAP 4 + // Inhibit 5 + // + if(subMode >= 0 && subMode < 3) + { + // Enable lower 4K block as DRAM + for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); + } + } + if(subMode == 0 || subMode == 3) + { + // Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM. + for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + // MZ-700 mode we only work in first 64K block. + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); + } + } + if(subMode == 1 || subMode == 4) + { + // Enable Video RAM and Memory mapped peripherals in upper 12K block. + for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx); + } + for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx); + } + } + if(subMode == 2 || subMode == 5) + { + // Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it. + for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx); + } + } + } + } + Z80Ctrl->memoryMode = (data & (MEMORY_MODES - 1)); break; case IO_TZ_SETXMHZ: diff --git a/software/asm/sa1510.asm b/software/asm/sa1510.asm index 759f95778..b9c780192 100644 --- a/software/asm/sa1510.asm +++ b/software/asm/sa1510.asm @@ -42,10 +42,14 @@ START: LD SP,STACK CALL ?CLER ; Clear 256 bytes from NAME 10F1h to 11F0h LD A,016H CALL PRNT - IF MODE80C = 0 - LD A,007H ; Black background, white characters. Bit 7 is clear as a write to bit 7 @ DFFFH selects 40Char mode. + IF KUMA = 1 + LD A,0CFH ELSE - LD A,017H ; Blue background, white characters in colour mode. Bit 7 is set as a write to bit 7 @ DFFFH selects 80Char mode. + IF MODE80C = 0 + LD A,007H ; Black background, white characters. Bit 7 is clear as a write to bit 7 @ DFFFH selects 40Char mode. + ELSE + LD A,017H ; Blue background, white characters in colour mode. Bit 7 is set as a write to bit 7 @ DFFFH selects 80Char mode. + ENDIF ENDIF LD HL,ARAM JR STRT1 @@ -130,13 +134,19 @@ LOAD: CALL ?RDI JR C,ST1 JP (HL) + ; LOADING MSG?2: DB 04CH, 0B7H, 0A1H, 09CH DB 0A6H, 0B0H, 097H, 020H DB 00DH - ; SIGN ON BANNER -MSG?3: DB "** MONITOR SA-1510 **", 0DH + ; SIGN ON BANNER - Different for Kuma 80 BIOS +MSG?3: IF KUMA = 0 + DB "** MONITOR SA-1510 **", 0DH + ELSE + DB "*K",0A5H,0B3H,0A1H," MZ-80A M",0B7H,0B0H,0A6H + DB 096H,0B7H,09DH,"*",00DH,"*",00DH + ENDIF ; For 80 Character mode we need some space, so shorten the Check Sum Error message. ; @@ -148,7 +158,7 @@ MSGE1: IF MODE80C = 0 DB "CK SUM?", 0DH ENDIF - ; Hook = 7 bytes. + ; Hook = 7 bytes using space taken from Check Sum message. HOOK: IF MODE80C = 1 LD A,0FFH LD (SPAGE),A @@ -156,27 +166,56 @@ HOOK: IF MODE80C = 1 ENDIF ; CR PAGE MODE1 -.CR: CALL .MANG - RRCA - JP NC,CURS2 - LD L,000H - INC H - CP ROW - 1 ; End of line? - JR Z,.CP1 - INC H - JP CURS1 +.CR: IF KUMA = 1 + LD HL,(DSPXY) + JP CURS2 + ELSE + CALL .MANG + RRCA + JP NC,CURS2 + LD L,000H + INC H + CP ROW - 1 ; End of line? + JR Z,.CP1 + INC H + JP CURS1 + ENDIF +.CR1: IF KUMA = 1 + NEG + LD (SPAGE),A + ADD A,004H + LD (KEYPF),A + RET + DB 00EH + ENDIF .CP1: LD (DSPXY),HL ; SCROLLER -.SCROL: LD BC,SCRNSZ - COLW ; Scroll COLW -1 lines +.SCROL: IF KUMA = 1 + LD BC, 0780H + ELSE + LD BC,SCRNSZ - COLW ; Scroll COLW -1 lines + ENDIF LD DE,SCRN ; Start of the screen. - LD HL,SCRN + COLW ; Start of screen + 1 line. + IF KUMA = 1 + LD HL,0D050H + ELSE + LD HL,SCRN + COLW ; Start of screen + 1 line. + ENDIF LDIR EX DE,HL - LD B,COLW ; Clear last line at bottom of screen. + IF KUMA = 1 + LD B, 050H + ELSE + LD B,COLW ; Clear last line at bottom of screen. + ENDIF CALL ?CLER - LD BC,0001AH + IF KUMA = 1 + JP ?RSTR + ELSE + LD BC,0001AH + ENDIF LD DE,MANG LD HL,MANG + 1 LDIR @@ -587,22 +626,46 @@ TIMIN: PUSH AF EI RET -.DSP03: EX DE,HL - LD (HL),001H - INC HL - LD (HL),000H - JP CURSR -.MANG2: LD A,(DSPXY + 1) - ADD A,L - LD L,A - LD A,(HL) - INC HL - RL (HL) - OR (HL) - RR (HL) - RRCA - EX DE,HL - LD HL,(DSPXY) +.DSP03: IF KUMA = 1 + LD A,(SPAGE) + OR A + LD A,027H + RET Z + ADD A,A + INC A + RET + +L03A7: PUSH BC + CALL .DSP03 + LD B,A + LD A,L + CP B + POP BC + RET + +L03B0: CALL .DSP03 + LD L,A + XOR A + DEC H + RET + ELSE + EX DE,HL + LD (HL),001H + INC HL + LD (HL),000H + JP CURSR +.MANG2: LD A,(DSPXY + 1) + ADD A,L + LD L,A + LD A,(HL) + INC HL + RL (HL) + OR (HL) + RR (HL) + RRCA + EX DE,HL + LD HL,(DSPXY) + ENDIF RET LD C,H @@ -1141,7 +1204,11 @@ L0743: DEC H ?MODE: LD HL,KEYPF LD (HL),08AH LD (HL),007H - LD (HL),005H + IF KUMA = 1 + LD (HL),004H + ELSE + LD (HL),005H + ENDIF LD (HL),001H RET @@ -1270,7 +1337,11 @@ CHGPA: XOR A JR CHGPK1 ENDIF CHGPK: LD A,0FFH -CHGPK1: LD (SPAGE),A +CHGPK1: IF KUMA = 1 + CALL .CR1 + ELSE + LD (SPAGE),A + ENDIF LD A,0C6H CALL ?DPCT CHGP1: JP GETL0 @@ -1581,7 +1652,12 @@ REV2: JP ?RSTR .MANG: LD HL,MANG LD A,(SPAGE) OR A - JP NZ,.MANG2 + IF KUMA = 1 + JR NZ,.MANG1 ; (+018H) + NOP + ELSE + JP NZ,.MANG2 + ENDIF LD A,(MGPNT) .MANG3: SUB 008H INC HL @@ -2407,14 +2483,24 @@ DLY12A: CALL DLY3 CALL ?PONT LD (HL),B LD HL,(DSPXY) - LD A,L -DSP01: CP COLW - 1 ; End of line. + IF KUMA = 1 + CALL L03A7 + ELSE + LD A,L + ENDIF +DSP01: IF KUMA = 0 + CP COLW - 1 ; End of line. + ENDIF JR NZ,DSP04 CALL .MANG JR C,DSP04 LD A,(SPAGE) OR A - JP NZ,.DSP03 + IF KUMA + JP NZ,CURSR + ELSE + JP NZ,.DSP03 + ENDIF EX DE,HL LD A,B CP 007H @@ -2535,8 +2621,12 @@ CURSU1: CALL MGP.D JR CURS3 CURSR: LD HL,(DSPXY) - LD A,L - CP COLW - 1 ; End of line + IF KUMA = 1 + CALL L03A7 + ELSE + LD A,L + CP COLW - 1 ; End of line + ENDIF JR NC,CURS2 INC L JR CURS3 @@ -2555,8 +2645,12 @@ CURSL: LD HL,(DSPXY) JR Z,CURS5A DEC L JR CURS3 -CURS5A: LD L,COLW - 1 ; End of line - DEC H +CURS5A: IF KUMA = 1 + CALL L03B0 + ELSE + LD L,COLW - 1 ; End of line + DEC H + ENDIF JP P,CURSU1 LD H,000H LD (DSPXY),HL @@ -2643,13 +2737,24 @@ INST: CALL .MANG RRCA LD L,COLW - 1 ; End of line LD A,L - JR NC,INST1A - INC H -INST1A: CALL ?PNT1 - PUSH HL - LD HL,(DSPXY) - JR NC,INST2 - LD A,(COLW*2)-1 ; 04FH + IF KUMA = 1 + JR NC,INST1B + LD A,028H + ADD A,L + LD L,A +INST1B: CALL ?PNT1 + PUSH HL + LD HL,(DSPXY) + NOP + ELSE + JR NC,INST1A + INC H +INST1A: CALL ?PNT1 + PUSH HL + LD HL,(DSPXY) + JR NC,INST2 + LD A,(COLW*2)-1 ; 04FH + ENDIF INST2: SUB L LD B,A POP DE @@ -2720,16 +2825,30 @@ ROLU1: CALL MGP.I PUSH HL POP BC LD DE,COLW - LD HL,SCRN - COLW - LD A,(SPAGE) - OR A - JR NZ,?PNT2 - LD HL,(PAGETP) - SBC HL,DE -?PNT2: ADD HL,DE - DEC B - JP P,?PNT2 - LD B,000H + IF KUMA = 1 + LD HL,(PAGETP) + INC B + LD A,(SPAGE) + OR A + JR Z,L0FCE ; (+008H) + LD HL,0D000H + LD E,050H + JR L0FCE ; (+001H) +L0FCD: ADD HL,DE +L0FCE: DJNZ L0FCD ; (-003H) + NOP + ELSE + LD HL,SCRN - COLW + LD A,(SPAGE) + OR A + JR NZ,?PNT2 + LD HL,(PAGETP) + SBC HL,DE +?PNT2: ADD HL,DE + DEC B + JP P,?PNT2 + LD B,000H + ENDIF ADD HL,BC RES 3,H POP DE