First implementation of BG0/BG1 mixed exception handling

This commit is contained in:
Lucas Scharenbroich 2021-07-16 23:09:08 -05:00
parent 6fc772ce78
commit bdf885dafd
6 changed files with 171 additions and 39 deletions

View File

@ -16,8 +16,13 @@ MoveRight
sec
sbc 1,s
bpl *+5
lda #163
lda #0
jsr SetBG0XPos
lda StartX
lsr
jsr SetBG1XPos
jsr DoFrame
pla
rts
@ -25,10 +30,12 @@ MoveRight
MoveDown
clc
adc StartY ; Increment the virtual X-position
cmp #207
bcc *+5
lda #0
jsr SetBG0YPos
lda StartY
lsr
jsr SetBG1YPos
jsr DoFrame
rts
@ -38,8 +45,13 @@ MoveUp
sec
sbc 1,s
bpl *+5
lda #207
lda #0
jsr SetBG0YPos
lda StartY
lsr
jsr SetBG1YPos
jsr DoFrame
pla
rts
@ -87,3 +99,8 @@ FPSStr str 'FPS'

View File

@ -406,6 +406,8 @@ CopyPicToField
:line_cnt equ tmp2
:dstptr equ tmp3
:col_cnt equ tmp5
:mask equ tmp6
:data equ tmp7
sta :srcptr
stx :srcptr+2
@ -429,26 +431,63 @@ CopyPicToField
:cloop
phy
lda [:srcptr],y ; load the picture data
beq :transparent ; a value of $0000 is transparent
jsr :toMask ; Infer a mask value for this. If it's $0000, then
bne :mixed ; the data is solid, otherwise mixed
; This is a solid word
lda [:srcptr],y
ldy Col2CodeOffset,x ; Get the offset to the code from the line start
cmp #0 ; Empty values are transparent
beq :transparent
pha
pha ; Save the data
lda #$00F4 ; PEA instruction
sta [:dstptr],y
iny
pla
sta [:dstptr],y
sta [:dstptr],y ; PEA operand
bra :next
:transparent
ldy Col2CodeOffset,x ; Get the offset to the code from the line start
lda #$B1 ; LDA (dp),y
sta [:dstptr],y
iny
lda 1,s ; load the saved Y-index
ora #$4800 ; put a PHA after the offset
sta [:dstptr],y
bra :next
:mixed
sta :mask ; Save the mask
lda [:srcptr],y ; Refetch the screen data
sta :data
ldy Col2CodeOffset,x ; Get the offset into the code field
lda #$4C ; JMP exception
sta [:dstptr],y
iny
lda JTableOffset,x ; Get the address offset and add to the base address
clc
adc :dstptr
sta [:dstptr],y
ldy JTableOffset,x ; This points to the code fragment
lda 1,s ; load the offset
xba
ora #$00B1
sta [:dstptr],y ; write the LDA (--),y instruction
iny
iny
iny ; advance to the AND #imm operand
lda :mask
sta [:dstptr],y
iny
iny
iny ; advance to the ORA #imm operand
lda :data
sta [:dstptr],y
:next
ply
@ -469,8 +508,35 @@ CopyPicToField
inc :line_cnt
lda :line_cnt
cmp #200
bcc :rloop
bcs :exit
brl :rloop
:exit
rts
:toMask bit #$F000
beq *+7
and #$0FFF
bra *+5
ora #$F000
bit #$0F00
beq *+7
and #$F0FF
bra *+5
ora #$0F00
bit #$00F0
beq *+7
and #$FF0F
bra *+5
ora #$00F0
bit #$000F
beq *+7
and #$FFF0
bra *+5
ora #$000F
rts
; Copy a binary image data file into BG1. Assumes the file is the correct size.
@ -872,6 +938,35 @@ qtRec adrl $0000

View File

@ -8,6 +8,10 @@ SetBG1XPos
sta BG1StartX
rts
SetBG1YPos
sta BG1StartY
rts
; Everytime either BG1 or BG0 X-position changes, we have to update the direct page values. We
; *could* do this by adjusting the since address offset, but we have to change up to 200 values
; when the vertical position changes, and only 41 when the horizontal value changes. Plus
@ -247,5 +251,6 @@ CopyBG1YTableToBG1Addr

View File

@ -28,6 +28,9 @@ StartXMod164 equ 36
BG1StartX equ 38 ; Logical offset of the second background
BG1StartXMod164 equ 40
BG1StartY equ 42
BG1StartYMod208 equ 44
bstk equ 208 ; 16-byte stack to push bank addresses
tmp8 equ 224
@ -66,4 +69,5 @@ DIRTY_BIT_BG1_Y equ $0008

View File

@ -22,6 +22,15 @@ Col2CodeOffset lup 82
--^
dw CODE_TOP
; A parallel table to Col2CodeOffset that hold the offset to the exception handler address for each column
SNIPPET_SIZE equ 32
]step equ 0
JTableOffset lup 82
dw SNIPPET_BASE+{]step*SNIPPET_SIZE}
]step equ ]step+1
--^
dw SNIPPET_BASE
; Table of BRA instructions that are used to exit the code field. Separate tables for
; even and odd aligned cases.
;

