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
Attend un pointeur sur un tableau de nombres dans $fb
/ $fc
et la longueur de ce tableau dans$fd
. Manipule le tableau en place pour avoir tous les nombres impairs devant. Il s'agit d'un code indépendant de la position, donc aucune adresse de chargement n'est nécessaire.
Comme le 6502 est une puce 8 bits (les instructions ne concernent donc que les valeurs 8 bits, éventuellement signées), la plage de numéros valide est [-128 .. 127]
la taille maximale du tableau 256
.
Démontage commenté
; 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
Exemple de programme assembleur C64 utilisant la routine:
Démo en ligne
Code dans la syntaxe 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