6502 command stream player, part 3

does not compile
This commit is contained in:
tildearrow 2025-04-16 20:39:07 -05:00
parent f18faa4655
commit 17a14f292f
5 changed files with 98 additions and 121 deletions

2
.gitignore vendored
View file

@ -37,3 +37,5 @@ res/docpdf/.venv
res/docpdf/htmldoc/
res/fonts/compressed/
res/furnace.appdata.xml
src/asm/6502/*.o
src/asm/6502/*.bin

20
src/asm/6502/6502base.i Normal file
View file

@ -0,0 +1,20 @@
; this defines a base 6502 machine with 64K RAM across the entire address space.
; use for testing!
.MEMORYMAP
DEFAULTSLOT 0
SLOT 0 START $0000 SIZE $2000
SLOT 1 START $2000 SIZE $2000
SLOT 2 START $4000 SIZE $2000
.ENDME
.ROMBANKMAP
BANKSTOTAL 3
BANKSIZE $2000
BANKS 2
BANKSIZE $C000
BANKS 1
.ENDRO
.BANK 1 SLOT 1
.ORGA $2000

View file

@ -0,0 +1,2 @@
[objects]
stream.o

View file

@ -1,73 +0,0 @@
patPos=$90
tempByte=$80
nextNote=$a0
nextIns=$a1
nextVolume=$b0
nextRow=$b1
nextEffect1=$c0
nextEffect2=$d0
nextEffect3=$e0
nextEffect4=$f0
.macro nextByte
lda (patPos,x)
inc patPos,x
bcc :+
inc patPos+1,x
: clc
.endmacro
; read next row.
; load X with channel<<1
readNext:
lda #$ff
sta nextNote,x ; clear last values
sta nextIns,x
sta nextVolume,x
sta nextEffect1,x
sta nextEffect2,x
sta nextEffect3,x
sta nextEffect4,x
nextByte
sta tempByte ; temporary store
beq endOfPat
lda #$20 ; start pattern check
bit tempByte ; NVI..EEE
bpl :+
php ; read note
nextByte
sta nextNote,x
plp
: bvc :+
php ; read volume
nextByte
sta nextVolume,x
plp
: bne :+
nextByte ; read instrument
sta nextIns,x
: lda tempByte
and #7
tay
txa
pha
clv
readEffectLoop:
dey ; check if we're done
beq readLength
nextByte ; effect
sta nextEffect1,x
nextByte ; effect val
sta nextEffect1+1,x
txa ; add 16 to offset
adc #$10
tax
bvc readEffectLoop
readLength:
pla
tax
nextByte
sta nextRow,x
endOfPat:
rts

View file

@ -10,10 +10,12 @@
; - short pointers only
; - little-endian only!
.include "6502base.i"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; constants
FCS_MAX_CHANS=8 ; maximum number of channels (up to 127, but see below!)
FCS_MAX_CHAN=8 ; maximum number of channels (up to 127, but see below!)
FCS_MAX_STACK=16 ; stack depth per channel (FCS_MAX_STACK*FCS_MAX_CHAN<256)
; player constants - change if necessary
@ -55,8 +57,8 @@ chanVibratoPos=fcsAddrBase+24+(FCS_MAX_CHAN*4) ; char
; may be used for driver detection
fcsDriverInfo:
.byte "Furnace"
.byte 0
.db "Furnace"
.db 0
; note on null
fcsNoteOnNull:
@ -80,6 +82,9 @@ fcsOneByteDispatch:
jsr fcsDispatchCmd
rts
fcsNoOp:
rts
; x: channel*2
; y: command
fcsDispatchCmd:
@ -91,24 +96,33 @@ fcsDispatchCmd:
; check for zero
lda fcsTempPtr
ora fcsTempPtr
beq :+ ; get out
beq + ; get out
; handle command in dispatch code
jmp (fcsTempPtr)
; only if pointer is zero
: rts
+ rts
; x: channel*2
; a is set to next byte
fcsReadNext:
; a=chanPC[x]+fcsPtr
clc
lda chanPC,x
adc #>fcsPtr
sta fcsTempPtr
lda chanPC+1,x
adc #<fcsPtr
sta fcsTempPtr+1
ldy chanPC,x
lda (fcsTempPtr),y
iny
bne :+
; increase PC
inc chanPC,x
bne +
inc chanPC+1,x
: sty chanPC,x
; read byte and put it into a
; this is at the end to ensure flags are set properly
+ ldy #0
lda (fcsTempPtr),y
rts
; x: channel*2 (for speed... char variables are interleaved)
@ -120,8 +134,8 @@ fcsChannelCmd:
; process and read arguments
; if (a<0xb3)
bmi fcsNote ; handle $00-$7f
cmp #$b3
bpl fcsOther
cmp #$b4
bpl fcsCheckOther
; this is a note
fcsNote:
@ -134,15 +148,29 @@ fcsChannelCmd:
jsr fcsDispatchCmd
rts
; check other instructions
fcsCheckOther:
; check for preset delays
cmp #$f0
bmi fcsOther
; handler for preset delays
fcsPresetDelay:
; load preset delay and store it
tay
lda fcsPtr+8-240,y
sta chanTicks,x
lda #0
sta chanTicks+1,x
rts
; other instructions
fcsOther:
; call respective handler
sec
sbc #$b4
tay
lda fcsInsTableLow,y
lda fcsInsTableLow-180,y
sta fcsTempPtr
lda fcsInsTableHigh,y
lda fcsInsTableHigh-180,y
sta fcsTempPtr+1
jmp (fcsTempPtr)
@ -170,15 +198,15 @@ fcsDoChannel:
; check whether this channel is halted (PC = 0)
lda chanPC,x
ora chanPC+1,x
beq :+
beq +
rts
; channel not halted... begin processing
; chanTicks--
: lda chanTicks,x
+ lda chanTicks,x
sec
sbc #1
sta chanTicks,x
bne :+ ; skip if our counter isn't zero
bne + ; skip if our counter isn't zero
; ticks lower is zero; check upper byte
ldy chanTicks+1,x
@ -194,51 +222,49 @@ fcsDoChannel:
fcsDoChannelLoop:
lda chanTicks,x
ora chanTicks+1,x
bne :+ ; get out if chanTicks is no longer zero
bne + ; get out if chanTicks is no longer zero
jsr fcsChannelCmd ; read next command
jmp fcsDoChannelLoop
: jsr fcsChannelPost
+ jsr fcsChannelPost
; end
rts
fcsTick:
; update channel state
; for (x=0; x<FCS_MAX_CHANS; x++)
; for (x=0; x<FCS_MAX_CHAN; x++)
ldx #0
: jsr fcsDoChannel
- jsr fcsDoChannel
inx
inx
cpx #FCS_MAX_CHANS*2
bne :-
cpx #FCS_MAX_CHAN*2
bne -
; increase tick counter
inc fcsTicks
bne :+
bne +
inc fcsTicks+1
; end
: rts
+ rts
fcsInit:
; set all tick counters to 1
lda #1
ldy #0
ldx #(FCS_MAX_CHANS*2)
: dex
ldx #(FCS_MAX_CHAN*2)
- dex
sty chanTicks,x
dex
sta chanTicks,x
bne :-
bne -
; set channel program counters
ldx #(FCS_MAX_CHANS*2)
: dex
ldx #(FCS_MAX_CHAN*2)
- dex
lda fcsPtr+40,x
sta chanPC,x
bne :-
; TODO: relocate and more...
bne -
; success
lda #0
@ -246,10 +272,10 @@ fcsInit:
; floor(127*sin((x/64)*(2*pi)))
fcsVibTable:
.byte 0, 12, 24, 36, 48, 59, 70, 80, 89, 98, 105, 112, 117, 121, 124, 126
.byte 127, 126, 124, 121, 117, 112, 105, 98, 89, 80, 70, 59, 48, 36, 24, 12
.byte 0, -12, -24, -36, -48, -59, -70, -80, -89, -98, -105, -112, -117, -121, -124, -126
.byte -126, -126, -124, -121, -117, -112, -105, -98, -89, -80, -70, -59, -48, -36, -24, -12
.db 0, 12, 24, 36, 48, 59, 70, 80, 89, 98, 105, 112, 117, 121, 124, 126
.db 127, 126, 124, 121, 117, 112, 105, 98, 89, 80, 70, 59, 48, 36, 24, 12
.db 0, -12, -24, -36, -48, -59, -70, -80, -89, -98, -105, -112, -117, -121, -124, -126
.db -126, -126, -124, -121, -117, -112, -105, -98, -89, -80, -70, -59, -48, -36, -24, -12
; "dummy" implementation - example only!
@ -257,15 +283,15 @@ fcsDummyFunc:
rts
fcsVolMaxExample:
.byte 127, 127, 127, 127, 127, 127, 127, 127
.db 127, 127, 127, 127, 127, 127, 127, 127
; first 64 commands
fcsCmdTableExample:
.word 0, 0, 0, 0, 0, 0, 0, 0
.word 0, 0, 0, 0, 0, 0, 0, 0
.word 0, 0, 0, 0, 0, 0, 0, 0
.word 0, 0, 0, 0, 0, 0, 0, 0
.word 0, 0, 0, 0, 0, 0, 0, 0
.word 0, 0, 0, 0, 0, 0, 0, 0
.word 0, 0, 0, 0, 0, 0, 0, 0
.word 0, 0, 0, 0, 0, 0, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0
.db 0, 0, 0, 0, 0, 0, 0, 0