Updates for tranZPUter SW

This commit is contained in:
Philip Smart
2020-06-03 23:59:10 +01:00
parent 4aad65c3dc
commit 443e8fcc92
9 changed files with 151 additions and 41 deletions

View File

@@ -99,15 +99,21 @@ static t_asciiMap asciiMap[] = {
{ 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 }, { 0x20 } // 0XFF
};
// This method is called everytime an active irq triggers on Port D. For this design, this means the IORQ line.
// Store all the ports as they are needed to capture the Address and Data of the asserted z80 I/O transaction.
// 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.
//
static void __attribute((naked, noinline)) irqPortD(void)
//
static void __attribute((naked, noinline)) irqPortE(void)
{
// Save register we use.
asm volatile ("push {r0-r6,lr}");
// Short circuit interrupt when not needed.
//asm volatile goto("b %l0" :::: irqPortE_Exit);
// Capture GPIO ports - this is necessary in order to make a clean capture and then decode.
#if DECODE_Z80_IO == 1
asm volatile ("ldr r5, =0x400ff010"); // GPIOA_PDIR
asm volatile ("ldr r0, [r5, #0]");
asm volatile ("ldr r5, =0x400ff050"); // GPIOB_PDIR
@@ -116,15 +122,76 @@ static void __attribute((naked, noinline)) irqPortD(void)
asm volatile ("ldr r2, [r5, #0]");
asm volatile ("ldr r5, =0x400ff0d0"); // GPIOD_PDIR
asm volatile ("ldr r3, [r5, #0]");
#endif
asm volatile ("ldr r5, =0x400ff110"); // GPIOE_PDIR
asm volatile ("ldr r4, [r5, #0]");
// Now save the GPIO values into the structure.
#if DECODE_Z80_IO == 1
asm volatile ("str r0, %0" : "+m" (z80Control.portA) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
asm volatile ("str r1, %0" : "+m" (z80Control.portB) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
asm volatile ("str r2, %0" : "+m" (z80Control.portC) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
asm volatile ("str r3, %0" : "+m" (z80Control.portD) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
asm volatile ("str r4, %0" : "+m" (z80Control.portE) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
#endif
// Is TZ_SVCREQ (E10) active (low), set flag and exit if it is.
asm volatile ("movs r3, #1");
asm volatile ("ror r4, r4, #11" );
asm volatile goto("bmi %l0" ::: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12" : ebr0);
asm volatile ("strb r3, %0" : "+m" (z80Control.svcRequest) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
ebr0:
// Is TZ_SYSREQ (E11) active (low), set flag and exit if it is.
asm volatile ("rrx r4, r4" );
asm volatile goto("bcs %l0" ::: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12" : irqPortE_Exit);
asm volatile ("strb r3, %0" : "+m" (z80Control.sysRequest) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
irqPortE_Exit:
// Reset the interrupt, PORTE_ISFR <= PORTE_ISFR
asm volatile ("ldr r3, =0x4004d0a0");
asm volatile ("ldr r2, [r3, #0]");
asm volatile ("str r2, [r3, #0]");
asm volatile ("pop {r0-r6,pc}");
return;
}
// This method is called everytime an active irq triggers on Port D. For this design, this means the IORQ line.
// Store all the ports as they are needed to capture the Address and Data of the asserted z80 I/O transaction.
//
static void __attribute((naked, noinline)) irqPortD(void)
{
// Save register we use.
asm volatile ("push {r0-r6,lr}");
// Short circuit interrupt when not needed.
//asm volatile goto("b %l0" :::: irqPortC_Exit);
// Capture GPIO ports - this is necessary in order to make a clean capture and then decode.
#if DECODE_Z80_IO == 1
asm volatile ("ldr r5, =0x400ff010"); // GPIOA_PDIR
asm volatile ("ldr r0, [r5, #0]");
asm volatile ("ldr r5, =0x400ff050"); // GPIOB_PDIR
asm volatile ("ldr r1, [r5, #0]");
asm volatile ("ldr r5, =0x400ff090"); // GPIOC_PDIR
asm volatile ("ldr r2, [r5, #0]");
#endif
asm volatile ("ldr r5, =0x400ff0d0"); // GPIOD_PDIR
asm volatile ("ldr r3, [r5, #0]");
#if DECODE_Z80_IO == 1
asm volatile ("ldr r5, =0x400ff110"); // GPIOE_PDIR
asm volatile ("ldr r4, [r5, #0]");
#endif
// Now save the GPIO values into the structure.
#if DECODE_Z80_IO == 1
asm volatile ("str r0, %0" : "+m" (z80Control.portA) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
asm volatile ("str r1, %0" : "+m" (z80Control.portB) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
asm volatile ("str r2, %0" : "+m" (z80Control.portC) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
asm volatile ("str r3, %0" : "+m" (z80Control.portD) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
asm volatile ("str r4, %0" : "+m" (z80Control.portE) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
#endif
// Is Z80_RESET active, set flag and exit.
asm volatile ("lsls r5, r3, #16" );
@@ -134,6 +201,7 @@ static void __attribute((naked, noinline)) irqPortD(void)
asm volatile goto("b %l0" :::: irqPortD_Exit);
cbr0:
#if DECODE_Z80_IO == 1
// Convert lower 8 address bits into a byte and store.
asm volatile ("lsrs r3, r1, #4"); // (z80Control.portB >> 4)&0x80)
asm volatile ("and.w r3, r3, #128");
@@ -160,9 +228,9 @@ cbr0:
asm volatile ("orrs r3, r5");
// Ignore IO requests which arent service related.
asm volatile ("movw r5, " XSTR(IO_TZ_SVCREQ) "");
asm volatile ("cmp r3, r5");
asm volatile goto("bne %l0" :::: irqPortD_Exit);
//asm volatile ("movw r5, " XSTR(IO_TZ_SVCREQ) "");
//asm volatile ("cmp r3, r5");
//asm volatile goto("bne %l0" :::: irqPortD_Exit);
// Not memory mode so store the address.
asm volatile ("str r3, %0" : "=m" (z80Control.ioAddr) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
@@ -197,6 +265,7 @@ cbr0:
// Process the IO request by setting the ioEvent flag.
asm volatile ("movs r3, #1");
asm volatile ("str r3, %0" : "=m" (z80Control.ioEvent) :: "r0","r1","r2","r3","r4","r5","r7","r8","r9","r10","r11","r12");
#endif
irqPortD_Exit:
// Reset the interrupt, PORTD_ISFR <= PORTD_ISFR
@@ -217,8 +286,9 @@ static void __attribute((naked, noinline)) irqPortC(void)
asm volatile ("push {r0-r6,lr}");
// Short circuit interrupt when not needed.
asm volatile goto("b %l0" :::: irqPortC_Exit);
//asm volatile goto("b %l0" :::: irqPortC_Exit);
#if DECODE_Z80_IO == 1
// Capture GPIO ports - this is necessary in order to make a clean capture and then decode.
asm volatile ("ldr r5, =0x400ff010"); // GPIOA_PDIR
asm volatile ("ldr r0, [r5, #0]");
@@ -356,6 +426,8 @@ br5:
asm volatile ("strb r0, %0" : "+m" (z80Control.scroll) :: "r0");
irqPortC_Exit:
#endif
// Reset the interrupt, PORTC_ISFR <= PORTC_ISFR
asm volatile ("ldr r3, =0x4004b0a0");
asm volatile ("ldr r2, [r3, #0]");
@@ -370,19 +442,30 @@ irqPortC_Exit:
//
static void setupIRQ(void)
{
__disable_irq();
__disable_irq();
// Install the method to be called when PortE triggers.
_VectorsRam[IRQ_PORTE + 16] = irqPortE;
// Install the method to be called when PortD triggers.
_VectorsRam[IRQ_PORTD + 16] = irqPortD;
// Install the method to be called when PortC triggers.
_VectorsRam[IRQ_PORTC + 16] = irqPortC;
__enable_irq();
__enable_irq();
// Setup the IRQ for TZ_SVCREQ.
installIRQ(TZ_SVCREQ, IRQ_MASK_FALLING);
// Setup the IRQ for TZ_SYSREQ.
installIRQ(TZ_SYSREQ, IRQ_MASK_FALLING);
#if DECODE_Z80_IO == 1
// Setup the IRQ for Z80_IORQ.
installIRQ(Z80_IORQ, IRQ_MASK_FALLING);
// Setup the IRQ for Z80_MREQ.
//installIRQ(Z80_MREQ, IRQ_MASK_FALLING);
installIRQ(Z80_MREQ, IRQ_MASK_FALLING);
#endif
// Setup the IRQ for Z80_RESET.
installIRQ(Z80_RESET, IRQ_MASK_FALLING);
@@ -392,11 +475,19 @@ static void setupIRQ(void)
//
static void restoreIRQ(void)
{
// Setup the IRQ for TZ_SVCREQ.
installIRQ(TZ_SVCREQ, IRQ_MASK_FALLING);
// Setup the IRQ for TZ_SYSREQ.
installIRQ(TZ_SYSREQ, IRQ_MASK_FALLING);
#if DECODE_Z80_IO == 1
// Setup the IRQ for Z80_IORQ.
installIRQ(Z80_IORQ, IRQ_MASK_FALLING);
// 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);
@@ -417,7 +508,6 @@ void setupZ80Pins(uint8_t initTeensy, volatile uint32_t *millisecondTick)
//
if(firstCall == 1)
{
printf("FirstCall\n");
if(initTeensy)
_init_Teensyduino_internal_();
@@ -474,6 +564,8 @@ printf("FirstCall\n");
pinMap[Z80_RESET] = Z80_RESET_PIN;
pinMap[MB_SYSCLK] = SYSCLK_PIN;
pinMap[TZ_BUSACK] = TZ_BUSACK_PIN;
pinMap[TZ_SVCREQ] = TZ_SVCREQ_PIN;
pinMap[TZ_SYSREQ] = TZ_SYSREQ_PIN;
pinMap[CTL_BUSACK] = CTL_BUSACK_PIN;
pinMap[CTL_BUSRQ] = CTL_BUSRQ_PIN;
@@ -526,12 +618,16 @@ printf("FirstCall\n");
// Control structure elements only in zOS.
//
z80Control.resetEvent = 0;
z80Control.svcRequest = 0;
z80Control.sysRequest = 0;
#if DECODE_Z80_IO == 1
z80Control.ioAddr = 0;
z80Control.ioData = 0;
z80Control.ioEvent = 0;
z80Control.memorySwap = 0;
z80Control.crtMode = 0;
z80Control.scroll = 0;
#endif
// Setup the Interrupts for IORQ and MREQ.
setupIRQ();
@@ -1857,23 +1953,33 @@ uint8_t isZ80Reset(void)
// Method to test to see if the main memory has been swapped from 0000-0FFF to C000-CFFF
uint8_t isZ80MemorySwapped(void)
{
#if DECODE_Z80_IO == 1
// Return the value which would have been updated in the interrupt routine.
return(z80Control.memorySwap == 1);
#else
return(0);
#endif
}
// Method to get an IO instruction event should one have occurred since last poll.
//
uint8_t getZ80IO(uint8_t *addr, uint8_t *data)
uint8_t getZ80IO(uint8_t *addr)
{
// Locals.
uint8_t retcode = z80Control.ioEvent;
uint8_t retcode = 1;
// Load up the variables if an event has occurred.
if(retcode == 1)
if(z80Control.svcRequest == 1)
{
*addr = z80Control.ioAddr;
*data = z80Control.ioData;
z80Control.ioEvent = 0;
*addr = IO_TZ_SVCREQ;
z80Control.svcRequest = 0;
} else
if(z80Control.sysRequest == 1)
{
*addr = IO_TZ_SYSREQ;
z80Control.sysRequest = 0;
} else
{
retcode = 0;
}
return(retcode);
@@ -2022,11 +2128,7 @@ static uint32_t getNextChar(const char** ptr)
uint8_t chr;
// Get a byte
do {
chr = (uint8_t)*(*ptr)++;
// Skip over CR.
} while(chr == 0x0D);
chr = (uint8_t)*(*ptr)++;
// To upper ASCII char
if(islower(chr)) chr -= 0x20;
@@ -2091,6 +2193,9 @@ static int matchFileWithWildcard(const char *pattern, const char *fileName, int
// Get a name char
nc = getNextChar(&np);
// Sharp uses null or CR to terminate a pattern and a filename, which is not determinate!
if((pc == 0x00 || pc == 0x0d) && (nc == 0x00 || nc == 0x0d)) return 1;
// Branch mismatched?
if (pc != nc) break;
@@ -2102,7 +2207,7 @@ static int matchFileWithWildcard(const char *pattern, const char *fileName, int
getNextChar(&fileName);
/* Retry until end of name if infinite search is specified */
} while (infinite && nc != 0x00 && nc != 0x0d);
} while (infinite && nc != 0x00 && nc != 0x0d && (np - fileName) < MZF_FILENAME_LEN);
return 0;
}

View File

@@ -35,6 +35,7 @@
// Configurable constants.
//
#define DECODE_Z80_IO 0 // Flag to enable code, via interrupt, to capture Z80 actions on I/O ports an Memory mapped I/O.
#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.
@@ -65,6 +66,7 @@
#define IO_TZ_SET2MHZ 0x64 // Switch to system CPU frequency.
#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.
// Sharp MZ80A constants.
//
@@ -129,8 +131,8 @@
#define TZSVC_DEFAULT_EXT "MZF" // Default file extension for MZF files.
#define TZSVC_DEFAULT_WILDCARD "*" // Default wildcard file matching.
#define TZSVC_RESULT_OFFSET 0x01 // Offset into structure of the result byte.
#define TZSVC_DIRNAME_SIZE 8 // Limit is size of FAT32 directory name.
#define TZSVC_WILDCARD_SIZE 8 // Very basic pattern matching so small size.
#define TZSVC_DIRNAME_SIZE 20 // Limit is size of FAT32 directory name.
#define TZSVC_WILDCARD_SIZE 20 // Very basic pattern matching so small size.
#define TZSVC_FILENAME_SIZE MZF_FILENAME_LEN // Length of a Sharp MZF filename.
#define TZSVC_SECTOR_SIZE 512 // SD Card sector buffer size.
#define TZSVC_STATUS_OK 0x00 // Flag to indicate the K64F processing completed successfully.
@@ -155,7 +157,7 @@
// Pin Constants - Pins assigned at the hardware level to specific tasks/signals.
//
#define MAX_TRANZPUTER_PINS 50
#define MAX_TRANZPUTER_PINS 52
#define Z80_MEM0_PIN 46
#define Z80_MEM1_PIN 47
#define Z80_MEM2_PIN 48
@@ -206,6 +208,8 @@
#define CTL_CLK_PIN 14
#define CTL_CLKSLCT_PIN 19
#define TZ_BUSACK_PIN 55
#define TZ_SVCREQ_PIN 56
#define TZ_SYSREQ_PIN 57
// IRQ mask values for the different types of IRQ trigger.
//
@@ -348,14 +352,16 @@ enum pinIdxToPinNumMap {
Z80_RESET = 40,
MB_SYSCLK = 41,
TZ_BUSACK = 42,
TZ_SVCREQ = 43,
TZ_SYSREQ = 44,
CTL_BUSACK = 43,
CTL_BUSRQ = 44,
CTL_RFSH = 45,
CTL_HALT = 46,
CTL_M1 = 47,
CTL_CLK = 48,
CTL_CLKSLCT = 49
CTL_BUSACK = 45,
CTL_BUSRQ = 46,
CTL_RFSH = 47,
CTL_HALT = 48,
CTL_M1 = 49,
CTL_CLK = 50,
CTL_CLKSLCT = 51
};
// Possible control modes that the K64F can be in, do nothing where the Z80 runs normally, control the Z80 and mainboard, or control the Z80 and tranZPUter.
@@ -449,6 +455,9 @@ typedef struct {
enum BUS_DIRECTION busDir; // Direction the bus has been configured for.
uint8_t resetEvent; // A Z80_RESET event occurred, probably user pressing RESET button.
uint8_t svcRequest; // A service request has been made by the Z80 (1).
uint8_t sysRequest; // A system request has been made by the Z80 (1).
#if DECODE_Z80_IO == 1
uint8_t ioAddr; // Address of a Z80 IO instruction.
uint8_t ioData; // Data of a Z80 IO instruction.
uint8_t ioEvent; // Event flag to indicate that an IO instruction was captured.
@@ -458,6 +467,7 @@ typedef struct {
volatile uint32_t portA; // ISR store of GPIO Port A used for signal decoding.
volatile uint32_t portB; // ISR store of GPIO Port B used for signal decoding.
volatile uint32_t portC; // ISR store of GPIO Port C used for signal decoding.
#endif
volatile uint32_t portD; // ISR store of GPIO Port D used for signal decoding.
volatile uint32_t portE; // ISR store of GPIO Port E used for signal decoding.
#endif
@@ -566,7 +576,7 @@ FRESULT loadMZFZ80Memory(const char *, uint32_t, uint8_t, uint8_t);
// Getter/Setter methods!
uint8_t isZ80Reset(void);
uint8_t isZ80MemorySwapped(void);
uint8_t getZ80IO(uint8_t *, uint8_t *);
uint8_t getZ80IO(uint8_t *);
void clearZ80Reset(void);
void convertSharpFilenameToAscii(char *, char *, uint8_t);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -239,7 +239,6 @@ void tranZPUterControl(void)
{
// Locals.
uint8_t ioAddr;
uint8_t ioData;
// Loop waiting on events and processing.
//
@@ -262,12 +261,8 @@ void tranZPUterControl(void)
// Has there been an IO instruction for a service request?
//
if(getZ80IO(&ioAddr, &ioData) == 1)
if(getZ80IO(&ioAddr) == 1)
{
// Interrupt triggering has artifcats, ignore them!
if(ioData == 0xff)
continue;
switch(ioAddr)
{
// Service request. Actual data about the request is stored in the Z80 memory, so read the request and process.