;
; Thistle Boot ROM
;
	.setcpu		"65c02"

.segment	"STARTUP"

.byte "--[[CABE:Thistle:"

.segment "RODATA"

; TSF Component Data
fslist: .byte 10,10,0,"filesystem",0
umlist: .byte 10,5,0,"drive",0
secread: .byte 10,10,0,"readSector",3,1,0
fsopend: .byte 10,4,0,"open",10,12,0,"Thistle/boot",0
fsopenf: .byte 10,4,0,"open",10,7,0,"Thistle",0
fsclose: .byte 10,5,0,"close"
fsread: .byte 10,4,0,"read",14,0,0,0,0,4,0,1,0

; Messages
greeting: .byte "Thistle Boot ROM",13,10,10
nomem: .byte "No Memory installed"
drives: .byte "Checking drives ...",13,10
fsmsg: .byte 10,"Checking filesystems ...",13,10
bootmsg: .byte "Booting ...",13,10
noboot: .byte "Nothing to boot from",13,10

hexlookup: .byte "0123456789abcdef"

unkcmd: .byte "Unknown Command",13,10

cmdlist:
.asciiz "ls"
.word cmd_ls
.asciiz "list"
.word cmd_list
.asciiz "load"
.word cmd_load
.asciiz "save"
.word cmd_save
.asciiz "run"
.word cmd_run
.asciiz "db"
.word cmd_db
.asciiz "at"
.word cmd_at
.asciiz "fs"
.word cmd_fs
.asciiz ""

.define inval $FF

