of816/platforms/W65C816SXB/fcode/romloader.fs

351 lines
7.8 KiB
Forth

\ W65C816SXB ROM loader. Itself in FCode, this defines some words to bootstrap
\ any FCode and files in the SXB's flash ROM.
\ This provides two facilities: FCode loader, and romfs.
\ romfs provides a simple filesystem of up to 32K (one bank of ROM) in the SXB for
\ files. Basic ANSI-ish functions to open/read/close the files are provided
\ as well as include and included. romfs was inspired by SLOF's romfs.
\ romfs may be omitted during tokenization by defining the commad-line symbol no-romfs
\ i.e. adding -d no-romfs to the toke command line, this saves more than 1K of output
\ in the tokenized FCode.
\ Note that the SXB-specific word $SXB-READROM takes a virtual address of the form
\ $bbaaaaaa where bb is the ROM bank to select, and the address is then used to read it
\ For practical purposes to read the ROM the addresses are restricted to:
\ $00008000-$0000FFFF - bank 0, $01008000-$0100FFFF - bank 1,
\ $02008000-$0200FFFF - bank 2, $03008000-$0300FFFF - bank 3.
start1 hex
." W65C816SXB ROM loader by M.G. ... "
headers
headerless
\ Stuff we need to get to that isn't supported by FCode
defer $sxb-readrom
s" $sxb-readrom" $find 0= if ." no $SXB-READROM" abort then to $sxb-readrom
[ifndef] no-romfs
defer -trailing
s" -trailing" $find drop to -trailing
defer parse-word
s" parse-word" $find drop to parse-word
: 2w@ dup w@ swap wa1+ w@ ;
\ temp vars for file I/O, headerless to save space
\ $fileno is used for susequent conditionals to compile remaining romfs code
0 value $fileno
0 value $bufsz
0 value $buffer
0 value $incbuffer
[endif]
headers
\ a $100-byte page buffer is provided to avoid slow reads of the ROM to a certain extent
fffffffff value $sxb-readrom-page
0 value $sxb-readrom-buf
[ifexist] $fileno
0 value $sxb-romfs-filebuf
0 value $sxb-romfs-files
0 value $sxb-romfs-tab
[endif]
\ fetch a page to the page buffer, allocating it if necessary, and doing nothing if
\ it's already in the page buffer
: $sxb-rom-fetchpage ( v-addr -- v-addr )
$sxb-readrom-buf 0= if
100 alloc-mem to $sxb-readrom-buf
ffffffff to $sxb-readrom-page ( invalid page number )
then
dup 8 >> $sxb-readrom-page <> if
dup ffffff00 and $sxb-readrom-buf 100 $sxb-readrom
dup 8 >> to $sxb-readrom-page
then
;
\ Byte read function for the ROM, used to execute FCode.
: $sxb-rom-rb@ ( v-addr -- byte )
$sxb-rom-fetchpage ff and $sxb-readrom-buf + c@
;
\ Free the page buffer to return memory to the user
: $sxb-readrom-free ( -- )
$sxb-readrom-buf if
$sxb-readrom-buf 100 free-mem
then
0 to $sxb-readrom-buf
ffffffff to $sxb-readrom-page
;
\ Magic test for FCode
: $$fcode-at? ( v-addr -- f )
$sxb-rom-fetchpage ff and $sxb-readrom-buf + @ 4346474D =
;
[ifexist] $fileno
\ Magit test for romfs
: $$romfs-at? ( v-addr -- f )
$sxb-rom-fetchpage ff and $sxb-readrom-buf + @ 5346474D =
;
[endif]
external
[ifexist] $fileno
\ Holds location of discovered romfs
0 value $sxb-romfs
[endif]
\ see if there is FCode in the SXB ROM at v-addr.
: $sxb-rom-fcode-at? ( v-addr -- f )
$$fcode-at? $sxb-readrom-free
;
[ifexist] $fileno
\ see if there is romfs in the SXB ROM at v-addr.
: $sxb-rom-romfs-at? ( v-addr -- f )
$$romfs-at? $sxb-readrom-free
;
[endif]
\ byte-load FCode in the SXB ROM.
: $sxb-rom-byte-load ( v-addr -- )
dup $$fcode-at? if
cell+ ['] $sxb-rom-rb@ ['] byte-load catch
$sxb-readrom-free
dup if
nip nip
then
throw
else
." no FCode at " . true abort
then
;
headers
\ Scan a bank for FCode and execute any that is found
: $sxb-fc-boot-bank ( bank -- )
1000000 *
ffff 8000 do dup i + dup $$fcode-at? if
$sxb-rom-byte-load
else
drop
then
1000 +loop
drop
;
[ifexist] $fileno
\ scan a bank for romfs and update $sxb-romfs if found
: $romfs-find-bank ( bank -- )
1000000 *
ffff 8000 do dup i + dup $$romfs-at? if
to $sxb-romfs leave
else
drop
then
1000 +loop
drop
;
\ return address of romfs or throw exception
: $sxb-romfs? ( -- addr )
$sxb-romfs ?dup 0= if d# -37 throw then
;
\ Normalize file ID and make sure it is valid
: romfs-file? ( u1 -- u2 / u2 = normalized file ID )
ffff and dup $sxb-romfs-files u>= if d# -38 throw then
;
\ Get file name of file in romfs
: romfs-file ( u -- c-addr u2 )
romfs-file? $sxb-romfs?
$sxb-rom-fetchpage drop $sxb-readrom-buf cell+ char+ swap 4 << + c -trailing
;
\ Return info about a romfs file
: romfs-finfo ( -- offset length )
romfs-file drop c + 2w@
;
\ Find a file in the romfs, return file number if we find it
: romfs-ffind ( c-addr u -- u2 true | false )
-1 -rot $sxb-romfs-files 0 ?do
2dup i romfs-file 2 pick = if
\ lengths equal
swap comp 0= if
i -rot >r >r swap drop r> r>
then
else
\ lengths unequal
3drop
then
loop
2drop
dup 0< if
drop false
else
true
then
;
\ Get ROMfs table entry for file number
: $romfs-t# ( file# -- addr )
2* cells $sxb-romfs-tab +
;
\ "open" a romfs file
\ Set up table entry for the file with current (start) and end addresses.
: $romfs-open ( u -- )
>r r@ romfs-finfo over + $sxb-romfs + swap $sxb-romfs + swap r> $romfs-t# 2!
;
\ "close" a romfs file. Set current address to end address
: $romfs-close ( u -- )
$romfs-t# >r r@ 2@ swap drop dup r> 2!
$sxb-readrom-free
;
\ Check if we hit EOF in open romfs file
: $romfs-eof? ( u -- f )
$romfs-t# 2@ u>=
;
\ Byte read routine for romfs
: $romfs-rb@ ( u -- byte )
$romfs-t# dup >r @ dup 1+ r> ! $sxb-rom-rb@
;
\ See if we hit a line-ending char
: is-eol?
case
0d of true endof \ CR
0a of true endof \ LF
>r false r>
endcase
;
\ Locate a romfs in the SXB ROM, updating $sxb-romfs and $sxb-romfs-files if found
\ and allocating the access table
: $romfs-find ( -- )
4 1 do $sxb-romfs if leave else i $romfs-find-bank then loop
$sxb-romfs if
$sxb-romfs $sxb-rom-fetchpage drop $sxb-readrom-buf cell+ c@ dup to $sxb-romfs-files
2* cells dup alloc-mem dup to $sxb-romfs-tab swap erase
then
$sxb-readrom-free
;
[endif]
external
\ Find and execute all FCode in ROM at $1000-aligned addresses
: $sxb-fc-boot
4 1 do i $sxb-fc-boot-bank loop
$sxb-readrom-free
;
[ifexist] $fileno
\ List files in romfs
: romfs-list
$sxb-romfs-files 0 ?do
i romfs-file type cr
loop
$sxb-readrom-free
;
\ open file in romfs
: open-file ( c-addr u fam -- fileid 0 )
drop
romfs-ffind if
dup 10000 or swap $romfs-open 0
else
d# -69 throw
endif
;
\ report position in open file
: file-position ( fid -- u )
romfs-file? $romfs-t# 2@ swap -
;
\ close romfs file
: close-file ( fileid -- 0 )
romfs-file? $romfs-close 0
$sxb-readrom-free
;
\ read open romfs file
: read-file ( c-addr u fileid - u2 0 )
romfs-file? to $fileno to $bufsz to $buffer
0
$bufsz 0 ?do
$fileno $romfs-eof? if leave then
$fileno $romfs-rb@
over $buffer + c! 1+
loop
0
;
\ read a line from open romfs file
: read-line ( c-addr u fileid - u2 f 0 )
romfs-file? to $fileno to $bufsz to $buffer
0
$bufsz 0 ?do
$fileno $romfs-eof? if leave then
$fileno $romfs-rb@
dup is-eol? if drop leave then
over $buffer + c! 1+
loop
$fileno $romfs-eof? 0= 0
;
headers
\ read and evaluate each line of file in romfs describe in incbuf
\ incbuf is a buffer 1 cell+80 bytes long, with the file id in the cell
: $inc ( incbuf -- )
$incbuffer ?dup 0= if d# -9 throw then
begin
>r r@ cell+ 80 r@ @
read-line 2drop
r@ cell+ swap eval
r> dup @ romfs-file?
$romfs-eof? until
drop
;
external
\ allocate a buffer and evaulate the given file
: included ( c-addr u -- )
0 open-file drop
$incbuffer >r 80 cell+ alloc-mem dup to $incbuffer !
['] $inc catch r> swap >r $incbuffer swap to $incbuffer
dup @ close-file drop 80 cell+ free-mem
r> throw
;
\ parse name and perform the function of included
: include ( " name " -- )
parse-word included
;
$romfs-find
[endif]
." loaded!" cr
[ifexist] $fileno
$sxb-romfs ?dup if ." ROMfs at " u. cr then
[endif]
fcode-end