Compile-time calculation: Difference between revisions

→‎{{header|6502 Assembly}}: Simplify by using .STRING
(→‎{{header|6502 Assembly}}: Simplify by using .STRING)
Line 58:
</pre>
=={{header|6502 Assembly}}==
{{works with|ca65 targeting the C-64}}
 
The ca65 cross-assembler supports computing and storing double-word (32-bit) integer values; unfortunately most 8-bit systems have no built-in support for manipulating such values. On Commodore machines, unless you write your own arithmetic routines, you have to use floating point instead of integers for numbers that large; unfortunatelyBut the assembler doesn'talso supportsupports generatingconverting floatingsuch pointvalues constants. Nor is there a ROM routinedirectly to convertstrings ain 32-bitmemory. integerSo, tohere's a float,straightforward even though there is one to go the other way.Commodore port:
 
So in this solution the assembler computes the value of 10! and stores it as a 32-bit integer; the runtime code converts that to floating point using ROM routines, dealing with it 16 bits at a time.
 
<lang 6502>; Display the value of 10!, which is precomputed at assembly time
; on any Commodore 8-bit.
;
 
fac = $61 ; location of the floating point accumulator used by ROM routines
.ifndef __CBM__
facsgn = fac+5 ; specific location of the sign byte
.error "Target must be a Commodore 8-bit."
.endif
 
; zero-page work pointer
temp = $fb
 
; ROM routines used
chrout = $ffd2
putfac = $aabc ; print out the value in the FAC
givayf = $b391 ; convert 16-bit integer in AY to floating-point value in FAC
fadd = $b867 ; add float in memory to FAC
fmult = $ba28 ; multiply FAC by float in memory
movfm = $bbd4 ; copy FAC to memory
 
.code
lda #<tenfactorial+1
; convert the upper half
ldysta tenfactorial+2temp
lda #>tenfactorial+3
jsrsta givayftemp+1
ldy #>fp655360
 
loop:
; and multiply by 65536
lda #<fp65536(temp),y
ldybeq #>fp65536done
jsr fmultchrout
iny
 
;bne stash itloop
done:
ldx #<fac_copy
ldy #>fac_copy
jsr movfm
 
; now convert the lower half
ldy tenfactorial
lda tenfactorial+1
jsr givayf
 
; in the general case, the bottom half of a 32-bit number
; may have the high bit set, which will cause the above conversion to
; treat it as negative. This logic detects that case and corrects, although
; it is not actually needed here since our value is hard-coded as 10!,
; which mod 65536 is 24320 < 32768 and so stays positive.
lda facsgn
beq ok ; it's positive, so skip the correction
 
; it's negative, so add 65536
lda #<fp65536
ldy #>fp65536
jsr fadd
 
ok:
; FAC now has lower half; add our copy of upper half
lda #<fac_copy
ldy #>fac_copy
jsr fadd
 
; and print out the result
jsr putfac
rts
 
.data
 
; 65536 as a float for operations
fp65536: .byte 129+16,0,0,0,0,0
 
; the actual value to print
tenfactorial: .dwordbyte 13,"10! = ",.string(10*9*8*7*6*5*4*3*2*1),13,0</lang>
 
.bss
; a place to stash partial results whlie using the FAC for other operations
fac_copy: .res 6</lang>
 
{{Out}}
Line 145 ⟶ 106:
READY.
RUN:
 
10! = 3628800
 
READY.</pre>
1,480

edits