opcodetbl:
.byte "BRK",$07,"ORA",$09,inval,$00,inval,$07,"TSB",$01,"ORA",$01,"ASL",$01,"RB0",$01,"PHP",$07,"ORA",$00,"ASL",$07,inval,$07,"TSB",$04,"ORA",$04,"ASL",$04,"BR0",$0E
.byte "BPL",$08,"ORA",$0A,"ORA",$0D,inval,$07,"TRB",$01,"ORA",$02,"ASL",$02,"RB1",$01,"CLC",$07,"ORA",$06,"INC",$07,inval,$07,"TRB",$04,"ORA",$05,"ASL",$05,"BR1",$0E
.byte "JSR",$04,"AND",$09,inval,$00,inval,$07,"BIT",$01,"AND",$01,"ROL",$01,"RB2",$01,"PLP",$07,"AND",$00,"ROL",$07,inval,$07,"BIT",$04,"AND",$04,"ROL",$04,"BR2",$0E
.byte "BMI",$08,"AND",$0A,"AND",$0D,inval,$07,"BIT",$02,"AND",$02,"ROL",$02,"RB3",$01,"SEC",$07,"AND",$06,"DEC",$07,inval,$07,"BIT",$05,"AND",$05,"ROL",$05,"BR3",$0E
.byte "RTI",$07,"EOR",$09,inval,$00,inval,$07,inval,$01,"EOR",$01,"LSR",$01,"RB4",$01,"PHA",$07,"EOR",$00,"LSR",$07,inval,$07,"JMP",$04,"EOR",$04,"LSR",$04,"BR4",$0E
.byte "BVC",$08,"EOR",$0A,"EOR",$0D,inval,$07,inval,$02,"EOR",$02,"LSR",$02,"RB5",$01,"CLI",$07,"EOR",$06,"PHY",$07,inval,$07,inval,$04,"EOR",$05,"LSR",$05,"BR5",$0E
.byte "RTS",$07,"ADC",$09,inval,$00,inval,$07,"STZ",$01,"ADC",$01,"ROR",$01,"RB6",$01,"PLA",$07,"ADC",$00,"ROR",$07,inval,$07,"JMP",$0B,"ADC",$04,"ROR",$04,"BR6",$0E
.byte "BVS",$08,"ADC",$0A,"ADC",$0D,inval,$07,"STZ",$02,"ADC",$02,"ROR",$02,"RB7",$01,"SEI",$07,"ADC",$06,"PLY",$07,inval,$07,"JMP",$0C,"ADC",$05,"ROR",$05,"BR7",$0E
.byte "BRA",$08,"STA",$09,inval,$00,inval,$07,"STY",$01,"STA",$01,"STX",$01,"SB0",$01,"DEY",$07,"BIT",$00,"TXA",$07,inval,$07,"STY",$04,"STA",$04,"STX",$04,"BS0",$0E
.byte "BCC",$08,"STA",$0A,"STA",$0D,inval,$07,"STY",$02,"STA",$02,"STX",$03,"SB1",$01,"TYA",$07,"STA",$06,"TXS",$07,inval,$07,"STZ",$04,"STA",$05,"STZ",$05,"BS1",$0E
.byte "LDY",$00,"LDA",$09,"LDX",$00,inval,$07,"LDY",$01,"LDA",$01,"LDX",$01,"SB2",$01,"TAY",$07,"LDA",$00,"TAX",$07,inval,$07,"LDY",$04,"LDA",$04,"LDX",$04,"BS2",$0E
.byte "BCS",$08,"LDA",$0A,"LDA",$0D,inval,$07,"LDY",$02,"LDA",$02,"LDX",$03,"SB3",$01,"CLV",$07,"LDA",$06,"TSX",$07,inval,$07,"LDY",$05,"LDA",$05,"LDX",$06,"BS3",$0E
.byte "CPY",$00,"CMP",$09,inval,$00,inval,$07,"CPY",$01,"CMP",$01,"DEC",$01,"SB4",$01,"INY",$07,"CMP",$00,"DEX",$07,"WAI",$07,"CPY",$04,"CMP",$04,"DEC",$04,"BS4",$0E
.byte "BNE",$08,"CMP",$0A,"CMP",$0D,inval,$07,inval,$02,"CMP",$02,"DEC",$02,"SB5",$01,"CLD",$07,"CMP",$06,"PHX",$07,"STP",$07,inval,$04,"CMP",$05,"DEC",$05,"BS5",$0E
.byte "CPX",$00,"SBC",$09,inval,$00,inval,$07,"CPX",$01,"SBC",$01,"INC",$01,"SB6",$01,"INX",$07,"SBC",$00,"NOP",$07,inval,$07,"CPX",$04,"SBC",$04,"INC",$04,"BS6",$0E
.byte "BEQ",$08,"SBC",$0A,"SBC",$0D,inval,$07,inval,$02,"SBC",$02,"INC",$02,"SB7",$01,"SED",$07,"SBC",$06,"PLX",$07,inval,$07,inval,$04,"SBC",$05,"INC",$05,"BS7",$0E

length: .byte 2,2,2,2,3,3,3,1,2,2,2,3,3,2,3

format:
.byte "#$__",$00,$00
.byte "#'_'",$00,$00
.byte "$__",$00,$01
.byte "$__,X",$00,$02
.byte "$__,Y",$00,$03
.byte "$____",$00,$04
.byte "$____,X",$00,$05
.byte "$____,Y",$00,$06
.byte "0X__",$00,$08
.byte "-0X__",$00,$08
.byte "($__,X)",$00,$09
.byte "($__),Y",$00,$0a
.byte "($____)",$00,$0b
.byte "($____,X)",$00,$0c
.byte "($__)",$00,$0d
.byte "$__,0X__",$00,$0e
.byte "$__,-0X__",$00,$0e
.byte $00,$07 ; Must be last

.segment "STARTUP"

; ZEROPAGE
; The input is stored at $00 forwards.

; this is the length of the input.
.define inputlen $80
; arguably various forms of temporary.
.define good $81
.define formattype $82
.define addrmode $83

; these 3 make up a runtime codegen buffer for indirect jumps,
;  but indlow/indhigh are also used as temporaries by themselves too.
.define opcode $84
; used in "($__),Y"-form
.define indlow $85
.define indhigh $86

; this is the writing pointer (cursor/current) ; it's used a lot.
; used in "($__),Y"-form
.define curlow $87
.define curhigh $88

