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 बाइट्स को घातांक पास करने के लिए रजिस्टर बदलते हैं, इसलिए हम प्रारंभिक कॉपी लूप में ज़ीरोपेज एड्रेसिंग मोड का उपयोग कर सकते हैं
यह स्थिति-स्वतंत्र कोड है, बस इसे रैम में कहीं रखें और इसे एक jsr
निर्देश के साथ कॉल करें ।
रूटीन (जटिल) आधार दो 16bit हस्ताक्षरित पूर्णांक (2 के पूरक, छोटे-एंडियन) में $fb/$fc
(वास्तविक) और $fd/$fe
(काल्पनिक) के रूप में लेता है , और Y
रजिस्टर में एक अहस्ताक्षरित 8 बिट पूर्णांक के रूप में घातांक ।
परिणाम $26/$27
(वास्तविक) और $28/$29
(काल्पनिक) में वापस आ जाता है ।
व्याख्या
यह 6502 सीपीयू पर अभी भी एक दिलचस्प चुनौती है क्योंकि इसमें कई गुणा करने के निर्देश नहीं हैं। दृष्टिकोण सीधे आगे है, एक जटिल गुणन को लागू करने और इसे अक्सर घातांक द्वारा आवश्यक रूप से निष्पादित करता है। गोल्फिंग एक "शाखा स्पेगेटी" की तरह बनाने के बजाय, सबरूटीन से बचने के द्वारा किया जाता है, इसलिए एक सरल 16 बिट गुणा करने के लिए कोड जिसे कई बार आवश्यक है, सबसे कम संभव ओवरहेड के साथ पुन: उपयोग किया जाता है। यहाँ टिप्पणी disassembly है:
.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 में विधानसभा स्रोत -syntax):
.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
)