diff --git a/software/FusionX/etc/startZ80_TZFS.sh b/software/FusionX/etc/startZ80_TZFS.sh index 28c3a5297..5b13915be 100755 --- a/software/FusionX/etc/startZ80_TZFS.sh +++ b/software/FusionX/etc/startZ80_TZFS.sh @@ -51,4 +51,4 @@ echo performance > /sys/devices//system/cpu/cpufreq/policy0/scaling_governor echo 1200000 > /sys/devices//system/cpu/cpufreq/policy0/scaling_min_freq # Done. -echo "FusionX loaded and configured in RFS mode." +echo "FusionX loaded and configured in TZFS mode." diff --git a/software/FusionX/src/driver/MZ80A/k64fcpu.c b/software/FusionX/src/driver/MZ80A/k64fcpu.c index 903aec32a..ea8fc9f90 100644 --- a/software/FusionX/src/driver/MZ80A/k64fcpu.c +++ b/software/FusionX/src/driver/MZ80A/k64fcpu.c @@ -19,6 +19,7 @@ // // History: Feb 2023 v1.0 - Source copied from zSoft and modified to run as a daemon, stripping // out all low level control methods. +// v1.01 - Updates to make compatible with the TZFS changes. // // Notes: See Makefile to enable/disable conditional components // @@ -64,7 +65,7 @@ extern "C" { #include "z80driver.h" #include "tzpu.h" -#define VERSION "1.0" +#define VERSION "1.01" #define AUTHOR "P.D.Smart" #define COPYRIGHT "(c) 2018-23" @@ -596,7 +597,7 @@ FRESULT loadZ80Memory(const char *src, uint32_t fileOffset, uint32_t addr, uint3 fr0 = (fseek(File, fileOffset, SEEK_SET) != -1) ? FR_OK : FR_DISK_ERR; #if(DEBUG_ENABLED & 0x02) - if(Z80Ctrl->debug & 0x02) printf("Loading file(%s,%08lx,%08lx)\n", src, addr, size); + if(Z80Ctrl->debug >= 2) printf("Loading file(%s,%08lx,%08lx)\n", src, addr, size); #endif // If no errors in opening the file, proceed with reading and loading into memory. @@ -2223,7 +2224,7 @@ uint8_t svcWriteCPMDrive(void) if(!result) { #if(DEBUG_ENABLED & 0x02) - if(Z80Ctrl->debug & 0x02) + if(Z80Ctrl->debug >= 3) { printf("Writing offset=%08lx\n", fileOffset); for(uint16_t idx=0; idx < TZSVC_SECTOR_SIZE; idx++) @@ -2359,7 +2360,7 @@ uint8_t loadBIOS(const char *biosFileName, uint32_t loadAddr) { // Locals. uint8_t result = FR_OK; - + // Load up the given BIOS into tranZPUter memory. if((result=loadZ80Memory(biosFileName, 0, loadAddr, 0, 0, TRANZPUTER)) != FR_OK) { @@ -2397,9 +2398,13 @@ FRESULT loadTZFS(char *biosFile, uint32_t loadAddr) { printf("Error: Failed to load page 3 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); } - if(!result && (result=loadZ80Memory((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_TZFS, 0x3800, MZ_BANKRAM_ADDR+0x30000, 0x1000, 0, TRANZPUTER) != FR_OK)) + if(!result && (result=loadZ80Memory((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_TZFS, 0x3800, MZ_FULLRAM_START_ADDR+0x30000, MZ_FULLRAM_SIZE, 0, TRANZPUTER) != FR_OK)) { - printf("Error: Failed to load page 4 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); + printf("Error: Failed to load page 4/1 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); + } + if(!result && (result=loadZ80Memory((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_TZFS, 0x3800+MZ_FULLRAM_SIZE, MZ_BANKRAM_ADDR+0x30000, 0x1000, 0, TRANZPUTER) != FR_OK)) + { + printf("Error: Failed to load page 4/2 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); } return(result); } @@ -2431,7 +2436,7 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) if(!result) { #if(DEBUG_ENABLED & 0x2) - if(Z80Ctrl->debug & 0x02) printf("Loading 1Z_013B\n"); + if(Z80Ctrl->debug >= 2) printf("Loading 1Z_013B\n"); #endif //result = loadBIOS(MZ_ROM_1Z_013B, MZ800, MZ_800_MROM_ADDR); @@ -2446,7 +2451,7 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) if(!result) { #if(DEBUG_ENABLED & 0x2) - if(Z80Ctrl->debug & 0x02) printf("Loading 9Z_504M\n"); + if(Z80Ctrl->debug >= 2) printf("Loading 9Z_504M\n"); #endif result = loadBIOS(MZ_ROM_9Z_504M, MZ_800_IPL_ADDR); } @@ -2455,7 +2460,7 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) if(!result) { #if(DEBUG_ENABLED & 0x2) - if(Z80Ctrl->debug & 0x02) printf("Loading BASIC IOCS\n"); + if(Z80Ctrl->debug >= 2) printf("Loading BASIC IOCS\n"); #endif result = loadBIOS(MZ_ROM_800_IOCS, MZ_800_IOCS_ADDR); } @@ -2469,7 +2474,7 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig) case HW_MZ2000: // Load up the IPL BIOS at least try even if the CGROM failed. #if(DEBUG_ENABLED & 0x2) - if(Z80Ctrl->debug & 0x02) printf("Loading IPL\n"); + if(Z80Ctrl->debug >= 2) printf("Loading IPL\n"); #endif result = loadBIOS(MZ_ROM_MZ2000_IPL_TZPU, MZ_MROM_ADDR); if(result != FR_OK) @@ -2622,7 +2627,7 @@ void processServiceRequest(void) // Load the 40 column version of the default host bios into memory. case TZSVC_CMD_LOAD40ABIOS: - loadBIOS(MZ_ROM_SA1510_40C, MZ_MROM_ADDR); + loadBIOS((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_SA1510_40C, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. if(z80Control.hostType != HW_MZ80A) @@ -2634,7 +2639,7 @@ void processServiceRequest(void) // Load the 80 column version of the default host bios into memory. case TZSVC_CMD_LOAD80ABIOS: - loadBIOS(MZ_ROM_SA1510_80C, MZ_MROM_ADDR); + loadBIOS((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_SA1510_80C, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. if(z80Control.hostType != HW_MZ80A) @@ -2646,7 +2651,7 @@ 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, MZ_MROM_ADDR); + loadBIOS((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_1Z_013A_40C, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. if(z80Control.hostType != HW_MZ700) @@ -2658,7 +2663,7 @@ 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, MZ_MROM_ADDR); + loadBIOS((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_1Z_013A_80C, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. if(z80Control.hostType != HW_MZ700) @@ -2670,7 +2675,7 @@ void processServiceRequest(void) // Load the MZ800 9Z-504M bios into memory for compatibility switch. case TZSVC_CMD_LOAD800BIOS: - loadBIOS(MZ_ROM_9Z_504M, MZ_MROM_ADDR); + loadBIOS((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_9Z_504M, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. if(z80Control.hostType != HW_MZ800) @@ -2682,7 +2687,7 @@ void processServiceRequest(void) // Load the MZ-80B IPL ROM into memory for compatibility switch. case TZSVC_CMD_LOAD80BIPL: - loadBIOS(MZ_ROM_MZ80B_IPL, MZ_MROM_ADDR); + loadBIOS((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_MZ80B_IPL, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. if(z80Control.hostType != HW_MZ80B) @@ -2694,7 +2699,7 @@ void processServiceRequest(void) // Load the MZ-2000 IPL ROM into memory for compatibility switch. case TZSVC_CMD_LOAD2000IPL: - loadBIOS(MZ_ROM_MZ2000_IPL, MZ_MROM_ADDR); + loadBIOS((const char *)OS_BASE_DIR TZSVC_DEFAULT_TZFS_DIR "/" MZ_ROM_MZ2000_IPL, MZ_MROM_ADDR); // Set the frequency of the CPU if we are emulating the hardware. if(z80Control.hostType != HW_MZ2000) diff --git a/software/FusionX/src/driver/MZ80A/tzpu.h b/software/FusionX/src/driver/MZ80A/tzpu.h index e84191f44..9859b7c0b 100755 --- a/software/FusionX/src/driver/MZ80A/tzpu.h +++ b/software/FusionX/src/driver/MZ80A/tzpu.h @@ -286,6 +286,10 @@ #define MZ_MROM_STACK_ADDR 0x01000 // Monitor ROM start stack address. #define MZ_MROM_STACK_SIZE 0x000EF // Monitor ROM stack size. #define MZ_UROM_ADDR 0x0E800 // User ROM start address. + +#define MZ_FULLRAM_START_ADDR 0x01200 // Start of full memory area available for bank switching. +#define MZ_FULLRAM_SIZE 0xD000 - 0x1200 // Size of full memory area. + #define MZ_BANKRAM_ADDR 0x0F000 // Floppy API address which is used in TZFS as the paged RAM for additional functionality. #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. diff --git a/software/FusionX/src/driver/MZ80A/z80ctrl.c b/software/FusionX/src/driver/MZ80A/z80ctrl.c index c50fafb64..5c33ada5f 100644 --- a/software/FusionX/src/driver/MZ80A/z80ctrl.c +++ b/software/FusionX/src/driver/MZ80A/z80ctrl.c @@ -124,9 +124,11 @@ enum CTRL_COMMANDS { // Shared memory between this process and the Z80 driver. -static t_Z80Ctrl *Z80Ctrl = NULL; -static uint8_t *Z80RAM = NULL; -static uint8_t *Z80ROM = NULL; +static t_Z80Ctrl *Z80Ctrl = NULL; +static uint8_t *Z80RAM = NULL; +static uint8_t *Z80ROM = NULL; +static uint32_t *Z80PAGE[MEMORY_MODES]; +static uint8_t memoryPage = 0; // Method to obtain and return the output screen width. // @@ -211,6 +213,13 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryType, uint32_t if(memoryType == 0) return(-1); + // Make sure the memory page is valid if we are dumping them out. + if(memoryType == 3 && Z80PAGE[memoryPage] == NULL) + { + printf("Page %d is not allocated.\n", memoryPage); + return(-1); + } + // Reconfigure terminal to allow non-blocking key input. // set_conio_terminal_mode(); @@ -245,7 +254,10 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryType, uint32_t { case 16: if(pnt+i < endAddr) - printf("%04X", memoryType == 1 ? (uint16_t)Z80RAM[pnt+i] : memoryType == 2 ? (uint16_t)Z80ROM[pnt+i] : memoryType == 3 ? (uint16_t)*(*(Z80Ctrl->page + Z80Ctrl->memoryMode) + (pnt+i)) : (uint16_t)Z80Ctrl->iopage[pnt+i]); + printf("%04X", memoryType == 1 ? (uint16_t)Z80RAM[pnt+i] : + memoryType == 2 ? (uint16_t)Z80ROM[pnt+i] : + memoryType == 3 ? (uint16_t)*(*(Z80PAGE + memoryPage) + (pnt+i)) : + (uint16_t)Z80Ctrl->iopage[pnt+i]); else printf(" "); i++; @@ -253,7 +265,10 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryType, uint32_t case 32: if(pnt+i < endAddr) - printf("%08lX", memoryType == 1 ? (uint32_t)Z80RAM[pnt+i] : memoryType == 2 ? (uint32_t)Z80ROM[pnt+i] : memoryType == 3 ? (uint32_t)*(*(Z80Ctrl->page + Z80Ctrl->memoryMode) + (pnt+i)) : (uint32_t)Z80Ctrl->iopage[pnt+i]); + printf("%08lX", memoryType == 1 ? (uint32_t)Z80RAM[pnt+i] : + memoryType == 2 ? (uint32_t)Z80ROM[pnt+i] : + memoryType == 3 ? (uint32_t)*(*(Z80PAGE + memoryPage) + (pnt+i)) : + (uint32_t)Z80Ctrl->iopage[pnt+i]); else printf(" "); i++; @@ -262,7 +277,10 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryType, uint32_t case 8: default: if(pnt+i < endAddr) - printf("%02X", memoryType == 1 ? (uint8_t)Z80RAM[pnt+i] : memoryType == 2 ? (uint8_t)Z80ROM[pnt+i] : memoryType == 3 ? (uint8_t)*(*(Z80Ctrl->page + Z80Ctrl->memoryMode) + (pnt+i)) : (uint8_t)Z80Ctrl->iopage[pnt+i]); + printf("%02X", memoryType == 1 ? (uint8_t)Z80RAM[pnt+i] : + memoryType == 2 ? (uint8_t)Z80ROM[pnt+i] : + memoryType == 3 ? (uint8_t)*(*(Z80PAGE + memoryPage) + (pnt+i)) : + (uint8_t)Z80Ctrl->iopage[pnt+i]); else printf(" "); i++; @@ -277,7 +295,9 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryType, uint32_t // print single ascii char for (i=0; i < displayWidth; i++) { - c = memoryType == 1 ? (char)Z80RAM[pnt+i] : memoryType == 2 ? (char)Z80ROM[pnt+i] : memoryType == 3 ? (char)*(*(Z80Ctrl->page + Z80Ctrl->memoryMode) + (pnt+i)) : (char)Z80Ctrl->iopage[pnt+i]; + c = memoryType == 1 ? (char)Z80RAM[pnt+i] : memoryType == 2 ? (char)Z80ROM[pnt+i] : + memoryType == 3 ? (char)*(*(Z80PAGE + (uint32_t)memoryPage) + (pnt+i)) : + (char)Z80Ctrl->iopage[pnt+i]; if ((pnt+i < endAddr) && (c >= ' ') && (c <= '~')) fputc((char)c, stdout); else @@ -721,10 +741,10 @@ void showArgs(char *progName, struct optparse *options) printf(" # Load contents of binary file into memory at address. default = 0x000000.\n"); printf(" = LOADMEM --file --addr <24 bit addr> --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM> [--offset --len ]\n"); printf(" = SAVE --file --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = PageTable, 4 = IOPageTable>\n"); - printf(" = DUMP --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = PageTable, 4 = IOPageTable>\n"); + printf(" = DUMP --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = MemoryPageTable, 4 = IOPageTable> [--memorypage <0..31>]\n"); printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n"); #if(DEBUG_ENABLED != 0) - printf(" = DEBUG --level # 0 = off, 1 = driver, 2 = k64f, 3 = both.\n"); + printf(" = DEBUG --level # 0 = off, 1..15 debug level, 15 is very verbose.\n"); #endif printf(" = Z80TEST # Perform various debugging tests\n"); printf(" = SPITEST # Perform SPI testing\n"); @@ -741,6 +761,7 @@ int main(int argc, char *argv[]) char cmd[64] = { 0 }; char fileName[256] = { 0 }; char devName[32] = { 0 }; + int idx; int opt; uint32_t hexData = 0; long speedMultiplier = 1; @@ -771,6 +792,7 @@ int main(int argc, char *argv[]) {"device", 'D', OPTPARSE_REQUIRED}, {"offset", 'O', OPTPARSE_REQUIRED}, {"len", 'L', OPTPARSE_REQUIRED}, + {"memorypage", 'm', OPTPARSE_REQUIRED}, #if(DEBUG_ENABLED != 0) {"level", 'l', OPTPARSE_REQUIRED}, #endif @@ -847,9 +869,15 @@ int main(int argc, char *argv[]) memoryType = atoi(options.optarg); break; + // Memory Page - which page, in the page table, to view. + case 'm': + memoryPage = atoi(options.optarg); + //printf("Memory Page:%02x\n", memoryPage); + break; + #if(DEBUG_ENABLED != 0) - // Debug level, 0 = off, 1 = driver, 2 = k64f, 3 = both. - case 'E': + // Debug level, 0 = off, 1..15 debug level, 15 is very verbose. + case 'l': debugLevel = atoi(options.optarg); break; #endif @@ -959,6 +987,13 @@ int main(int argc, char *argv[]) close(fdZ80); 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++) + { + // 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); + if(Z80PAGE[idx] == (void *)-1) Z80PAGE[idx] = NULL; + } } else { printf("Failed to open the Z80 Driver, exiting...\n"); @@ -1029,7 +1064,7 @@ int main(int argc, char *argv[]) #if(DEBUG_ENABLED != 0) if(strcasecmp(cmd, "DEBUG") == 0) { - ctrlCmd(fdZ80, Z80_CMD_DEBUG, debugLevel, 0, 0); + ctrlCmd(fdZ80, Z80_CMD_DEBUG, (long)debugLevel, 0, 0); } else #endif diff --git a/software/FusionX/src/driver/MZ80A/z80driver.c b/software/FusionX/src/driver/MZ80A/z80driver.c index d57f29c8d..8af67dd0a 100644 --- a/software/FusionX/src/driver/MZ80A/z80driver.c +++ b/software/FusionX/src/driver/MZ80A/z80driver.c @@ -553,7 +553,7 @@ static zuint8 z80_read(void *context, zuint16 address) Z80Ctrl->keyportHotKey = 0x01; } #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) + if(Z80Ctrl->debug >= 3) { pr_info("Read:%04x,%02x,%d\n", address, data, CPLD_Z80_INT()); } @@ -601,7 +601,7 @@ static void z80_write(void *context, zuint16 address, zuint8 data) writeVirtual(address, data, 0); } #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) + if(Z80Ctrl->debug >= 3) { pr_info("Write:%04x,%02x,%d\n", address, data, CPLD_Z80_INT()); } @@ -663,10 +663,16 @@ static zuint8 z80_fetch_opcode(void *context, zuint16 address) lookAhead(address, opcode, isVirtualROM((address+1)) ? readVirtualROM((address+1)) : readVirtualRAM((address+1))); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) + if(Z80Ctrl->debug >= 3) { if(address < 0xF036 || address > 0xF197) pr_info("Fetch:%04x,%02x,%d\n", address, opcode, CPLD_Z80_INT()); + + // If max level, add delay so that the kernel log doesnt overflow. + if(Z80Ctrl->debug >= 15) + { + udelay(2000); + } } //if(address >= 0xE800) pr_info("Fetch:%04x,%02x\n", address, opcode); #endif @@ -712,7 +718,7 @@ static zuint8 z80_fetch(void *context, zuint16 address) z80_int(&Z80CPU, CPLD_Z80_INT() != 0); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) + if(Z80Ctrl->debug >= 4) { if(address < 0xF036 || address > 0xF197) pr_info("FetchB:%04x,%02x,%d\n", address, data, CPLD_Z80_INT()); @@ -755,7 +761,7 @@ static zuint8 z80_in(void *context, zuint16 port) } #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("z80_in:0x%x, 0x%x\n", port, value); + if(Z80Ctrl->debug >= 3) pr_info("z80_in:0x%x, 0x%x\n", port, value); #endif return(value); } @@ -794,7 +800,7 @@ static void z80_out(void *context, zuint16 port, zuint8 value) } #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("z80_out:0x%x, 0x%x\n", port, value); + if(Z80Ctrl->debug >= 3) pr_info("z80_out:0x%x, 0x%x\n", port, value); #endif } @@ -870,7 +876,7 @@ static void z80_reti(void *context) if(CPLD_Z80_INT() != 0) { #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) + if(Z80Ctrl->debug >= 2) { pr_info("LOCKUP:%d\n", CPLD_Z80_INT()); } @@ -878,7 +884,7 @@ static void z80_reti(void *context) z80_int(&Z80CPU, false); } #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("z80_reti\n"); + if(Z80Ctrl->debug >= 3) pr_info("z80_reti\n"); #endif } static void z80_retn(void *context) @@ -923,8 +929,6 @@ int thread_z80(void * thread_nr) if(CPLD_RESET()) { resetZ80(); - //z80_instant_reset(&Z80CPU); - //setupMemory(Z80Ctrl->defaultPageMode); // Wait for release before restarting CPU. while(CPLD_RESET()); @@ -1028,6 +1032,7 @@ out: static int z80drv_mmap(struct file *filp, struct vm_area_struct *vma) { // Locals. + int idx; int ret = 0; struct page *page = NULL; unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start); @@ -1064,6 +1069,32 @@ static int z80drv_mmap(struct file *filp, struct vm_area_struct *vma) goto out; } } + // 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))) + { + // 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++) + { + if(size >= ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + ((idx+1)*0x1000)) && size < ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + ((idx+2) * 0x1000))) + { + // Map the memory if allocated and exit. + if(Z80Ctrl->page[idx] != NULL) + { + page = virt_to_page((unsigned long)Z80Ctrl->page[idx] + (vma->vm_pgoff << PAGE_SHIFT)); + ret = remap_pfn_range(vma, vma->vm_start, page_to_pfn(page), size, vma->vm_page_prot); + if (ret != 0) + { + goto out; + } + } else + { + ret = -EINVAL; + goto out; + } + } + } + } else { ret = -EINVAL; @@ -1323,6 +1354,10 @@ void setupMemory(enum Z80_MEMORY_PROFILE mode) { setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx); } + else if(idx >= 0x1000 && idx < 0xD000) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx); + } else if(idx >= 0xD000 && idx < 0xE000) { setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_VRAM, idx); @@ -1389,7 +1424,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) else { #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("IOCTL - Command (%08x)\n", ioctlCmd.cmd); + if(Z80Ctrl->debug >=3) pr_info("IOCTL - Command (%08x)\n", ioctlCmd.cmd); #endif switch(ioctlCmd.cmd) { @@ -1402,7 +1437,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) z80_power(&Z80CPU, FALSE); Z80_PC(Z80CPU) = 0; #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("Z80 stopped.\n"); + if(Z80Ctrl->debug >= 3) pr_info("Z80 stopped.\n"); #endif break; @@ -1412,7 +1447,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) z80_power(&Z80CPU, TRUE); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("Z80 started.\n"); + if(Z80Ctrl->debug >= 3) pr_info("Z80 started.\n"); #endif break; @@ -1420,7 +1455,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) case IOCTL_CMD_Z80_PAUSE: mutex_lock(&Z80RunModeMutex); Z80RunMode = Z80_PAUSE; mutex_unlock(&Z80RunModeMutex); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("Z80 paused.\n"); + if(Z80Ctrl->debug >= 3) pr_info("Z80 paused.\n"); #endif break; @@ -1428,7 +1463,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) case IOCTL_CMD_Z80_CONTINUE: mutex_lock(&Z80RunModeMutex); Z80RunMode = Z80_CONTINUE; mutex_unlock(&Z80RunModeMutex); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("Z80 running.\n"); + if(Z80Ctrl->debug >= 3) pr_info("Z80 running.\n"); #endif break; @@ -1443,7 +1478,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_lock(&Z80RunModeMutex); Z80RunMode = currentRunMode; mutex_unlock(&Z80RunModeMutex); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("Z80 Reset.\n"); + if(Z80Ctrl->debug >= 3) pr_info("Z80 Reset.\n"); #endif break; @@ -1459,7 +1494,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_lock(&Z80RunModeMutex); Z80RunMode = currentRunMode; mutex_unlock(&Z80RunModeMutex); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("Z80 Set to use Host Memory.\n"); + if(Z80Ctrl->debug >= 3) pr_info("Z80 Set to use Host Memory.\n"); #endif break; @@ -1478,7 +1513,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_lock(&Z80RunModeMutex); Z80RunMode = currentRunMode; mutex_unlock(&Z80RunModeMutex); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("Z80 Set to use Virtual Memory.\n"); + if(Z80Ctrl->debug >= 3) pr_info("Z80 Set to use Virtual Memory.\n"); #endif break; @@ -1497,7 +1532,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_lock(&Z80RunModeMutex); Z80RunMode = currentRunMode; mutex_unlock(&Z80RunModeMutex); #if(DEBUG_ENABLED & 1) - if(Z80Ctrl->debug & 0x01) pr_info("Z80 Host DRAM syncd with Virtual Memory.\n"); + if(Z80Ctrl->debug >= 3) pr_info("Z80 Host DRAM syncd with Virtual Memory.\n"); #endif break; @@ -1706,6 +1741,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg) // Method to turn on/off debug output. case IOCTL_CMD_DEBUG: Z80Ctrl->debug = ioctlCmd.debug.level; + pr_info("Debug level set to:%d\n", Z80Ctrl->debug); break; #endif @@ -2014,6 +2050,11 @@ static int __init ModuleInit(void) Z80_PC(Z80CPU) = 0; z80_power(&Z80CPU, TRUE); + // Initialise Debug logic if compile time enabled. + #if(DEBUG_ENABLED != 0) + Z80Ctrl->debug = 0; + #endif + // Init done. pr_info("Initialisation complete.\n"); diff --git a/software/FusionX/src/driver/MZ80A/z80driver.h b/software/FusionX/src/driver/MZ80A/z80driver.h index 54abfb44e..44e3abe46 100644 --- a/software/FusionX/src/driver/MZ80A/z80driver.h +++ b/software/FusionX/src/driver/MZ80A/z80driver.h @@ -53,7 +53,7 @@ #define DEVICE_NAME "z80drv" #define CLASS_NAME "mogu" #define IO_PROCESSOR_NAME "k64fcpu" // Name of the I/O processor user space application. -#define DEBUG_ENABLED 1 +#define DEBUG_ENABLED 0 // 0 = disabled, 1 = z80driver, 2 = k64fcpu, 3 = both. // Memory and IO page types. Used to create a memory page which maps type of address space to real address space on host or virtual memory. #define MEMORY_TYPE_VIRTUAL_MASK 0x00FFFFFF @@ -71,6 +71,23 @@ #define IO_TYPE_PHYSICAL_HW 0x80000000 #define IO_TYPE_VIRTUAL_HW 0x40000000 +//********************************************************************************************* +// Delay periods for the various hosts, which need adding to the primary opcode fetch in +// order to govern the virtual Z80 to a known speed. The timings are only used within +// virtual memory, if an opcode is being fetched from physical memory will self govern to the +// host speed. +// NB. As of v1.0 FusionX hardware, unless a method is forthcoming due to the low speed of the +// SSD202 CPU GPIO access (72MHz bus speed, 1x72MHz per bit, in theory 2.2M 32bit words per +// second, in practice 2MBytes per second! This is a shortcoming of the SSD202 CPU, others, +// such as the NXP K64FX512 Cortex-M4 has 32bit registers where a single access can write +// /read/toggle/clear 32bits and the bus is operating at 85MHz! If SigmaStar release an updated +// CPU, or another compatible system becomes available, v1.1 of the FusionX hardware will be +// created in order to allow full speed program execution within host memory. +// NBB: Actual Z80 transactions run at full speed, it is just the period from completion +// of 1 cycle to the next taking too much time in the SSD202 to setup. Workarounds using +// lookahead and queue techniques have been adopted to ensure I/O timing for things such as +// floppy drives functions as per the original host. +//********************************************************************************************* // Approximate governor delays to regulate emulated CPU speed. // MZ-700 @@ -184,23 +201,47 @@ enum Z80_INSTRUCTION_DELAY { #endif // MZ-80A - These values are dependent on the CPU Freq of the SSD202. Values are for 1.2GHz, in brackets for 1.0GHz +// The reason for having 2 sets of delays is due to original coding where ROM memory required less instructions +// than RAM. Also depending upon build slight differences need to be catered for, ie. when including debug logic +// there are extra instructions to process during the fetch cycle. #if(TARGET_HOST_MZ80A == 1) -#define INSTRUCTION_DELAY_ROM_2MHZ 436 // (420) -#define INSTRUCTION_DELAY_ROM_4MHZ 218 -#define INSTRUCTION_DELAY_ROM_8MHZ 109 -#define INSTRUCTION_DELAY_ROM_16MHZ 54 -#define INSTRUCTION_DELAY_ROM_32MHZ 27 -#define INSTRUCTION_DELAY_ROM_64MHZ 14 -#define INSTRUCTION_DELAY_ROM_128MHZ 7 -#define INSTRUCTION_DELAY_ROM_256MHZ 3 -#define INSTRUCTION_DELAY_RAM_2MHZ 420 -#define INSTRUCTION_DELAY_RAM_4MHZ 210 -#define INSTRUCTION_DELAY_RAM_8MHZ 105 -#define INSTRUCTION_DELAY_RAM_16MHZ 52 -#define INSTRUCTION_DELAY_RAM_32MHZ 26 -#define INSTRUCTION_DELAY_RAM_64MHZ 13 -#define INSTRUCTION_DELAY_RAM_128MHZ 7 -#define INSTRUCTION_DELAY_RAM_256MHZ 0 + +#if(DEBUG_ENABLED > 0) + #define INSTRUCTION_DELAY_ROM_2MHZ 427 // (420) + #define INSTRUCTION_DELAY_ROM_4MHZ 218 + #define INSTRUCTION_DELAY_ROM_8MHZ 109 + #define INSTRUCTION_DELAY_ROM_16MHZ 54 + #define INSTRUCTION_DELAY_ROM_32MHZ 27 + #define INSTRUCTION_DELAY_ROM_64MHZ 14 + #define INSTRUCTION_DELAY_ROM_128MHZ 7 + #define INSTRUCTION_DELAY_ROM_256MHZ 3 + #define INSTRUCTION_DELAY_RAM_2MHZ 425 + #define INSTRUCTION_DELAY_RAM_4MHZ 212 + #define INSTRUCTION_DELAY_RAM_8MHZ 106 + #define INSTRUCTION_DELAY_RAM_16MHZ 53 + #define INSTRUCTION_DELAY_RAM_32MHZ 26 + #define INSTRUCTION_DELAY_RAM_64MHZ 13 + #define INSTRUCTION_DELAY_RAM_128MHZ 7 + #define INSTRUCTION_DELAY_RAM_256MHZ 0 +#endif +#if(DEBUG_ENABLED == 0) + #define INSTRUCTION_DELAY_ROM_2MHZ 429 // (420) + #define INSTRUCTION_DELAY_ROM_4MHZ 218 + #define INSTRUCTION_DELAY_ROM_8MHZ 109 + #define INSTRUCTION_DELAY_ROM_16MHZ 54 + #define INSTRUCTION_DELAY_ROM_32MHZ 27 + #define INSTRUCTION_DELAY_ROM_64MHZ 14 + #define INSTRUCTION_DELAY_ROM_128MHZ 7 + #define INSTRUCTION_DELAY_ROM_256MHZ 3 + #define INSTRUCTION_DELAY_RAM_2MHZ 425 + #define INSTRUCTION_DELAY_RAM_4MHZ 210 + #define INSTRUCTION_DELAY_RAM_8MHZ 105 + #define INSTRUCTION_DELAY_RAM_16MHZ 52 + #define INSTRUCTION_DELAY_RAM_32MHZ 26 + #define INSTRUCTION_DELAY_RAM_64MHZ 13 + #define INSTRUCTION_DELAY_RAM_128MHZ 7 + #define INSTRUCTION_DELAY_RAM_256MHZ 0 +#endif #define INSTRUCTION_EQUIV_FREQ_2MHZ 2000000 #define INSTRUCTION_EQUIV_FREQ_4MHZ 4000000 #define INSTRUCTION_EQUIV_FREQ_8MHZ 8000000 @@ -210,6 +251,7 @@ enum Z80_INSTRUCTION_DELAY { #define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000 #define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000 +// Table of governor delays to be used to control run frequency, enum Z80_INSTRUCTION_DELAY { ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_2MHZ, ROM_DELAY_X2 = INSTRUCTION_DELAY_ROM_4MHZ, @@ -495,7 +537,7 @@ typedef struct { // An I/O processor, running as a User Space daemon, can register to receive signals and events. struct task_struct *ioTask; - #if(DEBUG_ENABLED == 1) + #if(DEBUG_ENABLED != 0) // Debugging flag. uint8_t debug; #endif @@ -520,7 +562,7 @@ struct virtual_device { struct cpld_ctrl { uint32_t cmd; }; -#if(DEBUG_ENABLED == 1) +#if(DEBUG_ENABLED != 0) struct debug { uint8_t level; }; @@ -533,7 +575,7 @@ struct ioctlCmd { struct speed speed; struct virtual_device vdev; struct cpld_ctrl cpld; - #if(DEBUG_ENABLED == 1) + #if(DEBUG_ENABLED != 0) struct debug debug; #endif }; diff --git a/software/FusionX/src/driver/MZ80A/z80vhw_rfs.c b/software/FusionX/src/driver/MZ80A/z80vhw_rfs.c index 906cfd579..592fdb6db 100644 --- a/software/FusionX/src/driver/MZ80A/z80vhw_rfs.c +++ b/software/FusionX/src/driver/MZ80A/z80vhw_rfs.c @@ -185,7 +185,7 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode) // Setup the initial state of the latch up-counter, used to enable access to the programmable registers. RFSCtrl.upCntr = ((RFSCtrl.regCtrl & 0x20) >> 2) | ((RFSCtrl.regCtrl & 0x10) >> 2) | ((RFSCtrl.regCtrl & 0x08) >> 2); - // Initialise the page pointers and memory to use physical RAM. + // Initialise the page pointers and memory to reflect an MZ-80A with an RFS board installed. for(idx=0x0000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY) { if(idx >= 0x0000 && idx < 0x1000) diff --git a/software/FusionX/src/driver/MZ80A/z80vhw_tzpu.c b/software/FusionX/src/driver/MZ80A/z80vhw_tzpu.c index cce2af527..ecc665967 100644 --- a/software/FusionX/src/driver/MZ80A/z80vhw_tzpu.c +++ b/software/FusionX/src/driver/MZ80A/z80vhw_tzpu.c @@ -167,7 +167,7 @@ static inline uint8_t tzpuRead(zuint16 address, uint8_t ioFlag) if(ioFlag) { #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("Read IO:%02x\n", address); + if(Z80Ctrl->debug >= 3) pr_info("Read IO:%02x\n", address); #endif // Only the lower 8 bits of the I/O address are processed as the upper byte is not used in the Sharp models. @@ -252,7 +252,7 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag) if(Z80Ctrl->page[Z80Ctrl->memoryMode] == NULL) { #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("Allocating memory page:%d\n", Z80Ctrl->memoryMode); + if(Z80Ctrl->debug >=3) pr_info("Allocating memory page:%d\n", Z80Ctrl->memoryMode); #endif (Z80Ctrl->page[Z80Ctrl->memoryMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL); if ((Z80Ctrl->page[Z80Ctrl->memoryMode]) == NULL) @@ -425,10 +425,14 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag) { setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM_RO, (SRAM_BANK0_ADDR+idx)); } - else if(idx >= 0x1000 && idx < 0xD000) + else if(idx >= 0x1000 && idx < 0x1200) { setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (SRAM_BANK0_ADDR+idx)); } + else if(idx >= 0x1200 && idx < 0xD000) + { + setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (SRAM_BANK3_ADDR+idx)); + } else if(idx >= 0xD000 && idx < 0xE000) { setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, (SRAM_BANK0_ADDR+idx)); @@ -655,27 +659,27 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag) case IO_TZ_SETXMHZ: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("SETXMHZ:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("SETXMHZ:%02x\n", data); #endif TZPUCtrl.clkSrc = 1; break; case IO_TZ_SET2MHZ: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("SET2MHZ:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("SET2MHZ:%02x\n", data); #endif TZPUCtrl.clkSrc = 0; break; case IO_TZ_CLKSELRD: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("CKSELRD:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("CKSELRD:%02x\n", data); #endif break; case IO_TZ_SVCREQ: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("SVCREQ:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("SVCREQ:%02x\n", data); #endif // If a k64f process has registered, send it a service request signal. @@ -696,32 +700,32 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag) case IO_TZ_SYSREQ: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("SYSREQ:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("SYSREQ:%02x\n", data); #endif break; case IO_TZ_CPLDCMD: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("CPLDCMD:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("CPLDCMD:%02x\n", data); #endif TZPUCtrl.regCmd = data; break; case IO_TZ_CPUINFO: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("CPUINFO:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("CPUINFO:%02x\n", data); #endif break; case IO_TZ_CPLDCFG: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("CPLDCFG:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("CPLDCFG:%02x\n", data); #endif break; case IO_TZ_CPLDINFO: #if(DEBUG_ENABLED & 0x01) - if(Z80Ctrl->debug & 0x01) pr_info("CPLDINFO:%02x\n", data); + if(Z80Ctrl->debug >= 3) pr_info("CPLDINFO:%02x\n", data); #endif break;