.macro dmacopy src, dest, len, mode
	.ifnblank src
		.if .const(src) .and .lobyte(src) = 0
			stz $E041
		.else
			lda #<src
			sta $E041
		.endif
		.if .const(src) .and .hibyte(src) = 0
			stz $E042
		.else
			lda #>src
			sta $E042
		.endif
	.endif
	.ifnblank dest
		.if .const(dest) .and .lobyte(dest) = 0
			stz $E043
		.else
			lda #<dest
			sta $E043
		.endif
		.if .const(dest) .and .hibyte(dest) = 0
			stz $E044
		.else
			lda #>dest
			sta $E044
		.endif
	.endif
	.ifnblank len
		.if .const(len) .and len = 0
			stz $E045
		.else
			lda #<len
			sta $E045
		.endif
	.endif
	.if .const(mode) .and mode = 0
		stz $E040
	.else
		lda #mode
		sta $E040
	.endif
.endmacro

.macro dmaload src, dest, len
	.ifnblank src
		.if .const(src) .and .lobyte(src) = 0
			stz $E041
		.else
			lda #<src
			sta $E041
		.endif
		.if .const(src) .and .hibyte(src) = 0
			stz $E042
		.else
			lda #>src
			sta $E042
		.endif
	.endif
	.ifnblank dest
		.if .const(dest) .and .lobyte(dest) = 0
			stz $E043
		.else
			lda #<dest
			sta $E043
		.endif
		.if .const(dest) .and .hibyte(dest) = 0
			stz $E044
		.else
			lda #>dest
			sta $E044
		.endif
	.endif
	.ifnblank len
		.if .const(len) .and len = 0
			stz $E045
		.else
			lda #<len
			sta $E045
		.endif
	.endif
.endmacro

.define mode_pp $00
.define mode_pu $01
.define mode_up $02
.define mode_uu $03

hexprint:
	; Prints a byte to the screen
	; A - byte to print
	; Clobbers: X
	pha
	phy
	tax
	lsr
	lsr
	lsr
	lsr
	tay
	lda hexlookup,Y
	sta $E003
	txa
	and #$0F
	tay
	lda hexlookup,Y
	sta $E003
	ply
	pla
	rts

crlf:
	lda #$0D
	sta $E003
	lda #$0A
	sta $E003
	rts

uuidprint:
	; Prints a UUID to the screen
	; $00, $01 - Address of UUID
	; Clobbers: A, X (hexprint), Y
	ldy #$00
@loop:
	lda (indlow),Y
	jsr hexprint
	iny
	cpy #$10
	beq @done
	cpy #$04
	beq @dash
	cpy #$06
	beq @dash
	cpy #$08
	beq @dash
	cpy #$0A
	beq @dash
	bra @loop
@dash:
	lda #$2D
	sta $E003
	bra @loop
@done:
	jmp crlf ; JSR/RTS

_readlist:
	; Reads component list to $0200
	; $02 - Bytes to skip for component type
	; Clobbers: A, X, Y, indlow, indhigh
	lda $E011
	sta $03
	stz indlow
	ldy #$00
	lda #$02
	sta indhigh
@loop1:
	lda $E012
	cmp #$00 ; TSF End Tag
	beq @done

	; Read UUID
	ldx #$10
@loop2:
	lda $E012
	sta (indlow),Y
	jsr inc_y
	dex
	cpx #$00
	bne @loop2

	; Drop component name
	ldx $02
@loop3:
	lda $E012
	dex
	cpx #$00
	bne @loop3
	bra @loop1
@done:
	lda #$02
	sta indhigh
	rts

.macro readlist skip
	lda #skip
	sta $02
	jsr _readlist
.endmacro

loaduuid:
	; Load a UUID into the component selector buffer
	; indlow, indhigh - Address to read from
	; Clobbers: A, X, Y, (uuidprint)
	jsr uuidprint
