diff --git a/common/tranzputer.c b/common/tranzputer.c index f4a34ec..bf52e94 100644 --- a/common/tranzputer.c +++ b/common/tranzputer.c @@ -382,7 +382,7 @@ static void restoreIRQ(void) // The OS millisecond counter address is passed into this library to gain access to time without the penalty of procedure calls. // Time is used for timeouts and seriously affects pulse width of signals when procedure calls are made. // -void setupZ80Pins(uint8_t initTeensy, volatile uint32_t *millisecondTick) +void setupZ80Pins(uint8_t initK64F, volatile uint32_t *millisecondTick) { // Locals. // @@ -393,7 +393,7 @@ void setupZ80Pins(uint8_t initTeensy, volatile uint32_t *millisecondTick) // if(firstCall == 1) { - if(initTeensy) + if(initK64F) _init_Teensyduino_internal_(); // Setup the pointer to the millisecond tick value updated by K64F interrupt. @@ -543,7 +543,7 @@ void resetZ80(void) // __disable_irq(); pinOutputSet(Z80_RESET, LOW); - for(volatile uint32_t pulseWidth=0; pulseWidth < 200; pulseWidth++); + for(volatile uint32_t pulseWidth=0; pulseWidth < DEFAULT_RESET_PULSE_WIDTH; pulseWidth++); pinHigh(Z80_RESET); pinInput(Z80_RESET); __enable_irq(); @@ -617,7 +617,7 @@ uint8_t reqMainboardBus(uint32_t timeout) pinLow(Z80_RD); pinLow(Z80_WR); - // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. + // On a K64F running at 120MHz this delay gives a pulsewidth of 760nS. for(volatile uint32_t pulseWidth=0; pulseWidth < 1; pulseWidth++); // Immediately return the RD/WR to HIGH to complete the ENABLE_BUS latch action. @@ -794,7 +794,7 @@ uint8_t writeZ80Memory(uint16_t addr, uint8_t data) // Start the write cycle, MREQ and WR go low. pinLow(Z80_WR); - // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. + // On a K64F running at 120MHz this delay gives a pulsewidth of 760nS. for(volatile uint32_t pulseWidth=0; pulseWidth < 4; pulseWidth++); // Another wait loop check as the Z80 can assert wait at the time of Write or anytime before it is deasserted. @@ -804,7 +804,7 @@ uint8_t writeZ80Memory(uint16_t addr, uint8_t data) // Start the write cycle, MREQ and WR go low. pinLow(Z80_WR); - // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. + // On a K64F running at 120MHz this delay gives a pulsewidth of 760nS. // 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++); } @@ -855,7 +855,7 @@ uint8_t readZ80Memory(uint16_t addr) // if(z80Control.ctrlMode == MAINBOARD_ACCESS) { - // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. This gives time for the addressed device to present the data + // 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 < 4; pulseWidth++); @@ -910,7 +910,7 @@ uint8_t writeZ80IO(uint16_t addr, uint8_t data) // Start the write cycle, MREQ and WR go low. pinLow(Z80_WR); - // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. + // On a K64F running at 120MHz this delay gives a pulsewidth of 760nS. for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); // Another wait loop check as the Z80 can assert wait at the time of Write or anytime before it is deasserted. @@ -953,12 +953,16 @@ uint8_t readZ80IO(uint16_t addr) // if(z80Control.ctrlMode == MAINBOARD_ACCESS) { - // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. This gives time for the addressed device to present the data + // 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++); + for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); // 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); + } else + { + // With the tranZPUter SW v2 boards, need to increase the read pulse width as the latch is synchronous, alternatively wait until a positive edge on the CPU clock. + for(volatile uint32_t pulseWidth=0; pulseWidth < 8; pulseWidth++); } // Fetch the data before deasserting the signals. @@ -2032,7 +2036,7 @@ uint8_t loadBIOS(const char *biosFileName, uint8_t machineMode, uint32_t loadAdd void loadTranZPUterDefaultROMS(void) { // Locals. - FRESULT result; + FRESULT result = 0; // Start off by clearing active memory banks, the AS6C4008 chip holds random values at power on. fillZ80Memory(0x000000, 0x10000, 0x00, 0); // TZFS and Sharp MZ80A mode. @@ -2045,6 +2049,10 @@ void loadTranZPUterDefaultROMS(void) result = loadBIOS(MZ_ROM_1Z_013A_40C, MZ700, MZ_MROM_ADDR); break; + case MZ800: + //result = loadBIOS(MZ_ROM_1Z_013A_40C, MZ700, MZ_MROM_ADDR); + break; + case MZ80B: result = loadBIOS(MZ_ROM_MZ80B_IPL, MZ700, MZ_MROM_ADDR); break; @@ -3509,7 +3517,7 @@ void processServiceRequest(void) // Update the service control record address according to memory mode. // z80Control.svcControlAddr = getServiceAddr(); - + // Get the command and associated parameters. copyFromZ80((uint8_t *)&svcControl, z80Control.svcControlAddr, TZSVC_CMD_SIZE, 0); @@ -3594,92 +3602,63 @@ void processServiceRequest(void) break; // Load the 40 column version of the default host bios into memory. - case TZSVC_CMD_LOAD40BIOS: - switch(z80Control.hostType) + case TZSVC_CMD_LOAD40ABIOS: + loadBIOS(MZ_ROM_SA1510_40C, MZ80A, MZ_MROM_ADDR); + + // Set the frequency of the CPU if we are emulating the hardware. + if(z80Control.hostType != MZ80A) { - case MZ700: - loadBIOS(MZ_ROM_1Z_013A_40C, MZ700, MZ_MROM_ADDR); - break; - - case MZ80B: - loadBIOS(MZ_ROM_MZ80B_IPL, MZ700, MZ_MROM_ADDR); - break; - - case MZ80A: - default: - loadBIOS(MZ_ROM_SA1510_40C, MZ80A, MZ_MROM_ADDR); - break; + // Change frequency to match Sharp MZ-80A + setZ80CPUFrequency(MZ_80A_CPU_FREQ, 1); } break; // Load the 80 column version of the default host bios into memory. - case TZSVC_CMD_LOAD80BIOS: - switch(z80Control.hostType) + case TZSVC_CMD_LOAD80ABIOS: + loadBIOS(MZ_ROM_SA1510_80C, MZ80A, MZ_MROM_ADDR); + + // Set the frequency of the CPU if we are emulating the hardware. + if(z80Control.hostType != MZ80A) { - case MZ700: - loadBIOS(MZ_ROM_1Z_013A_80C, MZ700, MZ_MROM_ADDR); - break; - - case MZ80B: - loadBIOS(MZ_ROM_MZ80B_IPL, MZ700, MZ_MROM_ADDR); - break; - - case MZ80A: - default: - loadBIOS(MZ_ROM_SA1510_80C, MZ80A, MZ_MROM_ADDR); - break; + // Change frequency to match Sharp MZ-80A + setZ80CPUFrequency(MZ_80A_CPU_FREQ, 1); } break; // Load the 40 column MZ700 1Z-013A bios into memory for compatibility switch. case TZSVC_CMD_LOAD700BIOS40: - if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_40C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) + loadBIOS(MZ_ROM_1Z_013A_40C, MZ700, MZ_MROM_ADDR); + + // Set the frequency of the CPU if we are emulating the hardware. + if(z80Control.hostType != MZ700) { - printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_1Z_013A_40C); + // Change frequency to match Sharp MZ-700 + setZ80CPUFrequency(MZ_700_CPU_FREQ, 1); } - - // Change frequency to match Sharp MZ-700 - setZ80CPUFrequency(MZ_700_CPU_FREQ, 1); - - // Set the machine mode according to BIOS loaded. - z80Control.machineMode = MZ700; - - // setup the IRQ's according to this machine. - setupIRQ(); break; // Load the 80 column MZ700 1Z-013A bios into memory for compatibility switch. case TZSVC_CMD_LOAD700BIOS80: - if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_80C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) - { - printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_1Z_013A_80C); - } + loadBIOS(MZ_ROM_1Z_013A_80C, MZ700, MZ_MROM_ADDR); - // Change frequency to match Sharp MZ-700 - setZ80CPUFrequency(MZ_700_CPU_FREQ, 1); - - // Set the machine mode according to BIOS loaded. - z80Control.machineMode = MZ700; - - // setup the IRQ's according to this machine. - setupIRQ(); + // Set the frequency of the CPU if we are emulating the hardware. + if(z80Control.hostType != MZ700) + { + // Change frequency to match Sharp MZ-700 + setZ80CPUFrequency(MZ_700_CPU_FREQ, 1); + } break; // Load the MZ-80B IPL ROM into memory for compatibility switch. case TZSVC_CMD_LOAD80BIPL: - if((status=loadZ80Memory((const char *)MZ_ROM_MZ80B_IPL, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) - { - printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_MZ80B_IPL); - } + loadBIOS(MZ_ROM_MZ80B_IPL, MZ80B, MZ_MROM_ADDR); - // Change frequency to match the Sharp MZ-80B - setZ80CPUFrequency(MZ_80B_CPU_FREQ, 1); - - // Set the machine mode according to BIOS loaded. - z80Control.machineMode = MZ80B; - - // setup the IRQ's according to this machine. - setupIRQ(); + // Set the frequency of the CPU if we are emulating the hardware. + if(z80Control.hostType != MZ80B) + { + // Change frequency to match Sharp MZ-80B + setZ80CPUFrequency(MZ_80B_CPU_FREQ, 1); + } break; // Load the CPM CCP+BDOS from file into the address given. @@ -3753,7 +3732,7 @@ void processServiceRequest(void) printf("WARNING: Unrecognised command:%02x\n", svcControl.cmd); break; } - + // Update the status in the service control record then copy it across to the Z80. // svcControl.result = status; @@ -3790,29 +3769,56 @@ uint8_t testTZFSAutoBoot(void) void setHost(void) { // Locals. - uint8_t buf[4]; + uint8_t cpldInfo; - // Copy the ID value from the host monitor so that we can identify the host type. + // Request the correct bus. // - copyFromZ80(buf, HOST_MON_TEST_VECTOR, 1, 1); + if( reqTranZPUterBus(DEFAULT_BUSREQ_TIMEOUT) == 0) + { + // Setup the pins to perform an IO read operation. + // + setupSignalsForZ80Access(READ); + + // Copy the ID value from the CPLD information register so that we can identify the host type. + // + cpldInfo = readZ80IO(IO_TZ_CPLDINFO); + + // Release the bus to continue. + // + releaseZ80(); + } else + { + printf("Failed to access tranZPUter bus to read CPLDINFO, defaulting to MZ80A\n"); + cpldInfo = MZ80A; + } // Setup the control variable to indicate type of host. This will affect processing of interrupts, BIOS loads etc. // - switch(buf[0]) + switch(cpldInfo & 0x07) { - case MZ700_MONITOR_ID: + case MZ700: z80Control.hostType = MZ700; z80Control.machineMode = MZ700; printf("Host Type: MZ-700\n"); break; - case MZ80B_MONITOR_ID: + case MZ800: + z80Control.hostType = MZ800; + z80Control.machineMode = MZ800; + printf("Host Type: MZ-800\n"); + break; + + case MZ80B: + case MZ2000: z80Control.hostType = MZ80B; z80Control.machineMode = MZ80B; printf("Host Type: MZ-80B\n"); break; - case MZ80A_MONITOR_ID: + case MZ80A: + case MZ80K: + case MZ80C: + case MZ1200: default: z80Control.hostType = MZ80A; z80Control.machineMode = MZ80A; @@ -3820,6 +3826,17 @@ void setHost(void) break; } + // Report on video hardware. + // + if(cpldInfo & VIDEO_FPGA) + { + printf("FPGA video hardware detected.\n"); + } + + // Report on CPLD version. + // + printf("CPLD Version: %d\n", (cpldInfo & CPLD_VERSION) >> 5); + return; } diff --git a/include/tranzputer.h b/include/tranzputer.h index 97ea4dc..3b12993 100755 --- a/include/tranzputer.h +++ b/include/tranzputer.h @@ -40,7 +40,8 @@ #define REFRESH_BYTE_COUNT 8 // This constant controls the number of bytes read/written to the z80 bus before a refresh cycle is needed. #define RFSH_BYTE_CNT 256 // Number of bytes we can write before needing a full refresh for the DRAM. #define HOST_MON_TEST_VECTOR 0x4 // Address in the host monitor to test to identify host type. -#define DEFAULT_BUSREQ_TIMEOUT 1000 // Timeout for a Z80 Bus request operation in milliseconds. +#define DEFAULT_BUSREQ_TIMEOUT 5000 // Timeout for a Z80 Bus request operation in milliseconds. +#define DEFAULT_RESET_PULSE_WIDTH 1000 // Pulse width of a reset signal in |K4F clock ticks. // tranZPUter Memory Modes - select one of the 32 possible memory models using these constants. // @@ -76,8 +77,19 @@ #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_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_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. -// Sharp MZ80A constants. +// Sharp MZ constants. // #define MZ_MROM_ADDR 0x0000 // Monitor ROM start address. #define MZ_MROM_STACK_ADDR 0x1000 // Monitor ROM start stack address. @@ -141,8 +153,8 @@ #define TZSVC_CMD_SAVEFILE 0x09 // Service command to save a file directly from tranZPUter memory. #define TZSVC_CMD_ERASEFILE 0x0a // Service command to erase a file on the SD card. #define TZSVC_CMD_CHANGEDIR 0x0b // Service command to change active directory on the SD card. -#define TZSVC_CMD_LOAD40BIOS 0x20 // Service command requesting that the 40 column version of the SA1510 BIOS is loaded. -#define TZSVC_CMD_LOAD80BIOS 0x21 // Service command requesting that the 80 column version of the SA1510 BIOS is loaded. +#define TZSVC_CMD_LOAD40ABIOS 0x20 // Service command requesting that the 40 column version of the SA1510 BIOS is loaded. +#define TZSVC_CMD_LOAD80ABIOS 0x21 // Service command requesting that the 80 column version of the SA1510 BIOS is loaded. #define TZSVC_CMD_LOAD700BIOS40 0x22 // Service command requesting that the MZ700 1Z-013A 40 column BIOS is loaded. #define TZSVC_CMD_LOAD700BIOS80 0x23 // Service command requesting that the MZ700 1Z-013A 80 column patched BIOS is loaded. #define TZSVC_CMD_LOAD80BIPL 0x24 // Service command requesting the MZ-80B IPL is loaded. @@ -405,20 +417,24 @@ enum VIDEO_FRAMES { WORKING = 1 }; -// Values in the host monitor ROM to identify a machine type. -// -enum MACHINE_MONITOR_ID { - MZ80A_MONITOR_ID = 0xa8, - MZ700_MONITOR_ID = 0xe6, - MZ80B_MONITOR_ID = 0x03 -}; - // Possible machines the tranZPUter can be hosted on and can emulate. // enum MACHINE_TYPES { - MZ80A = 0, - MZ700 = 1, - MZ80B = 2 + MZ80K = 0x00, // Machine = MZ-80K. + MZ80C = 0x01, // Machine = MZ-80C. + MZ1200 = 0x02, // Machine = MZ-1200. + MZ80A = 0x03, // Machine = MZ-80A. + MZ700 = 0x04, // Machine = MZ-700. + MZ800 = 0x05, // Machine = MZ-800. + MZ80B = 0x06, // Machine = MZ-80B. + MZ2000 = 0x07 // Machine = MZ-2000. +}; + +// Get and Set flags within the CPLD config and status registers. +// +enum CPLD_FLAGS { + VIDEO_FPGA = 0x08, // Bit to test for available functionality or enabling of the FPGA video hardware. + CPLD_VERSION = 0xE0 // CPLD version mask bits. }; // Types of file which have handlers and can be processed. diff --git a/libraries/lib/libimath2-k64f.a b/libraries/lib/libimath2-k64f.a index 2033885..a5e750c 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 31c68d7..0a9f9cd 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 f36de85..d96e7c6 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 d9818e0..f6727c5 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 ae09bb9..b673787 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 cfd0135..09ba09d 100644 Binary files a/libraries/lib/libumstdio-k64f.a and b/libraries/lib/libumstdio-k64f.a differ diff --git a/zOS/src/zOS.cpp b/zOS/src/zOS.cpp index bfe1242..d353c18 100644 --- a/zOS/src/zOS.cpp +++ b/zOS/src/zOS.cpp @@ -253,6 +253,9 @@ void tranZPUterControl(void) // if(isZ80Reset()) { + // Reset Z80 - This is to extend the reset signal to allow all the CPLD's/FPGA's to sync. + resetZ80(); + // Reload the memory on the tranZPUter to boot default. loadTranZPUterDefaultROMS();