mirror of
https://github.com/irmen/prog8.git
synced 2025-06-15 18:23:35 +00:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
f1ee3b4e60 | |||
6395e39d63 | |||
2a6d9d7e31 | |||
32a7cd31da | |||
dd4a56cb5f | |||
d110d1cb5f | |||
48858019b7 | |||
aff6b1fca5 | |||
d260182ef3 | |||
e39a38b0d9 | |||
82d7179c92 | |||
f42746ba06 | |||
1f69deaccd | |||
ea8b7ab193 | |||
9938959026 | |||
d5e5485d2e | |||
97b9c8f320 | |||
35aebbc209 | |||
81f7419f70 | |||
2f951bd54d | |||
18f5963b09 | |||
836509c1d1 | |||
949d536e42 | |||
f69b17e165 | |||
49a0584c54 | |||
e21aa2c8f0 | |||
40071b1431 | |||
02e29e6990 | |||
e19de0901e | |||
137d506e42 | |||
90c4a26d52 | |||
f378a8997b | |||
1377bed988 | |||
8f9f947c42 | |||
37f6c2858f | |||
13d7f239ab | |||
a6f3c84e28 | |||
fe4e0e9835 |
@ -1,11 +1,11 @@
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
// id "org.jetbrains.kotlin.jvm" version "1.4.0"
|
||||
// id "org.jetbrains.kotlin.jvm" version "1.4.10"
|
||||
id 'application'
|
||||
id 'org.jetbrains.dokka' version "0.9.18"
|
||||
id 'com.github.johnrengelman.shadow' version '5.2.0'
|
||||
|
@ -1,10 +1,15 @@
|
||||
; --- low level floating point assembly routines for the C64
|
||||
|
||||
FL_ONE_const .byte 129 ; 1.0
|
||||
FL_ZERO_const .byte 0,0,0,0,0 ; 0.0
|
||||
|
||||
floats_store_reg .byte 0 ; temp storage
|
||||
|
||||
|
||||
ub2float .proc
|
||||
; -- convert ubyte in SCRATCH_ZPB1 to float at address A/Y
|
||||
; clobbers A, Y
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
ldy P8ZP_SCRATCH_B1
|
||||
@ -13,14 +18,14 @@ ub2float .proc
|
||||
_fac_to_mem ldx P8ZP_SCRATCH_W2
|
||||
ldy P8ZP_SCRATCH_W2+1
|
||||
jsr MOVMF
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
b2float .proc
|
||||
; -- convert byte in SCRATCH_ZPB1 to float at address A/Y
|
||||
; clobbers A, Y
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
lda P8ZP_SCRATCH_B1
|
||||
@ -30,7 +35,7 @@ b2float .proc
|
||||
|
||||
uw2float .proc
|
||||
; -- convert uword in SCRATCH_ZPWORD1 to float at address A/Y
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
lda P8ZP_SCRATCH_W1
|
||||
@ -41,7 +46,7 @@ uw2float .proc
|
||||
|
||||
w2float .proc
|
||||
; -- convert word in SCRATCH_ZPWORD1 to float at address A/Y
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
ldy P8ZP_SCRATCH_W1
|
||||
@ -54,7 +59,7 @@ stack_b2float .proc
|
||||
; -- b2float operating on the stack
|
||||
inx
|
||||
lda P8ESTACK_LO,x
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr FREADSA
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -64,7 +69,7 @@ stack_w2float .proc
|
||||
inx
|
||||
ldy P8ESTACK_LO,x
|
||||
lda P8ESTACK_HI,x
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr GIVAYF
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -73,7 +78,7 @@ stack_ub2float .proc
|
||||
; -- ub2float operating on the stack
|
||||
inx
|
||||
lda P8ESTACK_LO,x
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
tay
|
||||
lda #0
|
||||
jsr GIVAYF
|
||||
@ -85,16 +90,16 @@ stack_uw2float .proc
|
||||
inx
|
||||
lda P8ESTACK_LO,x
|
||||
ldy P8ESTACK_HI,x
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr GIVUAYFAY
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
|
||||
stack_float2w .proc ; also used for float2b
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr AYINT
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
lda $64
|
||||
sta P8ESTACK_HI,x
|
||||
lda $65
|
||||
@ -105,9 +110,9 @@ stack_float2w .proc ; also used for float2b
|
||||
|
||||
stack_float2uw .proc ; also used for float2ub
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr GETADR
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
sta P8ESTACK_HI,x
|
||||
tya
|
||||
sta P8ESTACK_LO,x
|
||||
@ -231,15 +236,15 @@ inc_var_f .proc
|
||||
; -- add 1 to float pointed to by A/Y
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr MOVFM
|
||||
lda #<FL_FONE
|
||||
ldy #>FL_FONE
|
||||
lda #<FL_ONE_const
|
||||
ldy #>FL_ONE_const
|
||||
jsr FADD
|
||||
ldx P8ZP_SCRATCH_W1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
jsr MOVMF
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
@ -247,9 +252,9 @@ dec_var_f .proc
|
||||
; -- subtract 1 from float pointed to by A/Y
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
lda #<FL_FONE
|
||||
ldy #>FL_FONE
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #<FL_ONE_const
|
||||
ldy #>FL_ONE_const
|
||||
jsr MOVFM
|
||||
lda P8ZP_SCRATCH_W1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
@ -257,7 +262,7 @@ dec_var_f .proc
|
||||
ldx P8ZP_SCRATCH_W1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
jsr MOVMF
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
@ -286,7 +291,7 @@ push_fac1_as_result .proc
|
||||
jsr MOVMF
|
||||
lda #<fmath_float1
|
||||
ldy #>fmath_float1
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
jmp push_float
|
||||
.pend
|
||||
|
||||
@ -298,21 +303,21 @@ pow_f .proc
|
||||
lda #<fmath_float1
|
||||
ldy #>fmath_float1
|
||||
jsr pop_float
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #<fmath_float1
|
||||
ldy #>fmath_float1
|
||||
jsr CONUPK ; fac2 = float1
|
||||
lda #<fmath_float2
|
||||
ldy #>fmath_float2
|
||||
jsr FPWR
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
|
||||
div_f .proc
|
||||
; -- push f1/f2 on stack
|
||||
jsr pop_2_floats_f2_in_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #<fmath_float1
|
||||
ldy #>fmath_float1
|
||||
jsr FDIV
|
||||
@ -322,7 +327,7 @@ div_f .proc
|
||||
add_f .proc
|
||||
; -- push f1+f2 on stack
|
||||
jsr pop_2_floats_f2_in_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #<fmath_float1
|
||||
ldy #>fmath_float1
|
||||
jsr FADD
|
||||
@ -332,7 +337,7 @@ add_f .proc
|
||||
sub_f .proc
|
||||
; -- push f1-f2 on stack
|
||||
jsr pop_2_floats_f2_in_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #<fmath_float1
|
||||
ldy #>fmath_float1
|
||||
jsr FSUB
|
||||
@ -342,7 +347,7 @@ sub_f .proc
|
||||
mul_f .proc
|
||||
; -- push f1*f2 on stack
|
||||
jsr pop_2_floats_f2_in_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #<fmath_float1
|
||||
ldy #>fmath_float1
|
||||
jsr FMULT
|
||||
@ -352,7 +357,7 @@ mul_f .proc
|
||||
neg_f .proc
|
||||
; -- push -flt back on stack
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr NEGOP
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -360,7 +365,7 @@ neg_f .proc
|
||||
abs_f .proc
|
||||
; -- push abs(float) on stack (as float)
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr ABS
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -466,7 +471,7 @@ _return_true lda #1
|
||||
func_sin .proc
|
||||
; -- push sin(f) back onto stack
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr SIN
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -474,7 +479,7 @@ func_sin .proc
|
||||
func_cos .proc
|
||||
; -- push cos(f) back onto stack
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr COS
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -482,7 +487,7 @@ func_cos .proc
|
||||
func_tan .proc
|
||||
; -- push tan(f) back onto stack
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr TAN
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -490,7 +495,7 @@ func_tan .proc
|
||||
func_atan .proc
|
||||
; -- push atan(f) back onto stack
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr ATN
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -498,7 +503,7 @@ func_atan .proc
|
||||
func_ln .proc
|
||||
; -- push ln(f) back onto stack
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr LOG
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -506,7 +511,7 @@ func_ln .proc
|
||||
func_log2 .proc
|
||||
; -- push log base 2, ln(f)/ln(2), back onto stack
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr LOG
|
||||
jsr MOVEF
|
||||
lda #<c64.FL_LOG2
|
||||
@ -518,7 +523,7 @@ func_log2 .proc
|
||||
|
||||
func_sqrt .proc
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr SQR
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -526,7 +531,7 @@ func_sqrt .proc
|
||||
func_rad .proc
|
||||
; -- convert degrees to radians (d * pi / 180)
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #<_pi_div_180
|
||||
ldy #>_pi_div_180
|
||||
jsr FMULT
|
||||
@ -537,7 +542,7 @@ _pi_div_180 .byte 123, 14, 250, 53, 18 ; pi / 180
|
||||
func_deg .proc
|
||||
; -- convert radians to degrees (d * (1/ pi * 180))
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #<_one_over_pi_div_180
|
||||
ldy #>_one_over_pi_div_180
|
||||
jsr FMULT
|
||||
@ -547,7 +552,7 @@ _one_over_pi_div_180 .byte 134, 101, 46, 224, 211 ; 1 / (pi * 180)
|
||||
|
||||
func_round .proc
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr FADDH
|
||||
jsr INT
|
||||
jmp push_fac1_as_result
|
||||
@ -555,7 +560,7 @@ func_round .proc
|
||||
|
||||
func_floor .proc
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr INT
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -563,7 +568,7 @@ func_floor .proc
|
||||
func_ceil .proc
|
||||
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
|
||||
jsr pop_float_fac1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
ldx #<fmath_float1
|
||||
ldy #>fmath_float1
|
||||
jsr MOVMF
|
||||
@ -573,8 +578,8 @@ func_ceil .proc
|
||||
jsr FCOMP
|
||||
cmp #0
|
||||
beq +
|
||||
lda #<FL_FONE
|
||||
ldy #>FL_FONE
|
||||
lda #<FL_ONE_const
|
||||
ldy #>FL_ONE_const
|
||||
jsr FADD
|
||||
+ jmp push_fac1_as_result
|
||||
.pend
|
||||
@ -630,7 +635,7 @@ func_max_f .proc
|
||||
ldy #>_largest_neg_float
|
||||
_minmax_entry jsr MOVFM
|
||||
jsr prog8_lib.pop_array_and_lengthmin1Y
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx floats_store_reg
|
||||
- sty P8ZP_SCRATCH_REG
|
||||
lda P8ZP_SCRATCH_W1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
@ -650,6 +655,8 @@ _minmax_cmp cmp #255 ; modified
|
||||
dey
|
||||
cpy #255
|
||||
bne -
|
||||
ldx floats_store_reg
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jmp push_fac1_as_result
|
||||
_largest_neg_float .byte 255,255,255,255,255 ; largest negative float -1.7014118345e+38
|
||||
.pend
|
||||
@ -665,11 +672,11 @@ _largest_pos_float .byte 255,127,255,255,255 ; largest positive float
|
||||
.pend
|
||||
|
||||
func_sum_f .proc
|
||||
lda #<ZERO
|
||||
ldy #>ZERO
|
||||
lda #<FL_ZERO_const
|
||||
ldy #>FL_ZERO_const
|
||||
jsr MOVFM
|
||||
jsr prog8_lib.pop_array_and_lengthmin1Y
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx floats_store_reg
|
||||
- sty P8ZP_SCRATCH_REG
|
||||
lda P8ZP_SCRATCH_W1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
@ -685,7 +692,9 @@ func_sum_f .proc
|
||||
bcc -
|
||||
inc P8ZP_SCRATCH_W1+1
|
||||
bne -
|
||||
+ jmp push_fac1_as_result
|
||||
+ ldx floats_store_reg
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jmp push_fac1_as_result
|
||||
.pend
|
||||
|
||||
sign_f .proc
|
||||
|
@ -4,14 +4,14 @@
|
||||
;
|
||||
; indent format: TABS, size=8
|
||||
|
||||
%target c64
|
||||
%option enable_floats
|
||||
|
||||
c64flt {
|
||||
; ---- this block contains C-64 floating point related functions ----
|
||||
|
||||
const float PI = 3.141592653589793
|
||||
const float TWOPI = 6.283185307179586
|
||||
const float ZERO = 0.0
|
||||
const float PI = 3.141592653589793
|
||||
const float TWOPI = 6.283185307179586
|
||||
|
||||
|
||||
; ---- C64 basic and kernal ROM float constants and functions ----
|
||||
@ -194,20 +194,20 @@ asmsub GETADRAY () clobbers(X) -> uword @ AY {
|
||||
sub print_f (float value) {
|
||||
; ---- prints the floating point value (without a newline).
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx floats_store_reg
|
||||
lda #<value
|
||||
ldy #>value
|
||||
jsr MOVFM ; load float into fac1
|
||||
jsr FOUT ; fac1 to string in A/Y
|
||||
sta P8ZP_SCRATCH_B1
|
||||
sty P8ZP_SCRATCH_REG
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
ldy #0
|
||||
- lda (P8ZP_SCRATCH_B1),y
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
beq +
|
||||
jsr c64.CHROUT
|
||||
iny
|
||||
bne -
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx floats_store_reg
|
||||
+ rts
|
||||
}}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
%target c64
|
||||
%import c64textio
|
||||
|
||||
; bitmap pixel graphics module for the C64
|
||||
@ -180,9 +181,7 @@ graphics {
|
||||
; @(addr) |= ormask[lsb(px) & 7]
|
||||
; }
|
||||
|
||||
; TODO fix the use of X (or XY) as parameter so we can actually use this plot() routine
|
||||
; calling it with a byte results in a compiler crash, calling it with word results in clobbering X register I think
|
||||
asmsub plotXXX(uword plotx @XY, ubyte ploty @A) {
|
||||
asmsub plot(uword plotx @XY, ubyte ploty @A) clobbers (A, X, Y) {
|
||||
%asm {{
|
||||
stx internal_plotx
|
||||
sty internal_plotx+1
|
||||
@ -190,12 +189,14 @@ graphics {
|
||||
}}
|
||||
}
|
||||
|
||||
; for efficiency of internal algorithms here is the internal plot routine
|
||||
; that takes the plotx coordinate in a separate variable instead of the XY register pair:
|
||||
|
||||
uword internal_plotx ; 0..319 ; separate 'parameter' for internal_plot()
|
||||
|
||||
asmsub internal_plot(ubyte ploty @A) { ; internal_plotx is 16 bits 0 to 319... doesn't fit in a register
|
||||
asmsub internal_plot(ubyte ploty @A) clobbers (A, X, Y) { ; internal_plotx is 16 bits 0 to 319... doesn't fit in a register
|
||||
%asm {{
|
||||
tay
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
lda internal_plotx+1
|
||||
sta P8ZP_SCRATCH_W2+1
|
||||
lsr a ; 0
|
||||
@ -219,8 +220,6 @@ graphics {
|
||||
lda (P8ZP_SCRATCH_W2),y
|
||||
ora _ormask,x
|
||||
sta (P8ZP_SCRATCH_W2),y
|
||||
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
rts
|
||||
|
||||
_ormask .byte 128, 64, 32, 16, 8, 4, 2, 1
|
||||
|
@ -5,6 +5,7 @@
|
||||
;
|
||||
; indent format: TABS, size=8
|
||||
|
||||
%target c64
|
||||
|
||||
c64 {
|
||||
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
|
||||
@ -298,8 +299,6 @@ _irq_handler_init
|
||||
sta IRQ_SCRATCH_ZPB1
|
||||
lda P8ZP_SCRATCH_REG
|
||||
sta IRQ_SCRATCH_ZPREG
|
||||
lda P8ZP_SCRATCH_REG_X
|
||||
sta IRQ_SCRATCH_ZPREGX
|
||||
lda P8ZP_SCRATCH_W1
|
||||
sta IRQ_SCRATCH_ZPWORD1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
@ -324,8 +323,6 @@ _irq_handler_end
|
||||
sta P8ZP_SCRATCH_B1
|
||||
lda IRQ_SCRATCH_ZPREG
|
||||
sta P8ZP_SCRATCH_REG
|
||||
lda IRQ_SCRATCH_ZPREGX
|
||||
sta P8ZP_SCRATCH_REG_X
|
||||
lda IRQ_SCRATCH_ZPWORD1
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda IRQ_SCRATCH_ZPWORD1+1
|
||||
@ -340,7 +337,6 @@ _irq_handler_end
|
||||
IRQ_X_REG .byte 0
|
||||
IRQ_SCRATCH_ZPB1 .byte 0
|
||||
IRQ_SCRATCH_ZPREG .byte 0
|
||||
IRQ_SCRATCH_ZPREGX .byte 0
|
||||
IRQ_SCRATCH_ZPWORD1 .word 0
|
||||
IRQ_SCRATCH_ZPWORD2 .word 0
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
; indent format: TABS, size=8
|
||||
|
||||
|
||||
%target c64
|
||||
%import c64lib
|
||||
%import conv
|
||||
|
||||
@ -74,7 +75,7 @@ asmsub scroll_left_full (ubyte alsocolors @ Pc) clobbers(A, Y) {
|
||||
; Carry flag determines if screen color data must be scrolled too
|
||||
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
bcs +
|
||||
jmp _scroll_screen
|
||||
|
||||
@ -102,7 +103,7 @@ _scroll_screen ; scroll the screen memory
|
||||
dey
|
||||
bpl -
|
||||
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -112,7 +113,7 @@ asmsub scroll_right_full (ubyte alsocolors @ Pc) clobbers(A) {
|
||||
; contents of the leftmost column are unchanged, you should clear/refill this yourself
|
||||
; Carry flag determines if screen color data must be scrolled too
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
bcs +
|
||||
jmp _scroll_screen
|
||||
|
||||
@ -136,7 +137,7 @@ _scroll_screen ; scroll the screen memory
|
||||
dex
|
||||
bpl -
|
||||
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -146,7 +147,7 @@ asmsub scroll_up_full (ubyte alsocolors @ Pc) clobbers(A) {
|
||||
; contents of the bottom row are unchanged, you should refill/clear this yourself
|
||||
; Carry flag determines if screen color data must be scrolled too
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
bcs +
|
||||
jmp _scroll_screen
|
||||
|
||||
@ -170,7 +171,7 @@ _scroll_screen ; scroll the screen memory
|
||||
dex
|
||||
bpl -
|
||||
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -180,7 +181,7 @@ asmsub scroll_down_full (ubyte alsocolors @ Pc) clobbers(A) {
|
||||
; contents of the top row are unchanged, you should refill/clear this yourself
|
||||
; Carry flag determines if screen color data must be scrolled too
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
bcs +
|
||||
jmp _scroll_screen
|
||||
|
||||
@ -204,7 +205,7 @@ _scroll_screen ; scroll the screen memory
|
||||
dex
|
||||
bpl -
|
||||
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -230,7 +231,7 @@ asmsub print (str text @ AY) clobbers(A,Y) {
|
||||
asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr conv.ubyte2decimal
|
||||
pha
|
||||
tya
|
||||
@ -239,7 +240,7 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||
jsr c64.CHROUT
|
||||
txa
|
||||
jsr c64.CHROUT
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -247,7 +248,7 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||
asmsub print_ub (ubyte value @ A) clobbers(A,Y) {
|
||||
; ---- print the ubyte in A in decimal form, without left padding 0s
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr conv.ubyte2decimal
|
||||
_print_byte_digits
|
||||
pha
|
||||
@ -264,7 +265,7 @@ _print_byte_digits
|
||||
jsr c64.CHROUT
|
||||
_ones txa
|
||||
jsr c64.CHROUT
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -272,7 +273,7 @@ _ones txa
|
||||
asmsub print_b (byte value @ A) clobbers(A,Y) {
|
||||
; ---- print the byte in A in decimal form, without left padding 0s
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
pha
|
||||
cmp #0
|
||||
bpl +
|
||||
@ -280,16 +281,14 @@ asmsub print_b (byte value @ A) clobbers(A,Y) {
|
||||
jsr c64.CHROUT
|
||||
+ pla
|
||||
jsr conv.byte2decimal
|
||||
jsr print_ub._print_byte_digits
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
rts
|
||||
jmp print_ub._print_byte_digits
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub print_ubhex (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
bcc +
|
||||
pha
|
||||
lda #'$'
|
||||
@ -299,7 +298,7 @@ asmsub print_ubhex (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||
jsr c64.CHROUT
|
||||
tya
|
||||
jsr c64.CHROUT
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -307,7 +306,7 @@ asmsub print_ubhex (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||
asmsub print_ubbin (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
sta P8ZP_SCRATCH_B1
|
||||
bcc +
|
||||
lda #'%'
|
||||
@ -320,7 +319,7 @@ asmsub print_ubbin (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||
+ jsr c64.CHROUT
|
||||
dey
|
||||
bne -
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -353,7 +352,7 @@ asmsub print_uwhex (uword value @ AY, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||
asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr conv.uword2decimal
|
||||
ldy #0
|
||||
- lda conv.uword2decimal.decTenThousands,y
|
||||
@ -361,7 +360,7 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||
jsr c64.CHROUT
|
||||
iny
|
||||
bne -
|
||||
+ ldx P8ZP_SCRATCH_REG_X
|
||||
+ ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
@ -369,9 +368,9 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||
asmsub print_uw (uword value @ AY) clobbers(A,Y) {
|
||||
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
jsr conv.uword2decimal
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
ldy #0
|
||||
- lda conv.uword2decimal.decTenThousands,y
|
||||
beq _allzero
|
||||
@ -545,11 +544,11 @@ _colormod sta $ffff ; modified
|
||||
asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) {
|
||||
; ---- safe wrapper around PLOT kernel routine, to save the X register.
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
tax
|
||||
clc
|
||||
jsr c64.PLOT
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ asmsub byte2decimal (byte value @ A) -> ubyte @ Y, ubyte @ A, ubyte @ X {
|
||||
asmsub ubyte2hex (ubyte value @ A) -> ubyte @ A, ubyte @ Y {
|
||||
; ---- A to hex petscii string in AY (first hex char in A, second hex char in Y)
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
pha
|
||||
and #$0f
|
||||
tax
|
||||
@ -225,7 +225,7 @@ asmsub ubyte2hex (ubyte value @ A) -> ubyte @ A, ubyte @ Y {
|
||||
lsr a
|
||||
tax
|
||||
lda _hex_digits,x
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
|
||||
_hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
|
||||
|
@ -4,14 +4,14 @@
|
||||
;
|
||||
; indent format: TABS, size=8
|
||||
|
||||
%target cx16
|
||||
%option enable_floats
|
||||
|
||||
c64flt {
|
||||
; ---- this block contains C-64 floating point related functions ----
|
||||
|
||||
const float PI = 3.141592653589793
|
||||
const float TWOPI = 6.283185307179586
|
||||
const float ZERO = 0.0
|
||||
const float PI = 3.141592653589793
|
||||
const float TWOPI = 6.283185307179586
|
||||
|
||||
|
||||
; ---- ROM float functions ----
|
||||
@ -130,20 +130,20 @@ asmsub GETADRAY () clobbers(X) -> uword @ AY {
|
||||
sub print_f (float value) {
|
||||
; ---- prints the floating point value (without a newline).
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
phx
|
||||
lda #<value
|
||||
ldy #>value
|
||||
jsr MOVFM ; load float into fac1
|
||||
jsr FOUT ; fac1 to string in A/Y
|
||||
sta P8ZP_SCRATCH_B1
|
||||
sty P8ZP_SCRATCH_REG
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
ldy #0
|
||||
- lda (P8ZP_SCRATCH_B1),y
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
beq +
|
||||
jsr c64.CHROUT
|
||||
iny
|
||||
bne -
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
plx
|
||||
+ rts
|
||||
}}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
;
|
||||
; indent format: TABS, size=8
|
||||
|
||||
%target cx16
|
||||
|
||||
|
||||
c64 {
|
||||
|
||||
@ -14,42 +16,42 @@ c64 {
|
||||
; CLEARSCR -> use screen.clear_screen
|
||||
; HOMECRSR -> use screen.plot
|
||||
|
||||
romsub $FF81 = CINT() clobbers(A,X,Y) ; (alias: SCINIT) initialize screen editor and video chip
|
||||
romsub $FF84 = IOINIT() clobbers(A, X) ; initialize I/O devices (CIA, SID, IRQ)
|
||||
romsub $FF87 = RAMTAS() clobbers(A,X,Y) ; initialize RAM, tape buffer, screen
|
||||
romsub $FF8A = RESTOR() clobbers(A,X,Y) ; restore default I/O vectors
|
||||
romsub $FF8D = VECTOR(uword userptr @ XY, ubyte dir @ Pc) clobbers(A,Y) ; read/set I/O vector table
|
||||
romsub $FF81 = CINT() clobbers(A,X,Y) ; (alias: SCINIT) initialize screen editor and video chip
|
||||
romsub $FF84 = IOINIT() clobbers(A, X) ; initialize I/O devices (CIA, SID, IRQ)
|
||||
romsub $FF87 = RAMTAS() clobbers(A,X,Y) ; initialize RAM, tape buffer, screen
|
||||
romsub $FF8A = RESTOR() clobbers(A,X,Y) ; restore default I/O vectors
|
||||
romsub $FF8D = VECTOR(uword userptr @ XY, ubyte dir @ Pc) clobbers(A,Y) ; read/set I/O vector table
|
||||
romsub $FF90 = SETMSG(ubyte value @ A) ; set Kernal message control flag
|
||||
romsub $FF93 = SECOND(ubyte address @ A) clobbers(A) ; (alias: LSTNSA) send secondary address after LISTEN
|
||||
romsub $FF96 = TKSA(ubyte address @ A) clobbers(A) ; (alias: TALKSA) send secondary address after TALK
|
||||
romsub $FF93 = SECOND(ubyte address @ A) clobbers(A) ; (alias: LSTNSA) send secondary address after LISTEN
|
||||
romsub $FF96 = TKSA(ubyte address @ A) clobbers(A) ; (alias: TALKSA) send secondary address after TALK
|
||||
romsub $FF99 = MEMTOP(uword address @ XY, ubyte dir @ Pc) -> uword @ XY ; read/set top of memory pointer
|
||||
romsub $FF9C = MEMBOT(uword address @ XY, ubyte dir @ Pc) -> uword @ XY ; read/set bottom of memory pointer
|
||||
romsub $FF9F = SCNKEY() clobbers(A,X,Y) ; scan the keyboard
|
||||
romsub $FF9F = SCNKEY() clobbers(A,X,Y) ; scan the keyboard
|
||||
romsub $FFA2 = SETTMO(ubyte timeout @ A) ; set time-out flag for IEEE bus
|
||||
romsub $FFA5 = ACPTR() -> ubyte @ A ; (alias: IECIN) input byte from serial bus
|
||||
romsub $FFA8 = CIOUT(ubyte databyte @ A) ; (alias: IECOUT) output byte to serial bus
|
||||
romsub $FFAB = UNTLK() clobbers(A) ; command serial bus device to UNTALK
|
||||
romsub $FFAE = UNLSN() clobbers(A) ; command serial bus device to UNLISTEN
|
||||
romsub $FFB1 = LISTEN(ubyte device @ A) clobbers(A) ; command serial bus device to LISTEN
|
||||
romsub $FFB4 = TALK(ubyte device @ A) clobbers(A) ; command serial bus device to TALK
|
||||
romsub $FFAB = UNTLK() clobbers(A) ; command serial bus device to UNTALK
|
||||
romsub $FFAE = UNLSN() clobbers(A) ; command serial bus device to UNLISTEN
|
||||
romsub $FFB1 = LISTEN(ubyte device @ A) clobbers(A) ; command serial bus device to LISTEN
|
||||
romsub $FFB4 = TALK(ubyte device @ A) clobbers(A) ; command serial bus device to TALK
|
||||
romsub $FFB7 = READST() -> ubyte @ A ; read I/O status word
|
||||
romsub $FFBA = SETLFS(ubyte logical @ A, ubyte device @ X, ubyte address @ Y) ; set logical file parameters
|
||||
romsub $FFBD = SETNAM(ubyte namelen @ A, str filename @ XY) ; set filename parameters
|
||||
romsub $FFC0 = OPEN() clobbers(A,X,Y) ; (via 794 ($31A)) open a logical file
|
||||
romsub $FFC3 = CLOSE(ubyte logical @ A) clobbers(A,X,Y) ; (via 796 ($31C)) close a logical file
|
||||
romsub $FFC6 = CHKIN(ubyte logical @ X) clobbers(A,X) ; (via 798 ($31E)) define an input channel
|
||||
romsub $FFC9 = CHKOUT(ubyte logical @ X) clobbers(A,X) ; (via 800 ($320)) define an output channel
|
||||
romsub $FFCC = CLRCHN() clobbers(A,X) ; (via 802 ($322)) restore default devices
|
||||
romsub $FFCF = CHRIN() clobbers(Y) -> ubyte @ A ; (via 804 ($324)) input a character (for keyboard, read a whole line from the screen) A=byte read.
|
||||
romsub $FFC0 = OPEN() clobbers(A,X,Y) ; (via 794 ($31A)) open a logical file
|
||||
romsub $FFC3 = CLOSE(ubyte logical @ A) clobbers(A,X,Y) ; (via 796 ($31C)) close a logical file
|
||||
romsub $FFC6 = CHKIN(ubyte logical @ X) clobbers(A,X) ; (via 798 ($31E)) define an input channel
|
||||
romsub $FFC9 = CHKOUT(ubyte logical @ X) clobbers(A,X) ; (via 800 ($320)) define an output channel
|
||||
romsub $FFCC = CLRCHN() clobbers(A,X) ; (via 802 ($322)) restore default devices
|
||||
romsub $FFCF = CHRIN() clobbers(Y) -> ubyte @ A ; (via 804 ($324)) input a character (for keyboard, read a whole line from the screen) A=byte read.
|
||||
romsub $FFD2 = CHROUT(ubyte char @ A) ; (via 806 ($326)) output a character
|
||||
romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) -> ubyte @Pc, ubyte @ A, ubyte @ X, ubyte @ Y ; (via 816 ($330)) load from device
|
||||
romsub $FFD8 = SAVE(ubyte zp_startaddr @ A, uword endaddr @ XY) -> ubyte @ Pc, ubyte @ A ; (via 818 ($332)) save to a device
|
||||
romsub $FFDB = SETTIM(ubyte low @ A, ubyte middle @ X, ubyte high @ Y) ; set the software clock
|
||||
romsub $FFDE = RDTIM() -> ubyte @ A, ubyte @ X, ubyte @ Y ; read the software clock
|
||||
romsub $FFE1 = STOP() clobbers(A,X) -> ubyte @ Pz, ubyte @ Pc ; (via 808 ($328)) check the STOP key
|
||||
romsub $FFE4 = GETIN() clobbers(X,Y) -> ubyte @ A ; (via 810 ($32A)) get a character
|
||||
romsub $FFE7 = CLALL() clobbers(A,X) ; (via 812 ($32C)) close all files
|
||||
romsub $FFEA = UDTIM() clobbers(A,X) ; update the software clock
|
||||
romsub $FFE1 = STOP() clobbers(A,X) -> ubyte @ Pz, ubyte @ Pc ; (via 808 ($328)) check the STOP key
|
||||
romsub $FFE4 = GETIN() clobbers(X,Y) -> ubyte @ A ; (via 810 ($32A)) get a character
|
||||
romsub $FFE7 = CLALL() clobbers(A,X) ; (via 812 ($32C)) close all files
|
||||
romsub $FFEA = UDTIM() clobbers(A,X) ; update the software clock
|
||||
romsub $FFED = SCREEN() -> ubyte @ X, ubyte @ Y ; read number of screen rows and columns
|
||||
romsub $FFF0 = PLOT(ubyte col @ Y, ubyte row @ X, ubyte dir @ Pc) -> ubyte @ X, ubyte @ Y ; read/set position of cursor on screen. Use screen.plot for a 'safe' wrapper that preserves X.
|
||||
romsub $FFF3 = IOBASE() -> uword @ XY ; read base address of I/O devices
|
||||
@ -58,8 +60,11 @@ romsub $FFF3 = IOBASE() -> uword @ XY ; read base addr
|
||||
|
||||
cx16 {
|
||||
|
||||
; ---- Commander X-16 additions on top of C64 kernal routines ----
|
||||
; spelling of the names is taken from the Commander X-16 rom sources
|
||||
; 65c02 hardware vectors:
|
||||
&uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
|
||||
&uword RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in
|
||||
&uword IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in
|
||||
|
||||
|
||||
; the sixteen virtual 16-bit registers
|
||||
&uword r0 = $02
|
||||
@ -82,116 +87,159 @@ cx16 {
|
||||
; VERA registers
|
||||
|
||||
const uword VERA_BASE = $9F20
|
||||
&uword VERA_ADDR_L = VERA_BASE + $00
|
||||
&uword VERA_ADDR_M = VERA_BASE + $01
|
||||
&uword VERA_ADDR_H = VERA_BASE + $02
|
||||
&uword VERA_DATA0 = VERA_BASE + $03
|
||||
&uword VERA_DATA1 = VERA_BASE + $04
|
||||
&uword VERA_CTRL = VERA_BASE + $05
|
||||
&uword VERA_IEN = VERA_BASE + $06
|
||||
&uword VERA_ISR = VERA_BASE + $07
|
||||
&uword VERA_IRQ_LINE_L = VERA_BASE + $08
|
||||
&uword VERA_DC_VIDEO = VERA_BASE + $09
|
||||
&uword VERA_DC_HSCALE = VERA_BASE + $0A
|
||||
&uword VERA_DC_VSCALE = VERA_BASE + $0B
|
||||
&uword VERA_DC_BORDER = VERA_BASE + $0C
|
||||
&uword VERA_DC_HSTART = VERA_BASE + $09
|
||||
&uword VERA_DC_HSTOP = VERA_BASE + $0A
|
||||
&uword VERA_DC_VSTART = VERA_BASE + $0B
|
||||
&uword VERA_DC_VSTOP = VERA_BASE + $0C
|
||||
&uword VERA_L0_CONFIG = VERA_BASE + $0D
|
||||
&uword VERA_L0_MAPBASE = VERA_BASE + $0E
|
||||
&uword VERA_L0_TILEBASE = VERA_BASE + $0F
|
||||
&uword VERA_L0_HSCROLL_L = VERA_BASE + $10
|
||||
&uword VERA_L0_HSCROLL_H = VERA_BASE + $11
|
||||
&uword VERA_L0_VSCROLL_L = VERA_BASE + $12
|
||||
&uword VERA_L0_VSCROLL_H = VERA_BASE + $13
|
||||
&uword VERA_L1_CONFIG = VERA_BASE + $14
|
||||
&uword VERA_L1_MAPBASE = VERA_BASE + $15
|
||||
&uword VERA_L1_TILEBASE = VERA_BASE + $16
|
||||
&uword VERA_L1_HSCROLL_L = VERA_BASE + $17
|
||||
&uword VERA_L1_HSCROLL_H = VERA_BASE + $18
|
||||
&uword VERA_L1_VSCROLL_L = VERA_BASE + $19
|
||||
&uword VERA_L1_VSCROLL_H = VERA_BASE + $1A
|
||||
&uword VERA_AUDIO_CTRL = VERA_BASE + $1B
|
||||
&uword VERA_AUDIO_RATE = VERA_BASE + $1C
|
||||
&uword VERA_AUDIO_DATA = VERA_BASE + $1D
|
||||
&uword VERA_SPI_DATA = VERA_BASE + $1E
|
||||
&uword VERA_SPI_CTRL = VERA_BASE + $1F
|
||||
&ubyte VERA_ADDR_L = VERA_BASE + $00
|
||||
&ubyte VERA_ADDR_M = VERA_BASE + $01
|
||||
&ubyte VERA_ADDR_H = VERA_BASE + $02
|
||||
&ubyte VERA_DATA0 = VERA_BASE + $03
|
||||
&ubyte VERA_DATA1 = VERA_BASE + $04
|
||||
&ubyte VERA_CTRL = VERA_BASE + $05
|
||||
&ubyte VERA_IEN = VERA_BASE + $06
|
||||
&ubyte VERA_ISR = VERA_BASE + $07
|
||||
&ubyte VERA_IRQ_LINE_L = VERA_BASE + $08
|
||||
&ubyte VERA_DC_VIDEO = VERA_BASE + $09
|
||||
&ubyte VERA_DC_HSCALE = VERA_BASE + $0A
|
||||
&ubyte VERA_DC_VSCALE = VERA_BASE + $0B
|
||||
&ubyte VERA_DC_BORDER = VERA_BASE + $0C
|
||||
&ubyte VERA_DC_HSTART = VERA_BASE + $09
|
||||
&ubyte VERA_DC_HSTOP = VERA_BASE + $0A
|
||||
&ubyte VERA_DC_VSTART = VERA_BASE + $0B
|
||||
&ubyte VERA_DC_VSTOP = VERA_BASE + $0C
|
||||
&ubyte VERA_L0_CONFIG = VERA_BASE + $0D
|
||||
&ubyte VERA_L0_MAPBASE = VERA_BASE + $0E
|
||||
&ubyte VERA_L0_TILEBASE = VERA_BASE + $0F
|
||||
&ubyte VERA_L0_HSCROLL_L = VERA_BASE + $10
|
||||
&ubyte VERA_L0_HSCROLL_H = VERA_BASE + $11
|
||||
&ubyte VERA_L0_VSCROLL_L = VERA_BASE + $12
|
||||
&ubyte VERA_L0_VSCROLL_H = VERA_BASE + $13
|
||||
&ubyte VERA_L1_CONFIG = VERA_BASE + $14
|
||||
&ubyte VERA_L1_MAPBASE = VERA_BASE + $15
|
||||
&ubyte VERA_L1_TILEBASE = VERA_BASE + $16
|
||||
&ubyte VERA_L1_HSCROLL_L = VERA_BASE + $17
|
||||
&ubyte VERA_L1_HSCROLL_H = VERA_BASE + $18
|
||||
&ubyte VERA_L1_VSCROLL_L = VERA_BASE + $19
|
||||
&ubyte VERA_L1_VSCROLL_H = VERA_BASE + $1A
|
||||
&ubyte VERA_AUDIO_CTRL = VERA_BASE + $1B
|
||||
&ubyte VERA_AUDIO_RATE = VERA_BASE + $1C
|
||||
&ubyte VERA_AUDIO_DATA = VERA_BASE + $1D
|
||||
&ubyte VERA_SPI_DATA = VERA_BASE + $1E
|
||||
&ubyte VERA_SPI_CTRL = VERA_BASE + $1F
|
||||
; VERA_PSG_BASE = $1F9C0
|
||||
; VERA_PALETTE_BASE = $1FA00
|
||||
; VERA_SPRITES_BASE = $1FC00
|
||||
|
||||
; I/O
|
||||
|
||||
const uword via1 = $9f60 ;VIA 6522 #1
|
||||
&ubyte d1prb = via1+0
|
||||
&ubyte d1pra = via1+1
|
||||
&ubyte d1ddrb = via1+2
|
||||
&ubyte d1ddra = via1+3
|
||||
&ubyte d1t1l = via1+4
|
||||
&ubyte d1t1h = via1+5
|
||||
&ubyte d1t1ll = via1+6
|
||||
&ubyte d1t1lh = via1+7
|
||||
&ubyte d1t2l = via1+8
|
||||
&ubyte d1t2h = via1+9
|
||||
&ubyte d1sr = via1+10
|
||||
&ubyte d1acr = via1+11
|
||||
&ubyte d1pcr = via1+12
|
||||
&ubyte d1ifr = via1+13
|
||||
&ubyte d1ier = via1+14
|
||||
&ubyte d1ora = via1+15
|
||||
|
||||
const uword via2 = $9f70 ;VIA 6522 #2
|
||||
&ubyte d2prb =via2+0
|
||||
&ubyte d2pra =via2+1
|
||||
&ubyte d2ddrb =via2+2
|
||||
&ubyte d2ddra =via2+3
|
||||
&ubyte d2t1l =via2+4
|
||||
&ubyte d2t1h =via2+5
|
||||
&ubyte d2t1ll =via2+6
|
||||
&ubyte d2t1lh =via2+7
|
||||
&ubyte d2t2l =via2+8
|
||||
&ubyte d2t2h =via2+9
|
||||
&ubyte d2sr =via2+10
|
||||
&ubyte d2acr =via2+11
|
||||
&ubyte d2pcr =via2+12
|
||||
&ubyte d2ifr =via2+13
|
||||
&ubyte d2ier =via2+14
|
||||
&ubyte d2ora =via2+15
|
||||
|
||||
|
||||
; ---- Commander X-16 additions on top of C64 kernal routines ----
|
||||
; spelling of the names is taken from the Commander X-16 rom sources
|
||||
|
||||
; TODO specify the correct clobbers for alle these functions, for simplicity all 3 regs are marked clobbered atm
|
||||
|
||||
; supported C128 additions
|
||||
romsub $ff4a = close_all()
|
||||
romsub $ff59 = lkupla()
|
||||
romsub $ff5c = lkupsa()
|
||||
romsub $ff5f = screen_set_mode(ubyte mode @A) clobbers(A, X, Y) -> ubyte @Pc
|
||||
romsub $ff62 = screen_set_charset(ubyte charset @A, uword charsetptr @XY) clobbers(A,X,Y) ; incompatible with C128 dlchr()
|
||||
romsub $ff65 = pfkey()
|
||||
romsub $ff6e = jsrfar()
|
||||
romsub $ff74 = fetch()
|
||||
romsub $ff77 = stash()
|
||||
romsub $ff7a = cmpare()
|
||||
romsub $ff7d = primm()
|
||||
romsub $ff4a = close_all() clobbers(A,X,Y)
|
||||
romsub $ff59 = lkupla() clobbers(A,X,Y)
|
||||
romsub $ff5c = lkupsa() clobbers(A,X,Y)
|
||||
romsub $ff5f = screen_set_mode(ubyte mode @A) clobbers(A, X, Y) -> ubyte @Pc
|
||||
romsub $ff62 = screen_set_charset(ubyte charset @A, uword charsetptr @XY) clobbers(A,X,Y) ; incompatible with C128 dlchr()
|
||||
romsub $ff65 = pfkey() clobbers(A,X,Y)
|
||||
romsub $ff6e = jsrfar() clobbers(A,X,Y)
|
||||
romsub $ff74 = fetch() clobbers(A,X,Y)
|
||||
romsub $ff77 = stash() clobbers(A,X,Y)
|
||||
romsub $ff7a = cmpare() clobbers(A,X,Y)
|
||||
romsub $ff7d = primm() clobbers(A,X,Y)
|
||||
|
||||
; X16 additions
|
||||
romsub $ff44 = macptr()
|
||||
romsub $ff47 = enter_basic(ubyte cold_or_warm @Pc)
|
||||
romsub $ff68 = mouse_config(ubyte shape @A, ubyte scale @X) clobbers (A, X, Y)
|
||||
romsub $ff6b = mouse_get(ubyte zpdataptr @X) clobbers(A)
|
||||
romsub $ff71 = mouse_scan() clobbers(A, X, Y)
|
||||
romsub $ff53 = joystick_scan() clobbers(A, X, Y)
|
||||
romsub $ff44 = macptr() clobbers(A,X,Y)
|
||||
romsub $ff47 = enter_basic(ubyte cold_or_warm @Pc) clobbers(A,X,Y)
|
||||
romsub $ff68 = mouse_config(ubyte shape @A, ubyte scale @X) clobbers (A, X, Y)
|
||||
romsub $ff6b = mouse_get(ubyte zpdataptr @X) clobbers(A)
|
||||
romsub $ff71 = mouse_scan() clobbers(A, X, Y)
|
||||
romsub $ff53 = joystick_scan() clobbers(A, X, Y)
|
||||
romsub $ff56 = joystick_get(ubyte joynr @A) -> ubyte @A, ubyte @X, ubyte @Y
|
||||
romsub $ff4d = clock_set_date_time() clobbers(A, X, Y) ; args: r0, r1, r2, r3L
|
||||
romsub $ff50 = clock_get_date_time() clobbers(A) ; outout args: r0, r1, r2, r3L
|
||||
romsub $ff4d = clock_set_date_time() clobbers(A, X, Y) ; args: r0, r1, r2, r3L
|
||||
romsub $ff50 = clock_get_date_time() clobbers(A) ; outout args: r0, r1, r2, r3L
|
||||
|
||||
; high level graphics & fonts
|
||||
romsub $ff20 = GRAPH_init() ; uses vectors=r0
|
||||
romsub $ff23 = GRAPH_clear()
|
||||
romsub $ff26 = GRAPH_set_window() ; uses x=r0, y=r1, width=r2, height=r3
|
||||
romsub $ff29 = GRAPH_set_colors(ubyte stroke @A, ubyte fill @X, ubyte background @Y)
|
||||
romsub $ff2c = GRAPH_draw_line() ; uses x1=r0, y1=r1, x2=r2, y2=r3
|
||||
romsub $ff2f = GRAPH_draw_rect(ubyte fill @Pc) ; uses x=r0, y=r1, width=r2, height=r3, cornerradius=r4
|
||||
romsub $ff32 = GRAPH_move_rect() ; uses sx=r0, sy=r1, tx=r2, ty=r3, width=r4, height=r5
|
||||
romsub $ff35 = GRAPH_draw_oval(ubyte fill @Pc) ; uses x=r0, y=r1, width=r2, height=r3
|
||||
romsub $ff38 = GRAPH_draw_image() ; uses x=r0, y=r1, ptr=r2, width=r3, height=r4
|
||||
romsub $ff3b = GRAPH_set_font() ; uses ptr=r0
|
||||
romsub $ff3e = GRAPH_get_char_size(ubyte baseline @A, ubyte width @X, ubyte height_or_style @Y, ubyte is_control @Pc)
|
||||
romsub $ff41 = GRAPH_put_char(ubyte char @A) ; uses x=r0, y=r1
|
||||
romsub $ff20 = GRAPH_init() clobbers(A,X,Y) ; uses vectors=r0
|
||||
romsub $ff23 = GRAPH_clear() clobbers(A,X,Y)
|
||||
romsub $ff26 = GRAPH_set_window() clobbers(A,X,Y) ; uses x=r0, y=r1, width=r2, height=r3
|
||||
romsub $ff29 = GRAPH_set_colors(ubyte stroke @A, ubyte fill @X, ubyte background @Y) clobbers (A,X,Y)
|
||||
romsub $ff2c = GRAPH_draw_line() clobbers(A,X,Y) ; uses x1=r0, y1=r1, x2=r2, y2=r3
|
||||
romsub $ff2f = GRAPH_draw_rect(ubyte fill @Pc) clobbers(A,X,Y) ; uses x=r0, y=r1, width=r2, height=r3, cornerradius=r4
|
||||
romsub $ff32 = GRAPH_move_rect() clobbers(A,X,Y) ; uses sx=r0, sy=r1, tx=r2, ty=r3, width=r4, height=r5
|
||||
romsub $ff35 = GRAPH_draw_oval(ubyte fill @Pc) clobbers(A,X,Y) ; uses x=r0, y=r1, width=r2, height=r3
|
||||
romsub $ff38 = GRAPH_draw_image() clobbers(A,X,Y) ; uses x=r0, y=r1, ptr=r2, width=r3, height=r4
|
||||
romsub $ff3b = GRAPH_set_font() clobbers(A,X,Y) ; uses ptr=r0
|
||||
romsub $ff3e = GRAPH_get_char_size(ubyte baseline @A, ubyte width @X, ubyte height_or_style @Y, ubyte is_control @Pc) clobbers(A,X,Y)
|
||||
romsub $ff41 = GRAPH_put_char(ubyte char @A) clobbers(A,X,Y) ; uses x=r0, y=r1
|
||||
|
||||
; framebuffer
|
||||
romsub $fef6 = FB_init()
|
||||
romsub $fef9 = FB_get_info() -> byte @A ; also outputs width=r0, height=r1
|
||||
romsub $fefc = FB_set_palette(ubyte index @A, ubyte bytecount @X) ; also uses pointer=r0
|
||||
romsub $feff = FB_cursor_position() ; uses x=r0, y=r1
|
||||
romsub $ff02 = FB_cursor_next_line() ; uses x=r0
|
||||
romsub $ff05 = FB_get_pixel() -> ubyte @A
|
||||
romsub $ff08 = FB_get_pixels() ; uses ptr=r0, count=r1
|
||||
romsub $ff0b = FB_set_pixel(ubyte color @A)
|
||||
romsub $ff0e = FB_set_pixels() ; uses ptr=r0, count=r1
|
||||
romsub $ff11 = FB_set_8_pixels(ubyte pattern @A, ubyte color @X)
|
||||
romsub $ff14 = FB_set_8_pixels_opaque(ubyte pattern @A, ubyte color1 @X, ubyte color2 @Y) ; also uses mask=r0L
|
||||
romsub $ff17 = FB_fill_pixels(ubyte color @A) ; also uses count=r0, step=r1
|
||||
romsub $ff1a = FB_filter_pixels() ; uses ptr=r0, count=r1
|
||||
romsub $ff1d = FB_move_pixels() ; uses sx=r0, sy=r1, tx=r2, ty=r3, count=r4
|
||||
romsub $fef6 = FB_init() clobbers(A,X,Y)
|
||||
romsub $fef9 = FB_get_info() clobbers(X,Y) -> byte @A ; also outputs width=r0, height=r1
|
||||
romsub $fefc = FB_set_palette(ubyte index @A, ubyte bytecount @X) clobbers(A,X,Y) ; also uses pointer=r0
|
||||
romsub $feff = FB_cursor_position() clobbers(A,X,Y) ; uses x=r0, y=r1
|
||||
romsub $ff02 = FB_cursor_next_line() clobbers(A,X,Y) ; uses x=r0
|
||||
romsub $ff05 = FB_get_pixel() clobbers(X,Y) -> ubyte @A
|
||||
romsub $ff08 = FB_get_pixels() clobbers(A,X,Y) ; uses ptr=r0, count=r1
|
||||
romsub $ff0b = FB_set_pixel(ubyte color @A) clobbers(A,X,Y)
|
||||
romsub $ff0e = FB_set_pixels() clobbers(A,X,Y) ; uses ptr=r0, count=r1
|
||||
romsub $ff11 = FB_set_8_pixels(ubyte pattern @A, ubyte color @X) clobbers(A,X,Y)
|
||||
romsub $ff14 = FB_set_8_pixels_opaque(ubyte pattern @A, ubyte color1 @X, ubyte color2 @Y) clobbers(A,X,Y) ; also uses mask=r0L
|
||||
romsub $ff17 = FB_fill_pixels(ubyte color @A) clobbers(A,X,Y) ; also uses count=r0, step=r1
|
||||
romsub $ff1a = FB_filter_pixels() clobbers(A,X,Y) ; uses ptr=r0, count=r1
|
||||
romsub $ff1d = FB_move_pixels() clobbers(A,X,Y) ; uses sx=r0, sy=r1, tx=r2, ty=r3, count=r4
|
||||
|
||||
; misc
|
||||
romsub $fef0 = sprite_set_image(ubyte number @A, ubyte width @X, ubyte height @Y, ubyte apply_mask @Pc) -> ubyte @Pc ; also uses pixels=r0, mask=r1, bpp=r2L
|
||||
romsub $fef3 = sprite_set_position(ubyte number @A) ; also uses x=r0 and y=r1
|
||||
romsub $fee4 = memory_fill(ubyte value @A) ; uses address=r0, num_bytes=r1
|
||||
romsub $fee7 = memory_copy() ; uses source=r0, target=r1, num_bytes=r2
|
||||
romsub $feea = memory_crc() ; uses address=r0, num_bytes=r1 result->r2
|
||||
romsub $feed = memory_decompress() ; uses input=r0, output=r1 result->r1
|
||||
romsub $fedb = console_init() ; uses x=r0, y=r1, width=r2, height=r3
|
||||
romsub $fede = console_put_char(ubyte char @A, ubyte wrapping @Pc)
|
||||
romsub $fee1 = console_get_char() -> ubyte @A
|
||||
romsub $fed8 = console_put_image() ; uses ptr=r0, width=r1, height=r2
|
||||
romsub $fed5 = console_set_paging_message() ; uses messageptr=r0
|
||||
romsub $fed2 = kbdbuf_put(ubyte key @A)
|
||||
romsub $fef0 = sprite_set_image(ubyte number @A, ubyte width @X, ubyte height @Y, ubyte apply_mask @Pc) clobbers(A,X,Y) -> ubyte @Pc ; also uses pixels=r0, mask=r1, bpp=r2L
|
||||
romsub $fef3 = sprite_set_position(ubyte number @A) clobbers(A,X,Y) ; also uses x=r0 and y=r1
|
||||
romsub $fee4 = memory_fill(ubyte value @A) clobbers(A,X,Y) ; uses address=r0, num_bytes=r1
|
||||
romsub $fee7 = memory_copy() clobbers(A,X,Y) ; uses source=r0, target=r1, num_bytes=r2
|
||||
romsub $feea = memory_crc() clobbers(A,X,Y) ; uses address=r0, num_bytes=r1 result->r2
|
||||
romsub $feed = memory_decompress() clobbers(A,X,Y) ; uses input=r0, output=r1 result->r1
|
||||
romsub $fedb = console_init() clobbers(A,X,Y) ; uses x=r0, y=r1, width=r2, height=r3
|
||||
romsub $fede = console_put_char(ubyte char @A, ubyte wrapping @Pc) clobbers(A,X,Y)
|
||||
romsub $fee1 = console_get_char() clobbers(X,Y) -> ubyte @A
|
||||
romsub $fed8 = console_put_image() clobbers(A,X,Y) ; uses ptr=r0, width=r1, height=r2
|
||||
romsub $fed5 = console_set_paging_message() clobbers(A,X,Y) ; uses messageptr=r0
|
||||
romsub $fed2 = kbdbuf_put(ubyte key @A) clobbers(A,X,Y)
|
||||
romsub $fecf = entropy_get() -> ubyte @A, ubyte @X, ubyte @Y
|
||||
romsub $fecc = monitor()
|
||||
romsub $fecc = monitor() clobbers(A,X,Y)
|
||||
|
||||
|
||||
|
||||
@ -203,8 +251,11 @@ asmsub init_system() {
|
||||
%asm {{
|
||||
sei
|
||||
cld
|
||||
stz $00
|
||||
stz $01
|
||||
;stz $00
|
||||
;stz $01
|
||||
;stz d1prb ; select rom bank 0
|
||||
lda #$80
|
||||
sta VERA_CTRL
|
||||
jsr c64.IOINIT
|
||||
jsr c64.RESTOR
|
||||
jsr c64.CINT
|
||||
|
@ -4,7 +4,7 @@
|
||||
;
|
||||
; indent format: TABS, size=8
|
||||
|
||||
|
||||
%target cx16
|
||||
%import cx16lib
|
||||
%import conv
|
||||
|
||||
@ -54,6 +54,36 @@ asmsub fill_screen (ubyte char @ A, ubyte txtcolor @ Y) clobbers(A) {
|
||||
|
||||
}
|
||||
|
||||
asmsub clear_screenchars (ubyte char @ A) clobbers(Y) {
|
||||
; ---- clear the character screen with the given fill character (leaves colors)
|
||||
; (assumes screen matrix is at the default address)
|
||||
%asm {{
|
||||
pha
|
||||
phx
|
||||
jsr c64.SCREEN ; get dimensions in X/Y
|
||||
dex
|
||||
dey
|
||||
txa
|
||||
asl a
|
||||
sta P8ZP_SCRATCH_B1
|
||||
pla
|
||||
- ldx P8ZP_SCRATCH_B1
|
||||
- stz cx16.VERA_ADDR_H
|
||||
stx cx16.VERA_ADDR_L
|
||||
sty cx16.VERA_ADDR_M
|
||||
sta cx16.VERA_DATA0
|
||||
dex
|
||||
dex
|
||||
cpx #254
|
||||
bne -
|
||||
dey
|
||||
bpl --
|
||||
plx
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
ubyte[16] color_to_charcode = [$90,$05,$1c,$9f,$9c,$1e,$1f,$9e,$81,$95,$96,$97,$98,$99,$9a,$9b]
|
||||
|
||||
sub color (ubyte txtcol) {
|
||||
|
@ -11,6 +11,10 @@
|
||||
; http://codebase64.org/doku.php?id=base:6502_6510_maths
|
||||
;
|
||||
|
||||
|
||||
math_store_reg .byte 0 ; temporary storage
|
||||
|
||||
|
||||
multiply_bytes .proc
|
||||
; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned)
|
||||
sta P8ZP_SCRATCH_B1 ; num1
|
||||
@ -31,7 +35,7 @@ multiply_bytes_16 .proc
|
||||
; -- multiply 2 bytes A and Y, result as word in A/Y (unsigned)
|
||||
sta P8ZP_SCRATCH_B1
|
||||
sty P8ZP_SCRATCH_REG
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx math_store_reg
|
||||
lda #0
|
||||
ldx #8
|
||||
lsr P8ZP_SCRATCH_B1
|
||||
@ -44,7 +48,7 @@ multiply_bytes_16 .proc
|
||||
bne -
|
||||
tay
|
||||
lda P8ZP_SCRATCH_B1
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx math_store_reg
|
||||
rts
|
||||
.pend
|
||||
|
||||
@ -57,7 +61,7 @@ multiply_words .proc
|
||||
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
|
||||
mult16 lda #0
|
||||
sta result+2 ; clear upper bits of product
|
||||
@ -79,7 +83,7 @@ mult16 lda #0
|
||||
ror result
|
||||
dex
|
||||
bne -
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
|
||||
result .byte 0,0,0,0
|
||||
@ -124,7 +128,7 @@ divmod_ub_asm .proc
|
||||
; division by zero will result in quotient = 255 and remainder = original number
|
||||
sty P8ZP_SCRATCH_REG
|
||||
sta P8ZP_SCRATCH_B1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx math_store_reg
|
||||
|
||||
lda #0
|
||||
ldx #8
|
||||
@ -137,7 +141,7 @@ divmod_ub_asm .proc
|
||||
dex
|
||||
bne -
|
||||
ldy P8ZP_SCRATCH_B1
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx math_store_reg
|
||||
rts
|
||||
.pend
|
||||
|
||||
@ -197,7 +201,7 @@ result = dividend ;save memory by reusing divident to store the result
|
||||
|
||||
sta _divisor
|
||||
sty _divisor+1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda #0 ;preset remainder to 0
|
||||
sta remainder
|
||||
sta remainder+1
|
||||
@ -224,7 +228,7 @@ result = dividend ;save memory by reusing divident to store the result
|
||||
|
||||
lda result
|
||||
ldy result+1
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
_divisor .word 0
|
||||
.pend
|
||||
@ -308,7 +312,8 @@ _seed .word $2c9e
|
||||
.pend
|
||||
|
||||
|
||||
mul_byte_3 .proc
|
||||
; ----------- optimized multiplications (stack) : ---------
|
||||
stack_mul_byte_3 .proc
|
||||
; X + X*2
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -318,7 +323,7 @@ mul_byte_3 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_3 .proc
|
||||
stack_mul_word_3 .proc
|
||||
; W*2 + W
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -335,7 +340,7 @@ mul_word_3 .proc
|
||||
.pend
|
||||
|
||||
|
||||
mul_byte_5 .proc
|
||||
stack_mul_byte_5 .proc
|
||||
; X*4 + X
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -346,7 +351,7 @@ mul_byte_5 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_5 .proc
|
||||
stack_mul_word_5 .proc
|
||||
; W*4 + W
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -365,7 +370,7 @@ mul_word_5 .proc
|
||||
.pend
|
||||
|
||||
|
||||
mul_byte_6 .proc
|
||||
stack_mul_byte_6 .proc
|
||||
; (X*2 + X)*2
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -376,7 +381,7 @@ mul_byte_6 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_6 .proc
|
||||
stack_mul_word_6 .proc
|
||||
; (W*2 + W)*2
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -394,7 +399,7 @@ mul_word_6 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_7 .proc
|
||||
stack_mul_byte_7 .proc
|
||||
; X*8 - X
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -406,7 +411,7 @@ mul_byte_7 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_7 .proc
|
||||
stack_mul_word_7 .proc
|
||||
; W*8 - W
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -426,7 +431,7 @@ mul_word_7 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_9 .proc
|
||||
stack_mul_byte_9 .proc
|
||||
; X*8 + X
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -438,7 +443,7 @@ mul_byte_9 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_9 .proc
|
||||
stack_mul_word_9 .proc
|
||||
; W*8 + W
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -458,7 +463,7 @@ mul_word_9 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_10 .proc
|
||||
stack_mul_byte_10 .proc
|
||||
; (X*4 + X)*2
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -470,7 +475,7 @@ mul_byte_10 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_10 .proc
|
||||
stack_mul_word_10 .proc
|
||||
; (W*4 + W)*2
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -490,7 +495,7 @@ mul_word_10 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_11 .proc
|
||||
stack_mul_byte_11 .proc
|
||||
; (X*2 + X)*4 - X
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -506,7 +511,7 @@ mul_byte_11 .proc
|
||||
|
||||
; mul_word_11 is skipped (too much code)
|
||||
|
||||
mul_byte_12 .proc
|
||||
stack_mul_byte_12 .proc
|
||||
; (X*2 + X)*4
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -518,7 +523,7 @@ mul_byte_12 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_12 .proc
|
||||
stack_mul_word_12 .proc
|
||||
; (W*2 + W)*4
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -538,7 +543,7 @@ mul_word_12 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_13 .proc
|
||||
stack_mul_byte_13 .proc
|
||||
; (X*2 + X)*4 + X
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -554,7 +559,7 @@ mul_byte_13 .proc
|
||||
|
||||
; mul_word_13 is skipped (too much code)
|
||||
|
||||
mul_byte_14 .proc
|
||||
stack_mul_byte_14 .proc
|
||||
; (X*8 - X)*2
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -569,7 +574,7 @@ mul_byte_14 .proc
|
||||
|
||||
; mul_word_14 is skipped (too much code)
|
||||
|
||||
mul_byte_15 .proc
|
||||
stack_mul_byte_15 .proc
|
||||
; X*16 - X
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -582,7 +587,7 @@ mul_byte_15 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_15 .proc
|
||||
stack_mul_word_15 .proc
|
||||
; W*16 - W
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -604,7 +609,7 @@ mul_word_15 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_20 .proc
|
||||
stack_mul_byte_20 .proc
|
||||
; (X*4 + X)*4
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -617,7 +622,7 @@ mul_byte_20 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_20 .proc
|
||||
stack_mul_word_20 .proc
|
||||
; (W*4 + W)*4
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -639,7 +644,7 @@ mul_word_20 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_25 .proc
|
||||
stack_mul_byte_25 .proc
|
||||
; (X*2 + X)*8 + X
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
@ -654,27 +659,26 @@ mul_byte_25 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_25 .proc
|
||||
; W + W*8 + W*16
|
||||
stack_mul_word_25 .proc
|
||||
; W = (W*2 + W) *8 + W
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W1
|
||||
clc
|
||||
adc P8ESTACK_LO+1,x
|
||||
sta P8ESTACK_LO+1,x
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ESTACK_HI+1,x
|
||||
sta P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
lda P8ZP_SCRATCH_W1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ESTACK_LO+1,x
|
||||
sta P8ESTACK_LO+1,x
|
||||
@ -684,21 +688,16 @@ mul_word_25 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_40 .proc
|
||||
; (X*4 + X)*8
|
||||
stack_mul_byte_40 .proc
|
||||
lda P8ESTACK_LO+1,x
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc P8ESTACK_LO+1,x
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
and #7
|
||||
tay
|
||||
lda mul_byte_40._forties,y
|
||||
sta P8ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_40 .proc
|
||||
stack_mul_word_40 .proc
|
||||
; (W*4 + W)*8
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_REG
|
||||
@ -722,6 +721,529 @@ mul_word_40 .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
stack_mul_byte_50 .proc
|
||||
lda P8ESTACK_LO+1,x
|
||||
and #7
|
||||
tay
|
||||
lda mul_byte_50._fifties, y
|
||||
sta P8ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
stack_mul_word_50 .proc
|
||||
; W = W * 25 * 2
|
||||
jsr stack_mul_word_25
|
||||
asl P8ESTACK_LO+1,x
|
||||
rol P8ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
stack_mul_byte_80 .proc
|
||||
lda P8ESTACK_LO+1,x
|
||||
and #3
|
||||
tay
|
||||
lda mul_byte_80._eighties, y
|
||||
sta P8ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
stack_mul_word_80 .proc
|
||||
; W = W * 40 * 2
|
||||
jsr stack_mul_word_40
|
||||
asl P8ESTACK_LO+1,x
|
||||
rol P8ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
stack_mul_byte_100 .proc
|
||||
lda P8ESTACK_LO+1,x
|
||||
and #3
|
||||
tay
|
||||
lda mul_byte_100._hundreds, y
|
||||
sta P8ESTACK_LO+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
stack_mul_word_100 .proc
|
||||
; W = W * 25 * 4
|
||||
jsr stack_mul_word_25
|
||||
asl P8ESTACK_LO+1,x
|
||||
rol P8ESTACK_HI+1,x
|
||||
asl P8ESTACK_LO+1,x
|
||||
rol P8ESTACK_HI+1,x
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
; ----------- optimized multiplications (in-place A (byte) and ?? (word)) : ---------
|
||||
mul_byte_3 .proc
|
||||
; A = A + A*2
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
clc
|
||||
adc P8P_P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_3 .proc
|
||||
; AY = AY*2 + AY
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
tay
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
mul_byte_5 .proc
|
||||
; A = A*4 + A
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_5 .proc
|
||||
; AY = AY*4 + AY
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
tay
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
mul_byte_6 .proc
|
||||
; A = (A*2 + A)*2
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_6 .proc
|
||||
; AY = (AY*2 + AY)*2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
tay
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
tya
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_7 .proc
|
||||
; A = A*8 - A
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_7 .proc
|
||||
; AY = AY*8 - AY
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
sbc P8ZP_SCRATCH_W2+1
|
||||
tay
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_9 .proc
|
||||
; A = A*8 + A
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_9 .proc
|
||||
; AY = AY*8 + AY
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
tay
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_10 .proc
|
||||
; A=(A*4 + A)*2
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_10 .proc
|
||||
; AY=(AY*4 + AY)*2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
lda P8ZP_SCRATCH_W1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_11 .proc
|
||||
; A=(A*2 + A)*4 - A
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
; mul_word_11 is skipped (too much code)
|
||||
|
||||
mul_byte_12 .proc
|
||||
; A=(A*2 + A)*4
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_12 .proc
|
||||
; AY=(AY*2 + AY)*4
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
lda P8ZP_SCRATCH_W1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_13 .proc
|
||||
; A=(A*2 + A)*4 + A
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
; mul_word_13 is skipped (too much code)
|
||||
|
||||
mul_byte_14 .proc
|
||||
; A=(A*8 - A)*2
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
rts
|
||||
.pend
|
||||
|
||||
; mul_word_14 is skipped (too much code)
|
||||
|
||||
mul_byte_15 .proc
|
||||
; A=A*16 - A
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_15 .proc
|
||||
; AY = AY * 16 - AY
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
sbc P8ZP_SCRATCH_W2+1
|
||||
tay
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_20 .proc
|
||||
; A=(A*4 + A)*4
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_20 .proc
|
||||
; AY = AY * 10 * 2
|
||||
jsr mul_word_10
|
||||
sty P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_REG
|
||||
ldy P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_25 .proc
|
||||
; A=(A*2 + A)*8 + A
|
||||
sta P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_word_25 .proc
|
||||
; AY = (AY*2 + AY) *8 + AY
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
lda P8ZP_SCRATCH_W1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
tay
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_40 .proc
|
||||
and #7
|
||||
tay
|
||||
lda _forties,y
|
||||
rts
|
||||
_forties .byte 0*40, 1*40, 2*40, 3*40, 4*40, 5*40, 6*40, 7*40 & 255
|
||||
.pend
|
||||
|
||||
mul_word_40 .proc
|
||||
; AY = (AY*4 + AY)*8
|
||||
sta P8ZP_SCRATCH_W1
|
||||
sty P8ZP_SCRATCH_W1+1
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sty P8ZP_SCRATCH_W2+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_W1+1
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ZP_SCRATCH_W1+1
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
asl P8ZP_SCRATCH_W1
|
||||
rol a
|
||||
asl P8ZP_SCRATCH_W1
|
||||
rol a
|
||||
asl P8ZP_SCRATCH_W1
|
||||
rol a
|
||||
asl P8ZP_SCRATCH_W1
|
||||
rol a
|
||||
tay
|
||||
lda P8ZP_SCRATCH_W1
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_50 .proc
|
||||
and #7
|
||||
tay
|
||||
lda _fifties, y
|
||||
rts
|
||||
_fifties .byte 0*50, 1*50, 2*50, 3*50, 4*50, 5*50, 6*50 & 255, 7*50 & 255
|
||||
.pend
|
||||
|
||||
mul_word_50 .proc
|
||||
; AY = AY * 25 * 2
|
||||
jsr mul_word_25
|
||||
sty P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_REG
|
||||
ldy P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_80 .proc
|
||||
and #3
|
||||
tay
|
||||
lda _eighties, y
|
||||
rts
|
||||
_eighties .byte 0*80, 1*80, 2*80, 3*80
|
||||
.pend
|
||||
|
||||
mul_word_80 .proc
|
||||
; AY = AY * 40 * 2
|
||||
jsr mul_word_40
|
||||
sty P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_REG
|
||||
ldy P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
mul_byte_100 .proc
|
||||
and #3
|
||||
tay
|
||||
lda _hundreds, y
|
||||
rts
|
||||
_hundreds .byte 0*100, 1*100, 2*100, 3*100 & 255
|
||||
.pend
|
||||
|
||||
mul_word_100 .proc
|
||||
; AY = AY * 25 * 4
|
||||
jsr mul_word_25
|
||||
sty P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_REG
|
||||
asl a
|
||||
rol P8ZP_SCRATCH_REG
|
||||
ldy P8ZP_SCRATCH_REG
|
||||
rts
|
||||
.pend
|
||||
|
||||
; ----------- end optimized multiplications -----------
|
||||
|
||||
|
||||
sign_b .proc
|
||||
lda P8ESTACK_LO+1,x
|
||||
beq _sign_zero
|
||||
|
@ -686,7 +686,7 @@ func_sqrt16 .proc
|
||||
sta P8ZP_SCRATCH_W2
|
||||
lda P8ESTACK_HI+1,x
|
||||
sta P8ZP_SCRATCH_W2+1
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
ldy #$00 ; r = 0
|
||||
ldx #$07
|
||||
clc ; clear bit 16 of m
|
||||
@ -721,7 +721,7 @@ _skip1
|
||||
_skip2
|
||||
iny ; r = r or d (d is 1 here)
|
||||
_skip3
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
tya
|
||||
sta P8ESTACK_LO+1,x
|
||||
lda #0
|
||||
@ -1216,7 +1216,7 @@ func_rndw .proc
|
||||
func_memcopy .proc
|
||||
; note: clobbers A,Y
|
||||
inx
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda P8ESTACK_LO+2,x
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ESTACK_HI+2,x
|
||||
@ -1233,7 +1233,7 @@ func_memcopy .proc
|
||||
iny
|
||||
dex
|
||||
bne -
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
inx
|
||||
inx
|
||||
rts
|
||||
@ -1242,7 +1242,7 @@ func_memcopy .proc
|
||||
func_memset .proc
|
||||
; note: clobbers A,Y
|
||||
inx
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda P8ESTACK_LO+2,x
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ESTACK_HI+2,x
|
||||
@ -1253,7 +1253,7 @@ func_memset .proc
|
||||
lda P8ESTACK_LO,x
|
||||
ldx P8ZP_SCRATCH_B1
|
||||
jsr memset
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
inx
|
||||
inx
|
||||
rts
|
||||
@ -1264,7 +1264,7 @@ func_memsetw .proc
|
||||
; -- fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY.
|
||||
|
||||
inx
|
||||
stx P8ZP_SCRATCH_REG_X
|
||||
stx P8ZP_SCRATCH_REG
|
||||
lda P8ESTACK_LO+2,x
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda P8ESTACK_HI+2,x
|
||||
@ -1276,7 +1276,7 @@ func_memsetw .proc
|
||||
lda P8ESTACK_LO,x
|
||||
ldy P8ESTACK_HI,x
|
||||
jsr memsetw
|
||||
ldx P8ZP_SCRATCH_REG_X
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
inx
|
||||
inx
|
||||
rts
|
||||
@ -1328,9 +1328,9 @@ memset .proc
|
||||
; -- fill memory from (SCRATCH_ZPWORD1), length XY, with value in A.
|
||||
; clobbers X, Y
|
||||
stx P8ZP_SCRATCH_B1
|
||||
sty P8ZP_SCRATCH_REG
|
||||
sty _save_reg
|
||||
ldy #0
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
ldx _save_reg
|
||||
beq _lastpage
|
||||
|
||||
_fullpage sta (P8ZP_SCRATCH_W1),y
|
||||
@ -1347,6 +1347,7 @@ _lastpage ldy P8ZP_SCRATCH_B1
|
||||
bne -
|
||||
|
||||
+ rts
|
||||
_save_reg .byte 0
|
||||
.pend
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
4.1
|
||||
4.2
|
||||
|
@ -4,13 +4,10 @@ import kotlinx.cli.*
|
||||
import prog8.ast.base.AstException
|
||||
import prog8.compiler.CompilationResult
|
||||
import prog8.compiler.compileProgram
|
||||
import prog8.compiler.target.C64Target
|
||||
import prog8.compiler.target.Cx16Target
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.compiler.target.c64.C64MachineDefinition
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.compiler.target.cx16.CX16MachineDefinition
|
||||
import prog8.parser.ParsingFailedError
|
||||
import java.io.IOException
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardWatchEventKinds
|
||||
@ -41,7 +38,8 @@ private fun compileMain(args: Array<String>) {
|
||||
val dontWriteAssembly by cli.flagArgument("-noasm", "don't create assembly code")
|
||||
val dontOptimize by cli.flagArgument("-noopt", "don't perform any optimizations")
|
||||
val watchMode by cli.flagArgument("-watch", "continuous compilation mode (watches for file changes), greatly increases compilation speed")
|
||||
val compilationTarget by cli.flagValueArgument("-target", "compilertarget", "target output of the compiler, currently 'c64' and 'cx16' available", "c64")
|
||||
val compilationTarget by cli.flagValueArgument("-target", "compilertarget",
|
||||
"target output of the compiler, currently '${C64Target.name}' and '${Cx16Target.name}' available", C64Target.name)
|
||||
val moduleFiles by cli.positionalArgumentsList("modules", "main module file(s) to compile", minArgs = 1)
|
||||
|
||||
try {
|
||||
@ -50,39 +48,6 @@ private fun compileMain(args: Array<String>) {
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
when(compilationTarget) {
|
||||
"c64" -> {
|
||||
with(CompilationTarget) {
|
||||
name = "Commodore-64"
|
||||
machine = C64MachineDefinition
|
||||
encodeString = { str, altEncoding ->
|
||||
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
|
||||
}
|
||||
decodeString = { bytes, altEncoding ->
|
||||
if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
||||
}
|
||||
asmGenerator = ::AsmGen
|
||||
}
|
||||
}
|
||||
"cx16" -> {
|
||||
with(CompilationTarget) {
|
||||
name = "Commander X16"
|
||||
machine = CX16MachineDefinition
|
||||
encodeString = { str, altEncoding ->
|
||||
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
|
||||
}
|
||||
decodeString = { bytes, altEncoding ->
|
||||
if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
||||
}
|
||||
asmGenerator = ::AsmGen
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
System.err.println("invalid compilation target. Available are: c64, cx16")
|
||||
exitProcess(1)
|
||||
}
|
||||
}
|
||||
|
||||
val outputPath = pathFrom(outputDir)
|
||||
if(!outputPath.toFile().isDirectory) {
|
||||
System.err.println("Output path doesn't exist")
|
||||
@ -97,7 +62,7 @@ private fun compileMain(args: Array<String>) {
|
||||
println("Continuous watch mode active. Main module: $filepath")
|
||||
|
||||
try {
|
||||
val compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, outputDir=outputPath)
|
||||
val compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, compilationTarget, outputPath)
|
||||
println("Imported files (now watching:)")
|
||||
for (importedFile in compilationResult.importedFiles) {
|
||||
print(" ")
|
||||
@ -122,7 +87,7 @@ private fun compileMain(args: Array<String>) {
|
||||
val filepath = pathFrom(filepathRaw).normalize()
|
||||
val compilationResult: CompilationResult
|
||||
try {
|
||||
compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, outputDir=outputPath)
|
||||
compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, compilationTarget, outputPath)
|
||||
if(!compilationResult.success)
|
||||
exitProcess(1)
|
||||
} catch (x: ParsingFailedError) {
|
||||
@ -135,7 +100,7 @@ private fun compileMain(args: Array<String>) {
|
||||
if (compilationResult.programName.isEmpty())
|
||||
println("\nCan't start emulator because no program was assembled.")
|
||||
else if(startEmulator) {
|
||||
CompilationTarget.machine.launchEmulator(compilationResult.programName)
|
||||
CompilationTarget.instance.machine.launchEmulator(compilationResult.programName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
||||
param.second.stack -> "stack"
|
||||
param.second.registerOrPair!=null -> param.second.registerOrPair.toString()
|
||||
param.second.statusflag!=null -> param.second.statusflag.toString()
|
||||
else -> "?????1"
|
||||
else -> "?????"
|
||||
}
|
||||
output("${datatypeString(param.first.type)} ${param.first.name} @$reg")
|
||||
if(param.first!==subroutine.parameters.last())
|
||||
|
@ -254,7 +254,7 @@ private fun prog8Parser.Asmsub_declContext.toAst(): AsmsubDecl {
|
||||
val clobbers = asmsub_clobbers()?.clobber()?.toAst() ?: emptySet()
|
||||
val normalParameters = params.map { SubroutineParameter(it.name, it.type, it.position) }
|
||||
val normalReturntypes = returns.map { it.type }
|
||||
val paramRegisters = params.map { RegisterOrStatusflag(it.registerOrPair, it.statusflag, it.stack) }
|
||||
val paramRegisters = params.map { RegisterOrStatusflag(it.registerOrPair, it.statusflag, false) }
|
||||
val returnRegisters = returns.map { RegisterOrStatusflag(it.registerOrPair, it.statusflag, it.stack) }
|
||||
return AsmsubDecl(name, normalParameters, normalReturntypes, paramRegisters, returnRegisters, clobbers)
|
||||
}
|
||||
@ -263,7 +263,7 @@ private class AsmSubroutineParameter(name: String,
|
||||
type: DataType,
|
||||
val registerOrPair: RegisterOrPair?,
|
||||
val statusflag: Statusflag?,
|
||||
val stack: Boolean,
|
||||
// TODO implement: val stack: Boolean,
|
||||
position: Position) : SubroutineParameter(name, type, position)
|
||||
|
||||
private class AsmSubroutineReturn(val type: DataType,
|
||||
@ -305,8 +305,7 @@ private fun prog8Parser.Asmsub_paramsContext.toAst(): List<AsmSubroutineParamete
|
||||
else -> throw FatalAstException("invalid register or status flag '$name'")
|
||||
}
|
||||
}
|
||||
AsmSubroutineParameter(vardecl.varname.text, datatype, registerorpair, statusregister,
|
||||
!it.stack?.text.isNullOrEmpty(), toPosition())
|
||||
AsmSubroutineParameter(vardecl.varname.text, datatype, registerorpair, statusregister, toPosition())
|
||||
}
|
||||
|
||||
private fun prog8Parser.Functioncall_stmtContext.toAst(): Statement {
|
||||
@ -472,7 +471,7 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression {
|
||||
litval.charliteral()!=null -> {
|
||||
try {
|
||||
val cc=litval.charliteral()
|
||||
NumericLiteralValue(DataType.UBYTE, CompilationTarget.encodeString(
|
||||
NumericLiteralValue(DataType.UBYTE, CompilationTarget.instance.encodeString(
|
||||
unescape(litval.charliteral().SINGLECHAR().text, litval.toPosition()),
|
||||
litval.charliteral().ALT_STRING_ENCODING()!=null)[0], litval.toPosition())
|
||||
} catch (ce: CharConversionException) {
|
||||
|
@ -56,8 +56,8 @@ enum class DataType {
|
||||
return when(this) {
|
||||
in ByteDatatypes -> 1
|
||||
in WordDatatypes -> 2
|
||||
FLOAT -> CompilationTarget.machine.FLOAT_MEM_SIZE
|
||||
in PassByReferenceDatatypes -> CompilationTarget.machine.POINTER_MEM_SIZE
|
||||
FLOAT -> CompilationTarget.instance.machine.FLOAT_MEM_SIZE
|
||||
in PassByReferenceDatatypes -> CompilationTarget.instance.machine.POINTER_MEM_SIZE
|
||||
else -> -9999999
|
||||
}
|
||||
}
|
||||
|
@ -671,8 +671,8 @@ class RangeExpr(var from: Expression,
|
||||
val toString = to as? StringLiteralValue
|
||||
if(fromString!=null && toString!=null ) {
|
||||
// string range -> int range over character values
|
||||
fromVal = CompilationTarget.encodeString(fromString.value, fromString.altEncoding)[0].toInt()
|
||||
toVal = CompilationTarget.encodeString(toString.value, fromString.altEncoding)[0].toInt()
|
||||
fromVal = CompilationTarget.instance.encodeString(fromString.value, fromString.altEncoding)[0].toInt()
|
||||
toVal = CompilationTarget.instance.encodeString(toString.value, fromString.altEncoding)[0].toInt()
|
||||
} else {
|
||||
val fromLv = from as? NumericLiteralValue
|
||||
val toLv = to as? NumericLiteralValue
|
||||
|
@ -7,7 +7,9 @@ import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.target.C64Target
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.compiler.target.Cx16Target
|
||||
import prog8.functions.BuiltinFunctions
|
||||
import java.io.File
|
||||
|
||||
@ -471,14 +473,11 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(decl: VarDecl) {
|
||||
fun err(msg: String, position: Position?=null) {
|
||||
errors.err(msg, position ?: decl.position)
|
||||
}
|
||||
fun err(msg: String, position: Position?=null) = errors.err(msg, position ?: decl.position)
|
||||
|
||||
// the initializer value can't refer to the variable itself (recursive definition)
|
||||
if(decl.value?.referencesIdentifiers(decl.name) == true || decl.arraysize?.index?.referencesIdentifiers(decl.name) == true) {
|
||||
if(decl.value?.referencesIdentifiers(decl.name) == true || decl.arraysize?.index?.referencesIdentifiers(decl.name) == true)
|
||||
err("recursive var declaration")
|
||||
}
|
||||
|
||||
// CONST can only occur on simple types (byte, word, float)
|
||||
if(decl.type== VarDeclType.CONST) {
|
||||
@ -486,10 +485,12 @@ internal class AstChecker(private val program: Program,
|
||||
err("const modifier can only be used on numeric types (byte, word, float)")
|
||||
}
|
||||
|
||||
// FLOATS
|
||||
if(!compilerOptions.floats && decl.datatype in setOf(DataType.FLOAT, DataType.ARRAY_F) && decl.type!= VarDeclType.MEMORY) {
|
||||
// FLOATS enabled?
|
||||
if(!compilerOptions.floats && decl.datatype in setOf(DataType.FLOAT, DataType.ARRAY_F) && decl.type!= VarDeclType.MEMORY)
|
||||
err("floating point used, but that is not enabled via options")
|
||||
}
|
||||
|
||||
if(decl.datatype == DataType.FLOAT && (decl.zeropage==ZeropageWish.REQUIRE_ZEROPAGE || decl.zeropage==ZeropageWish.PREFER_ZEROPAGE))
|
||||
errors.warn("floating point values won't be placed in Zeropage due to size constraints", decl.position)
|
||||
|
||||
// ARRAY without size specifier MUST have an iterable initializer value
|
||||
if(decl.isArray && decl.arraysize==null) {
|
||||
@ -558,9 +559,11 @@ internal class AstChecker(private val program: Program,
|
||||
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
|
||||
}
|
||||
else -> {
|
||||
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}")
|
||||
super.visit(decl)
|
||||
return
|
||||
if(decl.type==VarDeclType.CONST) {
|
||||
err("const declaration needs a compile-time constant initializer value, or range")
|
||||
super.visit(decl)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -709,6 +712,14 @@ internal class AstChecker(private val program: Program,
|
||||
else if(directive.args.map{it.name in setOf("enable_floats", "force_output")}.any { !it })
|
||||
err("invalid option directive argument(s)")
|
||||
}
|
||||
"%target" -> {
|
||||
if(directive.parent !is Block && directive.parent !is Module)
|
||||
err("this directive may only occur in a block or at module level")
|
||||
if(directive.args.size != 1)
|
||||
err("directive requires one argument")
|
||||
if(directive.args.single().name !in setOf(C64Target.name, Cx16Target.name))
|
||||
err("invalid compilation target")
|
||||
}
|
||||
else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position)
|
||||
}
|
||||
super.visit(directive)
|
||||
@ -1156,7 +1167,7 @@ internal class AstChecker(private val program: Program,
|
||||
|
||||
// check if the floating point values are all within range
|
||||
val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray()
|
||||
if(doubles.any { it < CompilationTarget.machine.FLOAT_MAX_NEGATIVE || it > CompilationTarget.machine.FLOAT_MAX_POSITIVE })
|
||||
if(doubles.any { it < CompilationTarget.instance.machine.FLOAT_MAX_NEGATIVE || it > CompilationTarget.instance.machine.FLOAT_MAX_POSITIVE })
|
||||
return err("floating point value overflow")
|
||||
return true
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
||||
}
|
||||
|
||||
override fun visit(block: Block) {
|
||||
if(block.name in CompilationTarget.machine.opcodeNames)
|
||||
if(block.name in CompilationTarget.instance.machine.opcodeNames)
|
||||
errors.err("can't use a cpu opcode name as a symbol: '${block.name}'", block.position)
|
||||
|
||||
val existing = blocks[block.name]
|
||||
@ -40,7 +40,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
||||
if(decl.name in BuiltinFunctions)
|
||||
errors.err("builtin function cannot be redefined", decl.position)
|
||||
|
||||
if(decl.name in CompilationTarget.machine.opcodeNames)
|
||||
if(decl.name in CompilationTarget.instance.machine.opcodeNames)
|
||||
errors.err("can't use a cpu opcode name as a symbol: '${decl.name}'", decl.position)
|
||||
|
||||
if(decl.datatype==DataType.STRUCT) {
|
||||
@ -74,7 +74,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
||||
}
|
||||
|
||||
override fun visit(subroutine: Subroutine) {
|
||||
if(subroutine.name in CompilationTarget.machine.opcodeNames) {
|
||||
if(subroutine.name in CompilationTarget.instance.machine.opcodeNames) {
|
||||
errors.err("can't use a cpu opcode name as a symbol: '${subroutine.name}'", subroutine.position)
|
||||
} else if(subroutine.name in BuiltinFunctions) {
|
||||
// the builtin functions can't be redefined
|
||||
@ -119,7 +119,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
||||
}
|
||||
|
||||
override fun visit(label: Label) {
|
||||
if(label.name in CompilationTarget.machine.opcodeNames)
|
||||
if(label.name in CompilationTarget.instance.machine.opcodeNames)
|
||||
errors.err("can't use a cpu opcode name as a symbol: '${label.name}'", label.position)
|
||||
|
||||
if(label.name in BuiltinFunctions) {
|
||||
|
@ -12,6 +12,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
|
||||
|
||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||
if(functionCallStatement.target.nameInSource == listOf("swap")) {
|
||||
// TODO don't replace swap(), let the code generator figure this all out
|
||||
// if x and y are both just identifiers, do not rewrite (there should be asm generation for that)
|
||||
// otherwise:
|
||||
// rewrite swap(x,y) as follows:
|
||||
|
@ -71,23 +71,6 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
val declValue = decl.value
|
||||
if(declValue!=null && decl.type== VarDeclType.VAR && decl.datatype in NumericDatatypes) {
|
||||
val declConstValue = declValue.constValue(program)
|
||||
if(declConstValue==null) {
|
||||
// move the vardecl (without value) to the scope and replace this with a regular assignment
|
||||
decl.value = null
|
||||
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
|
||||
val assign = Assignment(target, declValue, decl.position)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(decl, assign, parent),
|
||||
IAstModification.InsertFirst(decl, decl.definingScope() as Node)
|
||||
)
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(whenStatement: WhenStatement, parent: Node): Iterable<IAstModification> {
|
||||
val choices = whenStatement.choiceValues(program).sortedBy {
|
||||
|
@ -18,6 +18,21 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
||||
|
||||
private val noModifications = emptyList<IAstModification>()
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
val declValue = decl.value
|
||||
if(decl.type==VarDeclType.VAR && declValue!=null && decl.struct==null) {
|
||||
val valueDt = declValue.inferType(program)
|
||||
if(!valueDt.istype(decl.datatype)) {
|
||||
return listOf(IAstModification.ReplaceNode(
|
||||
declValue,
|
||||
TypecastExpression(declValue, decl.datatype, true, declValue.position),
|
||||
decl
|
||||
))
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||
val leftDt = expr.left.inferType(program)
|
||||
val rightDt = expr.right.inferType(program)
|
||||
@ -139,6 +154,7 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
||||
call.args[arg.second.index],
|
||||
TypecastExpression(arg.second.value, possibleType, true, arg.second.value.position),
|
||||
call as Node)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package prog8.compiler
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
@ -14,7 +15,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
|
||||
private val noModifications = emptyList<IAstModification>()
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
if (decl.value == null && decl.type == VarDeclType.VAR && decl.datatype in NumericDatatypes) {
|
||||
if (decl.value == null && !decl.autogeneratedDontRemove && decl.type == VarDeclType.VAR && decl.datatype in NumericDatatypes) {
|
||||
// a numeric vardecl without an initial value is initialized with zero.
|
||||
decl.value = decl.zeroElementValue()
|
||||
}
|
||||
@ -54,7 +55,8 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
|
||||
}
|
||||
}
|
||||
if (!conflicts) {
|
||||
val numericVarsWithValue = decls.filter { it.value != null && it.datatype in NumericDatatypes }
|
||||
// move vardecls of the scope into the upper scope. Make sure the order remains the same!
|
||||
val numericVarsWithValue = decls.filter { it.value != null && it.datatype in NumericDatatypes }.reversed()
|
||||
return numericVarsWithValue.map {
|
||||
val initValue = it.value!! // assume here that value has always been set by now
|
||||
it.value = null // make sure no value init assignment for this vardecl will be created later (would be superfluous)
|
||||
@ -114,6 +116,18 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
|
||||
// that the types of assignment values and their target are the same,
|
||||
// and that the types of both operands of a binaryexpression node are the same.
|
||||
// So, it is not easily possible to remove the typecasts that are there to make these conditions true.
|
||||
// The only place for now where we can do this is for:
|
||||
// asmsub register pair parameter.
|
||||
|
||||
if(typecast.type in WordDatatypes) {
|
||||
val fcall = typecast.parent as? IFunctionCall
|
||||
if (fcall != null) {
|
||||
val sub = fcall.target.targetStatement(program.namespace) as? Subroutine
|
||||
if (sub != null && sub.isAsmSubroutine) {
|
||||
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sourceDt in PassByReferenceDatatypes) {
|
||||
if(typecast.type==DataType.UWORD) {
|
||||
|
@ -27,7 +27,8 @@ data class CompilationOptions(val output: OutputType,
|
||||
val launcher: LauncherType,
|
||||
val zeropage: ZeropageType,
|
||||
val zpReserved: List<IntRange>,
|
||||
val floats: Boolean)
|
||||
val floats: Boolean,
|
||||
val compilationTarget: String?)
|
||||
|
||||
|
||||
class CompilerException(message: String?) : Exception(message)
|
||||
|
@ -4,7 +4,9 @@ import prog8.ast.AstToSourceCode
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.statements.Directive
|
||||
import prog8.compiler.target.C64Target
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.compiler.target.Cx16Target
|
||||
import prog8.optimizer.UnusedCodeRemover
|
||||
import prog8.optimizer.constantFold
|
||||
import prog8.optimizer.optimizeStatements
|
||||
@ -13,6 +15,7 @@ import prog8.parser.ModuleImporter
|
||||
import prog8.parser.ParsingFailedError
|
||||
import prog8.parser.moduleName
|
||||
import java.nio.file.Path
|
||||
import kotlin.system.exitProcess
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
|
||||
@ -25,12 +28,22 @@ class CompilationResult(val success: Boolean,
|
||||
fun compileProgram(filepath: Path,
|
||||
optimize: Boolean,
|
||||
writeAssembly: Boolean,
|
||||
compilationTarget: String,
|
||||
outputDir: Path): CompilationResult {
|
||||
var programName = ""
|
||||
lateinit var programAst: Program
|
||||
lateinit var importedFiles: List<Path>
|
||||
val errors = ErrorReporter()
|
||||
|
||||
when(compilationTarget) {
|
||||
C64Target.name -> CompilationTarget.instance = C64Target
|
||||
Cx16Target.name -> CompilationTarget.instance = Cx16Target
|
||||
else -> {
|
||||
System.err.println("invalid compilation target")
|
||||
exitProcess(1)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
val totalTime = measureTimeMillis {
|
||||
// import main module and everything it needs
|
||||
@ -90,8 +103,8 @@ private fun parseImports(filepath: Path, errors: ErrorReporter): Triple<Program,
|
||||
if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG)
|
||||
throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.")
|
||||
|
||||
// depending on the mach9ine and compiler options we may have to include some libraries
|
||||
CompilationTarget.machine.importLibs(compilerOptions, importer, programAst)
|
||||
// depending on the machine and compiler options we may have to include some libraries
|
||||
CompilationTarget.instance.machine.importLibs(compilerOptions, importer, programAst)
|
||||
|
||||
// always import prog8lib and math
|
||||
importer.importLibraryModule(programAst, "math")
|
||||
@ -129,16 +142,26 @@ private fun determineCompilationOptions(program: Program): CompilationOptions {
|
||||
.map { it[0].int!!..it[1].int!! }
|
||||
.toList()
|
||||
|
||||
var target = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%target" }
|
||||
as? Directive)?.args?.single()?.name
|
||||
|
||||
when(target) {
|
||||
C64Target.name -> CompilationTarget.instance = C64Target
|
||||
Cx16Target.name -> CompilationTarget.instance = Cx16Target
|
||||
null -> target = CompilationTarget.instance.name
|
||||
else -> throw FatalAstException("invalid target")
|
||||
}
|
||||
|
||||
return CompilationOptions(
|
||||
if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType),
|
||||
if (launcherType == null) LauncherType.BASIC else LauncherType.valueOf(launcherType),
|
||||
zpType, zpReserved, floatsEnabled
|
||||
zpType, zpReserved, floatsEnabled, target
|
||||
)
|
||||
}
|
||||
|
||||
private fun processAst(programAst: Program, errors: ErrorReporter, compilerOptions: CompilationOptions) {
|
||||
// perform initial syntax checks and processings
|
||||
println("Processing...")
|
||||
println("Processing for target ${CompilationTarget.instance.name}...")
|
||||
programAst.checkIdentifiers(errors)
|
||||
errors.handle()
|
||||
programAst.constantFold(errors)
|
||||
@ -191,11 +214,14 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir:
|
||||
|
||||
// printAst(programAst)
|
||||
|
||||
CompilationTarget.machine.initializeZeropage(compilerOptions)
|
||||
val assembly = CompilationTarget.asmGenerator(
|
||||
if(compilerOptions.compilationTarget!=null && compilerOptions.compilationTarget != CompilationTarget.instance.name)
|
||||
throw AssemblyError("program's compilation target differs from configured target")
|
||||
|
||||
CompilationTarget.instance.machine.initializeZeropage(compilerOptions)
|
||||
val assembly = CompilationTarget.instance.asmGenerator(
|
||||
programAst,
|
||||
errors,
|
||||
CompilationTarget.machine.zeropage,
|
||||
CompilationTarget.instance.machine.zeropage,
|
||||
compilerOptions,
|
||||
outputDir).compileToAssembly(optimize)
|
||||
assembly.assemble(compilerOptions)
|
||||
|
@ -10,7 +10,6 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
||||
|
||||
abstract val SCRATCH_B1 : Int // temp storage for a single byte
|
||||
abstract val SCRATCH_REG : Int // temp storage for a register
|
||||
abstract val SCRATCH_REG_X : Int // temp storage for register X (the evaluation stack pointer)
|
||||
abstract val SCRATCH_W1 : Int // temp storage 1 for a word $fb+$fc
|
||||
abstract val SCRATCH_W2 : Int // temp storage 2 for a word $fb+$fc
|
||||
|
||||
|
@ -4,15 +4,50 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.ErrorReporter
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.Zeropage
|
||||
import prog8.compiler.target.c64.C64MachineDefinition
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.compiler.target.cx16.CX16MachineDefinition
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
internal interface CompilationTarget {
|
||||
val name: String
|
||||
val machine: IMachineDefinition
|
||||
fun encodeString(str: String, altEncoding: Boolean): List<Short>
|
||||
fun decodeString(bytes: List<Short>, altEncoding: Boolean): String
|
||||
fun asmGenerator(program: Program, errors: ErrorReporter, zp: Zeropage, options: CompilationOptions, path: Path): IAssemblyGenerator
|
||||
val asmForSystemReset: String
|
||||
val initProcName: String?
|
||||
|
||||
companion object {
|
||||
lateinit var name: String
|
||||
lateinit var machine: IMachineDefinition
|
||||
lateinit var encodeString: (str: String, altEncoding: Boolean) -> List<Short>
|
||||
lateinit var decodeString: (bytes: List<Short>, altEncoding: Boolean) -> String
|
||||
lateinit var asmGenerator: (Program, ErrorReporter, Zeropage, CompilationOptions, Path) -> IAssemblyGenerator
|
||||
lateinit var instance: CompilationTarget
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal object C64Target: CompilationTarget {
|
||||
override val name = "c64"
|
||||
override val machine = C64MachineDefinition
|
||||
override fun encodeString(str: String, altEncoding: Boolean) =
|
||||
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
|
||||
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
|
||||
if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
||||
override fun asmGenerator(program: Program, errors: ErrorReporter, zp: Zeropage, options: CompilationOptions, path: Path) =
|
||||
AsmGen(program, errors, zp, options, path)
|
||||
override val asmForSystemReset = " sei | lda #14 | sta $1 | jmp (c64.RESET_VEC)"
|
||||
override val initProcName = "c64.init_system"
|
||||
}
|
||||
|
||||
internal object Cx16Target: CompilationTarget {
|
||||
override val name = "cx16"
|
||||
override val machine = CX16MachineDefinition
|
||||
override fun encodeString(str: String, altEncoding: Boolean) =
|
||||
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
|
||||
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
|
||||
if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
||||
override fun asmGenerator(program: Program, errors: ErrorReporter, zp: Zeropage, options: CompilationOptions, path: Path) =
|
||||
AsmGen(program, errors, zp, options, path)
|
||||
override val asmForSystemReset = " sei | stz cx16.d1prb | jmp (cx16.RESET_VEC)"
|
||||
override val initProcName = "cx16.init_system"
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ internal interface IMachineDefinition {
|
||||
|
||||
val opcodeNames: Set<String>
|
||||
var zeropage: Zeropage
|
||||
val initSystemProcname: String
|
||||
val cpu: CpuType
|
||||
|
||||
fun initializeZeropage(compilerOptions: CompilationOptions)
|
||||
|
@ -2,6 +2,7 @@ package prog8.compiler.target.c64
|
||||
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.OutputType
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.compiler.target.IAssemblyProgram
|
||||
import prog8.compiler.target.generatedLabelPrefix
|
||||
import java.nio.file.Path
|
||||
@ -22,12 +23,12 @@ class AssemblyProgram(override val name: String, outputDir: Path) : IAssemblyPro
|
||||
val outFile = when (options.output) {
|
||||
OutputType.PRG -> {
|
||||
command.add("--cbm-prg")
|
||||
println("\nCreating prg.")
|
||||
println("\nCreating prg for target ${CompilationTarget.instance.name}.")
|
||||
prgFile
|
||||
}
|
||||
OutputType.RAW -> {
|
||||
command.add("--nostart")
|
||||
println("\nCreating raw binary.")
|
||||
println("\nCreating raw binary for target ${CompilationTarget.instance.name}.")
|
||||
binFile
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ internal object C64MachineDefinition: IMachineDefinition {
|
||||
override val ESTACK_HI = 0xcf00 // $ce00-$ceff inclusive
|
||||
|
||||
override lateinit var zeropage: Zeropage
|
||||
override val initSystemProcname = "c64.init_system"
|
||||
|
||||
override fun getFloat(num: Number) = Mflpt5.fromNumber(num)
|
||||
|
||||
@ -109,7 +108,6 @@ internal object C64MachineDefinition: IMachineDefinition {
|
||||
|
||||
override val SCRATCH_B1 = 0x02 // temp storage for a single byte
|
||||
override val SCRATCH_REG = 0x03 // temp storage for a register
|
||||
override val SCRATCH_REG_X = 0xfa // temp storage for register X (the evaluation stack pointer)
|
||||
override val SCRATCH_W1 = 0xfb // temp storage 1 for a word $fb+$fc
|
||||
override val SCRATCH_W2 = 0xfd // temp storage 2 for a word $fb+$fc
|
||||
|
||||
@ -127,7 +125,7 @@ internal object C64MachineDefinition: IMachineDefinition {
|
||||
if (options.zeropage == ZeropageType.FULL) {
|
||||
free.addAll(0x04..0xf9)
|
||||
free.add(0xff)
|
||||
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||
free.removeAll(listOf(0xa0, 0xa1, 0xa2, 0x91, 0xc0, 0xc5, 0xcb, 0xf5, 0xf6)) // these are updated by IRQ
|
||||
} else {
|
||||
if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
|
||||
@ -170,7 +168,6 @@ internal object C64MachineDefinition: IMachineDefinition {
|
||||
}
|
||||
require(SCRATCH_B1 !in free)
|
||||
require(SCRATCH_REG !in free)
|
||||
require(SCRATCH_REG_X !in free)
|
||||
require(SCRATCH_W1 !in free)
|
||||
require(SCRATCH_W2 !in free)
|
||||
|
||||
|
@ -35,6 +35,10 @@ internal class AsmGen(private val program: Program,
|
||||
val options: CompilationOptions,
|
||||
private val outputDir: Path): IAssemblyGenerator {
|
||||
|
||||
// for expressions and augmented assignments:
|
||||
val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40,50,80,100)
|
||||
val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100)
|
||||
|
||||
private val assemblyLines = mutableListOf<String>()
|
||||
private val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
|
||||
private val allocatedZeropageVariables = mutableMapOf<String, Pair<Int, DataType>>()
|
||||
@ -79,7 +83,7 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
private fun header() {
|
||||
val ourName = this.javaClass.name
|
||||
val cpu = when(CompilationTarget.machine.cpu) {
|
||||
val cpu = when(CompilationTarget.instance.machine.cpu) {
|
||||
CpuType.CPU6502 -> "6502"
|
||||
CpuType.CPU65c02 -> "65c02"
|
||||
else -> "unsupported"
|
||||
@ -94,18 +98,16 @@ internal class AsmGen(private val program: Program,
|
||||
program.actualLoadAddress = program.definedLoadAddress
|
||||
if (program.actualLoadAddress == 0) // fix load address
|
||||
program.actualLoadAddress = if (options.launcher == LauncherType.BASIC)
|
||||
CompilationTarget.machine.BASIC_LOAD_ADDRESS else CompilationTarget.machine.RAW_LOAD_ADDRESS
|
||||
CompilationTarget.instance.machine.BASIC_LOAD_ADDRESS else CompilationTarget.instance.machine.RAW_LOAD_ADDRESS
|
||||
|
||||
// the global prog8 variables needed
|
||||
val zp = CompilationTarget.machine.zeropage
|
||||
val initproc = CompilationTarget.machine.initSystemProcname
|
||||
val zp = CompilationTarget.instance.machine.zeropage
|
||||
out("P8ZP_SCRATCH_B1 = ${zp.SCRATCH_B1}")
|
||||
out("P8ZP_SCRATCH_REG = ${zp.SCRATCH_REG}")
|
||||
out("P8ZP_SCRATCH_REG_X = ${zp.SCRATCH_REG_X}")
|
||||
out("P8ZP_SCRATCH_W1 = ${zp.SCRATCH_W1} ; word")
|
||||
out("P8ZP_SCRATCH_W2 = ${zp.SCRATCH_W2} ; word")
|
||||
out("P8ESTACK_LO = ${CompilationTarget.machine.ESTACK_LO.toHex()}")
|
||||
out("P8ESTACK_HI = ${CompilationTarget.machine.ESTACK_HI.toHex()}")
|
||||
out("P8ESTACK_LO = ${CompilationTarget.instance.machine.ESTACK_LO.toHex()}")
|
||||
out("P8ESTACK_HI = ${CompilationTarget.instance.machine.ESTACK_HI.toHex()}")
|
||||
|
||||
when {
|
||||
options.launcher == LauncherType.BASIC -> {
|
||||
@ -120,16 +122,16 @@ internal class AsmGen(private val program: Program,
|
||||
out("_prog8_entrypoint\t; assembly code starts here\n")
|
||||
out(" tsx")
|
||||
out(" stx prog8_lib.orig_stackpointer")
|
||||
if(!initproc.isNullOrEmpty())
|
||||
out(" jsr $initproc")
|
||||
if(!CompilationTarget.instance.initProcName.isNullOrEmpty())
|
||||
out(" jsr ${CompilationTarget.instance.initProcName}")
|
||||
}
|
||||
options.output == OutputType.PRG -> {
|
||||
out("; ---- program without basic sys call ----")
|
||||
out("* = ${program.actualLoadAddress.toHex()}\n")
|
||||
out(" tsx")
|
||||
out(" stx prog8_lib.orig_stackpointer")
|
||||
if(!initproc.isNullOrEmpty())
|
||||
out(" jsr $initproc")
|
||||
if(!CompilationTarget.instance.initProcName.isNullOrEmpty())
|
||||
out(" jsr ${CompilationTarget.instance.initProcName}")
|
||||
}
|
||||
options.output == OutputType.RAW -> {
|
||||
out("; ---- raw assembler program ----")
|
||||
@ -161,7 +163,7 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
Zeropage.ExitProgramStrategy.SYSTEM_RESET -> {
|
||||
out(" jsr main.start\t; call program entrypoint")
|
||||
out(" jmp (c64.RESET_VEC)\t; cold reset")
|
||||
out(CompilationTarget.instance.asmForSystemReset)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,7 +172,7 @@ internal class AsmGen(private val program: Program,
|
||||
// the global list of all floating point constants for the whole program
|
||||
out("; global float constants")
|
||||
for (flt in globalFloatConsts) {
|
||||
val floatFill = CompilationTarget.machine.getFloat(flt.key).makeFloatFillAsm()
|
||||
val floatFill = CompilationTarget.instance.machine.getFloat(flt.key).makeFloatFillAsm()
|
||||
val floatvalue = flt.key
|
||||
out("${flt.value}\t.byte $floatFill ; float $floatvalue")
|
||||
}
|
||||
@ -340,7 +342,7 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
val floatFills = array.map {
|
||||
val number = (it as NumericLiteralValue).number
|
||||
CompilationTarget.machine.getFloat(number).makeFloatFillAsm()
|
||||
CompilationTarget.instance.machine.getFloat(number).makeFloatFillAsm()
|
||||
}
|
||||
out(name)
|
||||
for (f in array.zip(floatFills))
|
||||
@ -474,7 +476,7 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
|
||||
internal fun getFloatAsmConst(number: Double): String {
|
||||
var asmName = CompilationTarget.machine.getFloatRomConst(number)
|
||||
var asmName = CompilationTarget.instance.machine.getFloatRomConst(number)
|
||||
if(asmName.isNullOrEmpty()) {
|
||||
// no ROM float const for this value, create our own
|
||||
asmName = globalFloatConsts[number]
|
||||
@ -548,16 +550,35 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
internal fun fixNameSymbols(name: String) = name.replace("<", "prog8_").replace(">", "") // take care of the autogenerated invalid (anon) label names
|
||||
|
||||
|
||||
private val saveRegisterLabels = Stack<String>();
|
||||
|
||||
internal fun saveRegister(register: CpuRegister) {
|
||||
when(register) {
|
||||
CpuRegister.A -> out(" pha")
|
||||
CpuRegister.X -> {
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
out(" phx")
|
||||
else
|
||||
out(" stx P8ZP_SCRATCH_REG_X")
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phx")
|
||||
else {
|
||||
val save = makeLabel("saveX")
|
||||
saveRegisterLabels.push(save)
|
||||
out("""
|
||||
stx $save
|
||||
jmp +
|
||||
$save .byte 0
|
||||
+""")
|
||||
}
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phy")
|
||||
else {
|
||||
val save = makeLabel("saveY")
|
||||
out("""
|
||||
sty $save
|
||||
jmp +
|
||||
$save .byte 0
|
||||
+""")
|
||||
}
|
||||
}
|
||||
CpuRegister.Y -> out(" tya | pha")
|
||||
}
|
||||
}
|
||||
|
||||
@ -565,15 +586,23 @@ internal class AsmGen(private val program: Program,
|
||||
when(register) {
|
||||
CpuRegister.A -> out(" pla")
|
||||
CpuRegister.X -> {
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
out(" plx")
|
||||
else
|
||||
out(" ldx P8ZP_SCRATCH_REG_X")
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" plx")
|
||||
else {
|
||||
val save = saveRegisterLabels.pop()
|
||||
out(" ldx $save")
|
||||
}
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" ply")
|
||||
else {
|
||||
val save = saveRegisterLabels.pop()
|
||||
out(" ldy $save")
|
||||
}
|
||||
}
|
||||
CpuRegister.Y -> out(" pla | tay")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun translate(stmt: Statement) {
|
||||
outputSourceLine(stmt)
|
||||
when(stmt) {
|
||||
@ -684,7 +713,7 @@ internal class AsmGen(private val program: Program,
|
||||
+""")
|
||||
when(register) {
|
||||
CpuRegister.A -> out(" inx | lda P8ESTACK_LO,x")
|
||||
CpuRegister.X -> throw AssemblyError("can't use X here")
|
||||
CpuRegister.X -> out(" inx | lda P8ESTACK_LO,x | tax")
|
||||
CpuRegister.Y -> out(" inx | ldy P8ESTACK_LO,x")
|
||||
}
|
||||
}
|
||||
@ -722,7 +751,7 @@ internal class AsmGen(private val program: Program,
|
||||
expressionsAsmGen.translateExpression(index)
|
||||
when(register) {
|
||||
CpuRegister.A -> out(" inx | lda P8ESTACK_LO,x")
|
||||
CpuRegister.X -> throw AssemblyError("can't use X here")
|
||||
CpuRegister.X -> out(" inx | lda P8ESTACK_LO,x | tax")
|
||||
CpuRegister.Y -> out(" inx | ldy P8ESTACK_LO,x")
|
||||
}
|
||||
}
|
||||
@ -792,16 +821,38 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
|
||||
private fun translate(stmt: IfStatement) {
|
||||
expressionsAsmGen.translateExpression(stmt.condition)
|
||||
translateTestStack(stmt.condition.inferType(program).typeOrElse(DataType.STRUCT))
|
||||
val elseLabel = makeLabel("if_else")
|
||||
val endLabel = makeLabel("if_end")
|
||||
out(" beq $elseLabel")
|
||||
translate(stmt.truepart)
|
||||
out(" jmp $endLabel")
|
||||
out(elseLabel)
|
||||
translate(stmt.elsepart)
|
||||
out(endLabel)
|
||||
when {
|
||||
stmt.elsepart.containsNoCodeNorVars() -> {
|
||||
// empty else
|
||||
expressionsAsmGen.translateExpression(stmt.condition)
|
||||
translateTestStack(stmt.condition.inferType(program).typeOrElse(DataType.STRUCT))
|
||||
val endLabel = makeLabel("if_end")
|
||||
out(" beq $endLabel")
|
||||
translate(stmt.truepart)
|
||||
out(endLabel)
|
||||
}
|
||||
stmt.truepart.containsNoCodeNorVars() -> {
|
||||
// empty true part
|
||||
expressionsAsmGen.translateExpression(stmt.condition)
|
||||
translateTestStack(stmt.condition.inferType(program).typeOrElse(DataType.STRUCT))
|
||||
val endLabel = makeLabel("if_end")
|
||||
out(" bne $endLabel")
|
||||
translate(stmt.elsepart)
|
||||
out(endLabel)
|
||||
}
|
||||
else -> {
|
||||
expressionsAsmGen.translateExpression(stmt.condition)
|
||||
translateTestStack(stmt.condition.inferType(program).typeOrElse(DataType.STRUCT))
|
||||
val elseLabel = makeLabel("if_else")
|
||||
val endLabel = makeLabel("if_end")
|
||||
out(" beq $elseLabel")
|
||||
translate(stmt.truepart)
|
||||
out(" jmp $endLabel")
|
||||
out(elseLabel)
|
||||
translate(stmt.elsepart)
|
||||
out(endLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateTestStack(dataType: DataType) {
|
||||
|
@ -47,7 +47,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
||||
RegisterOrPair.X -> {
|
||||
// return value in X register has been discarded, just push a zero
|
||||
if(CompilationTarget.machine.cpu==CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
||||
asmgen.out(" stz P8ESTACK_LO,x")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta P8ESTACK_LO,x")
|
||||
@ -56,7 +56,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
RegisterOrPair.AX -> {
|
||||
// return value in X register has been discarded, just push a zero in this place
|
||||
asmgen.out(" sta P8ESTACK_LO,x")
|
||||
if(CompilationTarget.machine.cpu==CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
||||
asmgen.out(" stz P8ESTACK_HI,x")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta P8ESTACK_HI,x")
|
||||
@ -64,7 +64,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
}
|
||||
RegisterOrPair.XY -> {
|
||||
// return value in X register has been discarded, just push a zero in this place
|
||||
if(CompilationTarget.machine.cpu==CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
||||
asmgen.out(" stz P8ESTACK_LO,x")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta P8ESTACK_LO,x")
|
||||
@ -85,7 +85,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
when(expr.type) {
|
||||
DataType.UBYTE, DataType.BYTE -> {}
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
if(CompilationTarget.machine.cpu==CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
||||
asmgen.out(" stz P8ESTACK_HI+1,x")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x")
|
||||
@ -103,14 +103,9 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
asmgen.out("""
|
||||
lda P8ESTACK_LO+1,x
|
||||
ora #$7f
|
||||
bmi +""")
|
||||
if(CompilationTarget.machine.cpu==CpuType.CPU65c02)
|
||||
asmgen.out("""
|
||||
+ stz P8ESTACK_HI+1,x""")
|
||||
else
|
||||
asmgen.out("""
|
||||
lda #0
|
||||
+ sta P8ESTACK_HI+1,x""")
|
||||
bmi +
|
||||
lda #0
|
||||
+ sta P8ESTACK_HI+1,x""")
|
||||
}
|
||||
DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_b2float")
|
||||
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype")
|
||||
@ -212,9 +207,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
}
|
||||
}
|
||||
|
||||
private val optimizedByteMultiplications = setOf(3,5,6,7,9,10,11,12,13,14,15,20,25,40)
|
||||
private val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40)
|
||||
|
||||
private fun translateExpression(expr: BinaryExpression) {
|
||||
val leftIDt = expr.left.inferType(program)
|
||||
val rightIDt = expr.right.inferType(program)
|
||||
@ -308,40 +300,40 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
val amount = value.number.toInt()
|
||||
when(rightDt) {
|
||||
DataType.UBYTE -> {
|
||||
if(amount in optimizedByteMultiplications) {
|
||||
if(amount in asmgen.optimizedByteMultiplications) {
|
||||
translateExpression(expr.left)
|
||||
asmgen.out(" jsr math.mul_byte_$amount")
|
||||
asmgen.out(" jsr math.stack_mul_byte_$amount")
|
||||
return
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
if(amount in optimizedByteMultiplications) {
|
||||
if(amount in asmgen.optimizedByteMultiplications) {
|
||||
translateExpression(expr.left)
|
||||
asmgen.out(" jsr math.mul_byte_$amount")
|
||||
asmgen.out(" jsr math.stack_mul_byte_$amount")
|
||||
return
|
||||
}
|
||||
if(amount.absoluteValue in optimizedByteMultiplications) {
|
||||
if(amount.absoluteValue in asmgen.optimizedByteMultiplications) {
|
||||
translateExpression(expr.left)
|
||||
asmgen.out(" jsr prog8_lib.neg_b | jsr math.mul_byte_${amount.absoluteValue}")
|
||||
asmgen.out(" jsr prog8_lib.neg_b | jsr math.stack_mul_byte_${amount.absoluteValue}")
|
||||
return
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
if(amount in optimizedWordMultiplications) {
|
||||
if(amount in asmgen.optimizedWordMultiplications) {
|
||||
translateExpression(expr.left)
|
||||
asmgen.out(" jsr math.mul_word_$amount")
|
||||
asmgen.out(" jsr math.stack_mul_word_$amount")
|
||||
return
|
||||
}
|
||||
}
|
||||
DataType.WORD -> {
|
||||
if(amount in optimizedWordMultiplications) {
|
||||
if(amount in asmgen.optimizedWordMultiplications) {
|
||||
translateExpression(expr.left)
|
||||
asmgen.out(" jsr math.mul_word_$amount")
|
||||
asmgen.out(" jsr math.stack_mul_word_$amount")
|
||||
return
|
||||
}
|
||||
if(amount.absoluteValue in optimizedWordMultiplications) {
|
||||
if(amount.absoluteValue in asmgen.optimizedWordMultiplications) {
|
||||
translateExpression(expr.left)
|
||||
asmgen.out(" jsr prog8_lib.neg_w | jsr math.mul_word_${amount.absoluteValue}")
|
||||
asmgen.out(" jsr prog8_lib.neg_w | jsr math.stack_mul_word_${amount.absoluteValue}")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.RegisterOrStatusflag
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.SubroutineParameter
|
||||
import prog8.compiler.AssemblyError
|
||||
@ -18,7 +19,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
|
||||
val saveX = CpuRegister.X in sub.asmClobbers || sub.regXasResult() || sub.regXasParam()
|
||||
if(saveX)
|
||||
asmgen.saveRegister(CpuRegister.X) // we only save X for now (required! is the eval stack pointer), screw A and Y...
|
||||
asmgen.saveRegister(CpuRegister.X)
|
||||
|
||||
val subName = asmgen.asmSymbolName(stmt.target)
|
||||
if(stmt.args.isNotEmpty()) {
|
||||
@ -63,33 +64,79 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
private fun registerArgsViaStackEvaluation(stmt: IFunctionCall, sub: Subroutine) {
|
||||
// this is called when one or more of the arguments are 'complex' and
|
||||
// cannot be assigned to a register easily or risk clobbering other registers.
|
||||
|
||||
if(sub.parameters.isEmpty())
|
||||
return
|
||||
|
||||
// 1. load all arguments reversed onto the stack: first arg goes last (is on top).
|
||||
for (arg in stmt.args.reversed())
|
||||
asmgen.translateExpression(arg)
|
||||
for (regparam in sub.asmParameterRegisters) {
|
||||
|
||||
var argForCarry: IndexedValue<Pair<Expression, RegisterOrStatusflag>>? = null
|
||||
var argForXregister: IndexedValue<Pair<Expression, RegisterOrStatusflag>>? = null
|
||||
var argForAregister: IndexedValue<Pair<Expression, RegisterOrStatusflag>>? = null
|
||||
|
||||
asmgen.out(" inx") // align estack pointer
|
||||
|
||||
for(argi in stmt.args.zip(sub.asmParameterRegisters).withIndex()) {
|
||||
when {
|
||||
regparam.statusflag==Statusflag.Pc -> {
|
||||
asmgen.out("""
|
||||
inx
|
||||
pha
|
||||
lda P8ESTACK_LO,x
|
||||
beq +
|
||||
sec
|
||||
bcs ++
|
||||
+ clc
|
||||
+ pla""")
|
||||
argi.value.second.stack -> TODO("asmsub @stack parameter")
|
||||
argi.value.second.statusflag == Statusflag.Pc -> {
|
||||
require(argForCarry == null)
|
||||
argForCarry = argi
|
||||
}
|
||||
regparam.statusflag!=null -> {
|
||||
throw AssemblyError("can only use Carry as status flag parameter")
|
||||
argi.value.second.statusflag != null -> throw AssemblyError("can only use Carry as status flag parameter")
|
||||
argi.value.second.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) -> {
|
||||
require(argForXregister==null)
|
||||
argForXregister = argi
|
||||
}
|
||||
regparam.registerOrPair!=null -> {
|
||||
val tgt = AsmAssignTarget.fromRegisters(regparam.registerOrPair, program, asmgen)
|
||||
val source = AsmAssignSource(SourceStorageKind.STACK, program, tgt.datatype)
|
||||
val asgn = AsmAssignment(source, tgt, false, Position.DUMMY)
|
||||
asmgen.translateNormalAssignment(asgn)
|
||||
argi.value.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.AY) -> {
|
||||
require(argForAregister == null)
|
||||
argForAregister = argi
|
||||
}
|
||||
else -> {}
|
||||
argi.value.second.registerOrPair == RegisterOrPair.Y -> {
|
||||
asmgen.out(" ldy P8ESTACK_LO+${argi.index},x")
|
||||
}
|
||||
else -> throw AssemblyError("weird argument")
|
||||
}
|
||||
}
|
||||
|
||||
if(argForCarry!=null) {
|
||||
asmgen.out("""
|
||||
lda P8ESTACK_LO+${argForCarry.index},x
|
||||
beq +
|
||||
sec
|
||||
bcs ++
|
||||
+ clc
|
||||
+ php""") // push the status flags
|
||||
}
|
||||
|
||||
if(argForAregister!=null) {
|
||||
when(argForAregister.value.second.registerOrPair) {
|
||||
RegisterOrPair.A -> asmgen.out(" lda P8ESTACK_LO+${argForAregister.index},x")
|
||||
RegisterOrPair.AY -> asmgen.out(" lda P8ESTACK_LO+${argForAregister.index},x | ldy P8ESTACK_HI+${argForAregister.index},x")
|
||||
else -> throw AssemblyError("weird arg")
|
||||
}
|
||||
}
|
||||
|
||||
if(argForXregister!=null) {
|
||||
|
||||
if(argForAregister!=null)
|
||||
asmgen.out(" pha")
|
||||
when(argForXregister.value.second.registerOrPair) {
|
||||
RegisterOrPair.X -> asmgen.out(" lda P8ESTACK_LO+${argForXregister.index},x | tax")
|
||||
RegisterOrPair.AX -> asmgen.out(" ldy P8ESTACK_LO+${argForXregister.index},x | lda P8ESTACK_HI+${argForXregister.index},x | tax | tya")
|
||||
RegisterOrPair.XY -> asmgen.out(" ldy P8ESTACK_HI+${argForXregister.index},x | lda P8ESTACK_LO+${argForXregister.index},x | tax")
|
||||
else -> throw AssemblyError("weird arg")
|
||||
}
|
||||
if(argForAregister!=null)
|
||||
asmgen.out(" pla")
|
||||
} else {
|
||||
repeat(sub.parameters.size - 1) { asmgen.out(" inx") } // unwind stack
|
||||
}
|
||||
|
||||
if(argForCarry!=null)
|
||||
asmgen.out(" plp") // set the carry flag back to correct value
|
||||
}
|
||||
|
||||
private fun argumentViaVariable(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression) {
|
||||
|
@ -159,6 +159,7 @@ internal class AsmAssignment(val source: AsmAssignSource,
|
||||
val position: Position) {
|
||||
|
||||
init {
|
||||
require(source.datatype==target.datatype) {"source and target datatype must be identical"}
|
||||
if(target.register !in setOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY))
|
||||
require(source.datatype.memorySize() == target.datatype.memorySize()) { "source and target datatype must be same storage class" }
|
||||
}
|
||||
}
|
||||
|
@ -120,17 +120,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
is IdentifierReference -> throw AssemblyError("source kind should have been variable")
|
||||
is ArrayIndexedExpression -> throw AssemblyError("source kind should have been array")
|
||||
is DirectMemoryRead -> throw AssemblyError("source kind should have been memory")
|
||||
// is TypecastExpression -> {
|
||||
// if(assign.target.kind == TargetStorageKind.STACK) {
|
||||
// asmgen.translateExpression(value)
|
||||
// assignStackValue(assign.target)
|
||||
// } else {
|
||||
// println("!!!!TYPECAST to ${assign.target.kind} $value")
|
||||
// // TODO maybe we can do the typecast on the target directly instead of on the stack?
|
||||
// asmgen.translateExpression(value)
|
||||
// assignStackValue(assign.target)
|
||||
// }
|
||||
// }
|
||||
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, assign)
|
||||
// is FunctionCall -> {
|
||||
// if (assign.target.kind == TargetStorageKind.STACK) {
|
||||
// asmgen.translateExpression(value)
|
||||
@ -161,6 +151,52 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignTypeCastedValue(target: AsmAssignTarget, targetDt: DataType, value: Expression, origAssign: AsmAssignment) {
|
||||
val valueDt = value.inferType(program).typeOrElse(DataType.STRUCT)
|
||||
when(value) {
|
||||
is IdentifierReference -> {
|
||||
if (valueDt == DataType.UBYTE || valueDt == DataType.BYTE) {
|
||||
if(targetDt in WordDatatypes) {
|
||||
assignVariableByteIntoWord(target, value, valueDt)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
is DirectMemoryRead -> {
|
||||
if(targetDt in WordDatatypes) {
|
||||
if (value.addressExpression is NumericLiteralValue) {
|
||||
val address = (value.addressExpression as NumericLiteralValue).number.toInt()
|
||||
assignMemoryByteIntoWord(target, address, null)
|
||||
return
|
||||
}
|
||||
else if (value.addressExpression is IdentifierReference) {
|
||||
assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
is NumericLiteralValue -> throw AssemblyError("a cast of a literal value should have been const-folded away")
|
||||
else -> {}
|
||||
}
|
||||
|
||||
when(value) {
|
||||
is PrefixExpression -> {}
|
||||
is BinaryExpression -> {}
|
||||
is ArrayIndexedExpression -> {}
|
||||
is TypecastExpression -> {}
|
||||
is RangeExpr -> {}
|
||||
is FunctionCall -> {}
|
||||
else -> {
|
||||
// TODO optimize the others further?
|
||||
println("warning: slow stack evaluation used for typecast: into $targetDt at ${value.position}")
|
||||
}
|
||||
}
|
||||
|
||||
// give up, do it via eval stack
|
||||
asmgen.translateExpression(origAssign.source.expression!!)
|
||||
assignStackValue(target)
|
||||
}
|
||||
|
||||
private fun assignStackValue(target: AsmAssignTarget) {
|
||||
when(target.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
@ -260,16 +296,18 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
when(target.register!!) {
|
||||
RegisterOrPair.A -> asmgen.out(" inx | lda P8ESTACK_LO,x")
|
||||
RegisterOrPair.X -> throw AssemblyError("can't use X here")
|
||||
RegisterOrPair.X -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
|
||||
RegisterOrPair.Y -> asmgen.out(" inx | ldy P8ESTACK_LO,x")
|
||||
else -> throw AssemblyError("can't assign byte to register pair word")
|
||||
RegisterOrPair.AX -> asmgen.out(" inx | lda P8ESTACK_LO,x | ldx #0")
|
||||
RegisterOrPair.AY -> asmgen.out(" inx | lda P8ESTACK_LO,x | ldy #0")
|
||||
else -> throw AssemblyError("can't assign byte from stack to register pair XY")
|
||||
}
|
||||
}
|
||||
DataType.UWORD, DataType.WORD, in PassByReferenceDatatypes -> {
|
||||
when(target.register!!) {
|
||||
RegisterOrPair.AX -> throw AssemblyError("can't use X here")
|
||||
RegisterOrPair.AX -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
|
||||
RegisterOrPair.AY-> asmgen.out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x")
|
||||
RegisterOrPair.XY-> throw AssemblyError("can't use X here")
|
||||
RegisterOrPair.XY-> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
|
||||
else -> throw AssemblyError("can't assign word to single byte register")
|
||||
}
|
||||
}
|
||||
@ -518,6 +556,59 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignVariableByteIntoWord(wordtarget: AsmAssignTarget, bytevar: IdentifierReference, valueDt: DataType) {
|
||||
if(valueDt == DataType.BYTE)
|
||||
TODO("sign extend byte to word")
|
||||
|
||||
val sourceName = asmgen.asmVariableName(bytevar)
|
||||
when(wordtarget.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
asmgen.out("""
|
||||
lda $sourceName
|
||||
sta ${wordtarget.asmVarname}
|
||||
lda #0
|
||||
sta ${wordtarget.asmVarname}+1
|
||||
""")
|
||||
}
|
||||
TargetStorageKind.ARRAY -> {
|
||||
val index = wordtarget.array!!.arrayspec.index
|
||||
when {
|
||||
wordtarget.constArrayIndexValue!=null -> {
|
||||
val scaledIdx = wordtarget.constArrayIndexValue!! * 2
|
||||
asmgen.out(" lda $sourceName | sta ${wordtarget.asmVarname}+$scaledIdx | lda #0 | sta ${wordtarget.asmVarname}+$scaledIdx+1")
|
||||
}
|
||||
index is IdentifierReference -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array, wordtarget.datatype, CpuRegister.Y)
|
||||
asmgen.out(" lda $sourceName | sta ${wordtarget.asmVarname},y | lda #0 | iny | sta ${wordtarget.asmVarname},y")
|
||||
}
|
||||
else -> {
|
||||
asmgen.out(" lda $sourceName | sta P8ESTACK_LO,x | lda #0 | sta P8ESTACK_HI,x | dex")
|
||||
asmgen.translateExpression(index)
|
||||
asmgen.out(" inx | lda P8ESTACK_LO,x")
|
||||
popAndWriteArrayvalueWithUnscaledIndexA(wordtarget.datatype, wordtarget.asmVarname)
|
||||
}
|
||||
}
|
||||
}
|
||||
TargetStorageKind.REGISTER -> {
|
||||
when(wordtarget.register!!) {
|
||||
RegisterOrPair.AX -> asmgen.out(" lda $sourceName | ldx #0")
|
||||
RegisterOrPair.AY -> asmgen.out(" lda $sourceName | ldy #0")
|
||||
RegisterOrPair.XY -> asmgen.out(" ldx $sourceName | ldy #0")
|
||||
else -> throw AssemblyError("only reg pairs are words")
|
||||
}
|
||||
}
|
||||
TargetStorageKind.STACK -> {
|
||||
asmgen.out("""
|
||||
lda #$sourceName
|
||||
sta P8ESTACK_LO,x
|
||||
lda #0
|
||||
sta P8ESTACK_HI,x
|
||||
dex""")
|
||||
}
|
||||
else -> throw AssemblyError("other types aren't word")
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister) {
|
||||
require(target.datatype in ByteDatatypes)
|
||||
when(target.kind) {
|
||||
@ -571,19 +662,25 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
RegisterOrPair.A -> {}
|
||||
RegisterOrPair.X -> { asmgen.out(" tax") }
|
||||
RegisterOrPair.Y -> { asmgen.out(" tay") }
|
||||
else -> throw AssemblyError("attempt to assign byte to register pair word")
|
||||
RegisterOrPair.AY -> { asmgen.out(" ldy #0") }
|
||||
RegisterOrPair.AX -> { asmgen.out(" ldx #0") }
|
||||
RegisterOrPair.XY -> { asmgen.out(" tax | ldy #0") }
|
||||
}
|
||||
CpuRegister.X -> when(target.register!!) {
|
||||
RegisterOrPair.A -> { asmgen.out(" txa") }
|
||||
RegisterOrPair.X -> { }
|
||||
RegisterOrPair.Y -> { asmgen.out(" txy") }
|
||||
else -> throw AssemblyError("attempt to assign byte to register pair word")
|
||||
RegisterOrPair.AY -> { asmgen.out(" txa | ldy #0") }
|
||||
RegisterOrPair.AX -> { asmgen.out(" txa | ldx #0") }
|
||||
RegisterOrPair.XY -> { asmgen.out(" ldy #0") }
|
||||
}
|
||||
CpuRegister.Y -> when(target.register!!) {
|
||||
RegisterOrPair.A -> { asmgen.out(" tya") }
|
||||
RegisterOrPair.X -> { asmgen.out(" tyx") }
|
||||
RegisterOrPair.Y -> { }
|
||||
else -> throw AssemblyError("attempt to assign byte to register pair word")
|
||||
RegisterOrPair.AY -> { asmgen.out(" tya | ldy #0") }
|
||||
RegisterOrPair.AX -> { asmgen.out(" tya | ldx #0") }
|
||||
RegisterOrPair.XY -> { asmgen.out(" tya | tax | ldy #0") }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -692,7 +789,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
RegisterOrPair.A -> asmgen.out(" lda #${byte.toHex()}")
|
||||
RegisterOrPair.X -> asmgen.out(" ldx #${byte.toHex()}")
|
||||
RegisterOrPair.Y -> asmgen.out(" ldy #${byte.toHex()}")
|
||||
else -> throw AssemblyError("can't assign byte to word register apir")
|
||||
RegisterOrPair.AX -> asmgen.out(" lda #${byte.toHex()} | ldx #0")
|
||||
RegisterOrPair.AY -> asmgen.out(" lda #${byte.toHex()} | ldy #0")
|
||||
RegisterOrPair.XY -> asmgen.out(" ldx #${byte.toHex()} | ldy #0")
|
||||
}
|
||||
TargetStorageKind.STACK -> {
|
||||
asmgen.out("""
|
||||
@ -708,7 +807,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
// optimized case for float zero
|
||||
when(target.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
|
||||
asmgen.out("""
|
||||
stz ${target.asmVarname}
|
||||
stz ${target.asmVarname}+1
|
||||
@ -847,7 +946,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
RegisterOrPair.A -> asmgen.out(" lda ${address.toHex()}")
|
||||
RegisterOrPair.X -> asmgen.out(" ldx ${address.toHex()}")
|
||||
RegisterOrPair.Y -> asmgen.out(" ldy ${address.toHex()}")
|
||||
else -> throw AssemblyError("can't assign byte to word register apir")
|
||||
RegisterOrPair.AX -> asmgen.out(" lda ${address.toHex()} | ldx #0")
|
||||
RegisterOrPair.AY -> asmgen.out(" lda ${address.toHex()} | ldy #0")
|
||||
RegisterOrPair.XY -> asmgen.out(" ldy ${address.toHex()} | ldy #0")
|
||||
}
|
||||
TargetStorageKind.STACK -> {
|
||||
asmgen.out("""
|
||||
@ -875,7 +976,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
RegisterOrPair.A -> {}
|
||||
RegisterOrPair.X -> asmgen.out(" tax")
|
||||
RegisterOrPair.Y -> asmgen.out(" tay")
|
||||
else -> throw AssemblyError("can't assign byte to word register apir")
|
||||
RegisterOrPair.AX -> asmgen.out(" ldx #0")
|
||||
RegisterOrPair.AY -> asmgen.out(" ldy #0")
|
||||
RegisterOrPair.XY -> asmgen.out(" tax | ldy #0")
|
||||
}
|
||||
}
|
||||
TargetStorageKind.STACK -> {
|
||||
@ -886,6 +989,63 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignMemoryByteIntoWord(wordtarget: AsmAssignTarget, address: Int?, identifier: IdentifierReference?) {
|
||||
if (address != null) {
|
||||
when(wordtarget.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
asmgen.out("""
|
||||
lda ${address.toHex()}
|
||||
sta ${wordtarget.asmVarname}
|
||||
lda #0
|
||||
sta ${wordtarget.asmVarname}+1
|
||||
""")
|
||||
}
|
||||
TargetStorageKind.ARRAY -> {
|
||||
throw AssemblyError("no asm gen for assign memory byte at $address to array ${wordtarget.asmVarname}")
|
||||
}
|
||||
TargetStorageKind.REGISTER -> when(wordtarget.register!!) {
|
||||
RegisterOrPair.AX -> asmgen.out(" lda ${address.toHex()} | ldx #0")
|
||||
RegisterOrPair.AY -> asmgen.out(" lda ${address.toHex()} | ldy #0")
|
||||
RegisterOrPair.XY -> asmgen.out(" ldy ${address.toHex()} | ldy #0")
|
||||
else -> throw AssemblyError("word regs can only be pair")
|
||||
}
|
||||
TargetStorageKind.STACK -> {
|
||||
asmgen.out("""
|
||||
lda ${address.toHex()}
|
||||
sta P8ESTACK_LO,x
|
||||
lda #0
|
||||
sta P8ESTACK_HI,x
|
||||
dex""")
|
||||
}
|
||||
else -> throw AssemblyError("other types aren't word")
|
||||
}
|
||||
} else if (identifier != null) {
|
||||
when(wordtarget.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
asmgen.loadByteFromPointerIntoA(identifier)
|
||||
asmgen.out(" sta ${wordtarget.asmVarname} | lda #0 | sta ${wordtarget.asmVarname}+1")
|
||||
}
|
||||
TargetStorageKind.ARRAY -> {
|
||||
throw AssemblyError("no asm gen for assign memory byte $identifier to array ${wordtarget.asmVarname} ")
|
||||
}
|
||||
TargetStorageKind.REGISTER -> {
|
||||
asmgen.loadByteFromPointerIntoA(identifier)
|
||||
when(wordtarget.register!!) {
|
||||
RegisterOrPair.AX -> asmgen.out(" ldx #0")
|
||||
RegisterOrPair.AY -> asmgen.out(" ldy #0")
|
||||
RegisterOrPair.XY -> asmgen.out(" tax | ldy #0")
|
||||
else -> throw AssemblyError("word regs can only be pair")
|
||||
}
|
||||
}
|
||||
TargetStorageKind.STACK -> {
|
||||
asmgen.loadByteFromPointerIntoA(identifier)
|
||||
asmgen.out(" sta P8ESTACK_LO,x | lda #0 | sta P8ESTACK_HI,x | dex")
|
||||
}
|
||||
else -> throw AssemblyError("other types aren't word")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeByteViaRegisterAInMemoryAddress(ldaInstructionArg: String, memoryAddress: DirectMemoryWrite) {
|
||||
val addressExpr = memoryAddress.addressExpression
|
||||
val addressLv = addressExpr as? NumericLiteralValue
|
||||
|
@ -8,6 +8,7 @@ import prog8.compiler.target.CompilationTarget
|
||||
import prog8.compiler.target.CpuType
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.compiler.toHex
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
private val assignmentAsmGen: AssignmentAsmGen,
|
||||
@ -22,8 +23,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// A = -A , A = +A, A = ~A, A = not A
|
||||
val type = value.inferType(program).typeOrElse(DataType.STRUCT)
|
||||
when (value.operator) {
|
||||
"+" -> {
|
||||
}
|
||||
"+" -> {}
|
||||
"-" -> inplaceNegate(assign.target, type)
|
||||
"~" -> inplaceInvert(assign.target, type)
|
||||
"not" -> inplaceBooleanNot(assign.target, type)
|
||||
@ -193,7 +193,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
asmgen.translateExpression(memory.addressExpression)
|
||||
// TODO buggy?:
|
||||
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1")
|
||||
val zp = CompilationTarget.machine.zeropage
|
||||
val zp = CompilationTarget.instance.machine.zeropage
|
||||
when {
|
||||
valueLv != null -> inplaceModification_byte_litval_to_variable(zp.SCRATCH_B1.toHex(), DataType.UBYTE, operator, valueLv.toInt())
|
||||
ident != null -> inplaceModification_byte_variable_to_variable(zp.SCRATCH_B1.toHex(), DataType.UBYTE, operator, ident)
|
||||
@ -250,7 +250,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
else
|
||||
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
|
||||
}
|
||||
"*" -> TODO("mul mem byte")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"*" -> {
|
||||
TODO("mul mem byte")// asmgen.out(" jsr prog8_lib.mul_byte")
|
||||
}
|
||||
"/" -> TODO("div mem byte")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("mem byte remainder")
|
||||
@ -309,7 +311,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
else
|
||||
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
|
||||
}
|
||||
"*" -> TODO("mem mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
"*" -> {
|
||||
TODO("mem mul")// asmgen.out(" jsr prog8_lib.mul_byte")
|
||||
}
|
||||
"/" -> TODO("mem div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
"%" -> {
|
||||
TODO("mem byte remainder")
|
||||
@ -367,8 +371,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
|
||||
}
|
||||
"*" -> {
|
||||
TODO("mem mul byte litval")
|
||||
// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
if(value in asmgen.optimizedByteMultiplications) {
|
||||
TODO("optimized mem mul ubyte litval $value")
|
||||
} else {
|
||||
TODO("mem mul ubyte litval $value")
|
||||
// asmgen.out(" jsr prog8_lib.mul_byte")
|
||||
}
|
||||
}
|
||||
"/" -> {
|
||||
if(value==0)
|
||||
@ -443,7 +451,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
"-" -> asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name")
|
||||
"*" -> {
|
||||
TODO("var mul byte expr")
|
||||
// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
// asmgen.out(" jsr prog8_lib.mul_byte")
|
||||
}
|
||||
"/" -> {
|
||||
TODO("var div byte expr")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
|
||||
@ -572,9 +580,21 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
"+" -> asmgen.out(" lda $name | clc | adc #$value | sta $name")
|
||||
"-" -> asmgen.out(" lda $name | sec | sbc #$value | sta $name")
|
||||
"*" -> {
|
||||
// TODO what about the optimized mul_5 etc routines?
|
||||
TODO("var byte mul litval")
|
||||
// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier
|
||||
if(dt == DataType.UBYTE) {
|
||||
if(value in asmgen.optimizedByteMultiplications) {
|
||||
asmgen.out(" lda $name | jsr math.mul_byte_$value | sta $name")
|
||||
} else {
|
||||
TODO("var mul ubyte litval $value")
|
||||
// asmgen.out(" jsr prog8_lib.mul_byte")
|
||||
}
|
||||
} else {
|
||||
if(value.absoluteValue in asmgen.optimizedByteMultiplications) {
|
||||
asmgen.out(" lda $name | jsr math.mul_byte_$value | sta $name")
|
||||
} else {
|
||||
TODO("var mul sbyte litval $value")
|
||||
// asmgen.out(" jsr prog8_lib.mul_byte")
|
||||
}
|
||||
}
|
||||
}
|
||||
"/" -> {
|
||||
if (dt == DataType.UBYTE) {
|
||||
@ -669,19 +689,32 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
"*" -> {
|
||||
// TODO what about the optimized mul_5 etc routines?
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda $name+1
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
lda #<$value
|
||||
ldy #>$value
|
||||
jsr math.multiply_words
|
||||
lda math.multiply_words.result
|
||||
sta $name
|
||||
lda math.multiply_words.result+1
|
||||
sta $name+1""")
|
||||
if(dt == DataType.UWORD){
|
||||
if(value in asmgen.optimizedWordMultiplications) {
|
||||
asmgen.out(" lda $name | ldy $name+1 | jsr math.mul_word_$value | sta $name | sty $name+1")
|
||||
} else {
|
||||
TODO("var uword mul litval $value")
|
||||
}
|
||||
} else {
|
||||
if(value.absoluteValue in asmgen.optimizedWordMultiplications) {
|
||||
asmgen.out(" lda $name | ldy $name+1 | jsr math.mul_word_$value | sta $name | sty $name+1")
|
||||
} else {
|
||||
// TODO don't use stack here
|
||||
// TODO does this work for signed words?
|
||||
asmgen.out("""
|
||||
lda $name
|
||||
sta P8ZP_SCRATCH_W1
|
||||
lda $name+1
|
||||
sta P8ZP_SCRATCH_W1+1
|
||||
lda #<$value
|
||||
ldy #>$value
|
||||
jsr math.multiply_words
|
||||
lda math.multiply_words.result
|
||||
sta $name
|
||||
lda math.multiply_words.result+1
|
||||
sta $name+1""")
|
||||
}
|
||||
}
|
||||
}
|
||||
"/" -> {
|
||||
if(value==0)
|
||||
@ -747,13 +780,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
"&" -> {
|
||||
when {
|
||||
value == 0 -> {
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
|
||||
asmgen.out(" stz $name | stz $name+1")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta $name | sta $name+1")
|
||||
}
|
||||
value and 255 == 0 -> {
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
|
||||
asmgen.out(" stz $name")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta $name")
|
||||
@ -761,7 +794,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
value < 0x0100 -> {
|
||||
asmgen.out(" lda $name | and #$value | sta $name")
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
|
||||
asmgen.out(" stz $name+1")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta $name+1")
|
||||
@ -1088,11 +1121,11 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
// because the value is evaluated onto the eval stack (=slow).
|
||||
println("warning: slow stack evaluation used (2): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
||||
asmgen.translateExpression(value)
|
||||
asmgen.out(" jsr c64flt.pop_float_fac1")
|
||||
asmgen.saveRegister(CpuRegister.X)
|
||||
when (operator) {
|
||||
"**" -> {
|
||||
asmgen.out("""
|
||||
jsr c64flt.pop_float_fac1
|
||||
lda #<$name
|
||||
ldy #>$name
|
||||
jsr c64flt.CONUPK
|
||||
@ -1101,7 +1134,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
"+" -> {
|
||||
asmgen.out("""
|
||||
jsr c64flt.pop_float_fac1
|
||||
lda #<$name
|
||||
ldy #>$name
|
||||
jsr c64flt.FADD
|
||||
@ -1109,7 +1141,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
"-" -> {
|
||||
asmgen.out("""
|
||||
jsr c64flt.pop_float_fac1
|
||||
lda #<$name
|
||||
ldy #>$name
|
||||
jsr c64flt.FSUB
|
||||
@ -1117,7 +1148,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
"*" -> {
|
||||
asmgen.out("""
|
||||
jsr c64flt.pop_float_fac1
|
||||
lda #<$name
|
||||
ldy #>$name
|
||||
jsr c64flt.FMULT
|
||||
@ -1125,7 +1155,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
"/" -> {
|
||||
asmgen.out("""
|
||||
jsr c64flt.pop_float_fac1
|
||||
lda #<$name
|
||||
ldy #>$name
|
||||
jsr c64flt.FDIV
|
||||
@ -1133,7 +1162,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
else -> throw AssemblyError("invalid operator for in-place float modification $operator")
|
||||
}
|
||||
// store Fac1 back into memory
|
||||
asmgen.out("""
|
||||
ldx #<$name
|
||||
ldy #>$name
|
||||
@ -1250,6 +1278,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
""")
|
||||
}
|
||||
"*" -> {
|
||||
// assume that code optimization is already done on the AST level for special cases such as 0, 1, 2...
|
||||
asmgen.out("""
|
||||
lda #<$name
|
||||
ldy #>$name
|
||||
@ -1285,7 +1314,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
private fun inplaceCast(target: AsmAssignTarget, cast: TypecastExpression, position: Position) {
|
||||
val outerCastDt = cast.type
|
||||
val innerCastDt = (cast.expression as? TypecastExpression)?.type
|
||||
|
||||
if (innerCastDt == null) {
|
||||
// simple typecast where the value is the target
|
||||
when (target.datatype) {
|
||||
@ -1295,20 +1323,20 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
when(target.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
|
||||
asmgen.out(" stz ${target.asmVarname}+1")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta ${target.asmVarname}+1")
|
||||
}
|
||||
TargetStorageKind.ARRAY -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, target.datatype, CpuRegister.Y, true)
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
|
||||
asmgen.out(" stz ${target.asmVarname},y")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta ${target.asmVarname},y")
|
||||
}
|
||||
TargetStorageKind.STACK -> {
|
||||
if(CompilationTarget.machine.cpu == CpuType.CPU65c02)
|
||||
if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
|
||||
asmgen.out(" stz P8ESTACK_HI+1,x")
|
||||
else
|
||||
asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x")
|
||||
|
@ -26,7 +26,6 @@ internal object CX16MachineDefinition: IMachineDefinition {
|
||||
override val ESTACK_HI = 0x0500 // $0500-$05ff inclusive
|
||||
|
||||
override lateinit var zeropage: Zeropage
|
||||
override val initSystemProcname = "cx16.init_system"
|
||||
|
||||
override fun getFloat(num: Number) = C64MachineDefinition.Mflpt5.fromNumber(num)
|
||||
|
||||
@ -75,7 +74,6 @@ internal object CX16MachineDefinition: IMachineDefinition {
|
||||
|
||||
override val SCRATCH_B1 = 0x79 // temp storage for a single byte
|
||||
override val SCRATCH_REG = 0x7a // temp storage for a register
|
||||
override val SCRATCH_REG_X = 0x7b // temp storage for register X (the evaluation stack pointer)
|
||||
override val SCRATCH_W1 = 0x7c // temp storage 1 for a word $7c+$7d
|
||||
override val SCRATCH_W2 = 0x7e // temp storage 2 for a word $7e+$7f
|
||||
|
||||
@ -96,16 +94,16 @@ internal object CX16MachineDefinition: IMachineDefinition {
|
||||
when (options.zeropage) {
|
||||
ZeropageType.FULL -> {
|
||||
free.addAll(0x22..0xff)
|
||||
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||
}
|
||||
ZeropageType.KERNALSAFE -> {
|
||||
free.addAll(0x22..0x7f)
|
||||
free.addAll(0xa9..0xff)
|
||||
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||
}
|
||||
ZeropageType.BASICSAFE -> {
|
||||
free.addAll(0x22..0x7f)
|
||||
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||
}
|
||||
ZeropageType.DONTUSE -> {
|
||||
free.clear() // don't use zeropage at all
|
||||
@ -115,7 +113,6 @@ internal object CX16MachineDefinition: IMachineDefinition {
|
||||
|
||||
require(SCRATCH_B1 !in free)
|
||||
require(SCRATCH_REG !in free)
|
||||
require(SCRATCH_REG_X !in free)
|
||||
require(SCRATCH_W1 !in free)
|
||||
require(SCRATCH_W2 !in free)
|
||||
|
||||
|
@ -150,7 +150,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
|
||||
if(rangeExpr==null && litval!=null) {
|
||||
// arraysize initializer is a single int, and we know the size.
|
||||
val fillvalue = litval.number.toDouble()
|
||||
if (fillvalue < CompilationTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > CompilationTarget.machine.FLOAT_MAX_POSITIVE)
|
||||
if (fillvalue < CompilationTarget.instance.machine.FLOAT_MAX_NEGATIVE || fillvalue > CompilationTarget.instance.machine.FLOAT_MAX_POSITIVE)
|
||||
errors.err("float value overflow", litval.position)
|
||||
else {
|
||||
// create the array itself, filled with the fillvalue.
|
||||
|
@ -297,6 +297,49 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
|
||||
if(functionCall.target.nameInSource == listOf("lsb")) {
|
||||
val arg = functionCall.args[0]
|
||||
if(arg is TypecastExpression) {
|
||||
val valueDt = arg.expression.inferType(program)
|
||||
if (valueDt.istype(DataType.BYTE) || valueDt.istype(DataType.UBYTE)) {
|
||||
// useless lsb() of byte value that was casted to word
|
||||
return listOf(IAstModification.ReplaceNode(functionCall, arg.expression, parent))
|
||||
}
|
||||
} else {
|
||||
val argDt = arg.inferType(program)
|
||||
if (argDt.istype(DataType.BYTE) || argDt.istype(DataType.UBYTE)) {
|
||||
// useless lsb() of byte value
|
||||
return listOf(IAstModification.ReplaceNode(functionCall, arg, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(functionCall.target.nameInSource == listOf("msb")) {
|
||||
val arg = functionCall.args[0]
|
||||
if(arg is TypecastExpression) {
|
||||
val valueDt = arg.expression.inferType(program)
|
||||
if (valueDt.istype(DataType.BYTE) || valueDt.istype(DataType.UBYTE)) {
|
||||
// useless msb() of byte value that was casted to word, replace with 0
|
||||
return listOf(IAstModification.ReplaceNode(
|
||||
functionCall,
|
||||
NumericLiteralValue(valueDt.typeOrElse(DataType.UBYTE), 0, arg.expression.position),
|
||||
parent))
|
||||
}
|
||||
} else {
|
||||
val argDt = arg.inferType(program)
|
||||
if (argDt.istype(DataType.BYTE) || argDt.istype(DataType.UBYTE)) {
|
||||
// useless msb() of byte value, replace with 0
|
||||
return listOf(IAstModification.ReplaceNode(
|
||||
functionCall,
|
||||
NumericLiteralValue(argDt.typeOrElse(DataType.UBYTE), 0, arg.position),
|
||||
parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun determineY(x: Expression, subBinExpr: BinaryExpression): Expression? {
|
||||
return when {
|
||||
subBinExpr.left isSameAs x -> subBinExpr.right
|
||||
|
@ -104,7 +104,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
if(string!=null) {
|
||||
val pos = functionCallStatement.position
|
||||
if (string.value.length == 1) {
|
||||
val firstCharEncoded = CompilationTarget.encodeString(string.value, string.altEncoding)[0]
|
||||
val firstCharEncoded = CompilationTarget.instance.encodeString(string.value, string.altEncoding)[0]
|
||||
val chrout = FunctionCallStatement(
|
||||
IdentifierReference(listOf("c64", "CHROUT"), pos),
|
||||
mutableListOf(NumericLiteralValue(DataType.UBYTE, firstCharEncoded.toInt(), pos)),
|
||||
@ -112,7 +112,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
)
|
||||
return listOf(IAstModification.ReplaceNode(functionCallStatement, chrout, parent))
|
||||
} else if (string.value.length == 2) {
|
||||
val firstTwoCharsEncoded = CompilationTarget.encodeString(string.value.take(2), string.altEncoding)
|
||||
val firstTwoCharsEncoded = CompilationTarget.instance.encodeString(string.value.take(2), string.altEncoding)
|
||||
val chrout1 = FunctionCallStatement(
|
||||
IdentifierReference(listOf("c64", "CHROUT"), pos),
|
||||
mutableListOf(NumericLiteralValue(DataType.UBYTE, firstTwoCharsEncoded[0].toInt(), pos)),
|
||||
@ -220,7 +220,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
val size = sv.value.length
|
||||
if(size==1) {
|
||||
// loop over string of length 1 -> just assign the single character
|
||||
val character = CompilationTarget.encodeString(sv.value, sv.altEncoding)[0]
|
||||
val character = CompilationTarget.instance.encodeString(sv.value, sv.altEncoding)[0]
|
||||
val byte = NumericLiteralValue(DataType.UBYTE, character, iterable.position)
|
||||
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
||||
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, forLoop.position), byte, forLoop.position))
|
||||
|
@ -129,7 +129,7 @@ class TestC64Zeropage {
|
||||
|
||||
@Test
|
||||
fun testNames() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false))
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, "c64"))
|
||||
|
||||
zp.allocate("", DataType.UBYTE, null, errors)
|
||||
zp.allocate("", DataType.UBYTE, null, errors)
|
||||
@ -142,37 +142,37 @@ class TestC64Zeropage {
|
||||
|
||||
@Test
|
||||
fun testZpFloatEnable() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
|
||||
assertFailsWith<CompilerException> {
|
||||
zp.allocate("", DataType.FLOAT, null, errors)
|
||||
}
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true))
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), true, "c64"))
|
||||
assertFailsWith<CompilerException> {
|
||||
zp2.allocate("", DataType.FLOAT, null, errors)
|
||||
}
|
||||
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true))
|
||||
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, "c64"))
|
||||
zp3.allocate("", DataType.FLOAT, null, errors)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testZpModesWithFloats() {
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, "c64"))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, "c64"))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, "c64"))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, "c64"))
|
||||
assertFailsWith<CompilerException> {
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), true, "c64"))
|
||||
}
|
||||
assertFailsWith<CompilerException> {
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true))
|
||||
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true, "c64"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testZpDontuse() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false))
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, "c64"))
|
||||
println(zp.free)
|
||||
assertEquals(0, zp.available())
|
||||
assertFailsWith<CompilerException> {
|
||||
@ -182,19 +182,19 @@ class TestC64Zeropage {
|
||||
|
||||
@Test
|
||||
fun testFreeSpaces() {
|
||||
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
|
||||
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
|
||||
assertEquals(16, zp1.available())
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false))
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, "c64"))
|
||||
assertEquals(91, zp2.available())
|
||||
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false))
|
||||
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, "c64"))
|
||||
assertEquals(125, zp3.available())
|
||||
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
|
||||
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
|
||||
assertEquals(238, zp4.available())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReservedSpace() {
|
||||
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
|
||||
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
|
||||
assertEquals(238, zp1.available())
|
||||
assertTrue(50 in zp1.free)
|
||||
assertTrue(100 in zp1.free)
|
||||
@ -203,7 +203,7 @@ class TestC64Zeropage {
|
||||
assertTrue(200 in zp1.free)
|
||||
assertTrue(255 in zp1.free)
|
||||
assertTrue(199 in zp1.free)
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false))
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false, "c64"))
|
||||
assertEquals(139, zp2.available())
|
||||
assertFalse(50 in zp2.free)
|
||||
assertFalse(100 in zp2.free)
|
||||
@ -216,7 +216,7 @@ class TestC64Zeropage {
|
||||
|
||||
@Test
|
||||
fun testBasicsafeAllocation() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
|
||||
assertEquals(16, zp.available())
|
||||
|
||||
assertFailsWith<ZeropageDepletedError> {
|
||||
@ -239,7 +239,7 @@ class TestC64Zeropage {
|
||||
|
||||
@Test
|
||||
fun testFullAllocation() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false))
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
|
||||
assertEquals(238, zp.available())
|
||||
val loc = zp.allocate("", DataType.UWORD, null, errors)
|
||||
assertTrue(loc > 3)
|
||||
@ -269,7 +269,7 @@ class TestC64Zeropage {
|
||||
|
||||
@Test
|
||||
fun testEfficientAllocation() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true))
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
|
||||
assertEquals(16, zp.available())
|
||||
assertEquals(0x04, zp.allocate("", DataType.WORD, null, errors))
|
||||
assertEquals(0x06, zp.allocate("", DataType.UBYTE, null, errors))
|
||||
|
@ -33,6 +33,14 @@ This makes it easier to understand and relate the generated code. Examples::
|
||||
Directives
|
||||
-----------
|
||||
|
||||
.. data:: %target <target>
|
||||
|
||||
Level: module.
|
||||
Global setting, selects a compilation target from within the source file.
|
||||
The default compilation target is "c64" which targets the Commodore-64 machine.
|
||||
You can also omit this and use the ``-target`` command line option.
|
||||
|
||||
|
||||
.. data:: %output <type>
|
||||
|
||||
Level: module.
|
||||
@ -514,18 +522,20 @@ and returning stuff in several registers as well. The ``clobbers`` clause is use
|
||||
what CPU registers are clobbered by the call instead of being unchanged or returning a meaningful result value.
|
||||
|
||||
|
||||
Subroutines that are implemented purely in assembly code and which have an assembly calling convention (i.e.
|
||||
the parameters are strictly passed via cpu registers), are defined like this::
|
||||
User subroutines in the program source code that are implemented purely in assembly and which have an assembly calling convention (i.e.
|
||||
the parameters are strictly passed via cpu registers), are defined with ``asmsub`` like this::
|
||||
|
||||
asmsub FREADS32() clobbers(A,X,Y) {
|
||||
asmsub clear_screenchars (ubyte char @ A) clobbers(Y) {
|
||||
%asm {{
|
||||
lda $62
|
||||
eor #$ff
|
||||
asl a
|
||||
lda #0
|
||||
ldx #$a0
|
||||
jmp $bc4f
|
||||
}}
|
||||
ldy #0
|
||||
_loop sta c64.Screen,y
|
||||
sta c64.Screen+$0100,y
|
||||
sta c64.Screen+$0200,y
|
||||
sta c64.Screen+$02e8,y
|
||||
iny
|
||||
bne _loop
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
the statement body of such a subroutine should consist of just an inline assembly block.
|
||||
|
@ -2,12 +2,15 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- optimize assignment codegeneration
|
||||
- get rid of all TODO's ;-)
|
||||
- get rid of all other TODO's in the code ;-)
|
||||
- line-circle-gfx examples are now a few hundred bytes larger than before. Why is that, can it be fixed?
|
||||
- compiler errors and warnings in standard format so the IDE shows them as clickable links; ./test.asm:2578:3: blablabla
|
||||
- further optimize assignment codegeneration
|
||||
- auto select correct library to import based on target, instead of having c64- and cx16- prefix variants
|
||||
- implement @stack for asmsub parameters
|
||||
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
|
||||
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
|
||||
- aliases for imported symbols for example perhaps '%alias print = c64scr.print' ?
|
||||
- investigate support for 8bitguy's Commander X16 platform https://www.commanderx16.com and https://github.com/commanderx16/x16-docs
|
||||
- see if we can group some errors together for instance the (now single) errors about unidentified symbols
|
||||
|
||||
|
||||
|
@ -57,7 +57,7 @@ main {
|
||||
float Azy = cosb*sinc
|
||||
float Azz = cosb*cosc
|
||||
|
||||
ubyte i
|
||||
ubyte @zp i
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
|
||||
rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*zcoor[i]
|
||||
@ -69,7 +69,7 @@ main {
|
||||
|
||||
; plot the points of the 3d cube
|
||||
; first the points on the back, then the points on the front (painter algorithm)
|
||||
ubyte i
|
||||
ubyte @zp i
|
||||
float rz
|
||||
float persp
|
||||
ubyte sx
|
||||
|
@ -1,12 +1,8 @@
|
||||
%import c64lib
|
||||
%import c64graphics
|
||||
|
||||
|
||||
main {
|
||||
|
||||
const uword width = 255
|
||||
const uword height = 200
|
||||
|
||||
; vertices
|
||||
word[] xcoor = [ -100, -100, -100, -100, 100, 100, 100, 100 ]
|
||||
word[] ycoor = [ -100, -100, 100, 100, -100, -100, 100, 100 ]
|
||||
@ -69,7 +65,7 @@ main {
|
||||
word Azy = wcosb*wsinc / 128
|
||||
word Azz = wcosb*wcosc / 128
|
||||
|
||||
ubyte i
|
||||
ubyte @zp i
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
; don't normalize by dividing by 128, instead keep some precision for perspective calc later
|
||||
rotatedx[i] = (Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i])
|
||||
@ -78,17 +74,21 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
const uword screen_width = 320
|
||||
const ubyte screen_height = 200
|
||||
|
||||
|
||||
sub draw_lines() {
|
||||
ubyte i
|
||||
ubyte @zp i
|
||||
for i in len(edgesFrom) -1 downto 0 {
|
||||
ubyte vFrom = edgesFrom[i]
|
||||
ubyte vTo = edgesTo[i]
|
||||
word persp1 = 256 + rotatedz[vFrom]/256
|
||||
word persp2 = 256 + rotatedz[vTo]/256
|
||||
graphics.line(rotatedx[vFrom] / persp1 + 160.w as uword,
|
||||
rotatedy[vFrom] / persp1 + 100 as ubyte,
|
||||
rotatedx[vTo] / persp2 + 160.w as uword,
|
||||
rotatedy[vTo] / persp2 + 100 as ubyte)
|
||||
ubyte @zp vFrom = edgesFrom[i]
|
||||
ubyte @zp vTo = edgesTo[i] ; TODO need compiler error for double declaration if also declared outside the for loop!
|
||||
word @zp persp1 = 256 + rotatedz[vFrom]/256
|
||||
word @zp persp2 = 256 + rotatedz[vTo]/256
|
||||
graphics.line(rotatedx[vFrom] / persp1 + screen_width/2 as uword,
|
||||
rotatedy[vFrom] / persp1 + screen_height/2 as ubyte,
|
||||
rotatedx[vTo] / persp2 + screen_width/2 as uword,
|
||||
rotatedy[vTo] / persp2 + screen_height/2 as ubyte)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ main {
|
||||
word Azy = wcosb*wsinc / 128
|
||||
word Azz = wcosb*wcosc / 128
|
||||
|
||||
ubyte i
|
||||
ubyte @zp i
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
; don't normalize by dividing by 128, instead keep some precision for perspective calc later
|
||||
rotatedx[i] = (Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i])
|
||||
@ -138,8 +138,8 @@ main {
|
||||
|
||||
; first sort vertices to sprite order so the back/front order is correct as well
|
||||
; (simple bubble sort as it's only 8 items to sort)
|
||||
ubyte i
|
||||
ubyte i1
|
||||
ubyte @zp i
|
||||
ubyte @zp i1
|
||||
for i in 6 downto 0 {
|
||||
for i1 in 0 to i {
|
||||
ubyte i2 = i1+1
|
||||
@ -154,7 +154,7 @@ main {
|
||||
ubyte[] spritecolors = [1,1,7,15,12,11,9,9]
|
||||
|
||||
for i in 0 to 7 {
|
||||
word zc = rotatedz[i]
|
||||
word @zp zc = rotatedz[i]
|
||||
word persp = 300+zc/256
|
||||
ubyte sx = rotatedx[i] / persp + width/2 as ubyte + 20
|
||||
ubyte sy = rotatedy[i] / persp + height/2 as ubyte + 40
|
||||
|
@ -62,7 +62,7 @@ main {
|
||||
word Azy = wcosb*wsinc / 128
|
||||
word Azz = wcosb*wcosc / 128
|
||||
|
||||
ubyte i
|
||||
ubyte @zp i
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
; don't normalize by dividing by 128, instead keep some precision for perspective calc later
|
||||
rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
|
||||
@ -76,9 +76,9 @@ main {
|
||||
; plot the points of the 3d cube
|
||||
; first the points on the back, then the points on the front (painter algorithm)
|
||||
|
||||
ubyte i
|
||||
word rz
|
||||
word persp
|
||||
ubyte @zp i
|
||||
word @zp rz
|
||||
word @zp persp
|
||||
byte sx
|
||||
byte sy
|
||||
|
||||
|
109
examples/cx16/arithmetic/aggregates.p8
Normal file
109
examples/cx16/arithmetic/aggregates.p8
Normal file
@ -0,0 +1,109 @@
|
||||
%target cx16
|
||||
%import cx16flt
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
ubyte[] ubarr = [100, 0, 99, 199, 22]
|
||||
byte[] barr = [-100, 0, 99, -122, 22]
|
||||
uword[] uwarr = [1000, 0, 222, 4444, 999]
|
||||
word[] warr = [-1000, 0, 999, -4444, 222]
|
||||
float[] farr = [-1000.1, 0, 999.9, -4444.4, 222.2]
|
||||
str name = "irmen"
|
||||
ubyte ub
|
||||
byte bb
|
||||
word ww
|
||||
uword uw
|
||||
float ff
|
||||
|
||||
; LEN/STRLEN
|
||||
ubyte length = len(name)
|
||||
if length!=5 txt.print("error len1\n")
|
||||
length = len(uwarr)
|
||||
if length!=5 txt.print("error len2\n")
|
||||
length=strlen(name)
|
||||
if length!=5 txt.print("error strlen1\n")
|
||||
name[3] = 0
|
||||
length=strlen(name)
|
||||
if length!=3 txt.print("error strlen2\n")
|
||||
|
||||
; MAX
|
||||
ub = max(ubarr)
|
||||
if ub!=199 txt.print("error max1\n")
|
||||
bb = max(barr)
|
||||
if bb!=99 txt.print("error max2\n")
|
||||
uw = max(uwarr)
|
||||
if uw!=4444 txt.print("error max3\n")
|
||||
ww = max(warr)
|
||||
if ww!=999 txt.print("error max4\n")
|
||||
ff = max(farr)
|
||||
if ff!=999.9 txt.print("error max5\n")
|
||||
|
||||
; MIN
|
||||
ub = min(ubarr)
|
||||
if ub!=0 txt.print("error min1\n")
|
||||
bb = min(barr)
|
||||
if bb!=-122 txt.print("error min2\n")
|
||||
uw = min(uwarr)
|
||||
if uw!=0 txt.print("error min3\n")
|
||||
ww = min(warr)
|
||||
if ww!=-4444 txt.print("error min4\n")
|
||||
ff = min(farr)
|
||||
if ff!=-4444.4 txt.print("error min5\n")
|
||||
|
||||
; SUM
|
||||
uw = sum(ubarr)
|
||||
if uw!=420 txt.print("error sum1\n")
|
||||
ww = sum(barr)
|
||||
if ww!=-101 txt.print("error sum2\n")
|
||||
uw = sum(uwarr)
|
||||
if uw!=6665 txt.print("error sum3\n")
|
||||
ww = sum(warr)
|
||||
if ww!=-4223 txt.print("error sum4\n")
|
||||
ff = sum(farr)
|
||||
if ff!=-4222.4 txt.print("error sum5\n")
|
||||
|
||||
; ANY
|
||||
ub = any(ubarr)
|
||||
if ub==0 txt.print("error any1\n")
|
||||
ub = any(barr)
|
||||
if ub==0 txt.print("error any2\n")
|
||||
ub = any(uwarr)
|
||||
if ub==0 txt.print("error any3\n")
|
||||
ub = any(warr)
|
||||
if ub==0 txt.print("error any4\n")
|
||||
ub = any(farr)
|
||||
if ub==0 txt.print("error any5\n")
|
||||
|
||||
; ALL
|
||||
ub = all(ubarr)
|
||||
if ub==1 txt.print("error all1\n")
|
||||
ub = all(barr)
|
||||
if ub==1 txt.print("error all2\n")
|
||||
ub = all(uwarr)
|
||||
if ub==1 txt.print("error all3\n")
|
||||
ub = all(warr)
|
||||
if ub==1 txt.print("error all4\n")
|
||||
ub = all(farr)
|
||||
if ub==1 txt.print("error all5\n")
|
||||
ubarr[1]=$40
|
||||
barr[1]=$40
|
||||
uwarr[1]=$4000
|
||||
warr[1]=$4000
|
||||
farr[1]=1.1
|
||||
ub = all(ubarr)
|
||||
if ub==0 txt.print("error all6\n")
|
||||
ub = all(barr)
|
||||
if ub==0 txt.print("error all7\n")
|
||||
ub = all(uwarr)
|
||||
if ub==0 txt.print("error all8\n")
|
||||
ub = all(warr)
|
||||
if ub==0 txt.print("error all9\n")
|
||||
ub = all(farr)
|
||||
if ub==0 txt.print("error all10\n")
|
||||
|
||||
txt.print("\nyou should see no errors printed above (only at first run).")
|
||||
}
|
||||
}
|
924
examples/cx16/arithmetic/bitshift.p8
Normal file
924
examples/cx16/arithmetic/bitshift.p8
Normal file
@ -0,0 +1,924 @@
|
||||
%target cx16
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
ubyte A
|
||||
|
||||
txt.print("ubyte shift left\n")
|
||||
A = shiftlb0()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb1()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb2()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb3()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb4()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb5()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb6()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb7()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb8()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftlb9()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
txt.print("enter to continue:\n")
|
||||
void c64.CHRIN()
|
||||
|
||||
txt.print("ubyte shift right\n")
|
||||
A = shiftrb0()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb1()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb2()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb3()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb4()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb5()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb6()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb7()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb8()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
A = shiftrb9()
|
||||
txt.print_ubbin(A, true)
|
||||
c64.CHROUT('\n')
|
||||
txt.print("enter to continue:\n")
|
||||
void c64.CHRIN()
|
||||
|
||||
|
||||
|
||||
|
||||
txt.print("signed byte shift left\n")
|
||||
byte signedb
|
||||
signedb = shiftlsb0()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb1()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb2()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb3()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb4()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb5()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb6()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb7()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb8()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftlsb9()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
txt.print("enter to continue:\n")
|
||||
void c64.CHRIN()
|
||||
|
||||
txt.print("signed byte shift right\n")
|
||||
signedb = shiftrsb0()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb1()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb2()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb3()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb4()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb5()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb6()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb7()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb8()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
signedb = shiftrsb9()
|
||||
txt.print_ubbin(signedb as ubyte, true)
|
||||
c64.CHROUT('\n')
|
||||
txt.print("enter to continue:\n")
|
||||
void c64.CHRIN()
|
||||
|
||||
|
||||
|
||||
|
||||
txt.print("uword shift left\n")
|
||||
uword uw
|
||||
uw = shiftluw0()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw1()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw2()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw3()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw4()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw5()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw6()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw7()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw8()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw9()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw10()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw11()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw12()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw13()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw14()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw15()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw16()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftluw17()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
txt.print("enter to continue:\n")
|
||||
void c64.CHRIN()
|
||||
|
||||
txt.print("uword shift right\n")
|
||||
uw = shiftruw0()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw1()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw2()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw3()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw4()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw5()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw6()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw7()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw8()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw9()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw10()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw11()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw12()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw13()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw14()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw15()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw16()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
uw = shiftruw17()
|
||||
txt.print_uwbin(uw, true)
|
||||
c64.CHROUT('\n')
|
||||
txt.print("enter to continue:\n")
|
||||
void c64.CHRIN()
|
||||
|
||||
txt.print("signed word shift left\n")
|
||||
word sw
|
||||
sw = shiftlsw0()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw1()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw2()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw3()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw4()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw5()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw6()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw7()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw8()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw9()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw10()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw11()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw12()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw13()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw14()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw15()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw16()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftlsw17()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
txt.print("enter to continue:\n")
|
||||
void c64.CHRIN()
|
||||
|
||||
txt.print("signed word shift right\n")
|
||||
sw = shiftrsw0()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw1()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw2()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw3()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw4()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw5()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw6()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw7()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw8()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw9()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw10()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw11()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw12()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw13()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw14()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw15()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw16()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
sw = shiftrsw17()
|
||||
txt.print_uwbin(sw as uword, true)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
}
|
||||
|
||||
sub shiftruw0() -> uword {
|
||||
uword q = $a49f
|
||||
return q >> 0
|
||||
}
|
||||
|
||||
sub shiftruw1() -> uword {
|
||||
uword q = $a49f
|
||||
return q >> 1
|
||||
}
|
||||
|
||||
sub shiftruw2() -> uword {
|
||||
uword q = $a49f
|
||||
return q >> 2
|
||||
}
|
||||
|
||||
sub shiftruw3() -> uword {
|
||||
uword q = $a49f
|
||||
return q >> 3
|
||||
}
|
||||
|
||||
sub shiftruw4() -> uword {
|
||||
uword q = $a49f
|
||||
return q >> 4
|
||||
}
|
||||
|
||||
sub shiftruw5() -> uword {
|
||||
uword q = $a49f
|
||||
return q >> 5
|
||||
}
|
||||
|
||||
sub shiftruw6() -> uword {
|
||||
uword q = $a49f
|
||||
return q >> 6
|
||||
}
|
||||
|
||||
sub shiftruw7() -> uword {
|
||||
uword q = $a49f
|
||||
return q >> 7
|
||||
}
|
||||
|
||||
sub shiftruw8() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 8)
|
||||
}
|
||||
|
||||
sub shiftruw9() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 9)
|
||||
}
|
||||
|
||||
sub shiftruw10() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 10)
|
||||
}
|
||||
|
||||
sub shiftruw11() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 11)
|
||||
}
|
||||
|
||||
sub shiftruw12() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 12)
|
||||
}
|
||||
|
||||
sub shiftruw13() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 13)
|
||||
}
|
||||
|
||||
sub shiftruw14() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 14)
|
||||
}
|
||||
|
||||
sub shiftruw15() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 15)
|
||||
}
|
||||
|
||||
sub shiftruw16() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 16)
|
||||
}
|
||||
|
||||
sub shiftruw17() -> uword {
|
||||
uword q = $a49f
|
||||
return (q >> 17)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sub shiftrsw0() -> word {
|
||||
word q = -12345
|
||||
return q >> 0
|
||||
}
|
||||
|
||||
sub shiftrsw1() -> word {
|
||||
word q = -12345
|
||||
return q >> 1
|
||||
}
|
||||
|
||||
sub shiftrsw2() -> word {
|
||||
word q = -12345
|
||||
return q >> 2
|
||||
}
|
||||
|
||||
sub shiftrsw3() -> word {
|
||||
word q = -12345
|
||||
return q >> 3
|
||||
}
|
||||
|
||||
sub shiftrsw4() -> word {
|
||||
word q = -12345
|
||||
return q >> 4
|
||||
}
|
||||
|
||||
sub shiftrsw5() -> word {
|
||||
word q = -12345
|
||||
return q >> 5
|
||||
}
|
||||
|
||||
sub shiftrsw6() -> word {
|
||||
word q = -12345
|
||||
return q >> 6
|
||||
}
|
||||
|
||||
sub shiftrsw7() -> word {
|
||||
word q = -12345
|
||||
return q >> 7
|
||||
}
|
||||
|
||||
sub shiftrsw8() -> word {
|
||||
word q = -12345
|
||||
return (q >> 8)
|
||||
}
|
||||
|
||||
sub shiftrsw9() -> word {
|
||||
word q = -12345
|
||||
return (q >> 9)
|
||||
}
|
||||
|
||||
sub shiftrsw10() -> word {
|
||||
word q = -12345
|
||||
return (q >> 10)
|
||||
}
|
||||
|
||||
sub shiftrsw11() -> word {
|
||||
word q = -12345
|
||||
return (q >> 11)
|
||||
}
|
||||
|
||||
sub shiftrsw12() -> word {
|
||||
word q = -12345
|
||||
return (q >> 12)
|
||||
}
|
||||
|
||||
sub shiftrsw13() -> word {
|
||||
word q = -12345
|
||||
return (q >> 13)
|
||||
}
|
||||
|
||||
sub shiftrsw14() -> word {
|
||||
word q = -12345
|
||||
return (q >> 14)
|
||||
}
|
||||
|
||||
sub shiftrsw15() -> word {
|
||||
word q = -12345
|
||||
return (q >> 15)
|
||||
}
|
||||
|
||||
sub shiftrsw16() -> word {
|
||||
word q = -12345
|
||||
return (q >> 16)
|
||||
}
|
||||
|
||||
sub shiftrsw17() -> word {
|
||||
word q = -12345
|
||||
return (q >> 17)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub shiftluw0() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 0
|
||||
}
|
||||
|
||||
sub shiftluw1() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 1
|
||||
}
|
||||
|
||||
sub shiftluw2() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 2
|
||||
}
|
||||
|
||||
sub shiftluw3() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 3
|
||||
}
|
||||
|
||||
sub shiftluw4() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 4
|
||||
}
|
||||
|
||||
sub shiftluw5() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 5
|
||||
}
|
||||
|
||||
sub shiftluw6() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 6
|
||||
}
|
||||
|
||||
sub shiftluw7() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 7
|
||||
}
|
||||
|
||||
sub shiftluw8() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 8
|
||||
}
|
||||
|
||||
sub shiftluw9() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 9
|
||||
}
|
||||
|
||||
sub shiftluw10() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 10
|
||||
}
|
||||
|
||||
sub shiftluw11() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 11
|
||||
}
|
||||
|
||||
sub shiftluw12() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 12
|
||||
}
|
||||
|
||||
sub shiftluw13() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 13
|
||||
}
|
||||
|
||||
sub shiftluw14() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 14
|
||||
}
|
||||
|
||||
sub shiftluw15() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 15
|
||||
}
|
||||
|
||||
sub shiftluw16() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 16
|
||||
}
|
||||
|
||||
sub shiftluw17() -> uword {
|
||||
uword q = $a49f
|
||||
return q << 17
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub shiftlsw0() -> word {
|
||||
word q = -12345
|
||||
return q << 0
|
||||
}
|
||||
|
||||
sub shiftlsw1() -> word {
|
||||
word q = -12345
|
||||
return q << 1
|
||||
}
|
||||
|
||||
sub shiftlsw2() -> word {
|
||||
word q = -12345
|
||||
return q << 2
|
||||
}
|
||||
|
||||
sub shiftlsw3() -> word {
|
||||
word q = -12345
|
||||
return q << 3
|
||||
}
|
||||
|
||||
sub shiftlsw4() -> word {
|
||||
word q = -12345
|
||||
return q << 4
|
||||
}
|
||||
|
||||
sub shiftlsw5() -> word {
|
||||
word q = -12345
|
||||
return q << 5
|
||||
}
|
||||
|
||||
sub shiftlsw6() -> word {
|
||||
word q = -12345
|
||||
return q << 6
|
||||
}
|
||||
|
||||
sub shiftlsw7() -> word {
|
||||
word q = -12345
|
||||
return q << 7
|
||||
}
|
||||
|
||||
sub shiftlsw8() -> word {
|
||||
word q = -12345
|
||||
return q << 8
|
||||
}
|
||||
|
||||
sub shiftlsw9() -> word {
|
||||
word q = -12345
|
||||
return q << 9
|
||||
}
|
||||
|
||||
sub shiftlsw10() -> word {
|
||||
word q = -12345
|
||||
return q << 10
|
||||
}
|
||||
|
||||
sub shiftlsw11() -> word {
|
||||
word q = -12345
|
||||
return q << 11
|
||||
}
|
||||
|
||||
sub shiftlsw12() -> word {
|
||||
word q = -12345
|
||||
return q << 12
|
||||
}
|
||||
|
||||
sub shiftlsw13() -> word {
|
||||
word q = -12345
|
||||
return q << 13
|
||||
}
|
||||
|
||||
sub shiftlsw14() -> word {
|
||||
word q = -12345
|
||||
return q << 14
|
||||
}
|
||||
|
||||
sub shiftlsw15() -> word {
|
||||
word q = -12345
|
||||
return q << 15
|
||||
}
|
||||
|
||||
sub shiftlsw16() -> word {
|
||||
word q = -12345
|
||||
return q << 16
|
||||
}
|
||||
|
||||
sub shiftlsw17() -> word {
|
||||
word q = -12345
|
||||
return q << 17
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub shiftlb0() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 0
|
||||
}
|
||||
sub shiftlb1() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 1
|
||||
}
|
||||
sub shiftlb2() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 2
|
||||
}
|
||||
sub shiftlb3() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 3
|
||||
}
|
||||
sub shiftlb4() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 4
|
||||
}
|
||||
sub shiftlb5() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 5
|
||||
}
|
||||
sub shiftlb6() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 6
|
||||
}
|
||||
sub shiftlb7() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 7
|
||||
}
|
||||
sub shiftlb8() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 8
|
||||
}
|
||||
sub shiftlb9() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy << 9
|
||||
}
|
||||
|
||||
sub shiftrb0() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 0
|
||||
}
|
||||
sub shiftrb1() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 1
|
||||
}
|
||||
sub shiftrb2() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 2
|
||||
}
|
||||
sub shiftrb3() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 3
|
||||
}
|
||||
sub shiftrb4() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 4
|
||||
}
|
||||
sub shiftrb5() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 5
|
||||
}
|
||||
sub shiftrb6() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 6
|
||||
}
|
||||
sub shiftrb7() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 7
|
||||
}
|
||||
sub shiftrb8() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 8
|
||||
}
|
||||
sub shiftrb9() -> ubyte {
|
||||
ubyte yy=$ed
|
||||
return yy >> 9
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub shiftlsb0() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 0
|
||||
}
|
||||
sub shiftlsb1() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 1
|
||||
}
|
||||
sub shiftlsb2() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 2
|
||||
}
|
||||
sub shiftlsb3() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 3
|
||||
}
|
||||
sub shiftlsb4() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 4
|
||||
}
|
||||
sub shiftlsb5() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 5
|
||||
}
|
||||
sub shiftlsb6() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 6
|
||||
}
|
||||
sub shiftlsb7() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 7
|
||||
}
|
||||
sub shiftlsb8() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 8
|
||||
}
|
||||
sub shiftlsb9() -> byte {
|
||||
byte yy=-123
|
||||
return yy << 9
|
||||
}
|
||||
|
||||
sub shiftrsb0() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 0
|
||||
}
|
||||
sub shiftrsb1() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 1
|
||||
}
|
||||
sub shiftrsb2() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 2
|
||||
}
|
||||
sub shiftrsb3() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 3
|
||||
}
|
||||
sub shiftrsb4() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 4
|
||||
}
|
||||
sub shiftrsb5() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 5
|
||||
}
|
||||
sub shiftrsb6() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 6
|
||||
}
|
||||
sub shiftrsb7() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 7
|
||||
}
|
||||
sub shiftrsb8() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 8
|
||||
}
|
||||
sub shiftrsb9() -> byte {
|
||||
byte yy=-123
|
||||
return yy >> 9
|
||||
}
|
||||
}
|
104
examples/cx16/arithmetic/div.p8
Normal file
104
examples/cx16/arithmetic/div.p8
Normal file
@ -0,0 +1,104 @@
|
||||
%target cx16
|
||||
%import cx16flt
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
div_ubyte(0, 1, 0)
|
||||
div_ubyte(100, 6, 16)
|
||||
div_ubyte(255, 2, 127)
|
||||
|
||||
div_byte(0, 1, 0)
|
||||
div_byte(100, -6, -16)
|
||||
div_byte(127, -2, -63)
|
||||
|
||||
div_uword(0,1,0)
|
||||
div_uword(40000,500,80)
|
||||
div_uword(43211,2,21605)
|
||||
|
||||
div_word(0,1,0)
|
||||
div_word(-20000,500,-40)
|
||||
div_word(-2222,2,-1111)
|
||||
|
||||
div_float(0,1,0)
|
||||
div_float(999.9,111.0,9.008108108108107)
|
||||
}
|
||||
|
||||
sub div_ubyte(ubyte a1, ubyte a2, ubyte c) {
|
||||
ubyte r = a1/a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("ubyte ")
|
||||
txt.print_ub(a1)
|
||||
txt.print(" / ")
|
||||
txt.print_ub(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_ub(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub div_byte(byte a1, byte a2, byte c) {
|
||||
byte r = a1/a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("byte ")
|
||||
txt.print_b(a1)
|
||||
txt.print(" / ")
|
||||
txt.print_b(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_b(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub div_uword(uword a1, uword a2, uword c) {
|
||||
uword r = a1/a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("uword ")
|
||||
txt.print_uw(a1)
|
||||
txt.print(" / ")
|
||||
txt.print_uw(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_uw(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub div_word(word a1, word a2, word c) {
|
||||
word r = a1/a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("word ")
|
||||
txt.print_w(a1)
|
||||
txt.print(" / ")
|
||||
txt.print_w(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_w(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub div_float(float a1, float a2, float c) {
|
||||
float r = a1/a2
|
||||
if abs(r-c)<0.00001
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
|
||||
txt.print("float ")
|
||||
c64flt.print_f(a1)
|
||||
txt.print(" / ")
|
||||
c64flt.print_f(a2)
|
||||
txt.print(" = ")
|
||||
c64flt.print_f(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
112
examples/cx16/arithmetic/minus.p8
Normal file
112
examples/cx16/arithmetic/minus.p8
Normal file
@ -0,0 +1,112 @@
|
||||
%target cx16
|
||||
%import cx16flt
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
minus_ubyte(0, 0, 0)
|
||||
minus_ubyte(200, 0, 200)
|
||||
minus_ubyte(200, 100, 100)
|
||||
minus_ubyte(100, 200, 156)
|
||||
|
||||
minus_byte(0, 0, 0)
|
||||
minus_byte(100, 100, 0)
|
||||
minus_byte(50, -50, 100)
|
||||
minus_byte(0, -30, 30)
|
||||
minus_byte(-30, 0, -30)
|
||||
|
||||
minus_uword(0,0,0)
|
||||
minus_uword(50000,0, 50000)
|
||||
minus_uword(50000,20000,30000)
|
||||
minus_uword(20000,50000,35536)
|
||||
|
||||
minus_word(0,0,0)
|
||||
minus_word(1000,1000,0)
|
||||
minus_word(-1000,1000,-2000)
|
||||
minus_word(1000,500,500)
|
||||
minus_word(0,-3333,3333)
|
||||
minus_word(-3333,0,-3333)
|
||||
|
||||
minus_float(0,0,0)
|
||||
minus_float(2.5,1.5,1.0)
|
||||
minus_float(-1.5,3.5,-5.0)
|
||||
}
|
||||
|
||||
sub minus_ubyte(ubyte a1, ubyte a2, ubyte c) {
|
||||
ubyte r = a1-a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("ubyte ")
|
||||
txt.print_ub(a1)
|
||||
txt.print(" - ")
|
||||
txt.print_ub(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_ub(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub minus_byte(byte a1, byte a2, byte c) {
|
||||
byte r = a1-a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("byte ")
|
||||
txt.print_b(a1)
|
||||
txt.print(" - ")
|
||||
txt.print_b(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_b(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub minus_uword(uword a1, uword a2, uword c) {
|
||||
uword r = a1-a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("uword ")
|
||||
txt.print_uw(a1)
|
||||
txt.print(" - ")
|
||||
txt.print_uw(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_uw(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub minus_word(word a1, word a2, word c) {
|
||||
word r = a1-a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("word ")
|
||||
txt.print_w(a1)
|
||||
txt.print(" - ")
|
||||
txt.print_w(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_w(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub minus_float(float a1, float a2, float c) {
|
||||
float r = a1-a2
|
||||
if abs(r-c)<0.00001
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
|
||||
txt.print("float ")
|
||||
c64flt.print_f(a1)
|
||||
txt.print(" - ")
|
||||
c64flt.print_f(a2)
|
||||
txt.print(" = ")
|
||||
c64flt.print_f(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
106
examples/cx16/arithmetic/mult.p8
Normal file
106
examples/cx16/arithmetic/mult.p8
Normal file
@ -0,0 +1,106 @@
|
||||
%target cx16
|
||||
%import cx16flt
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
mul_ubyte(0, 0, 0)
|
||||
mul_ubyte(20, 1, 20)
|
||||
mul_ubyte(20, 10, 200)
|
||||
|
||||
mul_byte(0, 0, 0)
|
||||
mul_byte(10, 10, 100)
|
||||
mul_byte(5, -5, -25)
|
||||
mul_byte(0, -30, 0)
|
||||
|
||||
mul_uword(0,0,0)
|
||||
mul_uword(50000,1, 50000)
|
||||
mul_uword(500,100,50000)
|
||||
|
||||
mul_word(0,0,0)
|
||||
mul_word(-10,1000,-10000)
|
||||
mul_word(1,-3333,-3333)
|
||||
|
||||
mul_float(0,0,0)
|
||||
mul_float(2.5,10,25)
|
||||
mul_float(-1.5,10,-15)
|
||||
}
|
||||
|
||||
sub mul_ubyte(ubyte a1, ubyte a2, ubyte c) {
|
||||
ubyte r = a1*a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("ubyte ")
|
||||
txt.print_ub(a1)
|
||||
txt.print(" * ")
|
||||
txt.print_ub(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_ub(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub mul_byte(byte a1, byte a2, byte c) {
|
||||
byte r = a1*a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("byte ")
|
||||
txt.print_b(a1)
|
||||
txt.print(" * ")
|
||||
txt.print_b(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_b(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub mul_uword(uword a1, uword a2, uword c) {
|
||||
uword r = a1*a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("uword ")
|
||||
txt.print_uw(a1)
|
||||
txt.print(" * ")
|
||||
txt.print_uw(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_uw(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub mul_word(word a1, word a2, word c) {
|
||||
word r = a1*a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("word ")
|
||||
txt.print_w(a1)
|
||||
txt.print(" * ")
|
||||
txt.print_w(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_w(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub mul_float(float a1, float a2, float c) {
|
||||
float r = a1*a2
|
||||
if abs(r-c)<0.00001
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
|
||||
txt.print("float ")
|
||||
c64flt.print_f(a1)
|
||||
txt.print(" * ")
|
||||
c64flt.print_f(a2)
|
||||
txt.print(" = ")
|
||||
c64flt.print_f(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
110
examples/cx16/arithmetic/plus.p8
Normal file
110
examples/cx16/arithmetic/plus.p8
Normal file
@ -0,0 +1,110 @@
|
||||
%target cx16
|
||||
%import cx16flt
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
plus_ubyte(0, 0, 0)
|
||||
plus_ubyte(0, 200, 200)
|
||||
plus_ubyte(100, 200, 44)
|
||||
|
||||
plus_byte(0, 0, 0)
|
||||
plus_byte(-100, 100, 0)
|
||||
plus_byte(-50, 100, 50)
|
||||
plus_byte(0, -30, -30)
|
||||
plus_byte(-30, 0, -30)
|
||||
|
||||
plus_uword(0,0,0)
|
||||
plus_uword(0,50000,50000)
|
||||
plus_uword(50000,20000,4464)
|
||||
|
||||
plus_word(0,0,0)
|
||||
plus_word(-1000,1000,0)
|
||||
plus_word(-500,1000,500)
|
||||
plus_word(0,-3333,-3333)
|
||||
plus_word(-3333,0,-3333)
|
||||
|
||||
plus_float(0,0,0)
|
||||
plus_float(1.5,2.5,4.0)
|
||||
plus_float(-1.5,3.5,2.0)
|
||||
plus_float(-1.1,3.3,2.2)
|
||||
}
|
||||
|
||||
sub plus_ubyte(ubyte a1, ubyte a2, ubyte c) {
|
||||
ubyte r = a1+a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("ubyte ")
|
||||
txt.print_ub(a1)
|
||||
txt.print(" + ")
|
||||
txt.print_ub(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_ub(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub plus_byte(byte a1, byte a2, byte c) {
|
||||
byte r = a1+a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("byte ")
|
||||
txt.print_b(a1)
|
||||
txt.print(" + ")
|
||||
txt.print_b(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_b(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub plus_uword(uword a1, uword a2, uword c) {
|
||||
uword r = a1+a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("uword ")
|
||||
txt.print_uw(a1)
|
||||
txt.print(" + ")
|
||||
txt.print_uw(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_uw(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub plus_word(word a1, word a2, word c) {
|
||||
word r = a1+a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("word ")
|
||||
txt.print_w(a1)
|
||||
txt.print(" + ")
|
||||
txt.print_w(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_w(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub plus_float(float a1, float a2, float c) {
|
||||
float r = a1+a2
|
||||
if abs(r-c)<0.00001
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
|
||||
txt.print("float ")
|
||||
c64flt.print_f(a1)
|
||||
txt.print(" + ")
|
||||
c64flt.print_f(a2)
|
||||
txt.print(" = ")
|
||||
c64flt.print_f(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
141
examples/cx16/arithmetic/postincrdecr.p8
Normal file
141
examples/cx16/arithmetic/postincrdecr.p8
Normal file
@ -0,0 +1,141 @@
|
||||
%target cx16
|
||||
%import cx16flt
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
|
||||
txt.plot(0,24)
|
||||
|
||||
ubyte Y
|
||||
ubyte ub=200
|
||||
byte bb=-100
|
||||
uword uw = 2000
|
||||
word ww = -1000
|
||||
float fl = 999.99
|
||||
ubyte[3] ubarr = 200
|
||||
byte[3] barr = -100
|
||||
uword[3] uwarr = 2000
|
||||
word[3] warr = -1000
|
||||
float[3] flarr = 999.99
|
||||
|
||||
txt.print("++\n")
|
||||
ub++
|
||||
bb++
|
||||
uw++
|
||||
ww++
|
||||
fl++
|
||||
ubarr[1]++
|
||||
barr[1]++
|
||||
uwarr[1]++
|
||||
warr[1]++
|
||||
flarr[1] ++
|
||||
|
||||
check_ub(ub, 201)
|
||||
Y=100
|
||||
Y++
|
||||
check_ub(Y, 101)
|
||||
check_fl(fl, 1000.99)
|
||||
check_b(bb, -99)
|
||||
check_uw(uw, 2001)
|
||||
check_w(ww, -999)
|
||||
check_ub(ubarr[0], 200)
|
||||
check_fl(flarr[0], 999.99)
|
||||
check_b(barr[0], -100)
|
||||
check_uw(uwarr[0], 2000)
|
||||
check_w(warr[0], -1000)
|
||||
check_ub(ubarr[1], 201)
|
||||
check_fl(flarr[1], 1000.99)
|
||||
check_b(barr[1], -99)
|
||||
check_uw(uwarr[1], 2001)
|
||||
check_w(warr[1], -999)
|
||||
|
||||
txt.print("--\n")
|
||||
ub--
|
||||
bb--
|
||||
uw--
|
||||
ww--
|
||||
fl--
|
||||
ubarr[1]--
|
||||
barr[1]--
|
||||
uwarr[1]--
|
||||
warr[1]--
|
||||
flarr[1] --
|
||||
check_ub(ub, 200)
|
||||
|
||||
Y=100
|
||||
Y--
|
||||
check_ub(Y, 99)
|
||||
check_fl(fl, 999.99)
|
||||
check_b(bb, -100)
|
||||
check_uw(uw, 2000)
|
||||
check_w(ww, -1000)
|
||||
check_ub(ubarr[1], 200)
|
||||
check_fl(flarr[1], 999.99)
|
||||
check_b(barr[1], -100)
|
||||
check_uw(uwarr[1], 2000)
|
||||
check_w(warr[1], -1000)
|
||||
}
|
||||
|
||||
sub check_ub(ubyte value, ubyte expected) {
|
||||
if value==expected
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print(" ubyte ")
|
||||
txt.print_ub(value)
|
||||
c64.CHROUT(',')
|
||||
txt.print_ub(expected)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub check_b(byte value, byte expected) {
|
||||
if value==expected
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print(" byte ")
|
||||
txt.print_b(value)
|
||||
c64.CHROUT(',')
|
||||
txt.print_b(expected)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub check_uw(uword value, uword expected) {
|
||||
if value==expected
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print(" uword ")
|
||||
txt.print_uw(value)
|
||||
c64.CHROUT(',')
|
||||
txt.print_uw(expected)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub check_w(word value, word expected) {
|
||||
if value==expected
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print(" word ")
|
||||
txt.print_w(value)
|
||||
c64.CHROUT(',')
|
||||
txt.print_w(expected)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub check_fl(float value, float expected) {
|
||||
if value==expected
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print(" float ")
|
||||
c64flt.print_f(value)
|
||||
c64.CHROUT(',')
|
||||
c64flt.print_f(expected)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
48
examples/cx16/arithmetic/remainder.p8
Normal file
48
examples/cx16/arithmetic/remainder.p8
Normal file
@ -0,0 +1,48 @@
|
||||
%target cx16
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
remainder_ubyte(0, 1, 0)
|
||||
remainder_ubyte(100, 6, 4)
|
||||
remainder_ubyte(255, 2, 1)
|
||||
remainder_ubyte(255, 20, 15)
|
||||
|
||||
remainder_uword(0,1,0)
|
||||
remainder_uword(40000,511,142)
|
||||
remainder_uword(40000,500,0)
|
||||
remainder_uword(43211,12,11)
|
||||
}
|
||||
|
||||
sub remainder_ubyte(ubyte a1, ubyte a2, ubyte c) {
|
||||
ubyte r = a1%a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("ubyte ")
|
||||
txt.print_ub(a1)
|
||||
txt.print(" % ")
|
||||
txt.print_ub(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_ub(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub remainder_uword(uword a1, uword a2, uword c) {
|
||||
uword r = a1%a2
|
||||
if r==c
|
||||
txt.print(" ok ")
|
||||
else
|
||||
txt.print("err! ")
|
||||
txt.print("uword ")
|
||||
txt.print_uw(a1)
|
||||
txt.print(" % ")
|
||||
txt.print_uw(a2)
|
||||
txt.print(" = ")
|
||||
txt.print_uw(r)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
132
examples/cx16/arithmetic/sgn.p8
Normal file
132
examples/cx16/arithmetic/sgn.p8
Normal file
@ -0,0 +1,132 @@
|
||||
%target cx16
|
||||
%import cx16flt
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
byte b1
|
||||
byte b2
|
||||
ubyte ub1
|
||||
ubyte ub2
|
||||
word w1
|
||||
word w2
|
||||
uword uw1
|
||||
uword uw2
|
||||
float f1
|
||||
float f2
|
||||
|
||||
b1 = 10
|
||||
b2 = 10
|
||||
if sgn(b2-b1) != 0
|
||||
txt.print("sgn1 error1\n")
|
||||
|
||||
b1 = -100
|
||||
b2 = -100
|
||||
if sgn(b2-b1) != 0
|
||||
txt.print("sgn1 error2\n")
|
||||
|
||||
ub1 = 200
|
||||
ub2 = 200
|
||||
if sgn(ub2-ub1) != 0
|
||||
txt.print("sgn1 error3\n")
|
||||
|
||||
w1 = 100
|
||||
w2 = 100
|
||||
if sgn(w2-w1) != 0
|
||||
txt.print("sgn1 error4\n")
|
||||
|
||||
w1 = -2000
|
||||
w2 = -2000
|
||||
if sgn(w2-w1) != 0
|
||||
txt.print("sgn1 error5\n")
|
||||
|
||||
uw1 = 999
|
||||
uw2 = 999
|
||||
if sgn(uw2-uw1) != 0
|
||||
txt.print("sgn1 error6\n")
|
||||
|
||||
f1 = 3.45
|
||||
f2 = 3.45
|
||||
if sgn(f2-f1) != 0
|
||||
txt.print("sgn1 error7\n")
|
||||
|
||||
|
||||
; -1
|
||||
b1 = 11
|
||||
b2 = 10
|
||||
if sgn(b2-b1) != -1
|
||||
txt.print("sgn2 error1\n")
|
||||
|
||||
b1 = -10
|
||||
b2 = -100
|
||||
if sgn(b2-b1) != -1
|
||||
txt.print("sgn2 error2\n")
|
||||
|
||||
ub1 = 202
|
||||
ub2 = 200
|
||||
if sgn(ub2 as byte - ub1 as byte) != -1
|
||||
txt.print("sgn2 error3\n")
|
||||
|
||||
w1 = 101
|
||||
w2 = 100
|
||||
if sgn(w2-w1) != -1
|
||||
txt.print("sgn2 error4\n")
|
||||
|
||||
w1 = -200
|
||||
w2 = -2000
|
||||
if sgn(w2-w1) != -1
|
||||
txt.print("sgn2 error5\n")
|
||||
|
||||
uw1 = 2222
|
||||
uw2 = 999
|
||||
if sgn((uw2 as word) - (uw1 as word)) != -1
|
||||
txt.print("sgn2 error6a\n")
|
||||
if sgn(uw2 - uw1) != 1 ; always 0 or 1 if unsigned
|
||||
txt.print("sgn2 error6b\n")
|
||||
|
||||
f1 = 3.45
|
||||
f2 = 1.11
|
||||
if sgn(f2-f1) != -1
|
||||
txt.print("sgn2 error7\n")
|
||||
|
||||
; +1
|
||||
b1 = 11
|
||||
b2 = 20
|
||||
if sgn(b2-b1) != 1
|
||||
txt.print("sgn3 error1\n")
|
||||
|
||||
b1 = -10
|
||||
b2 = -1
|
||||
if sgn(b2-b1) != 1
|
||||
txt.print("sgn3 error2\n")
|
||||
|
||||
ub1 = 202
|
||||
ub2 = 205
|
||||
if sgn(ub2-ub1) != 1
|
||||
txt.print("sgn3 error3\n")
|
||||
|
||||
w1 = 101
|
||||
w2 = 200
|
||||
if sgn(w2-w1) != 1
|
||||
txt.print("sgn3 error4\n")
|
||||
|
||||
w1 = -200
|
||||
w2 = -20
|
||||
if sgn(w2-w1) != 1
|
||||
txt.print("sgn3 error5\n")
|
||||
|
||||
uw1 = 2222
|
||||
uw2 = 9999
|
||||
if sgn(uw2-uw1) != 1
|
||||
txt.print("sgn3 error6\n")
|
||||
|
||||
f1 = 3.45
|
||||
f2 = 5.11
|
||||
if sgn(f2-f1) != 1
|
||||
txt.print("sgn3 error7\n")
|
||||
|
||||
txt.print("should see no sgn errors\n")
|
||||
}
|
||||
}
|
211
examples/cx16/cobramk3-gfx.p8
Normal file
211
examples/cx16/cobramk3-gfx.p8
Normal file
@ -0,0 +1,211 @@
|
||||
%target cx16
|
||||
%import cx16lib
|
||||
%import conv
|
||||
|
||||
main {
|
||||
|
||||
; storage for rotated coordinates
|
||||
word[shipdata.totalNumberOfPoints] rotatedx
|
||||
word[shipdata.totalNumberOfPoints] rotatedy
|
||||
word[shipdata.totalNumberOfPoints] rotatedz
|
||||
|
||||
|
||||
; TODO hidden surface removal - this needs surfaces data and surface normal calculations.
|
||||
; TODO add all other Elite's ships, show their name, advance to next ship on keypress
|
||||
|
||||
sub start() {
|
||||
uword anglex
|
||||
uword angley
|
||||
uword anglez
|
||||
|
||||
void cx16.screen_set_mode($80)
|
||||
cx16.r0 = 0
|
||||
cx16.GRAPH_init()
|
||||
cx16.GRAPH_set_colors(13, 6, 6)
|
||||
cx16.GRAPH_clear()
|
||||
print_ship_name()
|
||||
|
||||
|
||||
repeat {
|
||||
rotate_vertices(msb(anglex), msb(angley), msb(anglez))
|
||||
|
||||
cx16.GRAPH_set_colors(0, 0, 0)
|
||||
cx16.r0 = 32
|
||||
cx16.r1 = 10
|
||||
cx16.r2 = 256
|
||||
cx16.r3 = 185
|
||||
cx16.r4 = 0
|
||||
cx16.GRAPH_draw_rect(true)
|
||||
|
||||
cx16.GRAPH_set_colors(1, 0, 0)
|
||||
draw_lines()
|
||||
|
||||
anglex -= 505
|
||||
angley += 217
|
||||
anglez += 452
|
||||
}
|
||||
}
|
||||
|
||||
sub print_ship_name() {
|
||||
cx16.r0 = 32
|
||||
cx16.r1 = 8
|
||||
ubyte c
|
||||
for c in "ship: "
|
||||
cx16.GRAPH_put_char(c)
|
||||
for c in shipdata.shipName
|
||||
cx16.GRAPH_put_char(c)
|
||||
|
||||
cx16.r0 += 16
|
||||
print_number_gfx(shipdata.totalNumberOfPoints)
|
||||
for c in " vertices, "
|
||||
cx16.GRAPH_put_char(c)
|
||||
print_number_gfx(shipdata.totalNumberOfEdges)
|
||||
for c in " edges, "
|
||||
cx16.GRAPH_put_char(c)
|
||||
print_number_gfx(shipdata.totalNumberOfFaces)
|
||||
for c in " faces"
|
||||
cx16.GRAPH_put_char(c)
|
||||
}
|
||||
|
||||
asmsub print_number_gfx(ubyte num @ A) clobbers(A,Y) {
|
||||
%asm {{
|
||||
phx
|
||||
jsr conv.ubyte2decimal
|
||||
phx
|
||||
pha
|
||||
cpy #'0'
|
||||
beq +
|
||||
tya
|
||||
jsr cx16.GRAPH_put_char
|
||||
pla
|
||||
jsr cx16.GRAPH_put_char
|
||||
jmp _ones
|
||||
+ pla
|
||||
cmp #'0'
|
||||
beq _ones
|
||||
jsr cx16.GRAPH_put_char
|
||||
_ones pla
|
||||
jsr cx16.GRAPH_put_char
|
||||
plx
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
|
||||
; rotate around origin (0,0,0)
|
||||
|
||||
; set up the 3d rotation matrix values
|
||||
word wcosa = cos8(ax)
|
||||
word wsina = sin8(ax)
|
||||
word wcosb = cos8(ay)
|
||||
word wsinb = sin8(ay)
|
||||
word wcosc = cos8(az)
|
||||
word wsinc = sin8(az)
|
||||
|
||||
word wcosa_sinb = wcosa*wsinb / 128
|
||||
word wsina_sinb = wsina*wsinb / 128
|
||||
|
||||
word Axx = wcosa*wcosb / 128
|
||||
word Axy = (wcosa_sinb*wsinc - wsina*wcosc) / 128
|
||||
word Axz = (wcosa_sinb*wcosc + wsina*wsinc) / 128
|
||||
word Ayx = wsina*wcosb / 128
|
||||
word Ayy = (wsina_sinb*wsinc + wcosa*wcosc) / 128
|
||||
word Ayz = (wsina_sinb*wcosc - wcosa*wsinc) / 128
|
||||
word Azx = -wsinb
|
||||
word Azy = wcosb*wsinc / 128
|
||||
word Azz = wcosb*wcosc / 128
|
||||
|
||||
ubyte @zp i
|
||||
for i in 0 to shipdata.totalNumberOfPoints-1 {
|
||||
; don't normalize by dividing by 128, instead keep some precision for perspective calc later
|
||||
rotatedx[i] = Axx*shipdata.xcoor[i] + Axy*shipdata.ycoor[i] + Axz*shipdata.zcoor[i]
|
||||
rotatedy[i] = Ayx*shipdata.xcoor[i] + Ayy*shipdata.ycoor[i] + Ayz*shipdata.zcoor[i]
|
||||
rotatedz[i] = Azx*shipdata.xcoor[i] + Azy*shipdata.ycoor[i] + Azz*shipdata.zcoor[i]
|
||||
}
|
||||
}
|
||||
|
||||
const uword screen_width = 320
|
||||
const ubyte screen_height = 200
|
||||
|
||||
sub draw_lines() {
|
||||
ubyte @zp i
|
||||
for i in shipdata.totalNumberOfEdges -1 downto 0 {
|
||||
ubyte @zp vFrom = shipdata.edgesFrom[i]
|
||||
ubyte @zp vTo = shipdata.edgesTo[i]
|
||||
word persp1 = 200 + rotatedz[vFrom]/256
|
||||
word persp2 = 200 + rotatedz[vTo]/256
|
||||
cx16.r0 = rotatedx[vFrom] / persp1 + screen_width/2 as uword
|
||||
cx16.r1 = rotatedy[vFrom] / persp1 + screen_height/2 as uword
|
||||
cx16.r2 = rotatedx[vTo] / persp2 + screen_width/2 as uword
|
||||
cx16.r3 = rotatedy[vTo] / persp2 + screen_height/2 as uword
|
||||
cx16.GRAPH_draw_line()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shipdata {
|
||||
|
||||
; Ship model data converted from BBC Elite's Cobra MK 3
|
||||
; downloaded from http://www.elitehomepage.org/archive/index.htm
|
||||
|
||||
const ubyte totalNumberOfEdges = 51
|
||||
const ubyte totalNumberOfFaces = 22
|
||||
const ubyte totalNumberOfPoints = 34
|
||||
str shipName = "cobra-mk3"
|
||||
; vertices
|
||||
word[] xcoor = [ 32,-32,0,-120,120,-88,88,128,-128,0,-32,32,-36,-8,8,36,36,8,-8,-36,-1,-1,-80,-80,-88,80,88,80,1,1,1,1,-1,-1 ]
|
||||
word[] ycoor = [ 0,0,26,-3,-3,16,16,-8,-8,26,-24,-24,8,12,12,8,-12,-16,-16,-12,-1,-1,-6,6,0,6,0,-6,-1,-1,1,1,1,1 ]
|
||||
word[] zcoor = [ 76,76,24,-8,-8,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,76,90,-40,-40,-40,-40,-40,-40,76,90,76,90,76,90 ]
|
||||
; edges and faces
|
||||
ubyte[] edgesFrom = [ 0,1,0,10,1,0,2,0,4,0,4,7,2,1,1,3,8,3,2,5,6,5,6,16,15,14,14,18,13,12,12,26,25,25,22,23,22,20,28,21,20,28,29,30,31,30,32,20,21,20,20 ]
|
||||
ubyte[] edgesTo = [ 1,2,2,11,10,11,6,6,6,4,7,11,5,5,3,5,10,8,9,9,9,8,7,17,16,15,17,19,18,13,19,27,26,27,23,24,24,28,29,29,21,30,31,31,33,32,33,32,33,33,29 ]
|
||||
ubyte[] facesPoints = [
|
||||
0,1,2 ,255,
|
||||
11,10,1,0 ,255,
|
||||
0,2,6 ,255,
|
||||
6,4,0 ,255,
|
||||
4,7,11,0 ,255,
|
||||
5,2,1 ,255,
|
||||
1,3,5 ,255,
|
||||
10,8,3,1 ,255,
|
||||
9,2,5 ,255,
|
||||
9,6,2 ,255,
|
||||
3,8,5 ,255,
|
||||
4,6,7 ,255,
|
||||
5,8,10,11,7,6,9 ,255,
|
||||
17,16,15,14 ,255,
|
||||
19,18,13,12 ,255,
|
||||
27,26,25 ,255,
|
||||
22,23,24 ,255,
|
||||
20,28,29,21 ,255,
|
||||
30,28,29,31 ,255,
|
||||
33,31,30,32 ,255,
|
||||
20,32,33,21 ,255,
|
||||
29,31,33,20 ,255
|
||||
]
|
||||
ubyte[] facesEdges = [
|
||||
0,1,2 ,255,
|
||||
3,4,0,5 ,255,
|
||||
2,6,7 ,255,
|
||||
8,9,7 ,255,
|
||||
10,11,5,9 ,255,
|
||||
12,1,13 ,255,
|
||||
14,15,13 ,255,
|
||||
16,17,14,4 ,255,
|
||||
18,12,19 ,255,
|
||||
20,6,18 ,255,
|
||||
17,21,15 ,255,
|
||||
8,22,10 ,255,
|
||||
21,16,3,11,22,20,19 ,255,
|
||||
23,24,25,26 ,255,
|
||||
27,28,29,30 ,255,
|
||||
31,32,33 ,255,
|
||||
34,35,36 ,255,
|
||||
37,38,39,40 ,255,
|
||||
41,38,42,43 ,255,
|
||||
44,43,45,46 ,255,
|
||||
47,46,48,40 ,255,
|
||||
42,44,49,50 ,255
|
||||
]
|
||||
|
||||
}
|
110
examples/cx16/cube3d-float.p8
Normal file
110
examples/cx16/cube3d-float.p8
Normal file
@ -0,0 +1,110 @@
|
||||
%target cx16
|
||||
%import cx16flt
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
const uword width = 80
|
||||
const uword height = 60
|
||||
|
||||
; vertices
|
||||
float[] xcoor = [ -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0 ]
|
||||
float[] ycoor = [ -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0 ]
|
||||
float[] zcoor = [ -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 ]
|
||||
|
||||
; storage for rotated coordinates
|
||||
float[len(xcoor)] rotatedx=0.0
|
||||
float[len(ycoor)] rotatedy=0.0
|
||||
float[len(zcoor)] rotatedz=-1.0
|
||||
|
||||
sub start() {
|
||||
float time=0.0
|
||||
ubyte timer_jiffies
|
||||
|
||||
repeat {
|
||||
rotate_vertices(time)
|
||||
txt.clear_screenchars(' ')
|
||||
draw_edges()
|
||||
time+=0.1
|
||||
|
||||
txt.plot(0,0)
|
||||
txt.print("3d cube! (floating point calc) ")
|
||||
|
||||
%asm {{
|
||||
phx
|
||||
jsr c64.RDTIM ; A/X/Y
|
||||
sta timer_jiffies
|
||||
lda #0
|
||||
jsr c64.SETTIM
|
||||
plx
|
||||
}}
|
||||
txt.print_ub(timer_jiffies)
|
||||
txt.print(" jiffies/fr = ")
|
||||
txt.print_ub(60/timer_jiffies)
|
||||
txt.print(" fps")
|
||||
}
|
||||
}
|
||||
|
||||
sub rotate_vertices(float t) {
|
||||
; rotate around origin (0,0,0)
|
||||
|
||||
; set up the 3d rotation matrix values
|
||||
float cosa = cos(t)
|
||||
float sina = sin(t)
|
||||
float cosb = cos(t*0.33)
|
||||
float sinb = sin(t*0.33)
|
||||
float cosc = cos(t*0.78)
|
||||
float sinc = sin(t*0.78)
|
||||
|
||||
float cosa_sinb = cosa*sinb
|
||||
float sina_sinb = sina*sinb
|
||||
float Axx = cosa*cosb
|
||||
float Axy = cosa_sinb*sinc - sina*cosc
|
||||
float Axz = cosa_sinb*cosc + sina*sinc
|
||||
float Ayx = sina*cosb
|
||||
float Ayy = sina_sinb*sinc + cosa*cosc
|
||||
float Ayz = sina_sinb*cosc - cosa*sinc
|
||||
float Azx = -sinb
|
||||
float Azy = cosb*sinc
|
||||
float Azz = cosb*cosc
|
||||
|
||||
ubyte @zp i
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
|
||||
rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*zcoor[i]
|
||||
rotatedz[i] = Azx*xcoor[i] + Azy*ycoor[i] + Azz*zcoor[i]
|
||||
}
|
||||
}
|
||||
|
||||
sub draw_edges() {
|
||||
|
||||
; plot the points of the 3d cube
|
||||
; first the points on the back, then the points on the front (painter algorithm)
|
||||
ubyte @zp i
|
||||
float rz
|
||||
float persp
|
||||
ubyte sx
|
||||
ubyte sy
|
||||
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
rz = rotatedz[i]
|
||||
if rz >= 0.1 {
|
||||
persp = (5.0+rz)/(height as float)
|
||||
sx = rotatedx[i] / persp + width/2.0 as ubyte
|
||||
sy = rotatedy[i] / persp + height/2.0 as ubyte
|
||||
txt.setcc(sx, sy, 46, 1)
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
rz = rotatedz[i]
|
||||
if rz < 0.1 {
|
||||
persp = (5.0+rz)/(height as float)
|
||||
sx = rotatedx[i] / persp + width/2.0 as ubyte
|
||||
sy = rotatedy[i] / persp + height/2.0 as ubyte
|
||||
txt.setcc(sx, sy, 81, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
100
examples/cx16/cube3d.p8
Normal file
100
examples/cx16/cube3d.p8
Normal file
@ -0,0 +1,100 @@
|
||||
%target cx16
|
||||
%import cx16textio
|
||||
|
||||
main {
|
||||
|
||||
const uword screen_width = 80
|
||||
const uword screen_height = 60
|
||||
|
||||
; vertices
|
||||
word[] xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ]
|
||||
word[] ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ]
|
||||
word[] zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ]
|
||||
|
||||
; storage for rotated coordinates
|
||||
word[len(xcoor)] rotatedx
|
||||
word[len(ycoor)] rotatedy
|
||||
word[len(zcoor)] rotatedz
|
||||
|
||||
sub start() {
|
||||
|
||||
uword anglex
|
||||
uword angley
|
||||
uword anglez
|
||||
ubyte timer_jiffies
|
||||
|
||||
repeat {
|
||||
rotate_vertices(msb(anglex), msb(angley), msb(anglez))
|
||||
txt.clear_screenchars(' ')
|
||||
draw_edges()
|
||||
anglex+=500
|
||||
angley+=215
|
||||
anglez+=453
|
||||
}
|
||||
}
|
||||
|
||||
sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
|
||||
; rotate around origin (0,0,0)
|
||||
|
||||
; set up the 3d rotation matrix values
|
||||
word wcosa = cos8(ax)
|
||||
word wsina = sin8(ax)
|
||||
word wcosb = cos8(ay)
|
||||
word wsinb = sin8(ay)
|
||||
word wcosc = cos8(az)
|
||||
word wsinc = sin8(az)
|
||||
|
||||
word wcosa_sinb = wcosa*wsinb / 128
|
||||
word wsina_sinb = wsina*wsinb / 128
|
||||
|
||||
word Axx = wcosa*wcosb / 128
|
||||
word Axy = (wcosa_sinb*wsinc - wsina*wcosc) / 128
|
||||
word Axz = (wcosa_sinb*wcosc + wsina*wsinc) / 128
|
||||
word Ayx = wsina*wcosb / 128
|
||||
word Ayy = (wsina_sinb*wsinc + wcosa*wcosc) / 128
|
||||
word Ayz = (wsina_sinb*wcosc - wcosa*wsinc) / 128
|
||||
word Azx = -wsinb
|
||||
word Azy = wcosb*wsinc / 128
|
||||
word Azz = wcosb*wcosc / 128
|
||||
|
||||
ubyte @zp i
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
; don't normalize by dividing by 128, instead keep some precision for perspective calc later
|
||||
rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
|
||||
rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*zcoor[i]
|
||||
rotatedz[i] = Azx*xcoor[i] + Azy*ycoor[i] + Azz*zcoor[i]
|
||||
}
|
||||
}
|
||||
|
||||
sub draw_edges() {
|
||||
|
||||
; plot the points of the 3d cube
|
||||
; first the points on the back, then the points on the front (painter algorithm)
|
||||
|
||||
ubyte @zp i
|
||||
word @zp rz
|
||||
word @zp persp
|
||||
byte sx
|
||||
byte sy
|
||||
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
rz = rotatedz[i]
|
||||
if rz >= 10 {
|
||||
persp = 500 + rz/64
|
||||
sx = rotatedx[i] / persp as byte + screen_width/2
|
||||
sy = rotatedy[i] / persp as byte + screen_height/2
|
||||
txt.setcc(sx as ubyte, sy as ubyte, 46, 7)
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
rz = rotatedz[i]
|
||||
if rz < 10 {
|
||||
persp = 500 + rz/64
|
||||
sx = rotatedx[i] / persp as byte + screen_width/2
|
||||
sy = rotatedy[i] / persp as byte + screen_height/2
|
||||
txt.setcc(sx as ubyte, sy as ubyte, 81, 7)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
; CommanderX16 text clock example!
|
||||
; CommanderX16 text datetime example!
|
||||
; make sure to compile with the cx16 compiler target.
|
||||
|
||||
%target cx16
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
||||
@ -8,28 +9,6 @@ main {
|
||||
|
||||
sub start() {
|
||||
|
||||
; %asm {{
|
||||
; lda #$80
|
||||
; jsr cx16.screen_set_mode
|
||||
; }}
|
||||
; cx16.r0=0
|
||||
; cx16.GRAPH_init()
|
||||
; %asm {{
|
||||
; lda #4
|
||||
; ldy #0
|
||||
; ldx #1
|
||||
; jsr cx16.GRAPH_set_colors
|
||||
; }}
|
||||
; cx16.GRAPH_clear()
|
||||
; cx16.r0=10
|
||||
; cx16.r1=10
|
||||
; cx16.r2=100
|
||||
; cx16.r3=150
|
||||
; cx16.GRAPH_draw_line()
|
||||
;
|
||||
; repeat {
|
||||
; }
|
||||
|
||||
cx16.r0 = mkword(8, 2020 - 1900)
|
||||
cx16.r1 = mkword(19, 27)
|
||||
cx16.r2 = mkword(0, 16)
|
@ -1,23 +0,0 @@
|
||||
; CommanderX16 floating point example!
|
||||
; make sure to compile with the cx16 compiler target.
|
||||
|
||||
%import cx16textio
|
||||
%import cx16flt
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
float f1 = 5.55
|
||||
float f2 = 33.3
|
||||
float f3 = f1 * f2
|
||||
|
||||
c64flt.print_f(f1)
|
||||
c64.CHROUT('*')
|
||||
c64flt.print_f(f2)
|
||||
c64.CHROUT('=')
|
||||
c64flt.print_f(f3)
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
%target cx16
|
||||
%import cx16textio
|
||||
%import cx16flt
|
||||
%zeropage basicsafe
|
||||
@ -5,7 +6,7 @@
|
||||
main {
|
||||
const uword width = 256
|
||||
const uword height = 200
|
||||
const ubyte max_iter = 16 ; 32 looks pretty nice
|
||||
const ubyte max_iter = 16 ; 32 actually looks pretty nice but takes longer
|
||||
|
||||
sub start() {
|
||||
initialize()
|
||||
|
@ -1,3 +1,4 @@
|
||||
%target cx16
|
||||
%import cx16textio
|
||||
%import cx16flt
|
||||
%zeropage basicsafe
|
||||
|
@ -1,6 +1,7 @@
|
||||
; CommanderX16 text clock example!
|
||||
; CommanderX16 simple graphics example!
|
||||
; make sure to compile with the cx16 compiler target.
|
||||
|
||||
%target cx16
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
@ -1,3 +1,4 @@
|
||||
%target cx16
|
||||
%import cx16textio
|
||||
%import cx16flt
|
||||
%zeropage basicsafe
|
||||
|
@ -1,3 +1,4 @@
|
||||
%target cx16
|
||||
%import cx16lib
|
||||
%import cx16textio
|
||||
%zeropage basicsafe
|
||||
|
@ -38,9 +38,7 @@ main {
|
||||
}
|
||||
|
||||
if iter & 1
|
||||
; TODO fix plot() so we don't have to use separate internal variable
|
||||
graphics.internal_plotx = pixelx
|
||||
graphics.internal_plot(pixely)
|
||||
graphics.plot(pixelx, pixely)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,9 +385,9 @@ waitkey:
|
||||
}
|
||||
|
||||
sub drawBlock(ubyte x, ubyte y, ubyte character) {
|
||||
ubyte i
|
||||
ubyte @zp i
|
||||
for i in 15 downto 0 {
|
||||
ubyte c=blocklogic.currentBlock[i]
|
||||
ubyte @zp c=blocklogic.currentBlock[i]
|
||||
if c
|
||||
txt.setcc((i&3)+x, (i/4)+y, character, c)
|
||||
}
|
||||
@ -534,7 +534,7 @@ blocklogic {
|
||||
}
|
||||
|
||||
sub noCollision(ubyte xpos, ubyte ypos) -> ubyte {
|
||||
ubyte i
|
||||
ubyte @zp i
|
||||
for i in 15 downto 0 {
|
||||
if currentBlock[i] and txt.getchr(xpos + (i&3), ypos+i/4)!=32
|
||||
return false
|
||||
|
@ -1,8 +1,12 @@
|
||||
%import c64lib
|
||||
%import c64graphics
|
||||
%import c64textio
|
||||
;%import c64flt
|
||||
;%option enable_floats
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
;asmsub clear_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) { ...}
|
||||
; TODO dont cause name conflict if we define sub or sub with param 'color' or even a var 'color' later.
|
||||
@ -10,6 +14,7 @@ main {
|
||||
; sub color(...) {}
|
||||
; sub other(ubyte color) {} ; TODO don't cause name conflict
|
||||
|
||||
c64.CHROUT('\n')
|
||||
|
||||
sub start() {
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ unconditionaljump : 'goto' (integerliteral | scoped_identifier) ;
|
||||
|
||||
directive :
|
||||
directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' |
|
||||
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option')
|
||||
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option' | '%target' )
|
||||
(directivearg? | directivearg (',' directivearg)*)
|
||||
;
|
||||
|
||||
@ -273,7 +273,7 @@ asmsub_decl : identifier '(' asmsub_params? ')' asmsub_clobbers? asmsub_returns?
|
||||
|
||||
asmsub_params : asmsub_param (',' EOL? asmsub_param)* ;
|
||||
|
||||
asmsub_param : vardecl '@' (identifier | stack='stack') ; // A,X,Y,AX,AY,XY,Pc,Pz,Pn,Pv allowed
|
||||
asmsub_param : vardecl '@' identifier ; // A,X,Y,AX,AY,XY,Pc,Pz,Pn,Pv allowed. TODO implement stack='stack'
|
||||
|
||||
asmsub_clobbers : 'clobbers' '(' clobber? ')' ;
|
||||
|
||||
|
Reference in New Issue
Block a user