loaduuid2:
	ldy indlow
	stz indlow
	ldx #$10
	lda #$0b ; UUID Tag
	sta $E012
@loop:
	lda (indlow),Y ; UUID Byte loop
	sta $E012
	jsr inc_y
	dex
	cpx #$00
	bne @loop
	sty indlow
	stz $E012 ; End Tag
	stz $E010 ; Map Component
	rts

closehandle:
	; Closes an open file handle
	; $08-$0C - Handle to close
	; Clobbers: A
	dmacopy fsclose, $D001, .sizeof(fsclose), mode_up ; Call close
	dmacopy $0008, , 5, mode_up ; ($0008, $D001, 5, mode_up)
	stz $D001
	stz $D000
	dmacopy , $E012, , mode_up ; ($0008, $E012, 5, mode_up) Destroy value
	stz $E012
	lda #$04
	sta $E010
	rts

loadfile:
	; Reads a file into memory starting at $0200
	stz curlow
	lda #$02
	sta curhigh
	dmacopy fsread, $0001, .sizeof(fsread), mode_uu ; Copy read command
	dmacopy $D001, $0008, 5, mode_pu ; Inject handle
@loop:
	ldx curhigh
	cpx #$D0
	beq @done ; Too much data read
	dmacopy $0001, $D001, .sizeof(fsread), mode_up ; Call "read"
	stz $D000

	lda $D001 ; Check TSF Tag
	cmp #$09 ; Byte array?
	beq :+
	cmp #$0A ; String?
	bne @done ; No more data to read

:	lda $D001 ; Read length
	sta indlow
	lda $D001
	sta indhigh
	ldy #$01 ; Setup Copy Engine
	sty $E041
	lda #$D0
	sta $E042
	clc ; Load address and add at same time
	lda curlow
	sta $E043
	adc indlow
	sta curlow
	lda curhigh
	sta $E044
	adc indhigh
	sta curhigh
	lda indlow
	sta $E045
	lda indhigh
	sta $E046
	sty $E040 ; Execute Copy Engine Command
	bra @loop
@done:
	stz $E046 ; Put high byte of size back to 0
	jmp closehandle ; JSR/RTS

dispboot:
	dmacopy bootmsg, $E003, .sizeof(bootmsg), mode_up
	rts

bootdrive:
	; Checks and boots from a drive
	lda $D000
	cmp #$00
	beq :+
	rts
:	jsr dispboot
	pla ; Remove address from stack
	pla ; We're not returning to havemem
	lda #$01 ; Setup Copy Engine
	sta $E041
	lda #$D0
	sta $E042
	stz $E043
	lda #$02
	sta $E044

	lda $D001 ; Discard tag
	lda $D001
	sta $E045
	lda $D001
	sta $E046

	lda #mode_pu ; Copy
	sta $E040

	stz $E046
	jsr $0200 ; Boot
	jmp fschk

bootfs:
	; Boots from a file
	lda $D000
	cmp #$00
	beq :+
	rts ; No file opened
:	jsr dispboot
	pla ; Remove address from stack
	pla ; We're not returning to fschk
	jsr loadfile
	jsr $0200 ; Boot
	jmp commands

reset:
	; Display boot greeting
	dmacopy greeting, $E003, .sizeof(greeting), mode_up

	; Memory Check
	lda $E018
	cmp #$00
	bne havemem
	lda $E019
	cmp #$00
	bne havemem
	; No Memory Installed
	dmacopy nomem, , .sizeof(nomem), mode_up ; (nomem, $E003, .sizeof(nomem), mode_up)
@loop:	bra @loop

havemem:
	dmacopy drives, , .sizeof(drives), mode_up ; (drives, $E003, .sizeof(drives), mode_up)
	; Look for "drive" components
	dmacopy umlist, $E012, .sizeof(umlist), mode_up
	lda #$03
	sta $E010
	readlist 8 ; Store list to memory

	; Parse list
