From dcc471fc00fea26be6fa67e129a41326a4ab334e Mon Sep 17 00:00:00 2001 From: Philip Smart Date: Wed, 17 Jun 2020 23:10:24 +0100 Subject: [PATCH] More updates for the tranZPUter --- apps/tzload/tzload.c | 8 +- apps/tzpu/tzpu.c | 4 +- common/tranzputer.c | 342 +++++++++++++++++++++++++------- include/tranzputer.h | 57 ++++-- libraries/lib/libimath2-k64f.a | Bin 12504 -> 12504 bytes libraries/lib/libumansi-k64f.a | Bin 124218 -> 124218 bytes libraries/lib/libummath-k64f.a | Bin 2660 -> 2660 bytes libraries/lib/libummathf-k64f.a | Bin 63972 -> 63972 bytes libraries/lib/libummisc-k64f.a | Bin 6222 -> 6222 bytes libraries/lib/libumstdio-k64f.a | Bin 80050 -> 80050 bytes zOS/Makefile.k64f | 2 +- zOS/src/zOS.cpp | 2 +- 12 files changed, 316 insertions(+), 99 deletions(-) diff --git a/apps/tzload/tzload.c b/apps/tzload/tzload.c index 0d8d0d9..0ab160d 100644 --- a/apps/tzload/tzload.c +++ b/apps/tzload/tzload.c @@ -343,10 +343,10 @@ uint32_t app(uint32_t param1, uint32_t param2) // if(mzf_flag == 0) { - loadZ80Memory(uploadFile, 0, memAddr, 0, mainboard_flag, (idx == uploadCnt-1) ? 1 : 0); + loadZ80Memory(uploadFile, 0, memAddr, 0, 0, mainboard_flag, (idx == uploadCnt-1) ? 1 : 0); } else { - loadMZFZ80Memory(uploadFile, memAddr, mainboard_flag, (idx == uploadCnt-1) ? 1 : 0); + loadMZFZ80Memory(uploadFile, memAddr, 0, mainboard_flag, (idx == uploadCnt-1) ? 1 : 0); } } } @@ -385,10 +385,10 @@ uint32_t app(uint32_t param1, uint32_t param2) if(mzf_flag == 0) { - loadZ80Memory(uploadFile, 0, memAddr, 0, mainboard_flag, 1); + loadZ80Memory(uploadFile, 0, memAddr, 0, 0, mainboard_flag, 1); } else { - loadMZFZ80Memory(uploadFile, memAddr, mainboard_flag, 1); + loadMZFZ80Memory(uploadFile, memAddr, 0, mainboard_flag, 1); } } } diff --git a/apps/tzpu/tzpu.c b/apps/tzpu/tzpu.c index 8df1f71..38d18f8 100644 --- a/apps/tzpu/tzpu.c +++ b/apps/tzpu/tzpu.c @@ -127,10 +127,10 @@ uint32_t app(uint32_t param1, uint32_t param2) // setupZ80Pins(1, G->millis); printf("Loading Monitor ROM\n"); - loadZ80Memory("SA1510.rom", 0, 0x00000000, 0, 0, 1); + loadZ80Memory("SA1510.rom", 0, 0x00000000, 0, 0, 0, 1); printf("Loading Floppy ROM\n"); - loadZ80Memory("1Z-013A.rom", 0, 0x0000F000, 0, 0, 1); + loadZ80Memory("1Z-013A.rom", 0, 0x0000F000, 0, 0, 0, 1); printf("Testing Display\n"); testBus(); diff --git a/common/tranzputer.c b/common/tranzputer.c index 91cddd4..1940405 100644 --- a/common/tranzputer.c +++ b/common/tranzputer.c @@ -2290,7 +2290,7 @@ char *getAttributeFrame(enum VIDEO_FRAMES frame) // Method to load a file from the SD card directly into the tranZPUter static RAM or mainboard RAM. // -FRESULT loadZ80Memory(const char *src, uint32_t fileOffset, uint32_t addr, uint32_t size, uint8_t mainBoard, uint8_t releaseBus) +FRESULT loadZ80Memory(const char *src, uint32_t fileOffset, uint32_t addr, uint32_t size, uint32_t *bytesRead, uint8_t mainBoard, uint8_t releaseBus) { // Locals. // @@ -2415,6 +2415,13 @@ FRESULT loadZ80Memory(const char *src, uint32_t fileOffset, uint32_t addr, uint3 printf("File not found:%s\n", src); } + // Return number of bytes read if caller provided a variable. + // + if(bytesRead != NULL) + { + *bytesRead = loadSize; + } + // If requested or an error occurs, then release the Z80 bus as no more uploads will be taking place in this batch. // if(releaseBus == 1 || fr0) @@ -2432,7 +2439,7 @@ FRESULT loadZ80Memory(const char *src, uint32_t fileOffset, uint32_t addr, uint3 // Method to load an MZF format file from the SD card directly into the tranZPUter static RAM or mainboard RAM. // If the load address is specified then it overrides the MZF header value, otherwise load addr is taken from the header. // -FRESULT loadMZFZ80Memory(const char *src, uint32_t addr, uint8_t mainBoard, uint8_t releaseBus) +FRESULT loadMZFZ80Memory(const char *src, uint32_t addr, uint32_t *bytesRead, uint8_t mainBoard, uint8_t releaseBus) { // Locals. FIL File; @@ -2477,7 +2484,7 @@ printf("File:%s,attr=%02x,addr:%08lx\n", src, mzfHeader.attr, addr); } // Ok, load up the file into Z80 memory. - fr0 = loadZ80Memory(src, MZF_HEADER_SIZE, addr, 0, mainBoard, releaseBus); + fr0 = loadZ80Memory(src, MZF_HEADER_SIZE, addr, 0, bytesRead, mainBoard, releaseBus); } return(fr0 ? fr0 : FR_OK); @@ -2813,23 +2820,23 @@ void loadTranZPUterDefaultROMS(void) 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) + if((result=loadZ80Memory((const char *)MZ_ROM_SA1510_40C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) { printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_SA1510_40C); } - if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0, MZ_UROM_ADDR, 0x1800, 0, 1) != FR_OK)) + if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0, MZ_UROM_ADDR, 0x1800, 0, 0, 1) != FR_OK)) { printf("Error: Failed to load bank 1 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); } - if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x1800, MZ_BANKRAM_ADDR+0x10000, 0x1000, 0, 1) != FR_OK)) + if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x1800, MZ_BANKRAM_ADDR+0x10000, 0x1000, 0, 0, 1) != FR_OK)) { 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, 1) != FR_OK)) + if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x2800, MZ_BANKRAM_ADDR+0x20000, 0x1000, 0, 0, 1) != FR_OK)) { printf("Error: Failed to load page 3 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); } - if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x3800, MZ_BANKRAM_ADDR+0x30000, 0x1000, 0, 1) != FR_OK)) + if(!result && (result=loadZ80Memory((const char *)MZ_ROM_TZFS, 0x3800, MZ_BANKRAM_ADDR+0x30000, 0x1000, 0, 0, 1) != FR_OK)) { printf("Error: Failed to load page 4 of %s into tranZPUter memory.\n", MZ_ROM_TZFS); } @@ -2890,19 +2897,38 @@ uint8_t setZ80SvcStatus(uint8_t status) // Simple method to set defaults in the service structure if not already set by the Z80. // -void svcSetDefaults(void) +void svcSetDefaults(enum FILE_TYPE type) { - // If there is no directory path, use the inbuilt default. - if(svcControl.directory[0] == '\0') + // Set according to the type of file were working with. + // + switch(type) { - strcpy((char *)svcControl.directory, TZSVC_DEFAULT_DIR); - } + case CAS: + strcpy((char *)svcControl.directory, TZSVC_DEFAULT_CAS_DIR); + strcpy((char *)svcControl.wildcard, TZSVC_DEFAULT_WILDCARD); + break; + + case BAS: + strcpy((char *)svcControl.directory, TZSVC_DEFAULT_BAS_DIR); + strcpy((char *)svcControl.wildcard, TZSVC_DEFAULT_WILDCARD); + break; + + case MZF: + default: + // If there is no directory path, use the inbuilt default. + if(svcControl.directory[0] == '\0') + { + strcpy((char *)svcControl.directory, TZSVC_DEFAULT_MZF_DIR); + } - // If there is no wildcard matching, use default. - if(svcControl.wildcard[0] == '\0') - { - strcpy((char *)svcControl.wildcard, TZSVC_DEFAULT_WILDCARD); + // If there is no wildcard matching, use default. + if(svcControl.wildcard[0] == '\0') + { + strcpy((char *)svcControl.wildcard, TZSVC_DEFAULT_WILDCARD); + } + break; } + return; } // Helper method for matchFileWithWildcard. @@ -3027,7 +3053,7 @@ uint8_t svcReadDir(uint8_t mode) // Setup the defaults // - svcSetDefaults(); + svcSetDefaults(MZF); // Open the directory. result = f_opendir(&dirFp, (char *)&svcControl.directory); @@ -3085,7 +3111,7 @@ uint8_t svcReadDir(uint8_t mode) // Check to see if this is a valid MZF file. const char *ext = strrchr(fno.fname, '.'); - if(!ext || strcasecmp(++ext, TZSVC_DEFAULT_EXT) != 0) + if(!ext || strcasecmp(++ext, TZSVC_DEFAULT_MZF_EXT) != 0) continue; // Build filename. @@ -3158,7 +3184,7 @@ uint8_t svcFindFile(char *file, char *searchFile, uint8_t searchNo) // Setup the defaults // - svcSetDefaults(); + svcSetDefaults(MZF); // Open the directory. result = f_opendir(&dirFp, (char *)&svcControl.directory); @@ -3176,7 +3202,7 @@ uint8_t svcFindFile(char *file, char *searchFile, uint8_t searchNo) // Check to see if this is a valid MZF file. const char *ext = strrchr(fno.fname, '.'); - if(!ext || strcasecmp(++ext, TZSVC_DEFAULT_EXT) != 0) + if(!ext || strcasecmp(++ext, TZSVC_DEFAULT_MZF_EXT) != 0) continue; // Build filename. @@ -3251,7 +3277,7 @@ uint8_t svcReadDirCache(uint8_t mode) // Setup the defaults // - svcSetDefaults(); + svcSetDefaults(MZF); // If there is no cache revert to direct directory read. // @@ -3453,7 +3479,7 @@ uint8_t svcCacheDir(const char *directory, uint8_t force) // Check to see if this is a valid MZF file. const char *ext = strrchr(fno.fname, '.'); - if(!ext || strcasecmp(++ext, TZSVC_DEFAULT_EXT) != 0) + if(!ext || strcasecmp(++ext, TZSVC_DEFAULT_MZF_EXT) != 0) continue; // Build filename. @@ -3519,7 +3545,7 @@ uint8_t svcCacheDir(const char *directory, uint8_t force) // Method to open a file for reading and return requested sectors. // -uint8_t svcReadFile(uint8_t mode) +uint8_t svcReadFile(uint8_t mode, enum FILE_TYPE type) { // Locals - dont use global as this is a seperate thread. // @@ -3536,15 +3562,23 @@ uint8_t svcReadFile(uint8_t mode) { // Close if previously open. if(fileOpen == 1) - svcReadFile(TZSVC_CLOSE); + svcReadFile(TZSVC_CLOSE, type); // Setup the defaults // - svcSetDefaults(); + svcSetDefaults(type); + + if(type == CAS || type == BAS) + { + // Build the full filename from what has been provided. + // Cassette and basic images, create filename as they are not cached. + sprintf(fqfn, "0:\\%s\\%s.%s", svcControl.directory, svcControl.filename, (type == MZF ? TZSVC_DEFAULT_MZF_EXT : type == CAS ? TZSVC_DEFAULT_CAS_EXT : TZSVC_DEFAULT_BAS_EXT)); +printf("FQFN:%s\n", fqfn); + } // Find the file using the given file number or file name. // - if(svcFindFileCache(fqfn, (char *)&svcControl.filename, svcControl.fileNo)) + if( (type == MZF && (svcFindFileCache(fqfn, (char *)&svcControl.filename, svcControl.fileNo))) || type == CAS || type == BAS ) { // Open the file, fqfn has the FQFN of the correct file on the SD drive. result = f_open(&File, fqfn, FA_OPEN_EXISTING | FA_READ); @@ -3555,7 +3589,7 @@ uint8_t svcReadFile(uint8_t mode) // fileOpen = 1; fileSector = 0; - result = (FRESULT)svcReadFile(TZSVC_NEXT); + result = (FRESULT)svcReadFile(TZSVC_NEXT, type); } } } @@ -3577,6 +3611,10 @@ uint8_t svcReadFile(uint8_t mode) { // Read the required sector. result = f_read(&File, (char *)&svcControl.sector, TZSVC_SECTOR_SIZE, &readSize); + + // Place number of bytes read into the record for the Z80 to know where EOF is. + // + svcControl.loadSize = readSize; } // Move onto next sector. @@ -3586,6 +3624,7 @@ uint8_t svcReadFile(uint8_t mode) // Close the currently open file. else if(mode == TZSVC_CLOSE) { +printf("Closing file\n"); if(fileOpen) f_close(&File); fileOpen = 0; @@ -3596,40 +3635,151 @@ uint8_t svcReadFile(uint8_t mode) return(result == FR_OK ? TZSVC_STATUS_OK : TZSVC_STATUS_FILE_ERROR); } +// Method to create a file for writing and on subsequent calls write the data into that file. +// +uint8_t svcWriteFile(uint8_t mode, enum FILE_TYPE type) +{ + // Locals - dont use global as this is a seperate thread. + // + static FIL File; + static uint8_t fileOpen = 0; // Seperate flag as their is no public way to validate that File is open and valid, the method in FatFS is private for this functionality. + static uint8_t fileSector = 0; // Sector number being read. + FRESULT result = FR_OK; + unsigned int readSize; + char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\ + + // Request to createopen? Validate that we dont already have an open file and the create the file. + if(mode == TZSVC_OPEN) + { +printf("Open\n"); + // Close if previously open. + if(fileOpen == 1) + svcWriteFile(TZSVC_CLOSE, type); + + // Setup the defaults + // + svcSetDefaults(type); + + // Build the full filename from what has been provided. + sprintf(fqfn, "0:\\%s\\%s.%s", svcControl.directory, svcControl.filename, (type == MZF ? TZSVC_DEFAULT_MZF_EXT : type == CAS ? TZSVC_DEFAULT_CAS_EXT : TZSVC_DEFAULT_BAS_EXT)); +printf("FQFN:%s\n", fqfn); + + // Create the file, fqfn has the FQFN of the correct file on the SD drive. + result = f_open(&File, fqfn, FA_CREATE_ALWAYS | FA_WRITE | FA_READ); +printf("FOPEN:%d\n", result); + + // If the file was opened, set the flag to enable writing. + if(!result) + fileOpen = 1; + } + + // Write the next sector into the file. + else if(mode == TZSVC_NEXT && fileOpen == 1) + { + // If the Z80 is requesting a non sequential sector then seek to the correct location prior to the write. + // + if(fileSector != svcControl.fileSector) + { +printf("Different sector:%d %d\n", fileSector, svcControl.fileSector); + + result = f_lseek(&File, (svcControl.fileSector * TZSVC_SECTOR_SIZE)); + fileSector = svcControl.fileSector; + } + + // Proceed if no errors have occurred. + // + if(!result) + { + // Write the required sector. + result = f_write(&File, (char *)&svcControl.sector, svcControl.saveSize, &readSize); + printf("Write block:%d, %d, %d\n", svcControl.sector, svcControl.saveSize, readSize); + for(uint32_t idx=0; idx < svcControl.saveSize; idx++) + { + printf("%02x ", svcControl.sector[idx]); + } + } + + // Move onto next sector. + fileSector++; + printf("Sector:%d\n", fileSector); + } + + // Close the currently open file. + else if(mode == TZSVC_CLOSE) + { +printf("Close file\n"); + if(fileOpen) + f_close(&File); + fileOpen = 0; + } else + { + printf("WARNING: svcWriteFile called with unknown mode:%d\n", mode); + } + + // 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 load a file from SD directly into the tranZPUter memory. // -uint8_t svcLoadFile(void) +uint8_t svcLoadFile(enum FILE_TYPE type) { // Locals - dont use global as this is a seperate thread. // FRESULT result = FR_OK; + uint32_t bytesRead; char fqfn[FF_LFN_BUF + 13]; // 0:\12345678\ // Setup the defaults // - svcSetDefaults(); + svcSetDefaults(type); - // Find the file using the given file number or file name. + // MZF are handled with their own methods as it involves looking into the file to determine the name and details. // - if(svcFindFileCache(fqfn, (char *)&svcControl.filename, svcControl.fileNo)) + if(type == MZF) { - // Call method to load an MZF file. - result = loadMZFZ80Memory(fqfn, 0xFFFFFFFF, 0, 1); - - // Store the filename, used in reload or immediate saves. + // Find the file using the given file number or file name. // - osControl.lastFile = (uint8_t *)realloc(osControl.lastFile, strlen(fqfn)+1); - if(osControl.lastFile == NULL) + if(svcFindFileCache(fqfn, (char *)&svcControl.filename, svcControl.fileNo)) { - printf("Out of memory saving last file name, dependent applications (ie. CP/M) wont work!\n"); - result = FR_NOT_ENOUGH_CORE; + // Call method to load an MZF file. + result = loadMZFZ80Memory(fqfn, 0xFFFFFFFF, 0, 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 { - strcpy((char *)osControl.lastFile, fqfn); + result = FR_NO_FILE; } } else + // Cassette images are for NASCOM/Microsoft Basic. The files are in NASCOM format so the header needs to be skipped. + // BAS files are for human readable BASIC files. + if(type == CAS || type == BAS) { - result = FR_NO_FILE; + // Build the full filename from what has been provided. + sprintf(fqfn, "0:\\%s\\%s.%s", svcControl.directory, svcControl.filename, type == CAS ? TZSVC_DEFAULT_CAS_EXT : TZSVC_DEFAULT_BAS_EXT); + + // For the tokenised cassette, skip the header and load directly into the memory location provided. The load size given is the maximum size of file + // and the loadZ80Memory method will only load upto the given size. + // + if((result=loadZ80Memory((const char *)fqfn, 0, svcControl.loadAddr, svcControl.loadSize, &bytesRead, 0, 1)) != FR_OK) + { + printf("Error: Failed to load CAS:%s into tranZPUter memory.\n", fqfn); + } else + { + // Return the size of load in the service control record. + svcControl.loadSize = (uint16_t) bytesRead; + } } // Return values: 0 - Success : maps to TZSVC_STATUS_OK @@ -3639,7 +3789,7 @@ uint8_t svcLoadFile(void) // Method to save a file from tranZPUter memory directly into a file on the SD card. // -uint8_t svcSaveFile(void) +uint8_t svcSaveFile(enum FILE_TYPE type) { // Locals - dont use global as this is a seperate thread. // @@ -3650,21 +3800,36 @@ uint8_t svcSaveFile(void) // Setup the defaults // - svcSetDefaults(); + svcSetDefaults(type); - // Get the MZF header which contains the details of the file to save. - copyFromZ80((uint8_t *)&mzfHeader, MZ_CMT_ADDR, MZF_HEADER_SIZE, 0); - - // Need to extract and convert the filename to create a file. + // MZF are handled with their own methods as it involves looking into the file to determine the name and details. // - convertSharpFilenameToAscii(asciiFileName, (char *)mzfHeader.fileName, MZF_FILENAME_LEN); + if(type == MZF) + { + // Get the MZF header which contains the details of the file to save. + copyFromZ80((uint8_t *)&mzfHeader, MZ_CMT_ADDR, MZF_HEADER_SIZE, 0); - // Build filename. - // - sprintf(fqfn, "0:\\%s\\%s.%s", svcControl.directory, asciiFileName, TZSVC_DEFAULT_EXT); + // Need to extract and convert the filename to create a file. + // + convertSharpFilenameToAscii(asciiFileName, (char *)mzfHeader.fileName, MZF_FILENAME_LEN); - // Call the main method to save memory passing in the correct MZF details and header. - result = saveZ80Memory(fqfn, (mzfHeader.loadAddr < MZ_CMT_DEFAULT_LOAD_ADDR-3 ? MZ_CMT_DEFAULT_LOAD_ADDR : mzfHeader.loadAddr), mzfHeader.fileSize, &mzfHeader, 0); + // Build filename. + // + sprintf(fqfn, "0:\\%s\\%s.%s", svcControl.directory, asciiFileName, TZSVC_DEFAULT_MZF_EXT); + + // Call the main method to save memory passing in the correct MZF details and header. + result = saveZ80Memory(fqfn, (mzfHeader.loadAddr < MZ_CMT_DEFAULT_LOAD_ADDR-3 ? MZ_CMT_DEFAULT_LOAD_ADDR : mzfHeader.loadAddr), mzfHeader.fileSize, &mzfHeader, 0); + } else + // Cassette images are for NASCOM/Microsoft Basic. The files are in NASCOM format so the header needs to be skipped. + // BAS files are for human readable BASIC files. + if(type == CAS || type == BAS) + { + // Build the full filename from what has been provided. + sprintf(fqfn, "0:\\%s\\%s.%s", svcControl.directory, svcControl.filename, type == CAS ? TZSVC_DEFAULT_CAS_EXT : TZSVC_DEFAULT_BAS_EXT); + + // Call the main method to save memory passing in the correct details from the service record. + result = saveZ80Memory(fqfn, svcControl.saveAddr, svcControl.saveSize, NULL, 0); + } // Return values: 0 - Success : maps to TZSVC_STATUS_OK // 1 - Fail : maps to TZSVC_STATUS_FILE_ERROR @@ -3674,7 +3839,7 @@ uint8_t svcSaveFile(void) // Method to erase a file on the SD card. // -uint8_t svcEraseFile(void) +uint8_t svcEraseFile(enum FILE_TYPE type) { // Locals - dont use global as this is a seperate thread. // @@ -3683,17 +3848,26 @@ uint8_t svcEraseFile(void) // Setup the defaults // - svcSetDefaults(); + svcSetDefaults(MZF); - // Find the file using the given file number or file name. + // MZF are handled with their own methods as it involves looking into the file to determine the name and details. // - if(svcFindFileCache(fqfn, (char *)&svcControl.filename, svcControl.fileNo)) + if(type == MZF) { - // Call method to load an MZF file. - result = f_unlink(fqfn); + // Find the file using the given file number or file name. + // + if(svcFindFileCache(fqfn, (char *)&svcControl.filename, svcControl.fileNo)) + { + // Call method to load an MZF file. + result = f_unlink(fqfn); + } else + { + result = FR_NO_FILE; + } } else + // Cassette images are for NASCOM/Microsoft Basic. The files are in NASCOM format so the header needs to be skipped. + if(type == CAS) { - result = FR_NO_FILE; } // Return values: 0 - Success : maps to TZSVC_STATUS_OK @@ -3887,9 +4061,13 @@ uint32_t getServiceAddr(void) uint32_t addr = TZSVC_CMD_STRUCT_ADDR_TZFS; uint8_t memoryMode = readCtrlLatch(); - // Currently only CPM has a different service record address. + // If in CPM mode then set the service address accordingly. if(memoryMode == TZMM_CPM || memoryMode == TZMM_CPM2) addr = TZSVC_CMD_STRUCT_ADDR_CPM; + + // If in MZ700 mode then set the service address accordingly. + if(memoryMode == TZMM_MZ700_0 || memoryMode == TZMM_MZ700_2 || memoryMode == TZMM_MZ700_3 || memoryMode == TZMM_MZ700_4) + addr = TZSVC_CMD_STRUCT_ADDR_MZ700; return(addr); } @@ -3912,7 +4090,7 @@ void processServiceRequest(void) 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) + if(svcControl.cmd == TZSVC_CMD_WRITEFILE || svcControl.cmd == TZSVC_CMD_NEXTWRITEFILE || svcControl.cmd == TZSVC_CMD_WRITESDDRIVE) { copyFromZ80((uint8_t *)&svcControl.sector, z80Control.svcControlAddr+TZSVC_CMD_SIZE, TZSVC_SECTOR_SIZE, 0); } @@ -3940,18 +4118,29 @@ void processServiceRequest(void) // Open a file stream and return the first block. case TZSVC_CMD_READFILE: - status=svcReadDir(TZSVC_OPEN); + status=svcReadFile(TZSVC_OPEN, svcControl.fileType); break; // Read the next block in the file stream. - case TZSVC_CMD_MEXTREADFILE: - status=svcReadFile(TZSVC_NEXT); + case TZSVC_CMD_NEXTREADFILE: + status=svcReadFile(TZSVC_NEXT, svcControl.fileType); + break; + + // Create a file for data write. + case TZSVC_CMD_WRITEFILE: + status=svcWriteFile(TZSVC_OPEN, svcControl.fileType); + break; + + // Write a block of data to an open file. + case TZSVC_CMD_NEXTWRITEFILE: + status=svcWriteFile(TZSVC_NEXT, svcControl.fileType); break; // Close an open dir/file. case TZSVC_CMD_CLOSE: svcReadDir(TZSVC_CLOSE); - svcReadFile(TZSVC_CLOSE); + svcReadFile(TZSVC_CLOSE, svcControl.fileType); + svcWriteFile(TZSVC_CLOSE, svcControl.fileType); // Only need to copy the command section back to the Z80 for a close operation. // @@ -3960,18 +4149,18 @@ void processServiceRequest(void) // Load a file directly into target memory. case TZSVC_CMD_LOADFILE: - status=svcLoadFile(); + status=svcLoadFile(svcControl.fileType); break; // Save a file directly from target memory. case TZSVC_CMD_SAVEFILE: - status=svcSaveFile(); + status=svcSaveFile(svcControl.fileType); refreshCacheDir = 1; break; // Erase a file from the SD Card. case TZSVC_CMD_ERASEFILE: - status=svcEraseFile(); + status=svcEraseFile(svcControl.fileType); refreshCacheDir = 1; break; @@ -3982,7 +4171,7 @@ void processServiceRequest(void) // Load the 40 column version of the SA1510 bios into memory. case TZSVC_CMD_LOAD40BIOS: - if((status=loadZ80Memory((const char *)MZ_ROM_SA1510_40C, 0, MZ_MROM_ADDR, 0, 0, 1)) != FR_OK) + if((status=loadZ80Memory((const char *)MZ_ROM_SA1510_40C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) { printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_SA1510_40C); } @@ -3999,7 +4188,7 @@ void processServiceRequest(void) // Load the 80 column version of the SA1510 bios into memory. case TZSVC_CMD_LOAD80BIOS: - if((status=loadZ80Memory((const char *)MZ_ROM_SA1510_80C, 0, MZ_MROM_ADDR, 0, 0, 1)) != FR_OK) + if((status=loadZ80Memory((const char *)MZ_ROM_SA1510_80C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) { printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_SA1510_80C); } @@ -4016,7 +4205,7 @@ void processServiceRequest(void) // Load the 40 column MZ700 1Z-013A bios into memory. case TZSVC_CMD_LOAD700BIOS40: - if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_40C, 0, MZ_MROM_ADDR, 0, 0, 1)) != FR_OK) + if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_40C, 0, MZ_MROM_ADDR, 0, 0, 0, 1)) != FR_OK) { printf("Error: Failed to load %s into tranZPUter memory.\n", MZ_ROM_1Z_013A_40C); } @@ -4033,7 +4222,7 @@ void processServiceRequest(void) // Load the 80 column MZ700 1Z-013A bios into memory. case TZSVC_CMD_LOAD700BIOS80: - if((status=loadZ80Memory((const char *)MZ_ROM_1Z_013A_80C, 0, MZ_MROM_ADDR, 0, 0, 1)) != FR_OK) + 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); } @@ -4050,7 +4239,7 @@ void processServiceRequest(void) // Load the MZ-80B IPL ROM into memory. case TZSVC_CMD_LOAD80BIPL: - if((status=loadZ80Memory((const char *)MZ_ROM_MZ80B_IPL, 0, MZ_MROM_ADDR, 0, 0, 1)) != FR_OK) + 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); } @@ -4067,7 +4256,7 @@ void processServiceRequest(void) // 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) + if((status=loadZ80Memory((const char *)osControl.lastFile, MZF_HEADER_SIZE, svcControl.loadAddr+0x40000, svcControl.loadSize, 0, 0, 1)) != FR_OK) { printf("Error: Failed to load BDOS:%s into tranZPUter memory.\n", (char *)osControl.lastFile); } @@ -4111,6 +4300,7 @@ void processServiceRequest(void) break; default: + printf("WARNING: Unrecognised command:%02x\n", svcControl.cmd); break; } diff --git a/include/tranzputer.h b/include/tranzputer.h index 58e9cc6..190ea83 100755 --- a/include/tranzputer.h +++ b/include/tranzputer.h @@ -120,6 +120,7 @@ // #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_ADDR_MZ700 0x6FD80 // Address of the command structure within MZ700 compatible programs - exists in 64K Block 6. #define TZSVC_CMD_STRUCT_SIZE 0x280 // Size of the inter z80/K64 service command memory. #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. @@ -130,12 +131,14 @@ #define TZSVC_CMD_READDIR 0x01 // Service command to open a directory and return the first block of entries. #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_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_NEXTREADFILE 0x04 // Service command to return the next block of an open file. +#define TZSVC_CMD_WRITEFILE 0x05 // Service command to create a file and save the first block. +#define TZSVC_CMD_NEXTWRITEFILE 0x06 // Service command to write the next block to 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_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_LOAD700BIOS40 0x22 // Service command requesting that the MZ700 1Z-013A 40 column BIOS is loaded. @@ -148,8 +151,12 @@ #define TZSVC_CMD_CPU_BASEFREQ 0x40 // Service command to switch to the mainboard frequency. #define TZSVC_CMD_CPU_ALTFREQ 0x41 // Service command to switch to the alternate frequency provided by the K64F. #define TZSVC_CMD_CPU_CHGFREQ 0x42 // Service command to set the alternate frequency in hertz. -#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_MZF_DIR "MZF" // Default directory where MZF files are stored. +#define TZSVC_DEFAULT_CAS_DIR "CAS" // Default directory where BASIC CASsette files are stored. +#define TZSVC_DEFAULT_BAS_DIR "BAS" // Default directory where BASIC text files are stored. +#define TZSVC_DEFAULT_MZF_EXT "MZF" // Default file extension for MZF files. +#define TZSVC_DEFAULT_CAS_EXT "CAS" // Default file extension for CASsette files. +#define TZSVC_DEFAULT_BAS_EXT "BAS" // Default file extension for BASic script files stored in readable text. #define TZSVC_DEFAULT_WILDCARD "*" // Default wildcard file matching. #define TZSVC_RESULT_OFFSET 0x01 // Offset into structure of the result byte. #define TZSVC_DIRNAME_SIZE 20 // Limit is size of FAT32 directory name. @@ -176,6 +183,11 @@ #define MZF_COMMENT 0x18 // Comment, used for details of the file or startup code. #define MZF_COMMENT_LEN 104 // Length of the comment field. +// Constants for other handled file formats. +// +#define CAS_HEADER_SIZE 256 // Size of the CASsette header. + + // Pin Constants - Pins assigned at the hardware level to specific tasks/signals. // #define MAX_TRANZPUTER_PINS 52 @@ -419,6 +431,14 @@ enum MACHINE_MODE { MZ80B = 2 }; +// Types of file which have handlers and can be processed. +// +enum FILE_TYPE { + MZF = 0, + CAS = 1, + BAS = 2 +}; + // Structure to define a Sharp MZ80A MZF directory structure. This header appears at the beginning of every Sharp MZ80A tape (and more recently archived/emulator) images. // typedef struct __attribute__((__packed__)) { @@ -552,11 +572,16 @@ typedef struct __attribute__((__packed__)) { 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. + uint8_t fileType; // Type of file being processed. union { uint16_t loadAddr; // Load address for ROM/File images which need to be dynamic. + uint16_t saveAddr; // Save address for ROM/File images which need to be dynamic. uint16_t cpuFreq; // CPU Frequency in KHz - used for setting of the alternate CPU clock frequency. }; - uint16_t loadSize; // Size for ROM/File to be loaded. + union { + uint16_t loadSize; // Size for ROM/File to be loaded. + uint16_t saveSize; // Size for ROM/File to be saved. + }; 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. @@ -627,9 +652,9 @@ FRESULT loadVideoFrameBuffer(char *, enum VIDEO_FRAMES); FRESULT saveVideoFrameBuffer(char *, enum VIDEO_FRAMES); char *getVideoFrame(enum VIDEO_FRAMES); char *getAttributeFrame(enum VIDEO_FRAMES); -FRESULT loadZ80Memory(const char *, uint32_t, uint32_t, uint32_t, uint8_t, uint8_t); +FRESULT loadZ80Memory(const char *, uint32_t, uint32_t, uint32_t, uint32_t *, uint8_t, uint8_t); FRESULT saveZ80Memory(const char *, uint32_t, uint32_t, t_svcDirEnt *, uint8_t); -FRESULT loadMZFZ80Memory(const char *, uint32_t, uint8_t, uint8_t); +FRESULT loadMZFZ80Memory(const char *, uint32_t, uint32_t *, uint8_t, uint8_t); // Getter/Setter methods! uint8_t isZ80Reset(void); @@ -640,15 +665,17 @@ void convertSharpFilenameToAscii(char *, char *, uint8_t); // tranZPUter OS i/f methods. uint8_t setZ80SvcStatus(uint8_t); -void svcSetDefaults(void); +void svcSetDefaults(enum FILE_TYPE); uint8_t svcReadDir(uint8_t); uint8_t svcFindFile(char *, char *, uint8_t); uint8_t svcReadDirCache(uint8_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 svcReadFile(uint8_t, enum FILE_TYPE); +uint8_t svcWriteFile(uint8_t, enum FILE_TYPE); +uint8_t svcLoadFile(enum FILE_TYPE); +uint8_t svcSaveFile(enum FILE_TYPE); +uint8_t svcEraseFile(enum FILE_TYPE); uint8_t svcAddCPMDrive(void); uint8_t svcReadCPMDrive(void); uint8_t svcWriteCPMDrive(void); diff --git a/libraries/lib/libimath2-k64f.a b/libraries/lib/libimath2-k64f.a index 3a6cfd59b6b10170075fd534248563406862c8c0..d3f4bdf77e7b9e7c1ad856ee52b69dbceffcb77e 100644 GIT binary patch delta 76 zcmcbScq4IwG`o?Bfw6&!#O4s2o2UXlZaWbI7uHB_Rt3Kqoa+3`dST#)ohn(;v)Z6yN^d zg^`U1rT`)&9LU(m4-*1;ar?mpMpQp;f0V_D#O4s2o2UXlZaWbI7uHB_Rt3Kqoa+3`dST#)ohn(;v)Z6yN^d zg^`U1s=x#yBpk@t#}5+%d2#!}1V*?YO+ewh{ZSSp+><6iH%e{~En#edxzA+#gBr%W zFq=%kNof0>HpYoC$3boCp2+CO3$tlE&^>~19?;B$?GbAbAz`w8!4}3yxS8AbF)oC2 erUR{W+WzV|<7~JP*!PPsGJZq237C*)aRC76F72EE diff --git a/libraries/lib/libummath-k64f.a b/libraries/lib/libummath-k64f.a index e6986d9ac12e08bacaf91ead37f5d3b06e6d8e5e..38e756670eb94219f7fde4d0d1a0389099d829d5 100644 GIT binary patch delta 29 ecmaDN@rt!fA)~%P={D}W3TwwD$xlT@) z>}ETSiEz&3b#fA$-x+Gc1vblB-$Zc!x%}jX>-!gE2bcS~ZkUjipWXU_S+Emx8_M`$hE0~Ume|ZRVJTe2=5;fl!Z~2&8yA1$hAH2?Zv9%gZzkJmNN%p) vSAtLu@&w-rMTCHz#*)pqF23b}>pyo(7a=QW?X=nD$#jGOC;)%Hea#I3pRsQ{ delta 358 zcmaFznfb|Q<_Xg5hL#p)7KSDpm1G%V?8*OJ#5cz>rt!fA)~%P={D}W3TwwD$xlT@) z>}ETSiEz&3b#fA$-x+Gc1vblB-$Zc!x%}jX>-!gE2bcS~ZkUjipWXU_S+Emx8_M`$hE0~Ume|ZRVJTe2=5;fl!Z~2&8yA1$hAH2?Zv9%gZzkJmNN%p) vSAtLu@&w-rMTCHz#*)pqF23b}>pyo(7a=QW?X=nD$#jGOC;)%Hea#I3sPAyA diff --git a/libraries/lib/libummisc-k64f.a b/libraries/lib/libummisc-k64f.a index 5ff549978625f82acd9a040bac09f4c556090cf8..aa5a8bb30a62caf16d1558c5eb3f21ab0f98318c 100644 GIT binary patch delta 42 lcmX?SaL!1AMkWTv1}2spm5LdmY>UYsf+aR@Vf5rh5)j`k&3}joNkC%rA8A!& z6=Iw1G@rxF1DPSd+1Yg&A56>U55Z{4jS|ge;Iaj^bGcz0uwL!XG-T_dCfmudZT>O! zD6*jV=G%+5p$e>De+=1C;+rS$J%vzFP%E*y=F~)(O_mUwuBpLPKm_t16~WAa2>gF9 vgsMXSPY{a0_W2x)NJ%yV-$R6 delta 394 zcmdn=k!90ImI>1AhL#p)7KWx9m5LdmY?H|!f+aR@Vf5rh5)j`k&3}joNkC%rA8A!& z6=Iw1G@rxF1DPSd+1Yg&A56>U55aKdra)P-%|?mlGEiC5%>}h{xnUfzUhU2_m~|lK zQIqXt*f#%|dK6hueDm!^+fW78uRjKJ6iA!+=E-|cAygF9N^Gt