Further updates during tranZPUter SW dev

This commit is contained in:
Philip Smart
2020-06-03 00:39:12 +01:00
parent ef40a56160
commit 4aad65c3dc
12 changed files with 369 additions and 72 deletions

View File

@@ -151,6 +151,10 @@ else ifeq ($(__ZOS__),1)
CPPFLAGS += -D__ZOS__
endif
ifeq ($(__TRANZPUTER__),1)
CPPFLAGS += -D__TRANZPUTER__
endif
# Allow local overrides to the HEAPADDR for certain applications.
ifeq (,$(findstring __HEAPADDR__,$(CPPFLAGS)))
ifeq ($(HEAPADDR),)

View File

@@ -106,7 +106,7 @@ static void __attribute((naked, noinline)) irqPortD(void)
{
// Save register we use.
asm volatile ("push {r0-r6,lr}");
// 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]");
@@ -158,6 +158,13 @@ cbr0:
asm volatile ("lsrs r5, r0, #17"); // (z80Control.portA >> 17)&0x01)
asm volatile ("and.w r5, r5, #1");
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);
// 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");
// Convert data port bits into a byte and store.
@@ -209,6 +216,9 @@ static void __attribute((naked, noinline)) irqPortC(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.
asm volatile ("ldr r5, =0x400ff010"); // GPIOA_PDIR
asm volatile ("ldr r0, [r5, #0]");
@@ -372,7 +382,7 @@ static void setupIRQ(void)
installIRQ(Z80_IORQ, IRQ_MASK_FALLING);
// Setup the IRQ for Z80_MREQ.
installIRQ(Z80_MREQ, IRQ_MASK_FALLING);
//installIRQ(Z80_MREQ, IRQ_MASK_FALLING);
// Setup the IRQ for Z80_RESET.
installIRQ(Z80_RESET, IRQ_MASK_FALLING);
@@ -500,6 +510,7 @@ printf("FirstCall\n");
}
// Initialise control structure.
z80Control.svcControlAddr = getServiceAddr();
z80Control.refreshAddr = 0x00;
z80Control.disableRefresh = 0;
z80Control.runCtrlLatch = readCtrlLatch();
@@ -543,14 +554,13 @@ void resetZ80(void)
__disable_irq();
pinOutputSet(Z80_RESET, LOW);
for(volatile uint32_t pulseWidth=0; pulseWidth < 100; pulseWidth++);
//while((*ms - startTime) < 1);
pinHigh(Z80_RESET);
pinInput(Z80_RESET);
__enable_irq();
// Wait a futher settling period before reinstating the interrupt.
//
while((*ms - startTime) < 250);
while((*ms - startTime) < 400);
// Restore the Z80 RESET IRQ as we have changed the pin mode.
//
@@ -1548,7 +1558,7 @@ FRESULT loadMZFZ80Memory(const char *src, uint32_t addr, uint8_t mainBoard, uint
// Locals.
FIL File;
unsigned int readSize;
unsigned char buf[128];
t_svcDirEnt mzfHeader;
FRESULT fr0;
// Sanity check on filenames.
@@ -1561,7 +1571,7 @@ FRESULT loadMZFZ80Memory(const char *src, uint32_t addr, uint8_t mainBoard, uint
// If no error occurred, read in the header.
//
if(!fr0)
fr0 = f_read(&File, buf, MZF_HEADER_SIZE, &readSize);
fr0 = f_read(&File, (char *)&mzfHeader, MZF_HEADER_SIZE, &readSize);
// No errors, process.
if(!fr0 && readSize == MZF_HEADER_SIZE)
@@ -1570,13 +1580,22 @@ FRESULT loadMZFZ80Memory(const char *src, uint32_t addr, uint8_t mainBoard, uint
f_close(&File);
// Save the header into the CMT area for reference, some applications expect it.
// This assumes the TZFS is running and the memory bank is 64K block 0.
//
copyToZ80(MZ_CMT_ADDR, (uint8_t *)buf, MZF_HEADER_SIZE, 0);
copyToZ80(MZ_CMT_ADDR, (uint8_t *)&mzfHeader, MZF_HEADER_SIZE, 0);
printf("File:%s,attr=%02x,addr:%08lx\n", src, mzfHeader.attr, addr);
// Now obtain the parameters.
//
if(addr == 0xFFFFFFFF)
addr = (uint32_t)(buf[MZF_LOADADDR+1] << 8) | (uint32_t)buf[MZF_LOADADDR];
addr = mzfHeader.loadAddr;
// Look at the attribute byte, if it is >= 0xF8 then it is a special tranZPUter binary object requiring loading into a seperate memory bank.
// The attribute & 0x07 << 16 specifies the memory bank in which to load the image.
if(mzfHeader.attr >= 0xF8)
{
addr += ((mzfHeader.attr & 0x07) << 16);
printf("CPM: Addr=%08lx\n", addr);
}
// Ok, load up the file into Z80 memory.
fr0 = loadZ80Memory(src, MZF_HEADER_SIZE, addr, 0, mainBoard, releaseBus);
@@ -1899,8 +1918,9 @@ void loadTranZPUterDefaultROMS(void)
// Locals.
FRESULT result;
// Start off by clearing memory, the AS6C4008 chip holds random values at power on.
fillZ80Memory(0x000000, 0x80000, 0x00, 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.
fillZ80Memory(0x040000, 0x20000, 0x00, 0); // CPM Mode.
// Now load the necessary images into memory.
if((result=loadZ80Memory((const char *)MZ_ROM_SA1510_40C, 0, MZ_MROM_ADDR, 0, 0, 1)) != FR_OK)
@@ -1915,7 +1935,7 @@ void loadTranZPUterDefaultROMS(void)
{
printf("Error: Failed to load page 2 of %s into tranZPUter memory.\n", MZ_ROM_TZFS);
}
if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x2800, MZ_BANKRAM_ADDR+0x20000, 0x1000, 0, 0) != FR_OK))
if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x2800, MZ_BANKRAM_ADDR+0x20000, 0x1000, 0, 1) != FR_OK))
{
printf("Error: Failed to load page 3 of %s into tranZPUter memory.\n", MZ_ROM_TZFS);
}
@@ -1930,10 +1950,11 @@ void loadTranZPUterDefaultROMS(void)
{
// Set the memory model to BOOT so we can bootstrap TZFS.
setCtrlLatch(TZMM_BOOT);
// If autoboot flag set, force a restart to the ROM which will call User ROM startup code.
if(osControl.tzAutoBoot)
{
delay(100);
fillZ80Memory(MZ_MROM_STACK_ADDR, MZ_MROM_STACK_SIZE, 0x00, 1);
}
@@ -1962,7 +1983,7 @@ uint8_t setZ80SvcStatus(uint8_t status)
// Update the memory location.
//
result=writeZ80Memory(TZSVC_CMD_STRUCT_ADDR+TZSVC_RESULT_OFFSET, status);
result=writeZ80Memory(z80Control.svcControlAddr+TZSVC_RESULT_OFFSET, status);
// Release the Z80.
writeCtrlLatch(z80Control.runCtrlLatch);
@@ -2081,7 +2102,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);
} while (infinite && nc != 0x00 && nc != 0x0d);
return 0;
}
@@ -2104,7 +2125,7 @@ uint8_t svcReadDir(uint8_t mode)
static uint8_t dirSector = 0; // Virtual directory sector.
FRESULT result = FR_OK;
unsigned int readSize;
char fqfn[FF_SFN_BUF + 13]; // 0:\12345678\<filename>
char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\<filename>
FIL File;
t_svcCmpDirBlock *dirBlock = (t_svcCmpDirBlock *)&svcControl.sector;
@@ -2233,13 +2254,13 @@ uint8_t svcReadDir(uint8_t mode)
// It is a bit long winded as each file that matches the filename specification has to be opened and the MZF header filename
// has to be checked. Cacheing would help here but wasteful in resources for number of times it would be called.
//
uint8_t svcFindFile(char *file, char *searchFile, uint32_t searchNo)
uint8_t svcFindFile(char *file, char *searchFile, uint8_t searchNo)
{
// Locals
uint8_t fileNo = 0;
uint8_t found = 0;
unsigned int readSize;
char fqfn[FF_SFN_BUF + 13]; // 0:\12345678\<filename>
char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\<filename>
FIL File;
FILINFO fno;
DIR dirFp;
@@ -2303,7 +2324,7 @@ uint8_t svcFindFile(char *file, char *searchFile, uint32_t searchNo)
}
// If we are searching on file number and the latest directory entry retrieval matches, exit and return the filename.
if(searchNo != 0xFFFFFFFF && fileNo == (uint8_t)searchNo)
if(searchNo != 0xFF && fileNo == (uint8_t)searchNo)
{
found = 1;
} else
@@ -2419,7 +2440,7 @@ uint8_t svcReadDirCache(uint8_t mode)
// A method to find a file using the cached directory. If the cache is not available (ie. no memory) use the standard method.
//
uint8_t svcFindFileCache(char *file, char *searchFile, uint32_t searchNo)
uint8_t svcFindFileCache(char *file, char *searchFile, uint8_t searchNo)
{
// Locals
uint8_t fileNo = 0;
@@ -2435,7 +2456,7 @@ uint8_t svcFindFileCache(char *file, char *searchFile, uint32_t searchNo)
} else
{
// If we are searching on file number and there is no filter in place, see if it is valid and exit with data.
if(searchNo != 0xFFFFFFFF && strcmp((char *)svcControl.wildcard, TZSVC_DEFAULT_WILDCARD) == 0)
if(searchNo != 0xFF && strcmp((char *)svcControl.wildcard, TZSVC_DEFAULT_WILDCARD) == 0)
{
if(searchNo < osControl.dirMap.entries && osControl.dirMap.file[searchNo])
{
@@ -2464,7 +2485,7 @@ uint8_t svcFindFileCache(char *file, char *searchFile, uint32_t searchNo)
}
// If we are searching on file number then see if it matches (after filter has been applied above).
if(searchNo != 0xFFFFFFFF && fileNo == (uint8_t)searchNo)
if(searchNo != 0xFF && fileNo == (uint8_t)searchNo)
{
found = 1;
} else
@@ -2502,7 +2523,7 @@ uint8_t svcCacheDir(const char *directory, uint8_t force)
// Locals
uint8_t fileNo = 0;
unsigned int readSize;
char fqfn[FF_SFN_BUF + 13]; // 0:\12345678\<filename>
char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\<filename>
FIL File;
FILINFO fno;
DIR dirFp;
@@ -2618,7 +2639,7 @@ uint8_t svcReadFile(uint8_t mode)
static uint8_t fileSector = 0; // Sector number being read.
FRESULT result = FR_OK;
unsigned int readSize;
char fqfn[FF_SFN_BUF + 13]; // 0:\12345678\<filename>
char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\<filename>
// Find the required file.
// Request to open? Validate that we dont already have an open file then find and open the file.
@@ -2693,7 +2714,7 @@ uint8_t svcLoadFile(void)
// Locals - dont use global as this is a seperate thread.
//
FRESULT result = FR_OK;
char fqfn[FF_SFN_BUF + 13]; // 0:\12345678\<filename>
char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\<filename>
// Setup the defaults
//
@@ -2705,6 +2726,18 @@ uint8_t svcLoadFile(void)
{
// Call method to load an MZF file.
result = loadMZFZ80Memory(fqfn, 0xFFFFFFFF, 0, 1);
// Store the filename, used in reload or immediate saves.
//
osControl.lastFile = (uint8_t *)realloc(osControl.lastFile, strlen(fqfn)+1);
if(osControl.lastFile == NULL)
{
printf("Out of memory saving last file name, dependent applications (ie. CP/M) wont work!\n");
result = FR_NOT_ENOUGH_CORE;
} else
{
strcpy((char *)osControl.lastFile, fqfn);
}
} else
{
result = FR_NO_FILE;
@@ -2722,7 +2755,7 @@ uint8_t svcSaveFile(void)
// Locals - dont use global as this is a seperate thread.
//
FRESULT result = FR_OK;
char fqfn[FF_SFN_BUF + 13]; // 0:\12345678\<filename>
char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\<filename>
char asciiFileName[MZF_FILENAME_LEN+1];
t_svcDirEnt mzfHeader;
@@ -2757,7 +2790,7 @@ uint8_t svcEraseFile(void)
// Locals - dont use global as this is a seperate thread.
//
FRESULT result = FR_OK;
char fqfn[FF_SFN_BUF + 13]; // 0:\12345678\<filename>
char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\<filename>
// Setup the defaults
//
@@ -2779,6 +2812,198 @@ uint8_t svcEraseFile(void)
return(result == FR_OK ? TZSVC_STATUS_OK : TZSVC_STATUS_FILE_ERROR);
}
// Method to add a SD disk file as a CP/M disk drive for read/write by CP/M.
//
uint8_t svcAddCPMDrive(void)
{
// Locals
char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\<filename>
FRESULT result = FR_OK;
// Sanity checks.
//
if(svcControl.fileNo >= CPM_MAX_DRIVES)
return(TZSVC_STATUS_FILE_ERROR);
// Disk already allocated? May be a reboot or drive reassignment so free up the memory to reallocate.
//
if(osControl.cpmDriveMap.drive[svcControl.fileNo] != NULL)
{
if(osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName != NULL)
{
free(osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName);
osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName = 0;
}
free(osControl.cpmDriveMap.drive[svcControl.fileNo]);
osControl.cpmDriveMap.drive[svcControl.fileNo] = 0;
}
// Build filename for the drive.
//
sprintf(fqfn, CPM_DRIVE_TMPL, svcControl.fileNo);
osControl.cpmDriveMap.drive[svcControl.fileNo] = (t_cpmDrive *)malloc(sizeof(t_cpmDrive));
if(osControl.cpmDriveMap.drive[svcControl.fileNo] == NULL)
{
printf("Out of memory adding CP/M drive:%s\n", fqfn);
result = FR_NOT_ENOUGH_CORE;
} else
{
osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName = (uint8_t *)malloc(strlen(fqfn)+1);
if(osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName == NULL)
{
printf("Out of memory adding filename to CP/M drive:%s\n", fqfn);
result = FR_NOT_ENOUGH_CORE;
} else
{
strcpy((char *)osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName, fqfn);
// Open the file to verify it exists and is valid, also to assign the file handle.
//
result = f_open(&osControl.cpmDriveMap.drive[svcControl.fileNo]->File, (char *)osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName, FA_OPEN_ALWAYS | FA_WRITE | FA_READ);
// If no error occurred, read in the header.
//
if(!result)
{
osControl.cpmDriveMap.drive[svcControl.fileNo]->lastTrack = 0;
osControl.cpmDriveMap.drive[svcControl.fileNo]->lastSector = 0;
} else
{
// Error opening file so free up and release slot, return error.
free(osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName);
osControl.cpmDriveMap.drive[svcControl.fileNo]->fileName = 0;
free(osControl.cpmDriveMap.drive[svcControl.fileNo]);
osControl.cpmDriveMap.drive[svcControl.fileNo] = 0;
result = FR_NOT_ENOUGH_CORE;
}
}
}
// Return values: 0 - Success : maps to TZSVC_STATUS_OK
// 1 - Fail : maps to TZSVC_STATUS_FILE_ERROR
return(result == FR_OK ? TZSVC_STATUS_OK : TZSVC_STATUS_FILE_ERROR);
}
// Method to read one of the opened, attached CPM drive images according to the Track and Sector provided.
// Inputs:
// svcControl.trackNo = Track to read from.
// svcControl.sectorNo = Sector to read from.
// svcControl.fileNo = CPM virtual disk number, which should have been attached with the svcAddCPMDrive method.
// Outputs:
// svcControl.sector = 512 bytes read from file.
//
uint8_t svcReadCPMDrive(void)
{
// Locals.
FRESULT result = FR_OK;
uint32_t fileOffset;
unsigned int readSize;
// Sanity checks.
//
if(svcControl.fileNo >= CPM_MAX_DRIVES || osControl.cpmDriveMap.drive[svcControl.fileNo] == NULL)
{
printf("svcReadCPMDrive: Illegal input values: fileNo=%d, driveMap=%08lx\n", svcControl.fileNo, (uint32_t)osControl.cpmDriveMap.drive[svcControl.fileNo]);
return(TZSVC_STATUS_FILE_ERROR);
}
// Calculate the offset into the file.
fileOffset = ((svcControl.trackNo * CPM_SECTORS_PER_TRACK) + svcControl.sectorNo) * SECTOR_SIZE;
// Seek to the correct location as directed by the track/sector.
result = f_lseek(&osControl.cpmDriveMap.drive[svcControl.fileNo]->File, fileOffset);
if(!result)
result = f_read(&osControl.cpmDriveMap.drive[svcControl.fileNo]->File, (char *)svcControl.sector, SECTOR_SIZE, &readSize);
// No errors but insufficient bytes read, either the image is bad or there was an error!
if(!result && readSize != SECTOR_SIZE)
{
result = FR_DISK_ERR;
} else
{
osControl.cpmDriveMap.drive[svcControl.fileNo]->lastTrack = svcControl.trackNo;
osControl.cpmDriveMap.drive[svcControl.fileNo]->lastSector = svcControl.sectorNo;
}
// Return values: 0 - Success : maps to TZSVC_STATUS_OK
// 1 - Fail : maps to TZSVC_STATUS_FILE_ERROR
return(result == FR_OK ? TZSVC_STATUS_OK : TZSVC_STATUS_FILE_ERROR);
}
// Method to write to one of the opened, attached CPM drive images according to the Track and Sector provided.
// Inputs:
// svcControl.trackNo = Track to write into.
// svcControl.sectorNo = Sector to write into.
// svcControl.fileNo = CPM virtual disk number, which should have been attached with the svcAddCPMDrive method.
// svcControl.sector = 512 bytes to write into the file.
// Outputs:
//
uint8_t svcWriteCPMDrive(void)
{
// Locals.
FRESULT result = FR_OK;
uint32_t fileOffset;
unsigned int writeSize;
// Sanity checks.
//
if(svcControl.fileNo >= CPM_MAX_DRIVES || osControl.cpmDriveMap.drive[svcControl.fileNo] == NULL)
{
printf("svcWriteCPMDrive: Illegal input values: fileNo=%d, driveMap=%08lx\n", svcControl.fileNo, (uint32_t)osControl.cpmDriveMap.drive[svcControl.fileNo]);
return(TZSVC_STATUS_FILE_ERROR);
}
// Calculate the offset into the file.
fileOffset = ((svcControl.trackNo * CPM_SECTORS_PER_TRACK) + svcControl.sectorNo) * SECTOR_SIZE;
// Seek to the correct location as directed by the track/sector.
result = f_lseek(&osControl.cpmDriveMap.drive[svcControl.fileNo]->File, fileOffset);
if(!result)
{
printf("Writing offset=%08lx\n", fileOffset);
for(uint16_t idx=0; idx < SECTOR_SIZE; idx++)
{
printf("%02x ", svcControl.sector[idx]);
if(idx % 32 == 0)
printf("\n");
}
printf("\n");
result = f_write(&osControl.cpmDriveMap.drive[svcControl.fileNo]->File, (char *)svcControl.sector, SECTOR_SIZE, &writeSize);
if(!result)
{
f_sync(&osControl.cpmDriveMap.drive[svcControl.fileNo]->File);
}
}
// No errors but insufficient bytes written, either the image is bad or there was an error!
if(!result && writeSize != SECTOR_SIZE)
{
result = FR_DISK_ERR;
} else
{
osControl.cpmDriveMap.drive[svcControl.fileNo]->lastTrack = svcControl.trackNo;
osControl.cpmDriveMap.drive[svcControl.fileNo]->lastSector = svcControl.sectorNo;
}
// Return values: 0 - Success : maps to TZSVC_STATUS_OK
// 1 - Fail : maps to TZSVC_STATUS_FILE_ERROR
return(result == FR_OK ? TZSVC_STATUS_OK : TZSVC_STATUS_FILE_ERROR);
}
// Simple method to get the service record address which is dependent upon memory mode which in turn is dependent upon software being run.
//
uint32_t getServiceAddr(void)
{
// Locals.
uint32_t addr = TZSVC_CMD_STRUCT_ADDR_TZFS;
uint8_t memoryMode = readCtrlLatch();
// Currently only CPM has a different service record address.
if(memoryMode == TZMM_CPM || memoryMode == TZMM_CPM2)
addr = TZSVC_CMD_STRUCT_ADDR_CPM;
return(addr);
}
// Method to process a service request from the z80 running TZFS or CPM.
//
@@ -2790,8 +3015,22 @@ void processServiceRequest(void)
uint8_t status = 0;
uint32_t copySize = TZSVC_CMD_STRUCT_SIZE;
// Update the service control record address according to memory mode.
//
z80Control.svcControlAddr = getServiceAddr();
// Get the command and associated parameters.
copyFromZ80((uint8_t *)&svcControl, TZSVC_CMD_STRUCT_ADDR, TZSVC_CMD_SIZE, 0);
copyFromZ80((uint8_t *)&svcControl, z80Control.svcControlAddr, TZSVC_CMD_SIZE, 0);
// Need to get the remainder of the data for the write operations.
if(svcControl.cmd == TZSVC_CMD_WRITESDDRIVE)
{
copyFromZ80((uint8_t *)&svcControl.sector, z80Control.svcControlAddr+TZSVC_CMD_SIZE, TZSVC_SECTOR_SIZE, 0);
}
// Check this is a valid request.
if(svcControl.result != TZSVC_STATUS_REQUEST)
return;
// Set status to processing. Z80 can use this to decide if the K64F received its request after a given period of time.
setZ80SvcStatus(TZSVC_STATUS_PROCESSING);
@@ -2820,23 +3059,12 @@ void processServiceRequest(void)
status=svcReadFile(TZSVC_NEXT);
break;
// Create or write a file stream and save the passed block of data into it.
case TZSVC_CMD_WRITEFILE:
case TZSVC_CMD_NEXTWRITEFILE:
// Need to get the remainder of the data for the write operation.
copyFromZ80((uint8_t *)&svcControl.sector, TZSVC_CMD_STRUCT_ADDR, TZSVC_SECTOR_SIZE, 0);
// No need to copy the full record back to the Z80 for a write operation, just the command section.
//
copySize = TZSVC_CMD_SIZE;
break;
// Close an open dir/file.
case TZSVC_CMD_CLOSE:
svcReadDir(TZSVC_CLOSE);
svcReadFile(TZSVC_CLOSE);
// No need to copy the full record back to the Z80 for a close operation, just the command section.
// Only need to copy the command section back to the Z80 for a close operation.
//
copySize = TZSVC_CMD_SIZE;
break;
@@ -2879,6 +3107,36 @@ void processServiceRequest(void)
}
break;
// Load the CPM CCP+BDOS from file into the address given.
case TZSVC_CMD_LOADBDOS:
if((status=loadZ80Memory((const char *)osControl.lastFile, MZF_HEADER_SIZE, svcControl.loadAddr+0x40000, svcControl.loadSize, 0, 1)) != FR_OK)
{
printf("Error: Failed to load BDOS:%s into tranZPUter memory.\n", (char *)osControl.lastFile);
}
break;
// Add a CP/M disk to the system for read/write access by CP/M on the Sharp MZ80A.
//
case TZSVC_CMD_ADDSDDRIVE:
status=svcAddCPMDrive();
break;
// Read an assigned CP/M drive sector giving an LBA address and the drive number.
//
case TZSVC_CMD_READSDDRIVE:
status=svcReadCPMDrive();
break;
// Write a sector to an assigned CP/M drive giving an LBA address and the drive number.
//
case TZSVC_CMD_WRITESDDRIVE:
status=svcWriteCPMDrive();
// Only need to copy the command section back to the Z80 for a write operation.
//
copySize = TZSVC_CMD_SIZE;
break;
default:
break;
}
@@ -2886,10 +3144,7 @@ void processServiceRequest(void)
// Update the status in the service control record then copy it across to the Z80.
//
svcControl.result = status;
copyToZ80(TZSVC_CMD_STRUCT_ADDR, (uint8_t *)&svcControl, copySize, 0);
// Return status.
setZ80SvcStatus(status);
copyToZ80(z80Control.svcControlAddr, (uint8_t *)&svcControl, copySize, 0);
// Need to refresh the directory? Do this at the end of the routine so the Sharp MZ80A isnt held up.
if(refreshCacheDir)