@loop:
	lda $03
	cmp #$00
	beq fschk ; No "drive" componets left to check
	jsr loaduuid
	dmacopy secread, $D001, .sizeof(secread), mode_up ; Call readSector
	stz $D000
	jsr bootdrive
	dec $03
	bra @loop

fschk:
	dmacopy fsmsg, $E003, .sizeof(fsmsg), mode_up
	; Look for "filesystem" components
	dmacopy fslist, $E012, .sizeof(fslist), mode_up
	lda #$03
	sta $E010
	readlist 13 ; Store list to memory

	; Parse list
@loop:
	lda $03
	cmp #$00
	bne :+
	jmp failboot ; No "filesystem" componets left to check
:	jsr loaduuid
	dmaload , $D001
	dmacopy fsopend, , .sizeof(fsopend), mode_up ; (fsopend, $D001, .sizeof(fsopend), mode_up) open Thistle/boot
	stz $D000
	jsr bootfs
	dmacopy fsopenf, , .sizeof(fsopenf), mode_up ; (fsopenf, $D001, .sizeof(fsopenf), mode_up) open Thistle
	stz $D000
	jsr bootfs
	dec $03
	bra @loop

_hex2val:
	; Converts one hexadecimal characters to a value
	lda $00,X
	clc
	sbc #$2f
	cmp #$11
	bcc :+
	sbc #$07
:	dex
	rts

