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

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;