View File

@ -16,11 +16,12 @@ ODD_ENTRY equ odd_entry-base+1
CODE_TOP equ loop-base
CODE_LEN equ top-base
CODE_EXIT equ even_exit-base
OPCODE_SAVE equ odd_exit-base+1 ; spot to save the code field opcode when patching exit BRA
OPCODE_HIGH_SAVE equ odd_high_byte-base+1 ; save the third byte
OPCODE_SAVE equ odd_save-base ; spot to save the code field opcode when patching exit BRA
OPCODE_HIGH_SAVE equ odd_save-base+2 ; save the third byte
FULL_RETURN equ full_return-base ; offset that returns from the blitter
ENABLE_INT equ enable_int-base ; offset that re-enable interrupts and continues
LINES_PER_BANK equ 16
SNIPPET_BASE equ snippets-base
; Locations that need the page offset added
PagePatches da {long_0-base+2}
@ -456,10 +457,10 @@ right_odd bit #$000B ; Check the bottom nibble
long_1 stal *+4-base ; Everything else is a two-byte LDA opcode + PHA
dfb $00,$00
bra r_is_pea+1
bra r_jmp_rtn
r_is_pea xba ; fast code for PEA
sep #$20
r_jmp_rtn sep #$20 ; shared return code path by all methods
pha
rep #$20
odd_entry jmp $0100 ; unconditionally jump into the "next" instruction in the
@ -475,7 +476,7 @@ odd_entry jmp $0100 ; unconditionally jump in
r_is_jmp sep #$41 ; Set the C and V flags which tells a snippet to push only the low byte
long_2 ldal entry_jmp+1-base
long_3 stal *+5-base
dfb $4C,$00,$00 ; Jump back to address in entry_jmp (this takes 16 cycles, is there a better way?)
jmp $0000 ; Jumps into the exception code, which return to r_jmp_rtn
; The next labels are special, in that they are entry points into special subroutines. They are special
; because they are within the first 256 bytes of each code field, which allows them to be selectable
@ -517,16 +518,13 @@ loop lup 82 ; +6 Set up 82 PEA inst
loop_back jmp loop-base ; +252 Ensure execution continues to loop around
loop_exit_3 jmp even_exit-base ; +255
odd_exit lda #0000 ; This operand field is *always* used to hold the original 2 bytes of the code field
; that are replaced by the needed BRA instruction to exit the code field. When the
; left edge is odd-aligned, we are able to immediately load the value and perform
; similar logic to the right_odd code path above
long_5
odd_exit ldal l_is_jmp+1-base
bit #$000B
bne :chk_jmp
sep #$20
odd_high_byte lda #00 ; patch with high byte code operand
long_6 ldal l_is_jmp+3-base ; get the high byte of the PEA operand
; Fall-through when we have to push a byte on the left edge. Must be 8-bit on entry. Optimize
; for the PEA $0000 case -- only 19 cycles to handle the edge, so pretty good
@ -540,20 +538,18 @@ even_exit jmp $1000 ; Jump to the next line.
:chk_jmp
bit #$0040
bne :l_is_jmp
bne l_is_jmp
long_4 stal *+4-base
dfb $00,$00
xba
l_jmp_rtn xba
sep #$20
pha
rep #$20
bra even_exit
:l_is_jmp sec ; Set the C flag (V is always cleared at this point) which tells a snippet to push only the high byte
long_5 ldal entry_jmp+1-base
long_6 stal *+5-base
dfb $4C,$00,$00 ; Jump back to address in entry_jmp (this takes 13 cycles, is there a better way?)
l_is_jmp sec ; Set the C flag (V is always cleared at this point) which tells a snippet to push only the high byte
odd_save dfb $00,$00,$00 ; The odd exit 3-byte sequence is always stashed here
; Special epilogue: skip a number of bytes and jump back into the code field. This is useful for
; large, floating panels in the attract mode of a game, or to overlay solid
@ -604,18 +600,24 @@ epilogue_1 tsc
; jmp exit_rtn ; 3
; r_edge jmp entry_rtn ; 3
; snippets ds 32*82
ds \,$00 ; pad to the next page boundary
]index equ 0
snippets lup 82
ds 2 ; space for a 2-byte sequence; LDA (00),y LDA 00,x LDA 0,s
and #$0000 ; the mask operand will be set when the tile is drawn
ora #$0000 ; the data operand will be set when the tile is drawn
pha
bcs *+5
brl loop+3+{3*]index} ; use relative branch for convenience
bvs *+6 ; overflow set means this is the right edge (entry)
clc ; carry is set only for edge operations; force clear
brl l_jmp_rtn
rep #$41 ; clear V and C
brl r_jmp_rtn ; 25 bytes
ds 7 ; padding
]index equ ]index+1
--^
top