View File

@@ -177,6 +177,7 @@ static t_groupstruct groupTable[] = {
{ CMD_GROUP_EXEC, CMD_GROUP_EXEC_NAME },
{ CMD_GROUP_MISC, CMD_GROUP_MISC_NAME },
{ CMD_GROUP_APP, CMD_GROUP_APP_NAME },
{ CMD_GROUP_TZ, CMD_GROUP_TZ_NAME },
};
#endif

View File

@@ -46,10 +46,9 @@
#define TZMM_TZFS2 0x03 // TZFS main memory configuration. all memory is in tranZPUter RAM, E800-EFFF is used by TZFS, SA1510 is at 0000-1000 and RAM is 1000-CFFF, 64K Block 0 selected, F000-FFFF is in 64K Block 1.
#define TZMM_TZFS3 0x04 // TZFS main memory configuration. all memory is in tranZPUter RAM, E800-EFFF is used by TZFS, SA1510 is at 0000-1000 and RAM is 1000-CFFF, 64K Block 0 selected, F000-FFFF is in 64K Block 2.
#define TZMM_TZFS4 0x05 // TZFS main memory configuration. all memory is in tranZPUter RAM, E800-EFFF is used by TZFS, SA1510 is at 0000-1000 and RAM is 1000-CFFF, 64K Block 0 selected, F000-FFFF is in 64K Block 3.
#define TZMM_CPM 0x14 // CPM main memory configuration. all memory is in tranZPUter RAM, E800-EFFF is used as the static CBIOS and F000-FFFF is the paged CBIOS, TPA is from 0000-D000(BDOS+CCP = 1800), all is in 64K Block 4, F000-FFFF is in 64K Block 4.
#define TZMM_CPM2 0x15 // CPM main memory configuration. E800-EFFF and TPA 0000-D000 are in tranZPUter RAM 64K block 4, CBIOS2 F000-FFFF is in 64K block 5 and video and memory control D000-E7FF are on the mainboard.
#define TZMM_CPM3 0x16 // CPM main memory configuration. E800-EFFF and TPA 0000-D000 are in tranZPUter RAM 64K block 4, CBIOS2 F000-FFFF is in 64K block 6 and video and memory control D000-E7FF are on the mainboard.
#define TZMM_CPM4 0x17 // CPM main memory configuration. E800-EFFF and TPA 0000-D000 are in tranZPUter RAM 64K block 4, CBIOS2 F000-FFFF is in 64K block 7 and video and memory control D000-E7FF are on the mainboard.
#define TZMM_CPM 0x06 // CPM main memory configuration, all memory on the tranZPUter board, 64K block 4 selected. Special case for F3C0:F3FF & F7C0:F7FF (floppy disk paging vectors) which resides on the mainboard.
#define TZMM_CPM2 0x07 // CPM main memory configuration, F000-FFFF are on the tranZPUter board in block 4, 0040-CFFF and E800-EFFF are in block 5, mainboard for D000-DFFF (video), E000-E800 (Memory control) selected.
// Special case for 0000:003F (interrupt vectors) which resides in block 4, F3C0:F3FF & F7C0:F7FF (floppy disk paging vectors) which resides on the mainboard.
#define TZMM_TZPU0 0x18 // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
#define TZMM_TZPU1 0x19 // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 1 is selected.
#define TZMM_TZPU2 0x1A // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 2 is selected.
@@ -88,17 +87,24 @@
#define MZ_MEMORY_RESET 0xE010 // Address when read resets the memory to the default location 0000-0FFF.
#define MZ_CRT_NORMAL 0xE014 // Address when read sets the CRT to normal display mode.
#define MZ_CRT_INVERSE 0xE018 // Address when read sets the CRT to inverted display mode.
#define MZ_ROM_SA1510_40C "SA1510.ROM" // Original 40 character Monitor ROM.
#define MZ_ROM_SA1510_80C "SA1510-8.ROM" // Original Monitor ROM patched for 80 character screen mode.
#define MZ_ROM_TZFS "TZFS.ROM" // tranZPUter Filing System ROM.
#define MZ_ROM_SA1510_40C "0:\\TZFS\\SA1510.ROM" // Original 40 character Monitor ROM.
#define MZ_ROM_SA1510_80C "0:\\TZFS\\SA1510-8.ROM" // Original Monitor ROM patched for 80 character screen mode.
#define MZ_ROM_TZFS "0:\\TZFS\\TZFS.ROM" // tranZPUter Filing System ROM.
// CP/M constants.
//
#define CPM_MAX_DRIVES 16 // Maximum number of drives in CP/M.
#define CPM_FILE_CCPBDOS "0:\\CPM\\CPM22.BIN" // CP/M CCP and BDOS for warm start reloads.
#define CPM_DRIVE_TMPL "0:\\CPM\\CPMDSK%02u.RAW" // Template for CPM disk drives stored on the SD card.
#define CPM_SECTORS_PER_TRACK 32 // Number of sectors in a track on the virtual CPM disk.
#define CPM_TRACKS_PER_DISK 1024 // Number of tracks on a disk.
// Service request constants.
//
#define TZSVC_CMD_STRUCT_ADDR 0xEC80 // Address of the command structure.
#define TZSVC_CMD_STRUCT_ADDR_TZFS 0x0ED80 // Address of the command structure within TZFS - exists in 64K Block 0.
#define TZSVC_CMD_STRUCT_ADDR_CPM 0x4F560 // Address of the command structure within CP/M - exists in 64K Block 4.
#define TZSVC_CMD_STRUCT_SIZE 0x280 // Size of the inter z80/K64 service command memory.
#define TZSVC_CMD_SIZE 0x04+TZSVC_DIRNAME_SIZE+\
+TZSVC_FILENAME_SIZE+\
TZSVC_WILDCARD_SIZE // Size of the command/result portion of the control structure.
#define TZSVC_CMD_SIZE (sizeof(t_svcControl)-TZSVC_SECTOR_SIZE)
#define TZVC_MAX_CMPCT_DIRENT_BLOCK TZSVC_SECTOR_SIZE/TZSVC_CMPHDR_SIZE // Maximum number of directory entries per sector.
#define TZSVC_MAX_DIR_ENTRIES 255 // Maximum number of files in one directory, any more than this will be ignored.
#define TZSVC_CMPHDR_SIZE 32 // Compacted header size, contains everything except the comment field, padded out to 32bytes.
@@ -108,15 +114,17 @@
#define TZSVC_CMD_NEXTDIR 0x02 // Service command to return the next block of an open directory.
#define TZSVC_CMD_READFILE 0x03 // Service command to open a file and return the first block.
#define TZSVC_CMD_MEXTREADFILE 0x04 // Service command to return the next block of an open file.
#define TZSVC_CMD_WRITEFILE 0x05 // Service command to create a file and write the first block into it.
#define TZSVC_CMD_NEXTWRITEFILE 0x06 // Service command to write the next block into the open file.
#define TZSVC_CMD_CLOSE 0x07 // Service command to close any open file or directory.
#define TZSVC_CMD_LOADFILE 0x08 // Service command to load a file directly into tranZPUter memory.
#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_CLOSE 0x05 // Service command to close any open file or directory.
#define TZSVC_CMD_LOADFILE 0x06 // Service command to load a file directly into tranZPUter memory.
#define TZSVC_CMD_SAVEFILE 0x07 // Service command to save a file directly from tranZPUter memory.
#define TZSVC_CMD_ERASEFILE 0x08 // Service command to erase a file on the SD card.
#define TZSVC_CMD_CHANGEDIR 0x09 // 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_LOADBDOS 0x30 // Service command to reload CPM BDOS+CCP.
#define TZSVC_CMD_ADDSDDRIVE 0x31 // Service command to attach a CPM disk to a drive number.
#define TZSVC_CMD_READSDDRIVE 0x32 // Service command to read an attached SD file as a CPM disk drive.
#define TZSVC_CMD_WRITESDDRIVE 0x33 // Service command to write to a CPM disk drive which is an attached SD file.
#define TZSVC_DEFAULT_DIR "MZF" // Default directory where MZF files are stored.
#define TZSVC_DEFAULT_EXT "MZF" // Default file extension for MZF files.
#define TZSVC_DEFAULT_WILDCARD "*" // Default wildcard file matching.
@@ -402,6 +410,21 @@ typedef struct __attribute__((__packed__)) {
t_svcCmpDirEnt mzfHeader; // Compact Sharp header data of this file.
} t_sharpToSDMap;
// Structure to define the control information for a CP/M disk drive.
//
typedef struct {
uint8_t *fileName; // FQFN of the CPM disk image file.
uint32_t lastTrack; // Track of last successful operation.
uint32_t lastSector; // Sector of last successful operation.
FIL File; // Opened file handle of the CPM disk image.
} t_cpmDrive;
// Structure to define which CP/M drives are added to the system, mapping a number from CP/M into a record containing the details of the file on the SD card.
//
typedef struct {
t_cpmDrive *drive[CPM_MAX_DRIVES]; // 1:1 map of CP/M drive number to an actual file on the SD card.
} t_cpmDriveMap;
// Structure to hold a map of an entire directory of files on the SD card and their associated Sharp MZ0A filename.
typedef struct __attribute__((__packed__)) {
uint8_t valid; // Is this mapping valid?
@@ -414,6 +437,7 @@ typedef struct __attribute__((__packed__)) {
//
typedef struct {
#ifndef __APP__
uint32_t svcControlAddr; // Address of the service control record within the 512K static RAM bank.
uint8_t refreshAddr; // Refresh address for times when the K64F must issue refresh cycles on the Z80 bus.
uint8_t disableRefresh; // Disable refresh if the mainboard DRAM isnt being used.
uint8_t runCtrlLatch; // Latch value the Z80 is running with.
@@ -431,11 +455,11 @@ typedef struct {
uint8_t memorySwap; // A memory Swap event has occurred, 0000-0FFF -> C000-CFFF (1), or C000-CFFF -> 0000-0FFF (0)
uint8_t crtMode; // A CRT event has occurred, Normal mode (0) or Reverse Mode (1)
uint8_t scroll; // Hardware scroll offset.
volatile uint32_t portA;
volatile uint32_t portB;
volatile uint32_t portC;
volatile uint32_t portD;
volatile uint32_t portE;
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.
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
} t_z80Control;
@@ -444,6 +468,8 @@ typedef struct {
typedef struct {
uint8_t tzAutoBoot; // Autoboot the tranZPUter into TZFS mode.
t_dirMap dirMap; // Directory map of SD filenames to Sharp MZ80A filenames.
t_cpmDriveMap cpmDriveMap; // Map of file number to an open SD disk file to be used as a CPM drive.
uint8_t *lastFile; // Last file loaded - typically used for CPM to reload itself.
} t_osControl;
// Structure to contain inter CPU communications memory for command service processing and results.
@@ -459,8 +485,11 @@ typedef struct __attribute__((__packed__)) {
uint8_t dirSector; // Virtual directory sector number.
uint8_t fileSector; // Sector within open file to read/write.
};
// uint16_t sectorNo; // Sector number of file to retrieve.
uint16_t trackNo; // For virtual drives with track and sector this is the track number
uint16_t sectorNo; // For virtual drives with tracl and sector this is the sector number.
uint8_t fileNo; // File number of a file within the last directory listing to open/update.
uint16_t loadAddr; // Load address for ROM/File images which need to be dynamic.
uint16_t loadSize; // Size for ROM/File to be loaded.
uint8_t directory[TZSVC_DIRNAME_SIZE]; // Directory in which to look for a file. If no directory is given default to MZF.
uint8_t filename[TZSVC_FILENAME_SIZE]; // File to open or create.
uint8_t wildcard[TZSVC_WILDCARD_SIZE]; // A basic wildcard pattern match filter to be applied to a directory search.
@@ -545,13 +574,17 @@ void convertSharpFilenameToAscii(char *, char *, uint8_t);
uint8_t setZ80SvcStatus(uint8_t);
void svcSetDefaults(void);
uint8_t svcReadDir(uint8_t);
uint8_t svcFindFile(char *, char *, uint32_t);
uint8_t svcFindFile(char *, char *, uint8_t);
uint8_t svcReadDirCache(uint8_t);
uint8_t svcFindFileCache(char *, char *, uint32_t);
uint8_t svcFindFileCache(char *, char *, uint8_t);
uint8_t svcCacheDir(const char *, uint8_t);
uint8_t svcReadFile(uint8_t);
uint8_t svcLoadFile(void);
uint8_t svcEraseFile(void);
uint8_t svcAddCPMDrive(void);
uint8_t svcReadCPMDrive(void);
uint8_t svcWriteCPMDrive(void);
uint32_t getServiceAddr(void);
void processServiceRequest(void);
void loadTranZPUterDefaultROMS(void);
void tranZPUterControl(void);

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

@@ -37,7 +37,8 @@
#include <errno.h>
#if defined __TRANZPUTER__
#define FRESULT uint8_t
//#define FRESULT uint8_t
#include <ff.h>
#include <tranzputer.h>
#endif

View File

@@ -264,7 +264,10 @@ void tranZPUterControl(void)
//
if(getZ80IO(&ioAddr, &ioData) == 1)
{
printf("Got an IO request, addr:%02x, Data:%02x\n", ioAddr, ioData);
// 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.