Updates for v2.1 of the tranZPUter board
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -72,3 +72,5 @@ zOS/*.s
|
||||
zputa/*.i
|
||||
zputa/*.ii
|
||||
zputa/*.s
|
||||
zOS/main.save
|
||||
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2020 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
// Copyright: (c) 2019-2020 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user