boot.s | boot.s | |||
---|---|---|---|---|
;;; | ;;; | |||
;;; A Fuzix booter for the CoCo3 | ;;; A Fuzix booter for the CoCo2/3 | |||
;;; | ||||
;;; 2015-06-17: Brett Gordon: Original work | ||||
;;; 2016-12-10: Michael Furman: Hack it up for Coco2 | ||||
;;; | ;;; | |||
;;; This bootloader works from a DECB-like evironment, It loads | ;;; This bootloader works from a DECB-like evironment, It loads | |||
;;; FUZIX.BIN from a DECB disk and plops it in memory, starting | ;;; FUZIX.BIN from a DECB disk and plops it in memory, starting | |||
;;; at physical address 0x0000. | ;;; at physical address 0x0000. | |||
IFDEF COCO2 | ||||
org $1000 ; where am I loaded. | ||||
MYSTART EQU . ; first address this program uses | ||||
STKSTRT equ $18FF ; put the stack here | ||||
MYEND equ STKSTRT+1 ; last address this program uses | ||||
LOADLOC equ $8000 ; load the program in high ram | ||||
COPYEND equ $FF00 ; end of high ram | ||||
SDCBANK equ 1 ; CocoSDC Bank | ||||
RAMROM equ $FFDE ; poke to switch to RAM/ROM | ||||
ALLRAM equ $FFDF ; poke to switch to all RAM | ||||
ROMSTRT equ $C000 ; Address where FUZIX ROM starts | ||||
ELSE | ||||
org $7a00 ; where am I loaded. | org $7a00 ; where am I loaded. | |||
ENDC | ||||
frame .dw 0 ; on entry frame pointer | frame .dw 0 ; on entry frame pointer | |||
npage .db 0 ; next page no. | npage .db 0 ; next page no. | |||
pos .dw 0 ; buffer pos in memory | pos .dw 0 ; buffer pos in memory | |||
tickp .dw $400+(32*15) ; ticker next position | tickp .dw $400+(32*15) ; ticker next position | |||
tickb .db 0 ; | tickb .db 0 ; | |||
size .dw 0 ; no of grans | size .dw 0 ; no of grans | |||
secs .dw 0 ; init value of of sectors for each screen block | secs .dw 0 ; init value of of sectors for each screen block | |||
scount .dw 0 ; sector counter | scount .dw 0 ; sector counter | |||
nampre fcn /"FUZIX.BIN/ ; " image to load | nampre fcn /"FUZIX.BIN/ ; " image to load | |||
rmb 6 ; pad for max filename | rmb 6 ; pad for max filename | |||
wbuf rmb 32 ; word buffer for cmdline parsing | wbuf rmb 32 ; word buffer for cmdline parsing | |||
wptr .dw $88 ; static data for word routine | wptr .dw $88 ; static data for word routine | |||
bootstr fcn "BOOT=" | bootstr fcn "BOOT=" | |||
fnf .db 13 | fnf .db 13 | |||
fcc "KERNEL FILE NOT FOUND" | fcc "KERNEL FILE NOT FOUND" | |||
.db 13 | .db 13 | |||
.db 0 | .db 0 | |||
; fuzixfs filename block for SDC | ||||
fuzixfs | ||||
.ascii "M:FUZIXFS.DSK" | ||||
ZMB 256-(.-fuzixfs) | ||||
;;; CocoSDC | ||||
SDCLTCH equ $FF40 | ||||
SDCCREG equ $FF48 | ||||
SDCSTAT equ $FF48 | ||||
SDCPRM1 equ $FF49 | ||||
SDCPRM2 equ $FF4A | ||||
SDCPRM3 equ $FF4B | ||||
SDCDATA equ SDCPRM2 | ||||
SDCDATB equ SDCPRM3 | ||||
; Basic Variables | ||||
CHARAD equ $88 | ||||
; Color Basic Routines | ||||
PUTCHR equ $A282 | ||||
PUTSTR equ $B99C | ||||
FCLOSE equ $A42D | ||||
; Disk Basic 1.1 Routines | ||||
DBNAMF equ $C935 | ||||
SRCHDIR equ $C68C | ||||
GRANCNT equ $CD1E | ||||
OPENDF equ $C48D | ||||
;; And the Kick-off | ;; And the Kick-off | |||
start | start | |||
sts frame | sts frame | |||
IFDEF COCO2 | ||||
;; move the stack because fuzix may load on top of it | ||||
;; XXX: safety or will decb barf up on this?? | ||||
lds #STKSTRT | ||||
ENDC | ||||
lda #13 | lda #13 | |||
jsr 0xa282 | jsr PUTCHR | |||
ldd #$400+(32*14) | ldd #$400+(32*14) | |||
std $88 | std CHARAD | |||
lda #'F ; print F | lda #'F ; print F | |||
jsr 0xa282 ; | jsr PUTCHR ; | |||
IFNDEF COCO2 | ||||
;; Move to task one | ;; Move to task one | |||
ldx #$ffa0 | ldx #$ffa0 | |||
ldu #$ffa8 | ldu #$ffa8 | |||
ldd ,x++ ; copy mmu regs | ldd ,x++ ; copy mmu regs | |||
std ,u++ | std ,u++ | |||
ldd ,x++ | ldd ,x++ | |||
std ,u++ | std ,u++ | |||
ldd ,x++ | ldd ,x++ | |||
std ,u++ | std ,u++ | |||
ldd ,x++ | ldd ,x++ | |||
std ,u++ | std ,u++ | |||
ldb #1 | ldb #1 | |||
stb $ff91 ; set mmu to task 1 | stb $ff91 ; set mmu to task 1 | |||
ENDC | ||||
;; XXX: not sure what do do here for Coco2? | ||||
IFNDEF COCO2 | ||||
;; move and process command line | ;; move and process command line | |||
jsr cpcmd | jsr cpcmd | |||
jsr bootfile | jsr bootfile | |||
ENDC | ||||
;; open kernel image file | ;; open kernel image file | |||
ldb #'I ; input mode | ldb #'I ; input mode | |||
jsr open | jsr open | |||
lbcs abort | lbcs abort | |||
lda #'U ; print "U" | lda #'U ; print "U" | |||
jsr $a282 | jsr PUTCHR | |||
;; calculate sectors for each screen block | ;; calculate sectors for each screen block | |||
ldd size | ldd size | |||
lsra | lsra | |||
rorb | rorb | |||
lsra | lsra | |||
rorb | rorb | |||
lsra | lsra | |||
rorb | rorb | |||
lsra | lsra | |||
rorb | rorb | |||
skipping to change at line 86 ¶ | skipping to change at line 139 ¶ | |||
pshs b ; save on stack | pshs b ; save on stack | |||
ldb #1 | ldb #1 | |||
stb $6f ; switch in/out routine to disk file #1 | stb $6f ; switch in/out routine to disk file #1 | |||
c@ jsr $a176 ; get a byte in A | c@ jsr $a176 ; get a byte in A | |||
cmpa #$ff ; compare A to ff | cmpa #$ff ; compare A to ff | |||
beq post ; jump to post able handling | beq post ; jump to post able handling | |||
;; preamble | ;; preamble | |||
jsr getw ; D = length address | jsr getw ; D = length address | |||
tfr d,y ; U = length | tfr d,y ; U = length | |||
jsr getw ; D = load address | jsr getw ; D = load address | |||
jsr setload ; set load address | IFDEF COCO2 | |||
; skip the rom bytes, read entire section but don't copy to ram | ||||
cmpd #ROMSTRT | ||||
blo cc@ | ||||
s@ jsr $a176 ; A = byte | ||||
jsr tick | ||||
leay -1,y ; decrement U | ||||
bne s@ ; loop | ||||
bra c@ ; try next byte in stream | ||||
ENDC | ||||
cc@ jsr setload ; set load address | ||||
d@ jsr $a176 ; A = byte | d@ jsr $a176 ; A = byte | |||
jsr tick | jsr tick | |||
jsr putb ; put into kernel memory | jsr putb ; put into kernel memory | |||
leay -1,y ; decrement U | leay -1,y ; decrement U | |||
bne d@ ; loop | bne d@ ; loop | |||
bra c@ ; try next byte in stream | bra c@ ; try next byte in stream | |||
;; postable | ;; postable | |||
post jsr getw ; get zero's | post jsr getw ; get zero's | |||
cmpd #0 ; test D | cmpd #0 ; test D | |||
lbne abort ; abort if not zero | lbne abort ; abort if not zero | |||
jsr getw ; get exec address | jsr getw ; get exec address | |||
pshs d ; save on stack | pshs d ; save on stack | |||
jsr close ; close DECB file | jsr close ; close DECB file | |||
;; report load | ;; report load | |||
clr $6f ; set stream to console | clr $6f ; set stream to console | |||
lda #'L | lda #'L | |||
jsr $A282 | jsr PUTCHR | |||
IFNDEF COCO2 | ||||
ldd #0 ; Address = 0 | ldd #0 ; Address = 0 | |||
jsr setload | jsr setload | |||
ldy #bounce_end-bounce | ldy #bounce_end-bounce | |||
ldx #bounce | ldx #bounce | |||
e@ lda ,x+ | e@ lda ,x+ | |||
jsr putb | jsr putb | |||
leay -1,y | leay -1,y | |||
bne e@ | bne e@ | |||
lda ,s+ ; get jmp address high byte | lda ,s+ ; get jmp address high byte | |||
jsr putb ; put at end of bounce routine | jsr putb ; put at end of bounce routine | |||
lda ,s+ | lda ,s+ | |||
jsr putb ; put at end of bounce routine | jsr putb ; put at end of bounce routine | |||
lda #'O | lda #'O | |||
jsr $a282 ; report load | jsr PUTCHR ; report load | |||
;; map in kernel block 0 | ENDC | |||
orcc #$50 ; turn off interrupts | orcc #$50 ; turn off interrupts | |||
IFDEF COCO2 | ||||
; basic is toast after moving, save basic cursor pos | ||||
ldx CHARAD | ||||
stx tickp | ||||
jsr mover | ||||
lda #'O | ||||
jsr myputc ; report load | ||||
;; mount fuzixfs | ||||
ldy #fuzixfs | ||||
jsr mountFs | ||||
lda #'M | ||||
jsr myputc ; report mount | ||||
;; flip the sdc flash bank | ||||
lda #SDCBANK | ||||
sta $ff43 | ||||
lda #'F | ||||
jsr myputc ; report flip | ||||
jmp $c000 ; jump into the kernel | ||||
; testing | ||||
;sta ALLRAM | ||||
;bra . | ||||
ELSE | ||||
;; map in kernel block 0 | ||||
clr $ffa8 ; put bounce routine in memory | clr $ffa8 ; put bounce routine in memory | |||
jmp $0 ; and jump to bounce routine | jmp $0 ; and jump to bounce routine | |||
ENDC | ||||
IFDEF COCO2 | ||||
;;; Move kernel data from high to low ram | ||||
;;; Skiping this code section | ||||
mover | ||||
;; enter all ram mode | ||||
sta ALLRAM | ||||
;; Turn off interrupts | ||||
orcc #(0x10|0x40) | ||||
;; save the screen | ||||
ldx #$400 | ||||
ldy #$8400 | ||||
cpylp@ cmpx #$600 | ||||
beq done@ | ||||
ldd ,x++ | ||||
std ,y++ | ||||
bra cpylp@ | ||||
done@ | ||||
;; do the copy | ||||
ldx #LOADLOC | ||||
ldy #0 | ||||
mvlp@ cmpx #COPYEND | ||||
beq done@ | ||||
cmpy #MYSTART | ||||
blo copy@ | ||||
cmpy #MYEND | ||||
bge copy@ | ||||
leax 2,x | ||||
leay 2,y | ||||
bra mvlp@ | ||||
copy@ | ||||
ldd ,x++ | ||||
std ,y++ | ||||
bra mvlp@ | ||||
done@ sta RAMROM | ||||
rts | ||||
ENDC | ||||
;; Put characters on the screen after basic is toasted | ||||
myputc | ||||
ldx tickp | ||||
sta ,x+ | ||||
stx tickp | ||||
rts | ||||
;;; copy cmdline down to kernel 0 | ;;; copy cmdline down to kernel 0 | |||
cpcmd ;; find command line in input buffer | cpcmd ;; find command line in input buffer | |||
ldd #$88 ; set destination of cpy in kernel memory | ldd #$88 ; set destination of cpy in kernel memory | |||
jsr setload ; | jsr setload ; | |||
ldx $a6 ; X = position in program | ldx $a6 ; X = position in program | |||
a@ lda ,x+ ; get a byte | a@ lda ,x+ ; get a byte | |||
beq c@ ; end of line w/o remark token? | beq c@ ; end of line w/o remark token? | |||
cmpa #$83 ; is a ' token? | cmpa #$83 ; is a ' token? | |||
beq b@ | beq b@ | |||
skipping to change at line 195 ¶ | skipping to change at line 329 ¶ | |||
decb | decb | |||
bne b@ | bne b@ | |||
;; ok we've found a "BOOT=": copy arg to filename buffer | ;; ok we've found a "BOOT=": copy arg to filename buffer | |||
ldx #nampre+1 | ldx #nampre+1 | |||
c@ lda ,u+ ; get a byte | c@ lda ,u+ ; get a byte | |||
sta ,x+ ; store a byte in buffer | sta ,x+ ; store a byte in buffer | |||
bne c@ ; repeat if not zero | bne c@ ; repeat if not zero | |||
;; out of cmd to parse | ;; out of cmd to parse | |||
out@ puls d,x,u,pc | out@ puls d,x,u,pc | |||
IFNDEF COCO2 | ||||
;;; This routine is copied down to kernel map 0 | ;;; This routine is copied down to kernel map 0 | |||
bounce | bounce | |||
;; map in rest of kernel | ;; map in rest of kernel | |||
ldx #$ffa9 | ldx #$ffa9 | |||
lda #1 | lda #1 | |||
a@ sta ,x+ | a@ sta ,x+ | |||
inca | inca | |||
cmpa #8 | cmpa #8 | |||
bne a@ | bne a@ | |||
.db $7e ; jump | .db $7e ; jump | |||
bounce_end | bounce_end | |||
ENDC | ||||
;;; Gets next word from file | ;;; Gets next word from file | |||
;;; takes: nothing | ;;; takes: nothing | |||
;;; returns: D = next word | ;;; returns: D = next word | |||
getw | getw | |||
jsr $a176 ; A = high byte | jsr $a176 ; A = high byte | |||
tfr a,b ; B = high byte | tfr a,b ; B = high byte | |||
jsr $a176 ; A = low byte | jsr $a176 ; A = low byte | |||
exg a,b ; flip D = next word | exg a,b ; flip D = next word | |||
jsr tick | jsr tick | |||
jsr tick | jsr tick | |||
rts | rts | |||
;;; Sets load address | ;;; Sets load address | |||
;;; takes: D = Address | ;;; takes: D = Address | |||
;;; returns: X = cpu mapped address | ;;; returns: X = cpu mapped address | |||
;;; mods: D | ;;; mods: D | |||
setload | setload | |||
IFDEF COCO2 | ||||
addd #LOADLOC | ||||
ELSE | ||||
pshs d | pshs d | |||
;; find block number | ;; find block number | |||
lsra | lsra | |||
lsra | lsra | |||
lsra | lsra | |||
lsra | lsra | |||
lsra ; A= blk no | lsra ; A= blk no | |||
sta $ffaa ; put in mmu | sta $ffaa ; put in mmu | |||
puls d | puls d | |||
anda #$1f ; D = offset | anda #$1f ; D = offset | |||
addd #$4000 ; mmu offset | addd #$4000 ; mmu offset | |||
ENDC | ||||
std pos ; store | std pos ; store | |||
rts | rts | |||
;;; puts a byte into kernel memory, increments position | ;;; puts a byte into kernel memory, increments position | |||
;;; takes: A = byte to store | ;;; takes: A = byte to store | |||
;;; returns: nothing | ;;; returns: nothing | |||
;;; mods: | ;;; mods: | |||
putb pshs d,x | putb | |||
IFDEF COCO2 | ||||
pshs x | ||||
ldx pos | ||||
orcc #(0x10|0x40) | ||||
sta ALLRAM | ||||
sta ,x+ | ||||
sta RAMROM | ||||
andcc #~(0x10|0x40) | ||||
stx pos | ||||
puls x,pc | ||||
rts | ||||
ELSE | ||||
pshs d,x | ||||
a@ ldx pos | a@ ldx pos | |||
cmpx #$6000 ; too far ? | cmpx #$6000 ; too far ? | |||
beq inc@ | beq inc@ | |||
sta ,x+ | sta ,x+ | |||
stx pos | stx pos | |||
puls d,x,pc | puls d,x,pc | |||
inc@ ldx #$4000 ; inc pos | inc@ ldx #$4000 ; inc pos | |||
stx pos | stx pos | |||
inc $ffaa | inc $ffaa | |||
bra a@ | bra a@ | |||
ENDC | ||||
;;; Abort! | ;;; Abort! | |||
abort | abort | |||
ldx #fnf-1 | ldx #fnf-1 | |||
jsr $b99c | jsr PUTSTR | |||
lds frame | lds frame | |||
rts | rts | |||
;;; Open a file | ;;; Open a file | |||
;;; takes: B=ascii mode (I,O,D) | ;;; takes: B=ascii mode (I,O,D) | |||
;;; returns: C set on error | ;;; returns: C set on error | |||
open pshs b ; save mode | open pshs b ; save mode | |||
;; move local filename into BASIC's vars | ;; move local filename into BASIC's vars | |||
ldx $a6 | ldx $a6 | |||
pshs x | pshs x | |||
ldx #nampre ; pointer to our local filename | ldx #nampre ; pointer to our local filename | |||
stx $a6 ; set CHARAD | stx $a6 ; set CHARAD | |||
jsr $c935 ; have BASIC set up DNAMBF for us | jsr DBNAMF ; have BASIC set up DNAMBF for us | |||
puls x | puls x | |||
stx $a6 | stx $a6 | |||
;; end of string copy - get directory info | ;; end of string copy - get directory info | |||
f@ jsr $c68c ; search directory, U=ram directory image | f@ jsr SRCHDIR ; search directory, U=ram directory image | |||
tst $973 ; found? | tst $973 ; found? | |||
bne g@ ; yes - then return | bne g@ ; yes - then return | |||
;; not found | ;; not found | |||
ldb ,s ; get mode | ldb ,s ; get mode | |||
cmpb #'I ; is mode I? | cmpb #'I ; is mode I? | |||
beq err@ ; yes then error! | beq err@ ; yes then error! | |||
ldd #$00ff ; basic/ascii | ldd #$00ff ; basic/ascii | |||
bra h@ | bra h@ | |||
;; get size of file in granuals | ;; get size of file in granuals | |||
g@ pshs d,x,u | g@ pshs d,x,u | |||
ldb 2,u ; B = first granuals of file | ldb 2,u ; B = first granuals of file | |||
jsr $cd1e ; get no of granuals | jsr GRANCNT ; get no of granuals | |||
andb #0xf ; B = sectors used in last granual | andb #0xf ; B = sectors used in last granual | |||
pshs b ; save on stack ( last ) | pshs b ; save on stack ( last ) | |||
clr ,-s ; as 16 bit value | clr ,-s ; as 16 bit value | |||
deca ; A = whole granuals | deca ; A = whole granuals | |||
ldb #9 | ldb #9 | |||
mul ; D = sectors | mul ; D = sectors | |||
addd ,s++ ; D = sectors in file | addd ,s++ ; D = sectors in file | |||
std size ; save | std size ; save | |||
puls d,x,u | puls d,x,u | |||
;; copy directory stuff | ;; copy directory stuff | |||
ldd ,u ; D = type/ascii | ldd ,u ; D = type/ascii | |||
ldb #$ff ; force ascii | ldb #$ff ; force ascii | |||
h@ std $957 | h@ std $957 | |||
ldd #$100 ; record length | ldd #$100 ; record length | |||
std $976 | std $976 | |||
lda ,s ; A = Mode (I,O,D) | lda ,s ; A = Mode (I,O,D) | |||
ldb #1 ; B = FCB #1 | ldb #1 ; B = FCB #1 | |||
jsr $c48d ; open file | jsr OPENDF ; open file | |||
out@ clra ; clear C | out@ clra ; clear C | |||
puls b,pc ; return | puls b,pc ; return | |||
err@ coma ; set C | err@ coma ; set C | |||
puls b,pc ; return | puls b,pc ; return | |||
;;; Close file buffer | ;;; Close file buffer | |||
close | close | |||
ldb #1 ; set file number to 1 | ldb #1 ; set file number to 1 | |||
stb $6f | stb $6f | |||
jsr $a42d ; close file | jsr FCLOSE ; close file | |||
clr $6f ; set dev to screen | clr $6f ; set dev to screen | |||
rts | rts | |||
;;; Tick the ticker | ;;; Tick the ticker | |||
tick | tick | |||
pshs d,x | pshs d,x | |||
inc tickb ; inc byte counter | inc tickb ; inc byte counter | |||
bne out@ ; return if not 256 bytes | bne out@ ; return if not 256 bytes | |||
;; decrement block counter | ;; decrement block counter | |||
ldd scount | ldd scount | |||
skipping to change at line 337 ¶ | skipping to change at line 491 ¶ | |||
bne out@ ; leave if sector/block counter is not done | bne out@ ; leave if sector/block counter is not done | |||
;; else put new screen block | ;; else put new screen block | |||
ldd secs | ldd secs | |||
std scount | std scount | |||
ldb #$af ; a blue block | ldb #$af ; a blue block | |||
ldx tickp ; get position | ldx tickp ; get position | |||
stb ,x+ ; print it to screen buffer | stb ,x+ ; print it to screen buffer | |||
stx tickp ; and save position | stx tickp ; and save position | |||
out@ puls d,x,pc | out@ puls d,x,pc | |||
;;; Code to work with the CocoSDC | ||||
;;; Loosely based off of example code in the CoCo SDC Command Reference | ||||
;;; sdcPoll - Poll SDC Status | ||||
;;; Return X, 0-NotReady, Busy, or Error | ||||
;;; B - not saved | ||||
sdcPoll | ||||
ldx #$FFFF | ||||
sdcLoop ldb SDCSTAT | ||||
bmi sdcPErr ; error | ||||
lsrb | ||||
bcc sdcPRtn ; !busy | ||||
lsrb | ||||
bcs sdcPRtn ; ready | ||||
leax -1,x | ||||
bne sdcLoop | ||||
sdcPRtn rts | ||||
sdcPErr ldx #0 | ||||
rts | ||||
;; sdcDone - return sdc to fdc mode | ||||
sdcDone | ||||
clr SDCLTCH | ||||
rts | ||||
;; sdcAbrt - return to basic | ||||
sdcAbrt | ||||
bsr sdcDone | ||||
lbra abort | ||||
;; sdcCmd - send command to sdc | ||||
;; input- A-cmd | ||||
;; scratched: b,x | ||||
sdcCmd | ||||
ldb #$43 | ||||
stb SDCLTCH ; put CocoSDC in command mode | ||||
bsr sdcPoll ; wait for !busy | ||||
cmpx #0 | ||||
beq sdcAbrt | ||||
cmdRdy sta SDCCREG ; send command | ||||
rts | ||||
;; sdcData - send data to sdc | ||||
;; Y - address of 256 bytes to send | ||||
;; scratched: d,x | ||||
strEnd RMB 2 | ||||
sdcData | ||||
bsr sdcPoll ; wait for ready | ||||
cmpx #0 | ||||
beq sdcAbrt | ||||
txRdy tfr y,d | ||||
addd #256 | ||||
std strEnd ; data is always 256 bytes | ||||
txLoop cmpy strEnd | ||||
beq txCheck ; done sending data | ||||
ldd ,y++ | ||||
std SDCDATA ; send data | ||||
bra txLoop | ||||
txCheck bsr sdcPoll ; wait for !busy | ||||
cmpx #0 | ||||
beq sdcAbrt | ||||
txDone rts | ||||
;;; Tell the CocoSDC to load FUZIXFS.DSK | ||||
;; Y - address of 256 bytes to send | ||||
mountFs | ||||
lda #$E0 | ||||
bsr sdcCmd ; Send CocoSDC Mount Command | ||||
bsr sdcData ; Send name of image to mount | ||||
bsr sdcDone ; Tell CocoSDC to return to emulation mode | ||||
rts | ||||
end start | end start | |||
End of changes. 29 change blocks. | ||||
16 lines changed or deleted | 242 lines changed or added | |||
This html diff was produced by rfcdiff 1.45. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |