A0 00 84 FE B1 FB 4A 90 07 C8 C4 FD F0 20 D0 F4 2A 85 02 84 FE A4 FD 88 C4 FE
F0 12 B1 FB 4A 90 F6 2A AA A5 02 91 FB A4 FE 8A 91 FB 90 D6 60
Ожидается указатель на массив чисел в $fb
/ $fc
и длина этого массива в $fd
. Управляет массивом на месте, чтобы все нечетные числа были впереди. Это независимый от позиции код, поэтому адрес загрузки не требуется.
Поскольку 6502 является 8-битным чипом (поэтому инструкции имеют дело только с 8-битными значениями, с необязательной подписью), допустимый диапазон номеров равен [-128 .. 127]
максимальному размеру массива 256
.
Прокомментировал разборку
; function to "partially sort" array, so all odd numbers come before all
; even numbers.
;
; input:
; $fb/$fc: address of array to sort
; $fd: length of array to sort, 0 means 256 (maximum size)
;
; clobbers:
; $fd/$fe: position from back/front of array
; $2: temporary for exchanging two values
; A, X, Y
.oddfirst:
A0 00 LDY #$00 ; initialize index from front
84 FE STY $FE ; to 0
.search_front:
B1 FB LDA ($FB),Y ; load number from front
4A LSR A ; check for even/odd by shifting
90 07 BCC .search_back ; if odd -> to searching from back
C8 INY ; next position from front
C4 FD CPY $FD ; same as position searching from back?
F0 20 BEQ .done ; then we're finished
D0 F4 BNE .search_front ; else check next from front
.search_back:
2A ROL A ; shift carry back in
85 02 STA $02 ; and save number to temp
84 FE STY $FE ; save index from front
A4 FD LDY $FD ; load index from back
.sb_loop:
88 DEY ; previous position from back
C4 FE CPY $FE ; same as position searching from front?
F0 12 BEQ .done ; then we're finished
B1 FB LDA ($FB),Y ; load number from back
4A LSR A ; check for even/odd by shifting
90 F6 BCC .sb_loop ; if odd -> check previous position
2A ROL A ; shift carry back in
AA TAX ; remember in X
A5 02 LDA $02 ; load temporary from front
91 FB STA ($FB),Y ; store at current position
A4 FE LDY $FE ; load index from front
8A TXA ; load remembered number
91 FB STA ($FB),Y ; store at current position
90 D6 BCC .search_front ; and back to searching from front
.done:
60 RTS
Пример C64 ассемблерной программы с использованием подпрограммы:
Онлайн демо
Код в синтаксисе ca65 :
.import oddfirst ; link with routine above
.segment "BHDR" ; BASIC header
.word $0801 ; load address
.word $080b ; pointer next BASIC line
.word 2018 ; line number
.byte $9e ; BASIC token "SYS"
.byte "2061",$0,$0,$0 ; 2061 ($080d) and terminating 0 bytes
.bss
linebuf: .res 5 ; maximum length of a valid signed
; 8-bit number input
convbuf: .res 3 ; 3 BCD digits for signed 8-bit
; number conversion
numbers: .res $100 ; maximum array size that can be
; directly handled with indexing
; instructions
.data
prompt: .byte "> ", $0
message: .byte $d, $d, "Enter one number per line.", $d
.byte "just press enter (empty line) when done.", $0
errmsg: .byte "Error parsing number, try again.", $d, $0
.code
lda #$17 ; set upper/lower mode
sta $d018
lda #0
sta $2a ; index for number array
sta $52 ; flag that at least one number was
; entered
lda #<message ; display message
ldy #>message
jsr $ab1e
inputloop:
lda #<prompt ; display prompt
ldy #>prompt
jsr $ab1e
lda #<linebuf ; read string into buffer
ldy #>linebuf
ldx #5
jsr readline
lda linebuf ; empty line?
beq process ; -> start processing
lda #<linebuf ; convert input to int8
ldy #>linebuf
jsr toint8
bcc numok ; successful -> store number
lda #<errmsg ; else show error message and repeat
ldy #>errmsg
jsr $ab1e
bcs inputloop
numok: ldx #$ff ; set flag that we have a number
stx $52
ldx $2a
sta numbers,x
inc $2a ; next index
bne inputloop ; if array not full, next input
process: lda $52 ; check we have some numbers
beq exit ; otherwise exit program
lda #<numbers ; address of array to $fb/fc
sta $fb
lda #>numbers
sta $fc
lda $2a ; length of array to $fd
sta $fd
jsr oddfirst ; call "sorting" function
lda #$0 ; index variable for output loop
sta $52
outloop: ldy $52 ; load current index
lda numbers,y ; load current number
jsr printnum ; -> output
inc $52 ; next index
lda $52 ; compare with ...
cmp $2a ; ... array size
bne outloop ; not reached yet -> repeat
exit: rts ; done, exit program
; read a line of input from keyboard, terminate it with 0
; expects pointer to input buffer in A/Y, buffer length in X
.proc readline
dex
stx $fb
sta $fc
sty $fd
ldy #$0
sty $cc ; enable cursor blinking
sty $fe ; temporary for loop variable
getkey: jsr $f142 ; get character from keyboard
beq getkey
sta $2 ; save to temporary
and #$7f
cmp #$20 ; check for control character
bcs checkout ; no -> check buffer size
cmp #$d ; was it enter/return?
beq prepout ; -> normal flow
cmp #$14 ; was it backspace/delete?
bne getkey ; if not, get next char
lda $fe ; check current index
beq getkey ; zero -> backspace not possible
bne prepout ; skip checking buffer size for bs
checkout: lda $fe ; buffer index
cmp $fb ; check against buffer size
beq getkey ; if it would overflow, loop again
prepout: sei ; no interrupts
ldy $d3 ; get current screen column
lda ($d1),y ; and clear
and #$7f ; cursor in
sta ($d1),y ; current row
output: lda $2 ; load character
jsr $e716 ; and output
ldx $cf ; check cursor phase
beq store ; invisible -> to store
ldy $d3 ; get current screen column
lda ($d1),y ; and show
ora #$80 ; cursor in
sta ($d1),y ; current row
lda $2 ; load character
store: cli ; enable interrupts
cmp #$14 ; was it backspace/delete?
beq backspace ; to backspace handling code
cmp #$d ; was it enter/return?
beq done ; then we're done.
ldy $fe ; load buffer index
sta ($fc),y ; store character in buffer
iny ; advance buffer index
sty $fe
bne getkey ; not zero -> ok
done: lda #$0 ; terminate string in buffer with zero
ldy $fe ; get buffer index
sta ($fc),y ; store terminator in buffer
sei ; no interrupts
ldy $d3 ; get current screen column
lda ($d1),y ; and clear
and #$7f ; cursor in
sta ($d1),y ; current row
inc $cc ; disable cursor blinking
cli ; enable interrupts
rts ; return
backspace: dec $fe ; decrement buffer index
bcs getkey ; and get next key
.endproc
; print an int8 number to the screen
; input:
; A - the number to print
; clobbers:
; X, Y
.proc printnum
bpl doprint ; positive? -> direct number output
eor #$ff ; else invert,
sta $2 ; ...
inc $2 ; add one,
lda #'-' ; output a minus sign
jsr $e716
lda $2
doprint: tax ; number to X reg
lda #$0 ; set A to 0
jsr $bdcd ; routine for uint16 in X/A output
lda #' '
jmp $e716 ; and print a space
.endproc
; parse / convert int8 number using a BCD representation and double-dabble,
; handle negative numbers.
.proc toint8
sta $fb
sty $fc
ldy #$0
sty $fd
sty $fe
sty convbuf
sty convbuf+1
sty convbuf+2
scanloop: lda ($fb),y
beq copy
iny
cmp #$20
beq scanloop
cmp #$2d
beq minus
cmp #$30
bcc error
cmp #$3a
bcs error
inc $fd
bcc scanloop
minus: lda $fd
bne error
lda $fe
bne error
inc $fe
bne scanloop
error: sec
rts
copy: dey
bmi error
ldx #$2
copyloop: lda ($fb),y
cmp #$30
bcc copynext
cmp #$3a
bcs copynext
sec
sbc #$30
sta convbuf,x
dex
copynext: dey
bpl copyloop
lda #$0
sta $fb
ldx #$8
loop: lsr convbuf
lda convbuf+1
bcc skipbit1
ora #$10
skipbit1: lsr a
sta convbuf+1
lda convbuf+2
bcc skipbit2
ora #$10
skipbit2: lsr a
sta convbuf+2
ror $fb
dex
beq done
lda convbuf
cmp #$8
bmi nosub1
sbc #$3
sta convbuf
nosub1: lda convbuf+1
cmp #$8
bmi nosub2
sbc #$3
sta convbuf+1
nosub2: lda convbuf+2
cmp #$8
bmi loop
sbc #$3
sta convbuf+2
bcs loop
done: lda $fe
beq positive
lda #$ff
eor $fb
sta $fb
inc $fb
positive: lda $fb
clc
rts
.endproc