hex2val_a:
	; Converts two hexadecimal characters from $00,X to a value
	;  and stores that value in A.
	; Clobbers: A, the carry flag, good
	; Advances X *backwards* (as this is convenient for little-endian).
	; So for the string "0000", you would want X to start at the last 0 and make 2 calls.
	jsr _hex2val
	; if a non-capital letter is placed in the lower nibble,
	;  then #$20 is OR'd into the result. this isn't great.
	; flush it out completely here (doesn't matter if it happens to the upper nibble)
	and #$0F
	sta good
	jsr _hex2val
	asl
	asl
	asl
	asl
	eor good
	rts

hex2val:
	; Like hex2val_a, but stores to (curlow),Y & advances a Y 'relative-to-opcode' offset
	jsr hex2val_a
	sta (curlow),Y
	iny
	rts

inc_y:
	; Handle page wraps
	iny
	cpy #$00
	bne :+
	inc indhigh
:	rts

failboot:
	dmacopy noboot, $E003, .sizeof(noboot), mode_up

	; Try to select a non tmpfs filesystem
	dmacopy fslist, $E012, .sizeof(fslist), mode_up
	lda #$03
	sta $E010
	readlist 13 ; Store list to memory

@loop:
	lda $03
	cmp #$00
	beq commands
	ldx #$00
	ldy #$00
	stz good
@loop2:
	lda (indlow),Y
	cmp $E110,X
	beq :+
	sty good
	lda indlow
	clc
	adc good
	stx good
	sec
	sbc indlow
	sta indlow
	jsr loaduuid2
	bra commands
:	inx
	jsr inc_y
	cpx #$10
	bne @loop2
	ldx #$00
	dec $03
	bra @loop

commands:
	stz $E001 ; Drop all input
	stz curlow
	lda #$02
	sta curhigh
@setup:	lda #'$'
	sta $E003
	lda curhigh
	jsr hexprint
	lda curlow
	jsr hexprint
	ldx #' '
	stx $E003
	lda #'>'
	sta $E003
	stx $E003
	stz inputlen
@loop:	lda $E000
	cmp #$00
	beq @loop ; No Input
	ldx inputlen
	lda $E001
	cmp #$00 ; Scancode, discard
	bne :+
	lda $E001
	bra @loop
:	cmp #$08 ; Backspace
	bne :+
	cpx #$00
	beq @loop ; No input to delete
	sta $E003
	dec inputlen
	bra @loop
:	cmp #$0D ; Carriage Return
	beq @exec
	cmp #$0A ; Line Feed
	beq @exec
	cpx #$80 ; Character
	beq @loop
	sta $E003
	sta $00,X
	inc inputlen
	bra @loop
@exec:
	jsr crlf
	cpx #$00 ; No Input
	beq @setup
	; @setup for comparing cmd names
	lda #<cmdlist
	sta indlow
	lda #>cmdlist
	sta indhigh
	ldx #$00
	ldy #$00
	stz good
	; Compare against cmd list
@ncloop:
	lda (indlow),Y
	cmp #$00 ; NUL, end of cmd name
	beq @nccheck
	cmp $00,X ; Matches
	beq :+
	smb0 good ; Mark as bad
:	inx
	jsr inc_y
	bra @ncloop
@nccheck:
	jsr inc_y
	cpx #$00 ; No more cmd entries?
	beq @asm
	cmp good ; A = $00
	bne @ncbad
	cpx inputlen
	beq @ncfound
	lda $00,X
	cmp #' '
	beq @ncfound
@ncbad:
	stz good ; Did not match, reset
	ldx #$00
	jsr inc_y ; Skip over address
	jsr inc_y
	bra @ncloop
@ncfound:
	lda #$4C ; JMP $XXXX
	sta opcode
	lda (indlow),Y
	tax
	jsr inc_y
	lda (indlow),Y
	stx indlow
	sta indhigh
	jsr opcode
	jmp @setup
@asm:
	; Assembly code!
	; Uppercase it all
	ldx #$00
@ucloop:
	lda $00,X
	clc
	sbc #$60
	bmi :+
	adc #$40
	sta $00,X
:	inx
	cpx inputlen
	bne @ucloop
	; Setup for comparing format strings
	ldx #$04
	ldy #$00
	stz formattype
	stz good
	lda inputlen
	cmp #$03 ; Three characters?
	bcs :+
	jmp @badcmd
:	beq @amloop
	lda $03
	cmp #$20
	beq @amloop
	jmp @badcmd ; 4th character not a space
	; Identify addressing mode
@amloop:
	lda format,Y
	cmp #$00 ; NUL, end of format string
	beq @amcheck
	cmp #$5F ; Underscore
	beq :+
	cmp $00,X ; Matches
	beq :+
	smb0 good ; Mark as bad
:	inx
	iny
	bra @amloop
@amcheck:
	iny
	cpx #$04 ; No more format entries?
	beq @amfound ; Assume implied
	cmp good ; A = $00
	bne @ambad
	cpx inputlen
	beq @amfound
	bcs @ambad ; Not enough imput
	lda $00,X
	cmp #' '
	beq @amfound
@ambad:
	stz good ; Wrong addressing mode, reset
	ldx #$04
	iny
	inc formattype
	bra @amloop
@amfound:
	lda format,Y
	sta addrmode
	lda #<opcodetbl
	sta indlow
	lda #>opcodetbl
	sta indhigh
	ldy #$00
	ldx #$00
	stz opcode
	stz good
	; Compare opcode names
@oploop:
	lda (indlow),Y
	cmp $00,X
	beq :+
	smb0 good ; Mark as bad
:	inx
	jsr inc_y
	cpx #$03
	beq @opcheck
	cmp #$FF
	beq @opcheck
	bra @oploop
@opcheck:
	lda (indlow),Y
	cmp addrmode
	beq :+
	smb0 good ; Mark as bad
:	lda #$00
	cmp good
	beq @opfound

	stz good ; Wrong opcode, reset
	ldx #$00
	jsr inc_y
	inc opcode
	lda opcode
	cmp #$00 ; Wrapped back to 0
	bne :+
	jmp @badcmd
:	bra @oploop
@opfound:
	ldy #$00
	lda opcode
	sta (curlow),Y ; Write opcode to memory
	iny
	lda formattype
	cmp #$00 ; immediate
	beq @read21
	cmp #$01 ; immediate w/ character
	beq @readchar
	cmp #$02 ; zeropage
	beq @read20
	cmp #$03 ; zp indexed x
	beq @read20
	cmp #$04 ; zp indexed y
	beq @read20
	cmp #$05 ; absolute
	beq @read40
	cmp #$06 ; indexed x
	beq @read40
	cmp #$07 ; indexed y
	beq @read40
	cmp #$08 ; relative
	beq @read21
	cmp #$09 ; relative w/ minus
	beq @relminus
	cmp #$0a ; zp indirect x
	beq @read21
	cmp #$0b ; zp indirect y
	beq @read21
	cmp #$0c ; indirect
	beq @read41
	cmp #$0d ; indirect x
	beq @read41
	cmp #$0e ; zp indirect
	beq @read21
	cmp #$0f ; zp relative
	beq @readzpr
	cmp #$10 ; zp relative minus
	beq @zprminus
	bra @opskip
@readchar:
	ldx #$06
	lda $00,X
	sta (curlow),Y
	bra @opskip
@read20:
	ldx #$06
	jsr hex2val
	bra @opskip
@read21:
	ldx #$07
	jsr hex2val
	bra @opskip
@read40:
	ldx #$08
	jsr hex2val
	jsr hex2val
	bra @opskip
@read41:
	ldx #$09
	jsr hex2val
	jsr hex2val
	bra @opskip
@readzpr:
	ldx #$06
	jsr hex2val
	ldx #$0b
	jsr hex2val
	bra @opskip
@zprminus:
	ldx #$06
	jsr hex2val
	ldx #$0c
	bra :+
@relminus:
	ldx #$08
:	jsr hex2val
	dey
	sec
	lda #$00
	sbc (curlow),Y
	sta (curlow),Y
@opskip:
	ldy addrmode
	ldx length,Y
	ldy curlow
@incloop:
	iny
	cpy #$00
	bne :+
	inc curhigh
:	dex
	cpx #$00
	bne @incloop
	sty curlow
	bra :+
@badcmd:
	dmacopy unkcmd, $E003, .sizeof(unkcmd), mode_up ; (unkcmd, $E003, .sizeof(unkcmd), mode_up)
:	jmp @setup

loadinput:
	; Loads string from input buffer into Component 1
	lda inputlen
	cmp good
	bcs :+
	lda good
:	clc
	sbc good
	inc
	sta $D001
	sta $E045 ; Copy Engine Length
	stz $D001

	lda good ; Setup Copy Engine
	sta $E041
	stz $E042
	lda #$01
	sta $E043
	lda #$D0
	sta $E044
	lda #mode_up ; Copy
	sta $E040
	rts

.segment "RODATA"

listtest: .byte 10,4,0,"list",10
listfail: .byte "Listing failed",13,10

.segment "STARTUP"

; ls [directory]
; list [directory]
cmd_ls:
	lda #$03 ; inputlen
	sta good
	bra :+
cmd_list:
	lda #$05 ; inputlen
	sta good
:	dmacopy listtest, $D001, .sizeof(listtest), mode_up
	jsr loadinput
	stz $D001 ; TSF End Tag
	stz $D000 ; Invoke
	lda $D000
	cmp #$00
	beq :+
	dmacopy listfail, $E003, .sizeof(listfail), mode_up
	rts
:	lda $D001 ; Drop Array Tag
@loop:
	lda $D001
	cmp #$00 ; TSF End Tag
	beq @done
	ldy $D001 ; Length low
	ldx $D001 ; Length high
@readloop:
	cpy #$00
	bne :+
	cpx #$00
	bne :+
	jsr crlf
	bra @loop
:	lda $D001
	sta $E003
	dey
	cpy #$FF
	bne :+
	dex
:	bra @readloop
@done:
	rts

.segment "RODATA"

openfail: .byte "Could not open file",13,10
loadmsg: .byte "Loading file ...",13,10

.segment "STARTUP"

; load <filename>
cmd_load:
	lda inputlen
	cmp #$06
	bcs :+
	rts
:	dmacopy fsopenf, $D001, 8, mode_up ; Copy 10,4,0,"open",10
	lda #$05 ; inputlen
	sta good
	jsr loadinput
	stz $D001 ; TSF End Tag
	stz $D000 ; Invoke
	lda $D000
	cmp #$00
	beq :+
	dmacopy openfail, $E003, .sizeof(openfail), mode_up ; No file opened
	rts
:	dmacopy loadmsg, $E003, .sizeof(loadmsg), mode_up
	jmp loadfile ; JSR/RTS

.segment "RODATA"

savemsg: .byte "Saving file ...",13,10
fswrite: .byte 10,5,0,"write"

.segment "STARTUP"

; save <filename>
cmd_save:
	lda inputlen
	cmp #$06
	bcs :+
	rts
:	dmacopy fsopenf, $D001, 8, mode_up ; Copy 10,4,0,"open",10
	lda #$05 ; inputlen
	sta good
	jsr loadinput
	lda #10
	sta $D001
	lda #1
	sta $D001
	stz $D001
	lda #'w'
	sta $D001
	stz $D001 ; TSF End Tag
	stz $D000 ; Invoke
	lda $D000
	cmp #$00
	beq :+
	dmacopy openfail, $E003, .sizeof(openfail), mode_up ; No file opened
	rts
:	dmacopy savemsg, $E003, .sizeof(savemsg), mode_up
	dmacopy fswrite, $D001, .sizeof(fswrite), mode_up ; Copy write command
	dmacopy $D001, $0008, 5, mode_pu ; Save handle
	dmacopy $0008, $D001, 5, mode_up
	lda #9
	sta $D001
	ldx curlow
	stx $D001
	ldy curhigh
	dey
	dey
	sty $D001
	stz $E041
	lda #$02 ; Setup Copy Engine
	sta $E042
	lda #$01
	sta $E043
	lda #$D0
	sta $E044
	stx $E045
	sty $E046
	lda #mode_up ; Copy
	sta $E040
	stz $E046 ; Put high byte back to zero
	stz $D001 ; TSF End Tag
	stz $D000 ; Invoke
	jmp closehandle ; JSR/RTS

; run
cmd_run:
	stz $E005
	jmp $0200

; db __
cmd_db:
	ldy #$00
	ldx #$04 ; 'db ' plus an additional 1 for hex2val quirks
	jsr hex2val
	; Completed the actual write.
	; Need to adjust curlow/curhigh.
	lda #$01
	clc
	adc curlow
	sta curlow
	; keep carry flag...
	lda #$00
	adc curhigh
	sta curhigh
	rts

; at ____
cmd_at:
	; While using hex2val to overwrite curlow/curhigh would be good,
	;  it destroys curlow/curhigh as hex2val is trying to use it.
	; So take the manual route.
	ldx #$06
	jsr hex2val_a
	sta curlow
	jsr hex2val_a
	sta curhigh
	rts

; fs ________-____-____-____-____________
cmd_fs:
	; the part where the UUID is read is a little 'fun', and it starts here.

	ldx #$03 ; see below:
	; $03 : after 'fs '
	; $04 : inc because it needs to be pointed at the RHS digit
	; $03 : dec due to the placement of @dash
	
	ldy #$00
	; this part is similar to the UUID printer in principle.
@dash:
	inx
@loop:
	jsr hex2val_a
	inx
	inx
	inx
	inx
	; the command buffer is used as the storage, for convenience.
	sta $00,Y
	iny
	; This is the same pattern as in the UUID printer.
	; The question is, if having a separate pattern table would be an improvement...
	cpy #$10
	beq @done
	cpy #$04
	beq @dash
	cpy #$06
	beq @dash
	cpy #$08
	beq @dash
	cpy #$0A
	beq @dash
	bra @loop
@done:
	; the UUID is now written at $00
	lda #$00
	sta indlow
	sta indhigh
	jmp loaduuid ; JSR/RTS

.segment "RODATA"

.byte "]]error",$22,"Thistle architecture required",$22,"--"

.segment "STARTUP"

interrupt_handler:
	rti

.segment	"VECTORS"

.word interrupt_handler
.word reset
.word interrupt_handler
