6502 머신 코드 루틴, 199 (187) 185 바이트
A2 03 B5 FB 95 26 CA 10 F9 88 D0 01 60 A5 26 85 61 A5 27 85 62 A5 FB 85 63 A5
FC 85 64 A9 20 85 6F D0 36 18 A5 6D 65 65 85 28 A5 6E 65 66 85 29 A5 4B 85 26
A5 4C 85 27 50 CF 38 A5 6D E5 65 85 4B A5 6E E5 66 85 4C A5 28 85 61 A5 29 85
62 A5 FB 85 63 A5 FC 85 64 06 6F A9 00 85 65 85 66 A2 10 46 62 66 61 90 0D A5
63 18 65 65 85 65 A5 64 65 66 85 66 06 63 26 64 CA 10 E6 A9 FF 24 6F 70 B9 30
02 F0 9E A5 65 85 6D A5 66 85 6E 24 6F 30 14 A5 28 85 61 A5 29 85 62 A5 FD 85
63 A5 FE 85 64 06 6F D0 B4 A5 26 85 61 A5 27 85 62 A5 FD 85 63 A5 FE 85 64 06
6F B0 A0
- "스파게티"구조가 개선 된 -12 바이트
- 지수를 전달하기 위해 레지스터를 변경하는 -2 바이트이므로 초기 복사 루프에서 제로 페이지 주소 지정 모드를 사용할 수 있습니다
이것은 위치 독립적 인 코드입니다 .RAM에 어딘가에 넣고 코드를 호출하십시오. jsr
명령으로 .
이 루틴은 (복소수) 밑을 $fb/$fc
(실수) 및 $fd/$fe
(가상) 의 2 개의 16 비트 부호있는 정수 (2의 보수, 리틀 엔디안)로 , 지수에서 부호없는 8 비트 정수로 사용합니다 Y
.
결과는 $26/$27
(실제) 및 $28/$29
(가상)으로 반환됩니다 .
설명
곱하기 명령도 없기 때문에 6502 CPU에서 여전히 흥미로운 과제입니다. 이 접근법은 복잡한 곱셈을 구현하고 지수에 필요한 횟수만큼 자주 실행합니다. 골프는 서브 루틴을 피하는 대신 일종의 "분기 스파게티"를 만들어서 수행되므로 여러 번 필요한 간단한 16 비트 곱셈을 수행하기위한 코드는 가능한 가장 낮은 오버 헤드로 재사용됩니다. 주석 처리 된 분해는 다음과 같습니다.
.cexp:
A2 03 LDX #$03 ; copy argument ...
.copyloop:
B5 FB LDA $FB,X
95 26 STA $26,X
CA DEX
10 F9 BPL .copyloop ; ... to result
.exploop:
88 DEY ; decrement exponent
D0 01 BNE .mult ; zero reached -> done
60 RTS
.mult: ; multiply (complex) result by argument
A5 26 LDA $26 ; prepare to multiply real components
85 61 STA $61 ; (a*c)
A5 27 LDA $27
85 62 STA $62
A5 FB LDA $FB
85 63 STA $63
A5 FC LDA $FC
85 64 STA $64
A9 20 LDA #$20 ; marker for where to continue
85 6F STA $6F
D0 36 BNE .mult16 ; branch to 16bit multiplication
.mult5:
18 CLC ; calculate sum (a*d) + (b*c)
A5 6D LDA $6D
65 65 ADC $65
85 28 STA $28 ; and store to imaginary component of result
A5 6E LDA $6E
65 66 ADC $66
85 29 STA $29
A5 4B LDA $4B ; load temporary result (a*c) - (b*d)
85 26 STA $26 ; and store to real component of result
A5 4C LDA $4C
85 27 STA $27
50 CF BVC .exploop ; next exponentiation step
.mult3:
38 SEC ; calculate difference (a*c) - (b*d)
A5 6D LDA $6D
E5 65 SBC $65
85 4B STA $4B ; and store to temporary location
A5 6E LDA $6E
E5 66 SBC $66
85 4C STA $4C
A5 28 LDA $28 ; prepare to multiply real component of result
85 61 STA $61 ; with imaginary component of argument
A5 29 LDA $29 ; (a*d)
85 62 STA $62
A5 FB LDA $FB
85 63 STA $63
A5 FC LDA $FC
85 64 STA $64
06 6F ASL $6F ; advance "continue marker"
.mult16:
A9 00 LDA #$00 ; initialize 16bit multiplication
85 65 STA $65 ; result with 0
85 66 STA $66
A2 10 LDX #$10 ; bit counter (16)
.m16_loop:
46 62 LSR $62 ; shift arg1 right
66 61 ROR $61
90 0D BCC .m16_noadd ; no carry -> nothing to add
A5 63 LDA $63 ; add arg2 ...
18 CLC
65 65 ADC $65
85 65 STA $65
A5 64 LDA $64
65 66 ADC $66
85 66 STA $66 ; ... to result
.m16_noadd:
06 63 ASL $63 ; shift arg2 left
26 64 ROL $64
CA DEX ; decrement number of bits to go
10 E6 BPL .m16_loop
A9 FF LDA #$FF ; check marker for where to continue
24 6F BIT $6F
70 B9 BVS .mult3
30 02 BMI .saveres ; have to save result to temp in 2 cases
F0 9E BEQ .mult5
.saveres:
A5 65 LDA $65 ; save result to temporary
85 6D STA $6D
A5 66 LDA $66
85 6E STA $6E
24 6F BIT $6F ; check "continue marker" again
30 14 BMI .mult4
.mult2:
A5 28 LDA $28 ; prepare to multiply imaginary components
85 61 STA $61 ; (b*d)
A5 29 LDA $29
85 62 STA $62
A5 FD LDA $FD
85 63 STA $63
A5 FE LDA $FE
85 64 STA $64
06 6F ASL $6F ; advance "continue marker"
D0 B4 BNE .mult16 ; branch to 16bit multiplication
.mult4:
A5 26 LDA $26 ; prepare to multiply imaginary component of
85 61 STA $61 ; result with real component of argument
A5 27 LDA $27 ; (b*c)
85 62 STA $62
A5 FD LDA $FD
85 63 STA $63
A5 FE LDA $FE
85 64 STA $64
06 6F ASL $6F ; advance "continue marker"
B0 A0 BCS .mult16 ; branch to 16bit multiplication
그것을 사용하는 예제 프로그램 (C64, ca65의 구문 소스 -구문) :
.import cexp
CEXP_A = $fb
CEXP_AL = $fb
CEXP_AH = $fc
CEXP_B = $fd
CEXP_BL = $fd
CEXP_BH = $fe
CEXP_RA = $26
CEXP_RAL = $26
CEXP_RAH = $27
CEXP_RB = $28
CEXP_RBL = $28
CEXP_RBH = $29
.segment "LDADDR"
.word $c000
.segment "MAIN"
jsr $aefd ; consume comma
jsr $ad8a ; evaluate number
jsr $b1aa ; convert to 16bit int
sty CEXP_AL ; store as first argument
sta CEXP_AH
jsr $aefd ; ...
jsr $ad8a
jsr $b1aa
sty CEXP_BL ; store as second argument
sta CEXP_BH
jsr $b79b ; read 8bit unsigned into X
txa ; and transfer
tay ; to Y
jsr cexp ; call our function
lda CEXP_RAH ; read result (real part)
ldy CEXP_RAL
jsr numout ; output
ldx CEXP_RBH ; read result (imaginary part)
bmi noplus
lda #'+' ; output a `+` if it's not negative
jsr $ffd2
noplus: txa
ldy CEXP_RBL
jsr numout ; output (imaginary part)
lda #'i'
jsr $ffd2 ; output `i`
lda #$0d ; and newline
jmp $ffd2
numout:
jsr $b391 ; convert to floating point
jsr $bddd ; format floating point as string
ldy #$01
numout_loop: lda $ff,y ; output loop
bne numout_print ; until 0 terminator found
rts
numout_print: cmp #' ' ; skip space characters in output
beq numout_next
jsr $ffd2
numout_next: iny
bne numout_loop
사용법 : sys49152,[a],[b],[c]
예 sys49152,5,2,2
(출력 : 21+20i
)