diff --git a/examples/pgztest/pgztest.c b/examples/pgztest/pgztest.c index e385a0f..363a1bf 100644 --- a/examples/pgztest/pgztest.c +++ b/examples/pgztest/pgztest.c @@ -24,33 +24,57 @@ #include "f256.h" -int main(void) { - byte x; - byte y; +void dirtest(void) { + DIR *dir; + struct dirent *dirent; + + textPrint("Starting directory test.\n"); + + if ((dir = opendir("0:"))) { + textPrint("Directory opened.\n"); + for (;;) { + if ((dirent = readdir(dir))) { + + textPrint("dirent type="); + textPrintInt(dirent->d_type); + textPrint("\n"); + + if (_DE_ISREG(dirent->d_type)) { + textPrint(dirent->d_name); + textPrint(" ("); + textPrintInt(dirent->d_blocks); + textPrint(")\n"); + continue; + } + + if (_DE_ISDIR(dirent->d_type)) { + textPrint(dirent->d_name); + textPrint("/\n"); + continue; + } + + if (_DE_ISLBL(dirent->d_type)) { + textPrint("Directory of "); + textPrint(dirent->d_name); + textPrint(":\n"); + continue; + } + } + break; + } + textPrint("Closing.\n"); + closedir(dir); + } else { + textPrint("Failed to open directory.\n"); + } +} + + +int main(void) { f256Init(); - textPrint("F256 LIVES!\n"); - textSetColor(LIGHT_GREEN, BLACK); - textPrint("Green!\n\n"); - textSetColor(ORANGE, BLACK); - textPrint("byte is "); textPrintInt(sizeof(byte)); - textPrint("\nint is "); textPrintInt(sizeof(int)); - textPrint("\nint16_t is "); textPrintInt(sizeof(int16_t)); - textPrint("\nint32_t is "); textPrintInt(sizeof(int32_t)); - textPrint("\n"); - - textPrint("\nEvent Size: "); textPrintInt(sizeof(kernelEvent(key.PRESSED))); - textPrint("\n\n"); - textGetXY(&x, &y); - - while(1) { - //kernelCall(NextEvent); - textGotoXY(x, y); - textPrint("Pending: "); - textPrintInt(kernelGetPending()); - textPrint(" "); - } + dirtest(); return 0; } diff --git a/f256lib/f256.c b/f256lib/f256.c index e2ed532..c848f3e 100644 --- a/f256lib/f256.c +++ b/f256lib/f256.c @@ -32,6 +32,7 @@ #include "tile.c" #include "graphics.c" #include "sprite.c" +#include "file.c" void f256Init(void) { @@ -58,6 +59,7 @@ void f256Init(void) { bitmapReset(); tileReset(); spriteReset(); + fileReset(); randomSeed(0); //***TODO*** Use clock or something. } diff --git a/f256lib/f256.h b/f256lib/f256.h index 2cfe034..5587e62 100644 --- a/f256lib/f256.h +++ b/f256lib/f256.h @@ -163,6 +163,7 @@ void FAR_POKE(uint32_t address, byte value); #include "tile.h" #include "graphics.h" #include "sprite.h" +#include "file.h" #ifdef __cplusplus diff --git a/f256lib/file.c b/f256lib/file.c new file mode 100644 index 0000000..880de23 --- /dev/null +++ b/f256lib/file.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include + +#include "file.h" + + +#define MAX_DRIVES 8 + + +static char _dirStream[MAX_DRIVES]; + + +static char *pathWithoutDrive(char *path, char *drive); + + +int16_t fileCloseDir(fileDirT *dir) { + if (!dir) return -1; + + for (;;) { + if (*dir->stream) { + kernelArgs->directory.close.stream = *dir->stream; + kernelCall(Directory.Close); + if (!kernelError) { + *dir->stream = 0; + } + } + kernelNextEvent(); + if (kernelEventData.type == kernelEvent(directory.CLOSED)) { + free(dir); + dir = NULL; + return 0; + } + } +} + + +fileDirT *fileOpenDir(char *name) { + char drive; + char stream; + fileDirT *dir; + + name = pathWithoutDrive(name, &drive); + + if (_dirStream[drive]) return NULL; // Only one at a time. + + kernelArgs->directory.open.drive = drive; + kernelArgs->common.buf = name; + kernelArgs->common.buflen = strlen(name); + stream = kernelCall(Directory.Open); + + textPrint("kernelError = "); textPrintInt(kernelError); textPrint("\n"); + textPrint("kernelReturn = "); textPrintInt(kernelReturn); textPrint("\n"); + textPrint("stream = "); textPrintInt(stream); textPrint("\n"); + + if (kernelError) return NULL; + + for (;;) { + kernelNextEvent(); + + if (kernelEventData.type != 0) { + textPrintInt(kernelEventData.type); + textPrint(" "); + } + + if (kernelEventData.type == kernelEvent(directory.OPENED)) break; + if (kernelEventData.type == kernelEvent(directory.ERROR)) return NULL; + } + + _dirStream[drive] = stream; + dir = (fileDirT *)malloc(sizeof(fileDirT)); + dir->stream = &_dirStream[drive]; + + return dir; +} + + +fileDirEntT *fileReadDir(fileDirT *dir) { + static fileDirEntT dirent; + unsigned len; + + if (!dir) return NULL; + + textPrint("Calling Directory.Read.\n"); + + kernelArgs->directory.read.stream = *dir->stream; + kernelCall(Directory.Read); + if (kernelError) return NULL; + + textPrint("Directory.Read called.\n"); + + for (;;) { + + kernelNextEvent(); + + switch (kernelEventData.type) { + + textPrintInt(kernelEventData.type); + textPrint(" "); + + case kernelEvent(directory.VOLUME): + dirent.d_blocks = 0; + dirent.d_type = 2; + break; + + case kernelEvent(directory.FILE): + kernelArgs->common.buf = &dirent.d_blocks; + kernelArgs->common.buflen = sizeof(dirent.d_blocks); + kernelCall(ReadExt); + dirent.d_type = (dirent.d_blocks == 0); + break; + + case kernelEvent(directory.FREE): + // dirent doesn't care about these types of records. + kernelArgs->directory.read.stream = *dir->stream; + kernelCall(Directory.Read); + if (!kernelError) continue; + // Fall through. + + case kernelEvent(directory.EOF): + case kernelEvent(directory.ERROR): + return NULL; + + default: + continue; + } + + // Copy the name. + len = kernelEventData.directory.file.len; + if (len >= sizeof(dirent.d_name)) { + len = sizeof(dirent.d_name) - 1; + } + + if (len > 0) { + kernelArgs->common.buf = &dirent.d_name; + kernelArgs->common.buflen = len; + kernelCall(ReadData); + } + dirent.d_name[len] = '\0'; + + return &dirent; + } +} + + +void fileReset(void) { + byte x; + + for (x=0; x= '0') && (*path <= '7')) *drive = *path - '0'; + + return (path + 2); +} + + diff --git a/f256lib/file.h b/f256lib/file.h new file mode 100644 index 0000000..30cdda8 --- /dev/null +++ b/f256lib/file.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#ifndef FILE_H +#define FILE_H + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#include "f256.h" + + +typedef struct fileDirS { + char *stream; +} fileDirT; + +typedef struct fileDirEntS { + unsigned char d_blocks; + unsigned char d_type; + char d_name[256]; +} fileDirEntT; + + +int16_t fileCloseDir(fileDirT *dir); +fileDirT *fileOpenDir(char *name); +fileDirEntT *fileReadDir(fileDirT *dir); +void fileReset(void); + + +#define _DE_ISREG(t) (t == 0) +#define _DE_ISDIR(t) (t == 1) +#define _DE_ISLBL(t) (t == 2) +#define _DE_ISLNK(t) (0) + + +// Aliases to the standard names if they don't exist. +#ifndef DIR +#define DIR fileDirT +#define dirent fileDirEntS +#define opendir fileOpenDir +#define closedir fileCloseDir +#define readdir fileReadDir +#endif + + +#ifdef __cplusplus +} +#endif + + +#endif // FILE_H diff --git a/f256lib/kernel.c b/f256lib/kernel.c index 7bf5fe9..3de69e4 100644 --- a/f256lib/kernel.c +++ b/f256lib/kernel.c @@ -26,6 +26,7 @@ kernelEventT kernelEventData; // Allocate some RAM to hold event data. kernelArgsT *kernelArgs; // Create an alias for the kernel args. +char kernelReturn; char kernelError; @@ -43,7 +44,7 @@ void kernelReset(void) { /* - case EVENT(JOYSTICK): + case EVENT(GAME): // Joystick break; diff --git a/f256lib/kernel.h b/f256lib/kernel.h index e5ade60..ff9ca9b 100644 --- a/f256lib/kernel.h +++ b/f256lib/kernel.h @@ -34,24 +34,27 @@ extern "C" #include "f256.h" +#define kernelNextEvent() ({ kernelEventData.type = 0; kernelCall(NextEvent); }) #define kernelEvent(member) (size_t)(&((struct events *)0)->member) #define kernelVector(member) (size_t)(&((struct call *)0xff00)->member) #define kernelCall(fn) \ - asm("jsr %[addy] \n" \ + ({ asm("jsr %[addy] \n" \ "stz %[err] \n" \ - "ror %[err]" \ - : [err] "+m"(kernelError) \ + "ror %[err] \n" \ + "sta %[ret]" \ + : [err] "+m"(kernelError), [ret] "+m"(kernelReturn) \ : [addy] "i"(kernelVector(fn)) \ - : "a", "x", "y", "c", "v"); + : "a", "x", "y", "c", "v"); kernelReturn; }) typedef struct event_t kernelEventT; typedef struct call_args kernelArgsT; -extern char kernelError; -extern kernelArgsT *kernelArgs; extern kernelEventT kernelEventData; +extern kernelArgsT *kernelArgs; +extern char kernelReturn; +extern char kernelError; byte kernelGetPending(void); diff --git a/f256lib/text.c b/f256lib/text.c index a6bf775..4f788c4 100644 --- a/f256lib/text.c +++ b/f256lib/text.c @@ -112,10 +112,11 @@ void textGotoXY(byte x, byte y) { // Print a string to the screen. void textPrint(char *message) { - int x = 0; - int i = 0; - int j = 0; - byte mmu = PEEK(MMU_IO_CTRL); // Get current MMU state. + int16_t x = 0; + int16_t i = 0; + int16_t j = 0; + int16_t m = 0; + byte mmu = PEEK(MMU_IO_CTRL); // Get current MMU state. volatile byte *vram = (byte *)mathUnsignedAddition(TEXT_MATRIX, mathUnsignedMultiply(_MAX_COL, _row)); volatile byte *save = 0; @@ -136,9 +137,12 @@ void textPrint(char *message) { if (_row == _MAX_ROW) { // Scroll contents up one line. vram = (byte *)TEXT_MATRIX; + m = _MAX_COL * (_MAX_ROW - 1); // mathUnsignedMultiply(_MAX_COL, (_MAX_ROW - 1)); // It REALLY doesn't like using the copro for this. POKE(MMU_IO_CTRL, MMU_IO_COLOR); // Swap I/O page 3 into bank 6. - for (j=0; j<2; j++) { - for (i = 0; i < mathUnsignedMultiply(_MAX_COL, (_MAX_ROW - 1)); i++) vram[i] = vram[i+_MAX_COL]; + for (j=0; j<2; j++) { // Twice - first is the text, second is color. + for (i = 0; i < m; i++) { + vram[i] = vram[i + _MAX_COL]; + } POKE(MMU_IO_CTRL, MMU_IO_TEXT); // Swap I/O page 2 into bank 6. } // Clear bottom line. @@ -238,8 +242,6 @@ void textSetCursor(byte c) { void textSetDouble(bool x, bool y) { - //***TODO*** Adding this function seems to have screwed up scrolling. - POKE(VKY_MSTR_CTRL_1, (PEEK(VKY_MSTR_CTRL_1) & 0xf9) | (x << 1) | (y << 2)); _MAX_COL = x ? 40 : 80;