and3rson wrote:
This thread totally nerd-sniped me. I decided to go for time efficiency and implement a solution similar to Chromatix's idea of a decision-based algorithm that picks one of 8 cases (2 of which are invalid).
I was tempted to do some self-modifying code magic (
opcodes of "STY/STA/STX zp" and "LDY/LDA/LDX zp" are dangerously close to each other, and they all differ only with 2 lowest bits! ) - but I didn't have guts to make any use of that...
Snipe
! This is an interesting version, similar to gfoot's thoughts at one point too. I tried out the code here and noticed the second test is swapped with the third test (second test is really zp0 >= zp2 and third test is zp1 >= zp2) which means the table is mis-ordered, but this works otherwise. I only have humble 6502 here, not 65C02, so I replaced the "TAX: JMP (table,X)" with
Code:
STA .addr_low
.addr_low = *+1
JMP (.table)
for a bit of self modifying code, and put the table at the start of a page.
and3rson wrote:
EDIT: Turns out `reorder` macro can be easily improved:
Careful: The reads need to happen before the writes:
Code:
!macro reorder .aa, .bb, .cc {
!if .aa != zp0 {
LDA zp0
}
!if .cc != zp2 {
LDX zp2
}
!if .aa != zp0 {
STA .aa
}
!if .bb != zp1 {
; Y is already loaded with zp1
STY .bb
}
!if .cc != zp2 {
STX .cc
}
}
With these changes I get 84 bytes of code, and ~50 cycles on average (including the RTS).
EDIT: Actually, using the 6502 indirect jump leaves X register free which we can use to store zp0, reducing the size of the reorder operations. 75 bytes, ~48 cycles average.
Revised version for reference:
Code:
zp0 = $02
zp1 = $03
zp2 = $04
!macro reorder .aa, .bb, .cc {
!if .cc != zp2 {
LDA zp2
}
!if .aa != zp0 {
STX .aa
}
!if .bb != zp1 {
STY .bb
}
!if .cc != zp2 {
STA .cc
}
}
* = $0200
; table at start of page
.table
!word .swap0 ; zp0 < zp1, zp0 < zp2, zp1 < zp2
!word .swap2 ; zp0 < zp1, zp0 < zp2, zp1 >= zp2
!word 0 ; zp0 < zp1, zp0 >= zp2, zp1 < zp2 - not possible
!word .swap3 ; zp0 < zp1, zp0 >= zp2, zp1 >= zp2
!word .swap4 ; zp0 >= zp1, zp0 < zp2, zp1 < zp2
!word 0 ; zp0 >= zp1, zp0 < zp2, zp1 >= zp2 - not possible
!word .swap5 ; zp0 >= zp1, zp0 >= zp2, zp1 < zp2
!word .swap7 ; zp0 >= zp1, zp0 >= zp2, zp1 >= zp2
.sort
LDA #0
LDX zp0
CPX zp1
ROL ; 1 if zp0 >= zp1
CPX zp2
ROL ; 1 if zp0 >= zp2
LDY zp1
CPY zp2
ROL ; 1 if zp1 >= zp2
ASL
STA .addr_low
.addr_low = *+1
JMP (.table)
.swap2
+reorder zp0, zp2, zp1
.swap0
RTS
.swap3
+reorder zp1, zp2, zp0
RTS
.swap4
+reorder zp1, zp0, zp2
RTS
.swap5
+reorder zp2, zp0, zp1
RTS
.swap7
+reorder zp2, zp1, zp0
RTS