mirror of
https://github.com/thelbane/ConwayII.git
synced 2024-06-19 18:29:30 +00:00
Remove clever bit twiddling. Improve perf testing mode.
This commit is contained in:
parent
b14130299a
commit
fa68f4a536
190
src/conway.asm
190
src/conway.asm
|
@ -11,16 +11,19 @@
|
||||||
; ------------------------------------
|
; ------------------------------------
|
||||||
; Build Options
|
; Build Options
|
||||||
; ------------------------------------
|
; ------------------------------------
|
||||||
|
|
||||||
NOISY equ 1 ; 0 = Sound off, 1 = Sound on
|
NOISY equ 1 ; 0 = Sound off, 1 = Sound on
|
||||||
CHARSET equ 4 ; 0 = Olde Skoole, 1 = Pixel, 2 = Inverse, 3 = Small O's, 4 = Enhanced
|
CHARSET equ 4 ; 0 = Olde Skoole, 1 = Pixel, 2 = Inverse, 3 = Small O's, 4 = Enhanced
|
||||||
TEST_PERF equ 0
|
|
||||||
INIT_PATTERN equ 2 ; 0 = Glider gun, 1 = "Random", 2 = Edge test
|
INIT_PATTERN equ 2 ; 0 = Glider gun, 1 = "Random", 2 = Edge test
|
||||||
|
TEST_PERF equ 0 ; 0 = Normal, 1 = Instrument for emulator cycle counting (forces Glider gun layout and sound off)
|
||||||
|
|
||||||
; ------------------------------------
|
; ------------------------------------
|
||||||
; Constants
|
; Constants
|
||||||
; ------------------------------------
|
; ------------------------------------
|
||||||
|
|
||||||
|
soundEnabled equ NOISY && !TEST_PERF
|
||||||
|
initialPattern equ INIT_PATTERN - [TEST_PERF * INIT_PATTERN]
|
||||||
|
|
||||||
textRow equ ZPA0
|
textRow equ ZPA0
|
||||||
textRowH equ ZPA1
|
textRowH equ ZPA1
|
||||||
|
|
||||||
|
@ -67,24 +70,6 @@ charOn equ $ff ; | normalText
|
||||||
charOff equ ' | normalText
|
charOff equ ' | normalText
|
||||||
endif
|
endif
|
||||||
|
|
||||||
topleft equ %10000000 ; Neighbor bit flags
|
|
||||||
top equ %01000000 ; All combinations are decoded in conwayRules table
|
|
||||||
topright equ %00100000 ; This is faster than counting neighbors each pass
|
|
||||||
left equ %00010000
|
|
||||||
right equ %00001000
|
|
||||||
bottomleft equ %00000100
|
|
||||||
bottom equ %00000010
|
|
||||||
bottomright equ %00000001
|
|
||||||
|
|
||||||
n_topleft equ bottomright ; Inverse neighbor relationships
|
|
||||||
n_top equ bottom
|
|
||||||
n_topright equ bottomleft
|
|
||||||
n_left equ right
|
|
||||||
n_right equ left
|
|
||||||
n_bottomleft equ topright
|
|
||||||
n_bottom equ top
|
|
||||||
n_bottomright equ topleft
|
|
||||||
|
|
||||||
n_offset equ dataWidth+1 ; Alt data topleft offset from current cell
|
n_offset equ dataWidth+1 ; Alt data topleft offset from current cell
|
||||||
|
|
||||||
y_topleft equ 0 ; Alt data pointer offsets
|
y_topleft equ 0 ; Alt data pointer offsets
|
||||||
|
@ -96,11 +81,6 @@ y_bottomleft equ dataWidth*2
|
||||||
y_bottom equ dataWidth*2+1
|
y_bottom equ dataWidth*2+1
|
||||||
y_bottomright equ dataWidth*2+2
|
y_bottomright equ dataWidth*2+2
|
||||||
|
|
||||||
topRow equ $FF ^ [ topleft | top | topright ]
|
|
||||||
bottomRow equ $FF ^ [ bottomleft | bottom | bottomright ]
|
|
||||||
leftColumn equ $FF ^ [ topleft | left | bottomleft ]
|
|
||||||
rightColumn equ $FF ^ [ topright | right | bottomright ]
|
|
||||||
|
|
||||||
; ------------------------------------
|
; ------------------------------------
|
||||||
; Entry Point
|
; Entry Point
|
||||||
; ------------------------------------
|
; ------------------------------------
|
||||||
|
@ -111,7 +91,6 @@ start subroutine
|
||||||
lda #0
|
lda #0
|
||||||
sta currentPage ; Point main data segment to first block
|
sta currentPage ; Point main data segment to first block
|
||||||
jsr OUTPORT ; PR#0 (Set output to 40-column text screen)
|
jsr OUTPORT ; PR#0 (Set output to 40-column text screen)
|
||||||
jsr makeRules ; Create Conway rules table
|
|
||||||
jsr initScreen ; Render initial cell layout
|
jsr initScreen ; Render initial cell layout
|
||||||
jsr updateData ; Initialize backing data based on displayed cells
|
jsr updateData ; Initialize backing data based on displayed cells
|
||||||
if TEST_PERF
|
if TEST_PERF
|
||||||
|
@ -143,8 +122,9 @@ perfTest subroutine
|
||||||
|
|
||||||
mac TURN_ON
|
mac TURN_ON
|
||||||
ldy #y_{1}
|
ldy #y_{1}
|
||||||
|
clc
|
||||||
lda (altData),y
|
lda (altData),y
|
||||||
ora #n_{1}
|
adc #1
|
||||||
sta (altData),y
|
sta (altData),y
|
||||||
endm
|
endm
|
||||||
|
|
||||||
|
@ -164,7 +144,7 @@ iterate subroutine
|
||||||
.columnLoop ldy .column ; get neighbor bit flags
|
.columnLoop ldy .column ; get neighbor bit flags
|
||||||
lda (mainData),y ; at current data address
|
lda (mainData),y ; at current data address
|
||||||
tay
|
tay
|
||||||
lda conwayRules,y ; convert bit flags to cell state character (or 0 for do nothing)
|
lda rulesTable,y ; convert bit flags to cell state character (or 0 for do nothing)
|
||||||
beq .doNothing ; rule says do nothing, so update the neighbor data
|
beq .doNothing ; rule says do nothing, so update the neighbor data
|
||||||
ldy #0 ; .column
|
ldy #0 ; .column
|
||||||
.column equ .-1
|
.column equ .-1
|
||||||
|
@ -174,13 +154,13 @@ iterate subroutine
|
||||||
lda (textRow),y
|
lda (textRow),y
|
||||||
.setBits cmp #charOn ; A = cell character
|
.setBits cmp #charOn ; A = cell character
|
||||||
bne .clearTopLeft ; cell is disabled, so clear the topleft neighbor
|
bne .clearTopLeft ; cell is disabled, so clear the topleft neighbor
|
||||||
if NOISY
|
if soundEnabled
|
||||||
bit CLICK
|
bit CLICK
|
||||||
endif
|
endif
|
||||||
ldy #y_topleft ; cell is enabled, so turn on corresponding neighbor bits
|
ldy #y_topleft ; set top left value to one (previous value is stale)
|
||||||
lda #n_topleft ; top left neighbor is special since it contains stale data
|
lda #1
|
||||||
sta (altData),y ; so we just set the whole byte instead of ORing the bit
|
sta (altData),y
|
||||||
if NOISY
|
if soundEnabled
|
||||||
bit CLICK ; (Pretend I'm not here... I just click the speaker)
|
bit CLICK ; (Pretend I'm not here... I just click the speaker)
|
||||||
endif
|
endif
|
||||||
TURN_ON top
|
TURN_ON top
|
||||||
|
@ -191,7 +171,7 @@ iterate subroutine
|
||||||
TURN_ON bottom
|
TURN_ON bottom
|
||||||
TURN_ON bottomright
|
TURN_ON bottomright
|
||||||
jmp .continue
|
jmp .continue
|
||||||
.clearTopLeft ldy #y_topleft
|
.clearTopLeft ldy #y_topleft ; cell is off, so clear top left value to remove stale data
|
||||||
lda #0
|
lda #0
|
||||||
sta (altData),y
|
sta (altData),y
|
||||||
.continue sec
|
.continue sec
|
||||||
|
@ -243,9 +223,9 @@ updateData subroutine
|
||||||
lda (textRow),y
|
lda (textRow),y
|
||||||
cmp #charOff
|
cmp #charOff
|
||||||
beq .clearTopLeft
|
beq .clearTopLeft
|
||||||
ldy #y_topleft ; cell is enabled, so turn on corresponding neighbor bits
|
ldy #y_topleft ; set top left value to one (previous value is stale)
|
||||||
lda #n_topleft ; top left neighbor is special since it contains stale data
|
lda #1
|
||||||
sta (altData),y ; so we just set the whole byte instead of ORing the bit
|
sta (altData),y
|
||||||
TURN_ON top
|
TURN_ON top
|
||||||
TURN_ON topright
|
TURN_ON topright
|
||||||
TURN_ON left
|
TURN_ON left
|
||||||
|
@ -307,50 +287,29 @@ toggleDataPages subroutine ; toggles the current data page
|
||||||
clearBorders subroutine
|
clearBorders subroutine
|
||||||
|
|
||||||
mac CLEAR_BORDERS
|
mac CLEAR_BORDERS
|
||||||
.first set datapg{1} + dataWidth + 1
|
.bottomRow set datapg{2}_end - [dataWidth * 2] + 1
|
||||||
.last set datapg{1}_end - [dataWidth * 2] + 1
|
|
||||||
.clear set datapg{2}_end - [dataWidth * 2] + 1
|
|
||||||
ldx #fieldWidth
|
ldx #fieldWidth
|
||||||
.hloop lda .first,x
|
.hloop lda #0
|
||||||
and #topRow
|
sta .bottomRow,x
|
||||||
sta .first,x
|
|
||||||
lda .last,x
|
|
||||||
and #bottomRow
|
|
||||||
sta .last,x
|
|
||||||
lda #0
|
|
||||||
sta .clear,x
|
|
||||||
dex
|
dex
|
||||||
bne .hloop
|
bne .hloop
|
||||||
.firstAddr set ZPB0
|
.rightColumn set ZPB0
|
||||||
.lastAddr set ZPB2
|
.rightAddr set datapg{1}_end - dataWidth - 2
|
||||||
.first set datapg{1}_end - [dataWidth * 2] + 1
|
lda <#.rightAddr
|
||||||
.last set .first + fieldWidth - 1
|
sta <.rightColumn
|
||||||
lda <#.first
|
lda >#.rightAddr
|
||||||
sta <.firstAddr
|
sta >.rightColumn
|
||||||
lda >#.first
|
|
||||||
sta >.firstAddr
|
|
||||||
lda <#.last
|
|
||||||
sta <.lastAddr
|
|
||||||
lda >#.last
|
|
||||||
sta >.lastAddr
|
|
||||||
ldy #0
|
ldy #0
|
||||||
ldx #fieldHeight
|
ldx #fieldHeight
|
||||||
.vloop lda (.firstAddr),y
|
.vloop lda #0
|
||||||
and #leftColumn
|
sta (.rightColumn),y
|
||||||
sta (.firstAddr),y
|
|
||||||
lda (.lastAddr),y
|
|
||||||
and #leftColumn
|
|
||||||
sta (.lastAddr),y
|
|
||||||
lda #dataWidth
|
lda #dataWidth
|
||||||
sec
|
sec
|
||||||
sbc <.firstAddr
|
sbc <.rightColumn
|
||||||
|
sta <.rightColumn
|
||||||
lda #0
|
lda #0
|
||||||
sbc >.firstAddr
|
sbc >.rightColumn
|
||||||
lda #dataWidth
|
sta >.rightColumn
|
||||||
sec
|
|
||||||
sbc <.lastAddr
|
|
||||||
lda #0
|
|
||||||
sbc >.lastAddr
|
|
||||||
dex
|
dex
|
||||||
bne .vloop
|
bne .vloop
|
||||||
endm
|
endm
|
||||||
|
@ -425,70 +384,14 @@ getTextRow subroutine
|
||||||
sta textRowH
|
sta textRowH
|
||||||
rts
|
rts
|
||||||
|
|
||||||
makeRules subroutine ; Generate conway rules table
|
rulesTable dc.b charOff
|
||||||
lda #$ff
|
dc.b charOff
|
||||||
sta .neighbors
|
dc.b 0
|
||||||
.loop jsr getRule ; get the on/off char based on hamming weight of .neighbors...
|
dc.b charOn
|
||||||
ldx #0
|
dc.b charOff
|
||||||
.neighbors equ .-1
|
dc.b charOff
|
||||||
sta conwayRules,x ; ...and store it.
|
dc.b charOff
|
||||||
dec .neighbors
|
dc.b charOff
|
||||||
lda .neighbors
|
|
||||||
bne .loop
|
|
||||||
lda #charOff ; index offset 0 special handling (0 bits = 0 neighbors = turn off)
|
|
||||||
sta conwayRules
|
|
||||||
rts
|
|
||||||
|
|
||||||
getRule subroutine ; Returns #charOn, #charOff, or 0 (if no change)
|
|
||||||
jsr countBits ; Translate bit pattern to number of neighbors
|
|
||||||
cmp #2
|
|
||||||
bcc .off ; Fewer than 2 neighbors, dies of loneliness
|
|
||||||
cmp #3
|
|
||||||
beq .on ; Exactly 3 neighbors, reproduces
|
|
||||||
bcs .off ; More than 3 neighbors, dies of overpopulation
|
|
||||||
lda #0 ; Else exactly 2 neighbors, no change
|
|
||||||
rts
|
|
||||||
.off lda #charOff
|
|
||||||
rts
|
|
||||||
.on lda #charOn
|
|
||||||
rts
|
|
||||||
|
|
||||||
countBits subroutine ; Compute Hamming Weight (number of enabled bits) in Accumulator
|
|
||||||
.f1 equ %01010101 ; see: https://en.wikipedia.org/wiki/Hamming_weight
|
|
||||||
.f2 equ %00110011 ; (Takes approx. 1/2 the time compared to lsr/adc loop.)
|
|
||||||
.f3 equ %00001111
|
|
||||||
tax
|
|
||||||
and #.f1
|
|
||||||
sta .store1
|
|
||||||
txa
|
|
||||||
lsr
|
|
||||||
and #.f1
|
|
||||||
clc
|
|
||||||
adc #0 ; .store1
|
|
||||||
.store1 equ .-1
|
|
||||||
tax
|
|
||||||
and #.f2
|
|
||||||
sta .store2
|
|
||||||
txa
|
|
||||||
lsr
|
|
||||||
lsr
|
|
||||||
and #.f2
|
|
||||||
clc
|
|
||||||
adc #0 ; .store2
|
|
||||||
.store2 equ .-1
|
|
||||||
tax
|
|
||||||
and #.f3
|
|
||||||
sta .store3
|
|
||||||
txa
|
|
||||||
lsr
|
|
||||||
lsr
|
|
||||||
lsr
|
|
||||||
lsr
|
|
||||||
and #.f3
|
|
||||||
clc
|
|
||||||
adc #0 ; .store3
|
|
||||||
.store3 equ .-1
|
|
||||||
rts
|
|
||||||
|
|
||||||
; ------------------------------------
|
; ------------------------------------
|
||||||
; Utilities
|
; Utilities
|
||||||
|
@ -508,7 +411,7 @@ textRowsTable subroutine ; Lookup table for text page 0 r
|
||||||
repend
|
repend
|
||||||
LOG_REGION "textRowsTable", textRowsTable, 0
|
LOG_REGION "textRowsTable", textRowsTable, 0
|
||||||
|
|
||||||
if INIT_PATTERN == 0 ; Glider gun
|
if initialPattern == 0 ; Glider gun
|
||||||
initData dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
initData dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
dc.b %00000000,%00000000,%00000000,%01000000,%00000000
|
dc.b %00000000,%00000000,%00000000,%01000000,%00000000
|
||||||
dc.b %00000000,%00000000,%00000001,%01000000,%00000000
|
dc.b %00000000,%00000000,%00000001,%01000000,%00000000
|
||||||
|
@ -534,7 +437,7 @@ initData dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
endif
|
endif
|
||||||
if INIT_PATTERN == 1 ; "Random"
|
if initialPattern == 1 ; "Random"
|
||||||
initData dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
initData dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
dc.b %00000000,%00000000,%00000000,%00000000,%01000000
|
dc.b %00000000,%00000000,%00000000,%00000000,%01000000
|
||||||
|
@ -560,7 +463,7 @@ initData dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
dc.b %00000000,%00000000,%00000000,%00000000,%00000000
|
||||||
endif
|
endif
|
||||||
if INIT_PATTERN == 2 ; Edge test
|
if initialPattern == 2 ; Edge test
|
||||||
initData dc.b %11000000,%00000000,%00011000,%00000000,%00000011
|
initData dc.b %11000000,%00000000,%00011000,%00000000,%00000011
|
||||||
dc.b %11000000,%00000000,%00100100,%00000000,%00000011
|
dc.b %11000000,%00000000,%00100100,%00000000,%00000011
|
||||||
dc.b %00000000,%00000000,%00011000,%00000000,%00000000
|
dc.b %00000000,%00000000,%00011000,%00000000,%00000000
|
||||||
|
@ -592,9 +495,6 @@ dataSeg equ .
|
||||||
seg.u conwayData ; uninitialized data segment
|
seg.u conwayData ; uninitialized data segment
|
||||||
org dataSeg
|
org dataSeg
|
||||||
|
|
||||||
align 256
|
|
||||||
conwayRules ds.b 256 ; character lookup table goes here (see makeRules subroutine)
|
|
||||||
|
|
||||||
datapg0 ds.b dataWidth * dataHeight ; data page 0
|
datapg0 ds.b dataWidth * dataHeight ; data page 0
|
||||||
datapg0_lastRow equ . - dataWidth - fieldWidth ; first visible cell of the last row
|
datapg0_lastRow equ . - dataWidth - fieldWidth ; first visible cell of the last row
|
||||||
datapg0_tln equ . - [n_offset * 2] ; topleft neighbor of the bottomright-most visible cell
|
datapg0_tln equ . - [n_offset * 2] ; topleft neighbor of the bottomright-most visible cell
|
||||||
|
@ -603,6 +503,4 @@ datapg0_end equ .
|
||||||
datapg1 ds.b dataWidth * dataHeight ; data page 1
|
datapg1 ds.b dataWidth * dataHeight ; data page 1
|
||||||
datapg1_lastRow equ . - dataWidth - fieldWidth ; first visible cell of the last row
|
datapg1_lastRow equ . - dataWidth - fieldWidth ; first visible cell of the last row
|
||||||
datapg1_tln equ . - [n_offset * 2] ; topleft neighbor of the bottomright-most visible cell
|
datapg1_tln equ . - [n_offset * 2] ; topleft neighbor of the bottomright-most visible cell
|
||||||
datapg1_end equ .
|
datapg1_end equ .
|
||||||
|
|
||||||
echo "conwayRules:", conwayRules
|
|
Loading…
Reference in New Issue
Block a user