mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
7.7 KiB
390 lines
7.7 KiB
|
|
const IO_READ := 0;
|
|
const IO_WRITE := 1;
|
|
const IO_READ_WRITE := 2;
|
|
|
|
const IO_TEXT := 0;
|
|
const IO_BIN := 1;
|
|
|
|
const SUCCESS := 0;
|
|
const ERR_NO_FILE := 1;
|
|
const ERR_BAD_IO := 2;
|
|
const ERR_DIR_FULL := 3;
|
|
const ERR_DISK_FULL := 4;
|
|
const ERR_EOF := 5;
|
|
|
|
const CHAR_EOF := 0x1A;
|
|
|
|
record CpmFCB is
|
|
dr: uint8;
|
|
f: uint8[11];
|
|
ex: uint8;
|
|
s1: uint8;
|
|
s2: uint8;
|
|
rc: uint8;
|
|
d: uint8[16];
|
|
cr: uint8;
|
|
r0: uint8;
|
|
r1: uint8;
|
|
r2: uint8;
|
|
end record;
|
|
|
|
record FCB is
|
|
bufferptr: uint8; # offset in buffer
|
|
iotype: uint8;
|
|
datatype: uint8;
|
|
cpm: CpmFCB;
|
|
buffer: uint8[128];
|
|
end record;
|
|
|
|
sub MemSet(p:[uint8], char:uint8, size:uint16) is
|
|
@asm "ld a,(", char, ")";
|
|
@asm "ld de,(", size, ")";
|
|
@asm "ld hl,(", p, ")";
|
|
@asm "ld c,a";
|
|
@asm "loopm:";
|
|
@asm "ld a,e";
|
|
@asm "or d";
|
|
@asm "ret z";
|
|
@asm "ld (hl),c";
|
|
@asm "inc hl";
|
|
@asm "dec de";
|
|
@asm "jr loopm";
|
|
end sub;
|
|
|
|
sub MemCopy(src: [uint8], size: intptr, dest: [uint8]) is
|
|
@asm "ld de,(", dest, ")";
|
|
@asm "ld hl,(", src, ")";
|
|
@asm "ld bc,(", size, ")";
|
|
@asm "ld a,b";
|
|
@asm "or c";
|
|
@asm "ret z";
|
|
@asm "ldir";
|
|
@asm "ret";
|
|
end sub;
|
|
|
|
sub fcb_init(fcb: [FCB], filename: [uint8]) is
|
|
sub fill(dest: [uint8], src: [uint8], len: uint8): (srcout: [uint8]) is
|
|
loop
|
|
var c := [src];
|
|
if (c < 32) or (c == '.') then
|
|
c := ' ';
|
|
elseif (c == '*') then
|
|
c := '?';
|
|
else
|
|
src := src + 1;
|
|
end if;
|
|
if (c >= 'a') and (c <= 'z') then
|
|
c := c - ('a' - 'A');
|
|
end if;
|
|
[dest] := c;
|
|
dest := dest + 1;
|
|
|
|
len := len - 1;
|
|
if len == 0 then
|
|
break;
|
|
end if;
|
|
end loop;
|
|
srcout := src;
|
|
end sub;
|
|
|
|
MemSet(fcb as [uint8], 0, @bytesof FCB);
|
|
MemSet(&fcb.cpm.f[0] as [uint8], ' ', 11);
|
|
filename := fill(&fcb.cpm.f[0], filename, 8);
|
|
|
|
var c: uint8;
|
|
loop
|
|
c := [filename];
|
|
if (c < 32) or (c == '.') then
|
|
break;
|
|
end if;
|
|
filename := filename + 1;
|
|
end loop;
|
|
|
|
if c == '.' then
|
|
filename := fill(&fcb.cpm.f[8], filename+1, 3);
|
|
end if;
|
|
end sub;
|
|
|
|
sub FCBOpenIn(fcb: [FCB], filename: [uint8], type: uint8): (errno: uint8) @extern("FCBOpenIn") is
|
|
var cpmfcb := &fcb.cpm;
|
|
var cpmerr: uint8;
|
|
|
|
fcb_init(fcb, filename);
|
|
fcb.iotype := IO_READ;
|
|
fcb.datatype := type;
|
|
|
|
@asm "ld c, 15"; # OPEN_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", cpmerr, "), a";
|
|
|
|
if cpmerr == 0xFF then
|
|
errno := ERR_NO_FILE;
|
|
else
|
|
errno := SUCCESS;
|
|
end if;
|
|
end sub;
|
|
|
|
sub FCBOpenRW(fcb: [FCB], type: uint8, iotype: uint8): (errno: uint8) is
|
|
var cpmfcb := &fcb.cpm;
|
|
var cpmerr: uint8;
|
|
var c: uint8;
|
|
|
|
fcb.iotype := iotype;
|
|
fcb.datatype := type;
|
|
|
|
if iotype == IO_WRITE then
|
|
@asm "ld c, 19"; # DELETE_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
|
|
@asm "ld c, 22"; # CREATE_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", cpmerr, "), a";
|
|
|
|
if cpmerr == 0xFF then
|
|
errno := ERR_DIR_FULL;
|
|
else
|
|
errno := SUCCESS;
|
|
end if;
|
|
else #IO_READ_WRITE
|
|
@asm "ld c, 15"; # OPEN_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", cpmerr, "), a";
|
|
|
|
if cpmerr == 0xFF then
|
|
errno := ERR_NO_FILE;
|
|
else
|
|
errno := SUCCESS;
|
|
end if;
|
|
end if;
|
|
|
|
if fcb.datatype == IO_TEXT then
|
|
c := CHAR_EOF;
|
|
else
|
|
c := 0;
|
|
end if;
|
|
|
|
MemSet(&fcb.buffer[0], c, 128);
|
|
end sub;
|
|
|
|
sub FCBOpenOut(fcb: [FCB], filename: [uint8], type: uint8): (errno: uint8) @extern("FCBOpenOut") is
|
|
fcb_init(fcb, filename);
|
|
errno := FCBOpenRW(fcb, type, IO_WRITE);
|
|
end sub;
|
|
|
|
sub FCBOpenInOut(fcb: [FCB], filename: [uint8], type: uint8): (errno: uint8) @extern("FCBOpenInOut") is
|
|
fcb_init(fcb, filename);
|
|
errno := FCBOpenRW(fcb, type, IO_READ_WRITE);
|
|
end sub;
|
|
|
|
sub FCBOpenForAppend(fcb: [FCB], filename: [uint8]): (errno: uint8) @extern("FCBOpenForAppend") is
|
|
var cpmfcb := &fcb.cpm;
|
|
var cpmerr: uint8;
|
|
|
|
fcb_init(fcb, filename);
|
|
|
|
@asm "ld c, 17"; # SEARCH_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", cpmerr, "), a";
|
|
|
|
if cpmerr == 0xFF then
|
|
# not found, open it for write
|
|
errno := FCBOpenRW(fcb, IO_BIN, IO_WRITE);
|
|
else
|
|
# found, open it for read/write
|
|
errno := FCBOpenRW(fcb, IO_BIN, IO_READ_WRITE);
|
|
|
|
# errno should be SUCCESS
|
|
if errno != SUCCESS then
|
|
return;
|
|
end if;
|
|
|
|
var dma := &fcb.buffer[0];
|
|
@asm "ld c, 26"; # SET DMA
|
|
@asm "ld de, (", dma, ")";
|
|
@asm "call 5";
|
|
|
|
@asm "ld c, 35"; # COMPUTE FILE SIZE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
|
|
MemSet(&fcb.buffer[0] as [uint8], 0, 128);
|
|
|
|
@asm "ld c, 34"; # WRITE RANDOM
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
|
|
errno := SUCCESS;
|
|
end if;
|
|
end sub;
|
|
|
|
sub FCBGetChar(fcb: [FCB]): (c: uint8, errno: uint8) @extern("FCBGetChar") is
|
|
|
|
if fcb.iotype == IO_WRITE then
|
|
errno := ERR_BAD_IO;
|
|
c := 0;
|
|
return;
|
|
end if;
|
|
|
|
var index: uint8 := fcb.bufferptr;
|
|
|
|
if index == 0 then
|
|
var cpmfcb := &fcb.cpm;
|
|
var cpmerr: uint8;
|
|
|
|
var dma := &fcb.buffer[0];
|
|
@asm "ld c, 26"; # SET DMA
|
|
@asm "ld de, (", dma, ")";
|
|
@asm "call 5";
|
|
|
|
@asm "ld c, 20"; # READ SEQ
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", cpmerr, "),a";
|
|
|
|
if cpmerr != 0 then
|
|
c := 0;
|
|
errno := ERR_EOF;
|
|
return;
|
|
end if;
|
|
|
|
c := fcb.buffer[0];
|
|
fcb.bufferptr := 1;
|
|
else
|
|
c := fcb.buffer[index];
|
|
|
|
if index == 127 then
|
|
fcb.bufferptr := 0;
|
|
else
|
|
fcb.bufferptr := index + 1;
|
|
end if;
|
|
end if;
|
|
|
|
if fcb.datatype == IO_TEXT and c == CHAR_EOF then
|
|
errno := ERR_EOF;
|
|
else
|
|
errno := SUCCESS;
|
|
end if;
|
|
end sub;
|
|
|
|
sub FCBPutChar(fcb: [FCB], c: uint8): (errno: uint8) @extern("FCBPutChar") is
|
|
|
|
if fcb.iotype == IO_READ then
|
|
errno := ERR_BAD_IO;
|
|
return;
|
|
end if;
|
|
|
|
var index: uint8 := fcb.bufferptr;
|
|
fcb.buffer[index] := c;
|
|
|
|
if index == 127 then
|
|
var cpmfcb := &fcb.cpm;
|
|
var cpmerr: uint8;
|
|
|
|
var dma := &fcb.buffer[0];
|
|
@asm "ld c, 26"; # SET DMA
|
|
@asm "ld de, (", dma, ")";
|
|
@asm "call 5";
|
|
|
|
@asm "ld c, 21"; # WRITE SEQ
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", cpmerr, "),a";
|
|
|
|
if cpmerr != 0 then
|
|
errno := ERR_DISK_FULL;
|
|
return;
|
|
end if;
|
|
|
|
fcb.bufferptr := 0;
|
|
|
|
if fcb.datatype == IO_TEXT then
|
|
c := CHAR_EOF;
|
|
else
|
|
c := 0;
|
|
end if;
|
|
|
|
MemSet(&fcb.buffer[0], c, 128);
|
|
else
|
|
fcb.bufferptr := index + 1;
|
|
end if;
|
|
|
|
errno := SUCCESS;
|
|
end sub;
|
|
|
|
sub FCBClose(fcb: [FCB]): (errno: uint8) @extern("FCBClose") is
|
|
var cpmfcb := &fcb.cpm;
|
|
var closeerr: uint8;
|
|
var writeerr: uint8 := 0;
|
|
|
|
errno := SUCCESS;
|
|
|
|
if fcb.iotype == IO_READ then
|
|
return;
|
|
end if;
|
|
|
|
if fcb.bufferptr != 0 then
|
|
var dma := &fcb.buffer[0];
|
|
@asm "ld c, 26"; # SET DMA
|
|
@asm "ld de, (", dma, ")";
|
|
@asm "call 5";
|
|
|
|
@asm "ld c, 21"; # WRITE SEQ
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", writeerr, "),a";
|
|
end if;
|
|
|
|
@asm "ld c, 16"; # CLOSE_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", closeerr, "),a";
|
|
|
|
if writeerr != 0 then
|
|
errno := ERR_DISK_FULL;
|
|
return;
|
|
end if;
|
|
|
|
if closeerr == 0xFF then
|
|
errno := ERR_NO_FILE;
|
|
end if;
|
|
end sub;
|
|
|
|
# only for files open for READ
|
|
sub FCBRewind(fcb: [FCB]): (errno: uint8) @extern("FCBRewind") is
|
|
var cpmfcb := &fcb.cpm;
|
|
var cpmerr: uint8;
|
|
|
|
if fcb.iotype != IO_READ then
|
|
errno := ERR_BAD_IO;
|
|
return;
|
|
end if;
|
|
|
|
errno := FCBClose(fcb);
|
|
|
|
if errno != SUCCESS then
|
|
return;
|
|
end if;
|
|
|
|
var file: uint8[11];
|
|
MemCopy(&cpmfcb.f[0], 11, &file[0]);
|
|
MemSet(cpmfcb as [uint8], 0, @bytesof CpmFCB);
|
|
MemCopy(&file[0], 11, &cpmfcb.f[0]);
|
|
fcb.bufferptr := 0;
|
|
|
|
@asm "ld c, 15"; # OPEN_FILE
|
|
@asm "ld de, (", cpmfcb, ")";
|
|
@asm "call 5";
|
|
@asm "ld (", cpmerr, "), a";
|
|
|
|
if cpmerr == 0xFF then
|
|
errno := ERR_NO_FILE;
|
|
else
|
|
errno := SUCCESS;
|
|
end if;
|
|
end sub;
|
|
|