diff --git a/.gitignore b/.gitignore index 76cea0c..a0fc8e1 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,5 @@ zOS/*.s zputa/*.i zputa/*.ii zputa/*.s +zOS/main.save + diff --git a/apps/tzpu/tzpu.c b/apps/tzpu/tzpu.c index 38d18f8..46843a7 100644 --- a/apps/tzpu/tzpu.c +++ b/apps/tzpu/tzpu.c @@ -8,7 +8,10 @@ // Credits: // Copyright: (c) 2019-2020 Philip Smart // -// History: May 2020 - Initial write of the TranZPUter software. +// History: May 2020 - Initial write of the TranZPUter software. +// July 2020 - Another test, a bug with the VHDL on the v2.1 tranZPUter board, so +// needed to output a constant memory mode. The bug turned out to be +// a delayed tri-stating of the bus. // // Notes: See Makefile to enable/disable conditional components // @@ -101,6 +104,25 @@ void testBus(void) } } +void testSixtyBug(void) +{ + printf("Repeating a write to 0x0060\n"); + while(true) + { + if(reqTranZPUterBus(100) == 0) + { + setupSignalsForZ80Access(WRITE); + uint8_t data = 0x07; + writeZ80Memory(0x0060, data); + releaseZ80(); + } + else + { + printf("Failed to obtain the Z80 bus.\n"); + } + } +} + // Main entry and start point of a zOS/ZPUTA Application. Only 2 parameters are catered for and a 32bit return code, additional parameters can be added by changing the appcrt0.s // startup code to add them to the stack prior to app() call. @@ -125,6 +147,8 @@ uint32_t app(uint32_t param1, uint32_t param2) //} // _init_Teensyduino_internal_(); // setupZ80Pins(1, G->millis); + // + testSixtyBug(); printf("Loading Monitor ROM\n"); loadZ80Memory("SA1510.rom", 0, 0x00000000, 0, 0, 0, 1); diff --git a/common/tranzputer.c b/common/tranzputer.c index 3805b38..3c88af8 100644 --- a/common/tranzputer.c +++ b/common/tranzputer.c @@ -34,6 +34,9 @@ // for Z80 A11:A0 and Port A 15:12 for Z80 A15:12. This was done due to the // extra overhead required to piece together address and data lines in v1.0 // where the PCB was routed for linear reading and routing. +// v1.2 July 2020 - Updates for the v2.1 tranZPUter board. I've used macro processing +// to seperate v1+ and v2+ but I may well create two seperate directories +// as both projects are updated. Alternatively I use git flow or similar, TBD! // // Notes: See Makefile to enable/disable conditional components // @@ -164,6 +167,7 @@ static void __attribute((naked, noinline)) irqPortC_dummy(void) } #endif +#if TZBOARD == 100 || TZBOARD == 110 || TZBOARD == 200 || TZBOARD == 210 // This method is called everytime an active irq triggers on Port E. For this design, this means the two IO CS // lines, TZ_SVCREQ and TZ_SYSREQ. The SVCREQ is used when the Z80 requires a service, the SYSREQ is yet to // be utilised. @@ -202,7 +206,9 @@ static void __attribute((naked, noinline)) irqPortE(void) return; } +#endif +#if TZBOARD == 110 || TZBOARD == 200 || TZBOARD == 210 // This method is called everytime an active irq triggers on Port D. For this design, this means the IORQ and RESET lines. // // There are 3 versions of the same routine, originally using #if macro preprocessor statements but it became @@ -227,10 +233,10 @@ static void __attribute((naked, noinline)) irqPortD_Mode0(void) " str r0, [r1, #0] \n" // Is Z80_RESET active, set flag and exit. - " movs r0, #1 \n" - " tst r5, #0x010 \n" + " movs r1, #1 \n" + " tst r0, #0x0010 \n" " beq irqPortD_Exit \n" - " strb r0, %[val0] \n" + " strb r1, %[val0] \n" " irqPortD_Exit: \n" @@ -243,10 +249,11 @@ static void __attribute((naked, noinline)) irqPortD_Mode0(void) return; } +#endif // // Mode 1 & 2 - Capture and store an IORQ or MREQ Memory Mapped event for the main thread to process. // -#if 1 +#if TZBOARD == 110 static void __attribute((naked, noinline)) irqPortD_Mode12(void) { // Save minimum number of registers, cycles matter as we need to capture the address and halt the Z80 whilst we decode it. @@ -462,6 +469,7 @@ static void __attribute((naked, noinline)) irqPortD_Mode12(void) return; } #endif +#if TZBOARD == 110 // // Mode 3 - MZ700 processing. // @@ -840,6 +848,7 @@ static void __attribute((naked, noinline)) irqPortD_Mode3(void) return; } +#endif // Method to install the interrupt vector and enable it to capture Z80 memory/IO operations. // @@ -853,10 +862,18 @@ static void setupIRQ(void) // For the MZ700 we need to enable IORQ to process the OUT statements the Z80 generates for memory mode selection. case MZ700: // Install the dummy method to be called when PortE triggers. +#if TZBOARD == 110 _VectorsRam[IRQ_PORTE + 16] = irqPortE_dummy; - +#elif TZBOARD == 200 || TZBOARD == 210 + _VectorsRam[IRQ_PORTE + 16] = irqPortE; +#endif + // Install the method to be called when PortD triggers. +#if TZBOARD == 110 _VectorsRam[IRQ_PORTD + 16] = irqPortD_Mode3; +#elif TZBOARD == 200 || TZBOARD == 210 + _VectorsRam[IRQ_PORTD + 16] = irqPortD_Mode0; +#endif // Setup the IRQ for Z80_IORQ. installIRQ(Z80_IORQ, IRQ_MASK_FALLING); @@ -864,6 +881,7 @@ static void setupIRQ(void) // Setup the IRQ for Z80_RESET. installIRQ(Z80_RESET, IRQ_MASK_FALLING); +#if TZBOARD == 110 // Setup the IRQ for Z80_MREQ. //installIRQ(Z80_MREQ, IRQ_MASK_RISING); @@ -871,6 +889,14 @@ static void setupIRQ(void) removeIRQ(TZ_SVCREQ); removeIRQ(TZ_SYSREQ); +#elif TZBOARD == 200 || TZBOARD == 210 + // Setup the IRQ for TZ_SYSREQ. + installIRQ(TZ_SYSREQ, IRQ_MASK_FALLING); + + // Setup the IRQ for Z80_RESET. + installIRQ(Z80_RESET, IRQ_MASK_FALLING); +#endif + // Set relevant priorities to meet latency. NVIC_SET_PRIORITY(IRQ_PORTD, 0); NVIC_SET_PRIORITY(IRQ_PORTE, 16); @@ -882,7 +908,11 @@ static void setupIRQ(void) _VectorsRam[IRQ_PORTE + 16] = irqPortE_dummy; // Install the method to be called when PortD triggers. +#if TZBOARD == 110 _VectorsRam[IRQ_PORTD + 16] = irqPortD_Mode3; +#elif TZBOARD == 200 || TZBOARD == 210 + _VectorsRam[IRQ_PORTD + 16] = irqPortD_Mode0; +#endif // Setup the IRQ for Z80_IORQ. installIRQ(Z80_IORQ, IRQ_MASK_FALLING); @@ -890,8 +920,10 @@ static void setupIRQ(void) // Setup the IRQ for Z80_RESET. installIRQ(Z80_RESET, IRQ_MASK_FALLING); +#if TZBOARD == 110 // Setup the IRQ for Z80_MREQ. //installIRQ(Z80_MREQ, IRQ_MASK_RISING); +#endif // Remove previous interrupts not needed in this mode. removeIRQ(TZ_SVCREQ); @@ -947,8 +979,10 @@ static void restoreIRQ(void) // Setup the IRQ for Z80_IORQ. installIRQ(Z80_IORQ, IRQ_MASK_FALLING); +#if TZBOARD == 110 // Setup the IRQ for Z80_MREQ. //installIRQ(Z80_MREQ, IRQ_MASK_FALLING); +#endif // Setup the IRQ for Z80_RESET. installIRQ(Z80_RESET, IRQ_MASK_FALLING); @@ -959,8 +993,10 @@ static void restoreIRQ(void) // Setup the IRQ for Z80_IORQ. installIRQ(Z80_IORQ, IRQ_MASK_FALLING); +#if TZBOARD == 110 // Setup the IRQ for Z80_MREQ. //installIRQ(Z80_MREQ, IRQ_MASK_FALLING); +#endif // Setup the IRQ for Z80_RESET. installIRQ(Z80_RESET, IRQ_MASK_FALLING); @@ -1361,7 +1397,6 @@ uint8_t writeZ80Memory(uint16_t addr, uint8_t data) { // Locals. uint32_t startTime = *ms; - volatile uint32_t pulseWidth; // Set the data and address on the bus. // @@ -1369,8 +1404,9 @@ uint8_t writeZ80Memory(uint16_t addr, uint8_t data) setZ80Data(data); // Setup time before applying control signals. - for(pulseWidth = 0; pulseWidth < 5; pulseWidth++); + for(volatile uint32_t pulseWidth = 0; pulseWidth < 3; pulseWidth++); pinLow(Z80_MREQ); + for(volatile uint32_t pulseWidth = 0; pulseWidth < 3; pulseWidth++); // Different logic according to what is being accessed. The mainboard needs to uphold timing and WAIT signals whereas the Tranzputer logic has no wait // signals and faster memory. @@ -1385,7 +1421,11 @@ uint8_t writeZ80Memory(uint16_t addr, uint8_t data) pinLow(Z80_WR); // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. - for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); +#if TZBOARD == 100 || TZBOARD == 110 + for(volatile uint32_t pulseWidth=0; pulseWidth < 4; pulseWidth++); +#elif TZBOARD == 200 || TZBOARD == 210 + for(volatile uint32_t pulseWidth=0; pulseWidth < 5; pulseWidth++); +#endif // Another wait loop check as the Z80 can assert wait at the time of Write or anytime before it is deasserted. while((*ms - startTime) < 200 && pinGet(Z80_WAIT) == 0); @@ -1393,10 +1433,15 @@ uint8_t writeZ80Memory(uint16_t addr, uint8_t data) { // Start the write cycle, MREQ and WR go low. pinLow(Z80_WR); - } - // Hold time for the WR signal before clearing it. - for(pulseWidth = 0; pulseWidth < 5; pulseWidth++); + // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. +#if TZBOARD == 100 || TZBOARD == 110 + for(volatile uint32_t pulseWidth = 0; pulseWidth < 2; pulseWidth++); + // With the tranZPUter SW v2 boards, need to increase the write pulse width, alternatively wait until a positive edge on the CPU clock. +#elif TZBOARD == 200 || TZBOARD == 210 + for(volatile uint32_t pulseWidth=0; pulseWidth < 3; pulseWidth++); +#endif + } // Complete the write cycle. // @@ -1430,11 +1475,21 @@ uint8_t readZ80Memory(uint16_t addr) // 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 the data bus. +#if TZBOARD == 100 || TZBOARD == 110 for(volatile uint32_t pulseWidth=0; pulseWidth < 1; pulseWidth++); + // With the tranZPUter SW v2 boards, need to increase the write pulse width, alternatively wait until a positive edge on the CPU clock. +#elif TZBOARD == 200 || TZBOARD == 210 + for(volatile uint32_t pulseWidth=0; pulseWidth < 4; pulseWidth++); +#endif } else { // On the tranZPUter v1.1, because of reorganisation of the signals, the time to process is less and so the pulse width under v1.0 is insufficient. +#if TZBOARD == 100 || TZBOARD == 110 for(volatile uint32_t pulseWidth=0; pulseWidth < 1; pulseWidth++); + // With the tranZPUter SW v2 boards, need to increase the write pulse width to accommodate the different memories used. +#elif TZBOARD == 200 || TZBOARD == 210 + for(volatile uint32_t pulseWidth=0; pulseWidth < 4; pulseWidth++); +#endif } // Fetch the data before deasserting the signals. @@ -1481,14 +1536,23 @@ uint8_t writeZ80IO(uint16_t addr, uint8_t data) pinLow(Z80_WR); // On a Teensy3.5 K64F running at 120MHz this delay gives a pulsewidth of 760nS. +#if TZBOARD == 100 || TZBOARD == 110 //for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); +#elif TZBOARD == 200 || TZBOARD == 210 + for(volatile uint32_t pulseWidth=0; pulseWidth < 2; pulseWidth++); +#endif // Another wait loop check as the Z80 can assert wait at the time of Write or anytime before it is deasserted. while((*ms - startTime) < 200 && pinGet(Z80_WAIT) == 0); } else { - // Start the write cycle, MREQ and WR go low. + // Start the write cycle, WR go low. pinLow(Z80_WR); + + // With the tranZPUter SW v2 boards, need to increase the write pulse width as the latch is synchronous, alternatively wait until a positive edge on the CPU clock. +#if TZBOARD == 200 || TZBOARD == 210 + for(volatile uint32_t pulseWidth=0; pulseWidth < 8; pulseWidth++); +#endif } // Complete the write cycle. @@ -4013,7 +4077,7 @@ uint32_t getServiceAddr(void) { // Locals. uint32_t addr = TZSVC_CMD_STRUCT_ADDR_TZFS; - uint8_t memoryMode = readCtrlLatch(); + uint8_t memoryMode = readCtrlLatch() & 0x1F; // If in CPM mode then set the service address accordingly. if(memoryMode == TZMM_CPM || memoryMode == TZMM_CPM2) @@ -4160,7 +4224,11 @@ void processServiceRequest(void) // Load the 40 column MZ700 1Z-013A bios into memory. case TZSVC_CMD_LOAD700BIOS40: +#if TZBOARD == 100 || TZBOARD == 110 + if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_KM_40C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) +#elif TZBOARD == 200 || TZBOARD == 210 if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_40C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) +#endif { printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_1Z_013A_40C); } @@ -4177,7 +4245,11 @@ void processServiceRequest(void) // Load the 80 column MZ700 1Z-013A bios into memory. case TZSVC_CMD_LOAD700BIOS80: +#if TZBOARD == 100 || TZBOARD == 110 + if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_KM_80C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) +#elif TZBOARD == 200 || TZBOARD == 210 if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_80C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) +#endif { printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_1Z_013A_80C); } diff --git a/include/tranzputer.h b/include/tranzputer.h index b524c54..c75efbd 100755 --- a/include/tranzputer.h +++ b/include/tranzputer.h @@ -9,6 +9,7 @@ // Copyright: (c) 2019-2020 Philip Smart // // History: May 2020 - Initial write of the TranZPUter software. +// July 2020- Updates to accommodate v2.1 of the tranZPUter board. // // Notes: See Makefile to enable/disable conditional components // @@ -42,6 +43,7 @@ // 3 = NZ700 memory mode decode - This doesnt work per original, the memory change occurs one instruction after the OUT instruction due to the way the Z80 functions in respect to BUSRQ. #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 TZBOARD 210 // tranZPUter SW Hardware versions - v1.0 = 110, v1.1 = 110, v2.0 = 200 and v2.1 = 210 // tranZPUter Memory Modes - select one of the 32 possible memory models using these constants. // @@ -106,6 +108,8 @@ #define MZ_ROM_SA1510_80C "0:\\TZFS\\SA1510-8.ROM" // Original Monitor ROM patched for 80 character screen mode. #define MZ_ROM_1Z_013A_40C "0:\\TZFS\\1Z-013A.ROM" // Original 40 character Monitor ROM for the Sharp MZ700. #define MZ_ROM_1Z_013A_80C "0:\\TZFS\\1Z-013A-8.ROM" // Original Monitor ROM patched for the Sharp MZ700 patched for 80 column mode. +#define MZ_ROM_1Z_013A_KM_40C "0:\\TZFS\\1Z-013A-KM.ROM" // Original 40 character Monitor ROM for the Sharp MZ700 with keyboard remapped for the MZ80A. +#define MZ_ROM_1Z_013A_KM_80C "0:\\TZFS\\1Z-013A-KM-8.ROM" // Original Monitor ROM patched for the Sharp MZ700 with keyboard remapped for the MZ80A and patched for 80 column mode. #define MZ_ROM_MZ80B_IPL "0:\\TZFS\\MZ80B_IPL.ROM" // Original IPL ROM for the Sharp MZ-80B. #define MZ_ROM_TZFS "0:\\TZFS\\TZFS.ROM" // tranZPUter Filing System ROM. diff --git a/libraries/lib/libimath2-k64f.a b/libraries/lib/libimath2-k64f.a index d43fff8..8372f73 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 39b3f5b..bbc2b82 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 702026d..4e5fe1a 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 3295f36..8de27e7 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 dbc0da2..f33dc6b 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 f538570..59578eb 100644 Binary files a/libraries/lib/libumstdio-k64f.a and b/libraries/lib/libumstdio-k64f.a differ diff --git a/zOS/Makefile.k64f b/zOS/Makefile.k64f index 4fd30b9..da2412e 100644 --- a/zOS/Makefile.k64f +++ b/zOS/Makefile.k64f @@ -48,8 +48,8 @@ TARGET = main TEENSY = 35 # Set to 24000000, 48000000, or 96000000 to set CPU core speed -TEENSY_CORE_SPEED = 168000000 -#TEENSY_CORE_SPEED = 120000000 +#TEENSY_CORE_SPEED = 168000000 +TEENSY_CORE_SPEED = 120000000 # Some libraries will require this to be defined # If you define this, you will break the default main.cpp diff --git a/zOS/src/zOS.cpp b/zOS/src/zOS.cpp index 07560d8..bfe1242 100644 --- a/zOS/src/zOS.cpp +++ b/zOS/src/zOS.cpp @@ -19,6 +19,7 @@ // enhanced to work with both the ZPU and K64F for the original purpose // of testing but also now for end application programming using the // features of zOS where applicable. +// July 2020 - Tweaks to accomodate v2.1 of the tranZPUter board. // // Notes: See Makefile to enable/disable conditional components // USELOADB - The Byte write command is implemented in hw/sw so use it.