Compare commits

...

38 Commits
v4.1 ... v4.2

Author SHA1 Message Date
f1ee3b4e60 version 4.2 2020-09-16 23:04:18 +02:00
6395e39d63 avoid generating superfluous '0' variable initializations, and fix erroneous vardecl order shifting 2020-09-16 22:15:06 +02:00
2a6d9d7e31 more optimal codegen for some typecasts 2020-09-15 03:26:57 +02:00
32a7cd31da more optimal codegen for if statements 2020-09-15 00:31:44 +02:00
dd4a56cb5f cx16 safe clobbers for now 2020-09-15 00:14:36 +02:00
d110d1cb5f c64 system reset now banks kernel rom back in 2020-09-15 00:10:20 +02:00
48858019b7 added the last of the optimized mul_word asm routines 2020-09-14 23:54:01 +02:00
aff6b1fca5 added some more optimized mul_word asm routines 2020-09-14 23:03:18 +02:00
d260182ef3 added some more optimized mul_byte asm routines 2020-09-14 22:06:40 +02:00
e39a38b0d9 things 2020-09-13 21:04:51 +02:00
82d7179c92 printf now uses proper zp addressing 2020-09-13 21:01:19 +02:00
f42746ba06 reg_x removal: c64textio and c64lib. last one. 2020-09-13 20:52:29 +02:00
1f69deaccd reg_x removal: c64floats 2020-09-13 20:44:55 +02:00
ea8b7ab193 reg_x removal: math.asm and some others 2020-09-13 20:38:50 +02:00
9938959026 reg_x removal: prog8lib 2020-09-13 20:25:30 +02:00
d5e5485d2e fixed estack X corruption in float augmented assignments 2020-09-13 19:44:03 +02:00
97b9c8f320 don't clobber A when trying to save X at functioncall 2020-09-12 19:04:44 +02:00
35aebbc209 optimize unneeded type casts for register args 2020-09-12 02:48:16 +02:00
81f7419f70 fix X register clobbering in asmfunc call, fixed graphics.plot() 2020-09-12 01:23:56 +02:00
2f951bd54d tweaking cobra mk3 2020-09-11 19:46:11 +02:00
18f5963b09 cobra mk3 2020-09-10 01:31:21 +02:00
836509c1d1 mult todos. 2020-09-10 00:53:35 +02:00
949d536e42 mult todo's. Fixed wrong compilation target when compiling multiple files at once. 2020-09-10 00:26:35 +02:00
f69b17e165 mult todo's 2020-09-10 00:07:06 +02:00
49a0584c54 added a %target directive 2020-09-09 22:53:34 +02:00
e21aa2c8f0 better naming of the optimized math mult routines 2020-09-09 22:16:37 +02:00
40071b1431 fix compiler crash with adding too many typecasts to args. useless lsb() and msb() are optimized away. 2020-09-09 21:37:56 +02:00
02e29e6990 added some preliminary clobber specs to some cx16 graphics calls, This fixes the 3d cube gfx 2020-09-07 04:06:46 +02:00
e19de0901e Fix cx16 system reset. Added cx16 VIA registers. Fix cx16 VERA register widths. 2020-09-07 03:09:09 +02:00
137d506e42 improve register arg passing again 2020-09-07 02:29:03 +02:00
90c4a26d52 we don't implement asmsub params via @stack yet 2020-09-07 01:24:10 +02:00
f378a8997b improved ability to use register X in asm subroutine fuction arguments 2020-09-07 00:25:51 +02:00
1377bed988 fix assembly for cx16 when zp is not basicsafe 2020-09-06 17:58:05 +02:00
8f9f947c42 fix some issues with float const 0.0 and 1.0 2020-09-05 02:07:41 +02:00
37f6c2858f warning about attempt to put floats in zp 2020-09-05 01:45:58 +02:00
13d7f239ab floating point 1.0 no longer referenced from ROM because cx16 doesn't have it. Added some more cx16 examples. 2020-09-05 00:17:58 +02:00
a6f3c84e28 fix cx16 word sign extend in bitshift 2020-09-04 22:38:03 +02:00
fe4e0e9835 cleanups 2020-08-31 23:00:53 +02:00
81 changed files with 3824 additions and 667 deletions

View File

@ -1,11 +1,11 @@
buildscript { buildscript {
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10"
} }
} }
plugins { plugins {
// id "org.jetbrains.kotlin.jvm" version "1.4.0" // id "org.jetbrains.kotlin.jvm" version "1.4.10"
id 'application' id 'application'
id 'org.jetbrains.dokka' version "0.9.18" id 'org.jetbrains.dokka' version "0.9.18"
id 'com.github.johnrengelman.shadow' version '5.2.0' id 'com.github.johnrengelman.shadow' version '5.2.0'

View File

@ -1,10 +1,15 @@
; --- low level floating point assembly routines for the C64 ; --- 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 ub2float .proc
; -- convert ubyte in SCRATCH_ZPB1 to float at address A/Y ; -- convert ubyte in SCRATCH_ZPB1 to float at address A/Y
; clobbers A, Y ; clobbers A, Y
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1
ldy P8ZP_SCRATCH_B1 ldy P8ZP_SCRATCH_B1
@ -13,14 +18,14 @@ ub2float .proc
_fac_to_mem ldx P8ZP_SCRATCH_W2 _fac_to_mem ldx P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1 ldy P8ZP_SCRATCH_W2+1
jsr MOVMF jsr MOVMF
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
.pend .pend
b2float .proc b2float .proc
; -- convert byte in SCRATCH_ZPB1 to float at address A/Y ; -- convert byte in SCRATCH_ZPB1 to float at address A/Y
; clobbers A, Y ; clobbers A, Y
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1
lda P8ZP_SCRATCH_B1 lda P8ZP_SCRATCH_B1
@ -30,7 +35,7 @@ b2float .proc
uw2float .proc uw2float .proc
; -- convert uword in SCRATCH_ZPWORD1 to float at address A/Y ; -- convert uword in SCRATCH_ZPWORD1 to float at address A/Y
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1
lda P8ZP_SCRATCH_W1 lda P8ZP_SCRATCH_W1
@ -41,7 +46,7 @@ uw2float .proc
w2float .proc w2float .proc
; -- convert word in SCRATCH_ZPWORD1 to float at address A/Y ; -- convert word in SCRATCH_ZPWORD1 to float at address A/Y
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1
ldy P8ZP_SCRATCH_W1 ldy P8ZP_SCRATCH_W1
@ -54,7 +59,7 @@ stack_b2float .proc
; -- b2float operating on the stack ; -- b2float operating on the stack
inx inx
lda P8ESTACK_LO,x lda P8ESTACK_LO,x
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr FREADSA jsr FREADSA
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -64,7 +69,7 @@ stack_w2float .proc
inx inx
ldy P8ESTACK_LO,x ldy P8ESTACK_LO,x
lda P8ESTACK_HI,x lda P8ESTACK_HI,x
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr GIVAYF jsr GIVAYF
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -73,7 +78,7 @@ stack_ub2float .proc
; -- ub2float operating on the stack ; -- ub2float operating on the stack
inx inx
lda P8ESTACK_LO,x lda P8ESTACK_LO,x
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
tay tay
lda #0 lda #0
jsr GIVAYF jsr GIVAYF
@ -85,16 +90,16 @@ stack_uw2float .proc
inx inx
lda P8ESTACK_LO,x lda P8ESTACK_LO,x
ldy P8ESTACK_HI,x ldy P8ESTACK_HI,x
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr GIVUAYFAY jsr GIVUAYFAY
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
stack_float2w .proc ; also used for float2b stack_float2w .proc ; also used for float2b
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr AYINT jsr AYINT
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
lda $64 lda $64
sta P8ESTACK_HI,x sta P8ESTACK_HI,x
lda $65 lda $65
@ -105,9 +110,9 @@ stack_float2w .proc ; also used for float2b
stack_float2uw .proc ; also used for float2ub stack_float2uw .proc ; also used for float2ub
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr GETADR jsr GETADR
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
sta P8ESTACK_HI,x sta P8ESTACK_HI,x
tya tya
sta P8ESTACK_LO,x sta P8ESTACK_LO,x
@ -231,15 +236,15 @@ inc_var_f .proc
; -- add 1 to float pointed to by A/Y ; -- add 1 to float pointed to by A/Y
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1 sty P8ZP_SCRATCH_W1+1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr MOVFM jsr MOVFM
lda #<FL_FONE lda #<FL_ONE_const
ldy #>FL_FONE ldy #>FL_ONE_const
jsr FADD jsr FADD
ldx P8ZP_SCRATCH_W1 ldx P8ZP_SCRATCH_W1
ldy P8ZP_SCRATCH_W1+1 ldy P8ZP_SCRATCH_W1+1
jsr MOVMF jsr MOVMF
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
.pend .pend
@ -247,9 +252,9 @@ dec_var_f .proc
; -- subtract 1 from float pointed to by A/Y ; -- subtract 1 from float pointed to by A/Y
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1 sty P8ZP_SCRATCH_W1+1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #<FL_FONE lda #<FL_ONE_const
ldy #>FL_FONE ldy #>FL_ONE_const
jsr MOVFM jsr MOVFM
lda P8ZP_SCRATCH_W1 lda P8ZP_SCRATCH_W1
ldy P8ZP_SCRATCH_W1+1 ldy P8ZP_SCRATCH_W1+1
@ -257,7 +262,7 @@ dec_var_f .proc
ldx P8ZP_SCRATCH_W1 ldx P8ZP_SCRATCH_W1
ldy P8ZP_SCRATCH_W1+1 ldy P8ZP_SCRATCH_W1+1
jsr MOVMF jsr MOVMF
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
.pend .pend
@ -286,7 +291,7 @@ push_fac1_as_result .proc
jsr MOVMF jsr MOVMF
lda #<fmath_float1 lda #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
jmp push_float jmp push_float
.pend .pend
@ -298,21 +303,21 @@ pow_f .proc
lda #<fmath_float1 lda #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
jsr pop_float jsr pop_float
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #<fmath_float1 lda #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
jsr CONUPK ; fac2 = float1 jsr CONUPK ; fac2 = float1
lda #<fmath_float2 lda #<fmath_float2
ldy #>fmath_float2 ldy #>fmath_float2
jsr FPWR jsr FPWR
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
div_f .proc div_f .proc
; -- push f1/f2 on stack ; -- push f1/f2 on stack
jsr pop_2_floats_f2_in_fac1 jsr pop_2_floats_f2_in_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #<fmath_float1 lda #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
jsr FDIV jsr FDIV
@ -322,7 +327,7 @@ div_f .proc
add_f .proc add_f .proc
; -- push f1+f2 on stack ; -- push f1+f2 on stack
jsr pop_2_floats_f2_in_fac1 jsr pop_2_floats_f2_in_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #<fmath_float1 lda #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
jsr FADD jsr FADD
@ -332,7 +337,7 @@ add_f .proc
sub_f .proc sub_f .proc
; -- push f1-f2 on stack ; -- push f1-f2 on stack
jsr pop_2_floats_f2_in_fac1 jsr pop_2_floats_f2_in_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #<fmath_float1 lda #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
jsr FSUB jsr FSUB
@ -342,7 +347,7 @@ sub_f .proc
mul_f .proc mul_f .proc
; -- push f1*f2 on stack ; -- push f1*f2 on stack
jsr pop_2_floats_f2_in_fac1 jsr pop_2_floats_f2_in_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #<fmath_float1 lda #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
jsr FMULT jsr FMULT
@ -352,7 +357,7 @@ mul_f .proc
neg_f .proc neg_f .proc
; -- push -flt back on stack ; -- push -flt back on stack
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr NEGOP jsr NEGOP
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -360,7 +365,7 @@ neg_f .proc
abs_f .proc abs_f .proc
; -- push abs(float) on stack (as float) ; -- push abs(float) on stack (as float)
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr ABS jsr ABS
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -466,7 +471,7 @@ _return_true lda #1
func_sin .proc func_sin .proc
; -- push sin(f) back onto stack ; -- push sin(f) back onto stack
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr SIN jsr SIN
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -474,7 +479,7 @@ func_sin .proc
func_cos .proc func_cos .proc
; -- push cos(f) back onto stack ; -- push cos(f) back onto stack
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr COS jsr COS
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -482,7 +487,7 @@ func_cos .proc
func_tan .proc func_tan .proc
; -- push tan(f) back onto stack ; -- push tan(f) back onto stack
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr TAN jsr TAN
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -490,7 +495,7 @@ func_tan .proc
func_atan .proc func_atan .proc
; -- push atan(f) back onto stack ; -- push atan(f) back onto stack
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr ATN jsr ATN
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -498,7 +503,7 @@ func_atan .proc
func_ln .proc func_ln .proc
; -- push ln(f) back onto stack ; -- push ln(f) back onto stack
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr LOG jsr LOG
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -506,7 +511,7 @@ func_ln .proc
func_log2 .proc func_log2 .proc
; -- push log base 2, ln(f)/ln(2), back onto stack ; -- push log base 2, ln(f)/ln(2), back onto stack
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr LOG jsr LOG
jsr MOVEF jsr MOVEF
lda #<c64.FL_LOG2 lda #<c64.FL_LOG2
@ -518,7 +523,7 @@ func_log2 .proc
func_sqrt .proc func_sqrt .proc
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr SQR jsr SQR
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -526,7 +531,7 @@ func_sqrt .proc
func_rad .proc func_rad .proc
; -- convert degrees to radians (d * pi / 180) ; -- convert degrees to radians (d * pi / 180)
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #<_pi_div_180 lda #<_pi_div_180
ldy #>_pi_div_180 ldy #>_pi_div_180
jsr FMULT jsr FMULT
@ -537,7 +542,7 @@ _pi_div_180 .byte 123, 14, 250, 53, 18 ; pi / 180
func_deg .proc func_deg .proc
; -- convert radians to degrees (d * (1/ pi * 180)) ; -- convert radians to degrees (d * (1/ pi * 180))
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #<_one_over_pi_div_180 lda #<_one_over_pi_div_180
ldy #>_one_over_pi_div_180 ldy #>_one_over_pi_div_180
jsr FMULT jsr FMULT
@ -547,7 +552,7 @@ _one_over_pi_div_180 .byte 134, 101, 46, 224, 211 ; 1 / (pi * 180)
func_round .proc func_round .proc
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr FADDH jsr FADDH
jsr INT jsr INT
jmp push_fac1_as_result jmp push_fac1_as_result
@ -555,7 +560,7 @@ func_round .proc
func_floor .proc func_floor .proc
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr INT jsr INT
jmp push_fac1_as_result jmp push_fac1_as_result
.pend .pend
@ -563,7 +568,7 @@ func_floor .proc
func_ceil .proc func_ceil .proc
; -- ceil: tr = int(f); if tr==f -> return else return tr+1 ; -- ceil: tr = int(f); if tr==f -> return else return tr+1
jsr pop_float_fac1 jsr pop_float_fac1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
ldx #<fmath_float1 ldx #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
jsr MOVMF jsr MOVMF
@ -573,8 +578,8 @@ func_ceil .proc
jsr FCOMP jsr FCOMP
cmp #0 cmp #0
beq + beq +
lda #<FL_FONE lda #<FL_ONE_const
ldy #>FL_FONE ldy #>FL_ONE_const
jsr FADD jsr FADD
+ jmp push_fac1_as_result + jmp push_fac1_as_result
.pend .pend
@ -630,7 +635,7 @@ func_max_f .proc
ldy #>_largest_neg_float ldy #>_largest_neg_float
_minmax_entry jsr MOVFM _minmax_entry jsr MOVFM
jsr prog8_lib.pop_array_and_lengthmin1Y jsr prog8_lib.pop_array_and_lengthmin1Y
stx P8ZP_SCRATCH_REG_X stx floats_store_reg
- sty P8ZP_SCRATCH_REG - sty P8ZP_SCRATCH_REG
lda P8ZP_SCRATCH_W1 lda P8ZP_SCRATCH_W1
ldy P8ZP_SCRATCH_W1+1 ldy P8ZP_SCRATCH_W1+1
@ -650,6 +655,8 @@ _minmax_cmp cmp #255 ; modified
dey dey
cpy #255 cpy #255
bne - bne -
ldx floats_store_reg
stx P8ZP_SCRATCH_REG
jmp push_fac1_as_result jmp push_fac1_as_result
_largest_neg_float .byte 255,255,255,255,255 ; largest negative float -1.7014118345e+38 _largest_neg_float .byte 255,255,255,255,255 ; largest negative float -1.7014118345e+38
.pend .pend
@ -665,11 +672,11 @@ _largest_pos_float .byte 255,127,255,255,255 ; largest positive float
.pend .pend
func_sum_f .proc func_sum_f .proc
lda #<ZERO lda #<FL_ZERO_const
ldy #>ZERO ldy #>FL_ZERO_const
jsr MOVFM jsr MOVFM
jsr prog8_lib.pop_array_and_lengthmin1Y jsr prog8_lib.pop_array_and_lengthmin1Y
stx P8ZP_SCRATCH_REG_X stx floats_store_reg
- sty P8ZP_SCRATCH_REG - sty P8ZP_SCRATCH_REG
lda P8ZP_SCRATCH_W1 lda P8ZP_SCRATCH_W1
ldy P8ZP_SCRATCH_W1+1 ldy P8ZP_SCRATCH_W1+1
@ -685,7 +692,9 @@ func_sum_f .proc
bcc - bcc -
inc P8ZP_SCRATCH_W1+1 inc P8ZP_SCRATCH_W1+1
bne - bne -
+ jmp push_fac1_as_result + ldx floats_store_reg
stx P8ZP_SCRATCH_REG
jmp push_fac1_as_result
.pend .pend
sign_f .proc sign_f .proc

View File

@ -4,14 +4,14 @@
; ;
; indent format: TABS, size=8 ; indent format: TABS, size=8
%target c64
%option enable_floats %option enable_floats
c64flt { c64flt {
; ---- this block contains C-64 floating point related functions ---- ; ---- this block contains C-64 floating point related functions ----
const float PI = 3.141592653589793 const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586 const float TWOPI = 6.283185307179586
const float ZERO = 0.0
; ---- C64 basic and kernal ROM float constants and functions ---- ; ---- C64 basic and kernal ROM float constants and functions ----
@ -194,20 +194,20 @@ asmsub GETADRAY () clobbers(X) -> uword @ AY {
sub print_f (float value) { sub print_f (float value) {
; ---- prints the floating point value (without a newline). ; ---- prints the floating point value (without a newline).
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx floats_store_reg
lda #<value lda #<value
ldy #>value ldy #>value
jsr MOVFM ; load float into fac1 jsr MOVFM ; load float into fac1
jsr FOUT ; fac1 to string in A/Y jsr FOUT ; fac1 to string in A/Y
sta P8ZP_SCRATCH_B1 sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_REG sty P8ZP_SCRATCH_W1+1
ldy #0 ldy #0
- lda (P8ZP_SCRATCH_B1),y - lda (P8ZP_SCRATCH_W1),y
beq + beq +
jsr c64.CHROUT jsr c64.CHROUT
iny iny
bne - bne -
ldx P8ZP_SCRATCH_REG_X ldx floats_store_reg
+ rts + rts
}} }}
} }

View File

@ -1,3 +1,4 @@
%target c64
%import c64textio %import c64textio
; bitmap pixel graphics module for the C64 ; bitmap pixel graphics module for the C64
@ -180,9 +181,7 @@ graphics {
; @(addr) |= ormask[lsb(px) & 7] ; @(addr) |= ormask[lsb(px) & 7]
; } ; }
; TODO fix the use of X (or XY) as parameter so we can actually use this plot() routine asmsub plot(uword plotx @XY, ubyte ploty @A) clobbers (A, X, Y) {
; 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) {
%asm {{ %asm {{
stx internal_plotx stx internal_plotx
sty internal_plotx+1 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() 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 {{ %asm {{
tay tay
stx P8ZP_SCRATCH_REG_X
lda internal_plotx+1 lda internal_plotx+1
sta P8ZP_SCRATCH_W2+1 sta P8ZP_SCRATCH_W2+1
lsr a ; 0 lsr a ; 0
@ -219,8 +220,6 @@ graphics {
lda (P8ZP_SCRATCH_W2),y lda (P8ZP_SCRATCH_W2),y
ora _ormask,x ora _ormask,x
sta (P8ZP_SCRATCH_W2),y sta (P8ZP_SCRATCH_W2),y
ldx P8ZP_SCRATCH_REG_X
rts rts
_ormask .byte 128, 64, 32, 16, 8, 4, 2, 1 _ormask .byte 128, 64, 32, 16, 8, 4, 2, 1

View File

@ -5,6 +5,7 @@
; ;
; indent format: TABS, size=8 ; indent format: TABS, size=8
%target c64
c64 { c64 {
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte &ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
@ -298,8 +299,6 @@ _irq_handler_init
sta IRQ_SCRATCH_ZPB1 sta IRQ_SCRATCH_ZPB1
lda P8ZP_SCRATCH_REG lda P8ZP_SCRATCH_REG
sta IRQ_SCRATCH_ZPREG sta IRQ_SCRATCH_ZPREG
lda P8ZP_SCRATCH_REG_X
sta IRQ_SCRATCH_ZPREGX
lda P8ZP_SCRATCH_W1 lda P8ZP_SCRATCH_W1
sta IRQ_SCRATCH_ZPWORD1 sta IRQ_SCRATCH_ZPWORD1
lda P8ZP_SCRATCH_W1+1 lda P8ZP_SCRATCH_W1+1
@ -324,8 +323,6 @@ _irq_handler_end
sta P8ZP_SCRATCH_B1 sta P8ZP_SCRATCH_B1
lda IRQ_SCRATCH_ZPREG lda IRQ_SCRATCH_ZPREG
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
lda IRQ_SCRATCH_ZPREGX
sta P8ZP_SCRATCH_REG_X
lda IRQ_SCRATCH_ZPWORD1 lda IRQ_SCRATCH_ZPWORD1
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda IRQ_SCRATCH_ZPWORD1+1 lda IRQ_SCRATCH_ZPWORD1+1
@ -340,7 +337,6 @@ _irq_handler_end
IRQ_X_REG .byte 0 IRQ_X_REG .byte 0
IRQ_SCRATCH_ZPB1 .byte 0 IRQ_SCRATCH_ZPB1 .byte 0
IRQ_SCRATCH_ZPREG .byte 0 IRQ_SCRATCH_ZPREG .byte 0
IRQ_SCRATCH_ZPREGX .byte 0
IRQ_SCRATCH_ZPWORD1 .word 0 IRQ_SCRATCH_ZPWORD1 .word 0
IRQ_SCRATCH_ZPWORD2 .word 0 IRQ_SCRATCH_ZPWORD2 .word 0

View File

@ -5,6 +5,7 @@
; indent format: TABS, size=8 ; indent format: TABS, size=8
%target c64
%import c64lib %import c64lib
%import conv %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 ; Carry flag determines if screen color data must be scrolled too
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
bcs + bcs +
jmp _scroll_screen jmp _scroll_screen
@ -102,7 +103,7 @@ _scroll_screen ; scroll the screen memory
dey dey
bpl - bpl -
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts 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 ; contents of the leftmost column are unchanged, you should clear/refill this yourself
; Carry flag determines if screen color data must be scrolled too ; Carry flag determines if screen color data must be scrolled too
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
bcs + bcs +
jmp _scroll_screen jmp _scroll_screen
@ -136,7 +137,7 @@ _scroll_screen ; scroll the screen memory
dex dex
bpl - bpl -
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts 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 ; contents of the bottom row are unchanged, you should refill/clear this yourself
; Carry flag determines if screen color data must be scrolled too ; Carry flag determines if screen color data must be scrolled too
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
bcs + bcs +
jmp _scroll_screen jmp _scroll_screen
@ -170,7 +171,7 @@ _scroll_screen ; scroll the screen memory
dex dex
bpl - bpl -
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts 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 ; contents of the top row are unchanged, you should refill/clear this yourself
; Carry flag determines if screen color data must be scrolled too ; Carry flag determines if screen color data must be scrolled too
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
bcs + bcs +
jmp _scroll_screen jmp _scroll_screen
@ -204,7 +205,7 @@ _scroll_screen ; scroll the screen memory
dex dex
bpl - bpl -
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
}} }}
} }
@ -230,7 +231,7 @@ asmsub print (str text @ AY) clobbers(A,Y) {
asmsub print_ub0 (ubyte value @ A) 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) ; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr conv.ubyte2decimal jsr conv.ubyte2decimal
pha pha
tya tya
@ -239,7 +240,7 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
jsr c64.CHROUT jsr c64.CHROUT
txa txa
jsr c64.CHROUT jsr c64.CHROUT
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
}} }}
} }
@ -247,7 +248,7 @@ asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
asmsub print_ub (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 ; ---- print the ubyte in A in decimal form, without left padding 0s
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr conv.ubyte2decimal jsr conv.ubyte2decimal
_print_byte_digits _print_byte_digits
pha pha
@ -264,7 +265,7 @@ _print_byte_digits
jsr c64.CHROUT jsr c64.CHROUT
_ones txa _ones txa
jsr c64.CHROUT jsr c64.CHROUT
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
}} }}
} }
@ -272,7 +273,7 @@ _ones txa
asmsub print_b (byte value @ A) clobbers(A,Y) { asmsub print_b (byte value @ A) clobbers(A,Y) {
; ---- print the byte in A in decimal form, without left padding 0s ; ---- print the byte in A in decimal form, without left padding 0s
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
pha pha
cmp #0 cmp #0
bpl + bpl +
@ -280,16 +281,14 @@ asmsub print_b (byte value @ A) clobbers(A,Y) {
jsr c64.CHROUT jsr c64.CHROUT
+ pla + pla
jsr conv.byte2decimal jsr conv.byte2decimal
jsr print_ub._print_byte_digits jmp print_ub._print_byte_digits
ldx P8ZP_SCRATCH_REG_X
rts
}} }}
} }
asmsub print_ubhex (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) { 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) ; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
bcc + bcc +
pha pha
lda #'$' lda #'$'
@ -299,7 +298,7 @@ asmsub print_ubhex (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
jsr c64.CHROUT jsr c64.CHROUT
tya tya
jsr c64.CHROUT jsr c64.CHROUT
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts 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) { 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) ; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
sta P8ZP_SCRATCH_B1 sta P8ZP_SCRATCH_B1
bcc + bcc +
lda #'%' lda #'%'
@ -320,7 +319,7 @@ asmsub print_ubbin (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
+ jsr c64.CHROUT + jsr c64.CHROUT
dey dey
bne - bne -
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts 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) { 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) ; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr conv.uword2decimal jsr conv.uword2decimal
ldy #0 ldy #0
- lda conv.uword2decimal.decTenThousands,y - lda conv.uword2decimal.decTenThousands,y
@ -361,7 +360,7 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
jsr c64.CHROUT jsr c64.CHROUT
iny iny
bne - bne -
+ ldx P8ZP_SCRATCH_REG_X + ldx P8ZP_SCRATCH_REG
rts rts
}} }}
} }
@ -369,9 +368,9 @@ asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
asmsub print_uw (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 ; ---- print the uword in A/Y in decimal form, without left padding 0s
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
jsr conv.uword2decimal jsr conv.uword2decimal
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
ldy #0 ldy #0
- lda conv.uword2decimal.decTenThousands,y - lda conv.uword2decimal.decTenThousands,y
beq _allzero beq _allzero
@ -545,11 +544,11 @@ _colormod sta $ffff ; modified
asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) { asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) {
; ---- safe wrapper around PLOT kernel routine, to save the X register. ; ---- safe wrapper around PLOT kernel routine, to save the X register.
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
tax tax
clc clc
jsr c64.PLOT jsr c64.PLOT
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
}} }}
} }

View File

@ -213,7 +213,7 @@ asmsub byte2decimal (byte value @ A) -> ubyte @ Y, ubyte @ A, ubyte @ X {
asmsub ubyte2hex (ubyte value @ A) -> ubyte @ A, ubyte @ Y { 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) ; ---- A to hex petscii string in AY (first hex char in A, second hex char in Y)
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
pha pha
and #$0f and #$0f
tax tax
@ -225,7 +225,7 @@ asmsub ubyte2hex (ubyte value @ A) -> ubyte @ A, ubyte @ Y {
lsr a lsr a
tax tax
lda _hex_digits,x lda _hex_digits,x
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
_hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well _hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well

View File

@ -4,14 +4,14 @@
; ;
; indent format: TABS, size=8 ; indent format: TABS, size=8
%target cx16
%option enable_floats %option enable_floats
c64flt { c64flt {
; ---- this block contains C-64 floating point related functions ---- ; ---- this block contains C-64 floating point related functions ----
const float PI = 3.141592653589793 const float PI = 3.141592653589793
const float TWOPI = 6.283185307179586 const float TWOPI = 6.283185307179586
const float ZERO = 0.0
; ---- ROM float functions ---- ; ---- ROM float functions ----
@ -130,20 +130,20 @@ asmsub GETADRAY () clobbers(X) -> uword @ AY {
sub print_f (float value) { sub print_f (float value) {
; ---- prints the floating point value (without a newline). ; ---- prints the floating point value (without a newline).
%asm {{ %asm {{
stx P8ZP_SCRATCH_REG_X phx
lda #<value lda #<value
ldy #>value ldy #>value
jsr MOVFM ; load float into fac1 jsr MOVFM ; load float into fac1
jsr FOUT ; fac1 to string in A/Y jsr FOUT ; fac1 to string in A/Y
sta P8ZP_SCRATCH_B1 sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_REG sty P8ZP_SCRATCH_W1+1
ldy #0 ldy #0
- lda (P8ZP_SCRATCH_B1),y - lda (P8ZP_SCRATCH_W1),y
beq + beq +
jsr c64.CHROUT jsr c64.CHROUT
iny iny
bne - bne -
ldx P8ZP_SCRATCH_REG_X plx
+ rts + rts
}} }}
} }

View File

@ -5,6 +5,8 @@
; ;
; indent format: TABS, size=8 ; indent format: TABS, size=8
%target cx16
c64 { c64 {
@ -14,42 +16,42 @@ c64 {
; CLEARSCR -> use screen.clear_screen ; CLEARSCR -> use screen.clear_screen
; HOMECRSR -> use screen.plot ; HOMECRSR -> use screen.plot
romsub $FF81 = CINT() clobbers(A,X,Y) ; (alias: SCINIT) initialize screen editor and video chip 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 $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 $FF87 = RAMTAS() clobbers(A,X,Y) ; initialize RAM, tape buffer, screen
romsub $FF8A = RESTOR() clobbers(A,X,Y) ; restore default I/O vectors 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 $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 $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 $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 $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 $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 $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 $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 $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 $FFA8 = CIOUT(ubyte databyte @ A) ; (alias: IECOUT) output byte to serial bus
romsub $FFAB = UNTLK() clobbers(A) ; command serial bus device to UNTALK romsub $FFAB = UNTLK() clobbers(A) ; command serial bus device to UNTALK
romsub $FFAE = UNLSN() clobbers(A) ; command serial bus device to UNLISTEN 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 $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 $FFB4 = TALK(ubyte device @ A) clobbers(A) ; command serial bus device to TALK
romsub $FFB7 = READST() -> ubyte @ A ; read I/O status word 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 $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 $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 $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 $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 $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 $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 $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 $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 $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 $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 $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 $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 $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 $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 $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 $FFE7 = CLALL() clobbers(A,X) ; (via 812 ($32C)) close all files
romsub $FFEA = UDTIM() clobbers(A,X) ; update the software clock 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 $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 $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 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 { cx16 {
; ---- Commander X-16 additions on top of C64 kernal routines ---- ; 65c02 hardware vectors:
; spelling of the names is taken from the Commander X-16 rom sources &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 ; the sixteen virtual 16-bit registers
&uword r0 = $02 &uword r0 = $02
@ -82,116 +87,159 @@ cx16 {
; VERA registers ; VERA registers
const uword VERA_BASE = $9F20 const uword VERA_BASE = $9F20
&uword VERA_ADDR_L = VERA_BASE + $00 &ubyte VERA_ADDR_L = VERA_BASE + $00
&uword VERA_ADDR_M = VERA_BASE + $01 &ubyte VERA_ADDR_M = VERA_BASE + $01
&uword VERA_ADDR_H = VERA_BASE + $02 &ubyte VERA_ADDR_H = VERA_BASE + $02
&uword VERA_DATA0 = VERA_BASE + $03 &ubyte VERA_DATA0 = VERA_BASE + $03
&uword VERA_DATA1 = VERA_BASE + $04 &ubyte VERA_DATA1 = VERA_BASE + $04
&uword VERA_CTRL = VERA_BASE + $05 &ubyte VERA_CTRL = VERA_BASE + $05
&uword VERA_IEN = VERA_BASE + $06 &ubyte VERA_IEN = VERA_BASE + $06
&uword VERA_ISR = VERA_BASE + $07 &ubyte VERA_ISR = VERA_BASE + $07
&uword VERA_IRQ_LINE_L = VERA_BASE + $08 &ubyte VERA_IRQ_LINE_L = VERA_BASE + $08
&uword VERA_DC_VIDEO = VERA_BASE + $09 &ubyte VERA_DC_VIDEO = VERA_BASE + $09
&uword VERA_DC_HSCALE = VERA_BASE + $0A &ubyte VERA_DC_HSCALE = VERA_BASE + $0A
&uword VERA_DC_VSCALE = VERA_BASE + $0B &ubyte VERA_DC_VSCALE = VERA_BASE + $0B
&uword VERA_DC_BORDER = VERA_BASE + $0C &ubyte VERA_DC_BORDER = VERA_BASE + $0C
&uword VERA_DC_HSTART = VERA_BASE + $09 &ubyte VERA_DC_HSTART = VERA_BASE + $09
&uword VERA_DC_HSTOP = VERA_BASE + $0A &ubyte VERA_DC_HSTOP = VERA_BASE + $0A
&uword VERA_DC_VSTART = VERA_BASE + $0B &ubyte VERA_DC_VSTART = VERA_BASE + $0B
&uword VERA_DC_VSTOP = VERA_BASE + $0C &ubyte VERA_DC_VSTOP = VERA_BASE + $0C
&uword VERA_L0_CONFIG = VERA_BASE + $0D &ubyte VERA_L0_CONFIG = VERA_BASE + $0D
&uword VERA_L0_MAPBASE = VERA_BASE + $0E &ubyte VERA_L0_MAPBASE = VERA_BASE + $0E
&uword VERA_L0_TILEBASE = VERA_BASE + $0F &ubyte VERA_L0_TILEBASE = VERA_BASE + $0F
&uword VERA_L0_HSCROLL_L = VERA_BASE + $10 &ubyte VERA_L0_HSCROLL_L = VERA_BASE + $10
&uword VERA_L0_HSCROLL_H = VERA_BASE + $11 &ubyte VERA_L0_HSCROLL_H = VERA_BASE + $11
&uword VERA_L0_VSCROLL_L = VERA_BASE + $12 &ubyte VERA_L0_VSCROLL_L = VERA_BASE + $12
&uword VERA_L0_VSCROLL_H = VERA_BASE + $13 &ubyte VERA_L0_VSCROLL_H = VERA_BASE + $13
&uword VERA_L1_CONFIG = VERA_BASE + $14 &ubyte VERA_L1_CONFIG = VERA_BASE + $14
&uword VERA_L1_MAPBASE = VERA_BASE + $15 &ubyte VERA_L1_MAPBASE = VERA_BASE + $15
&uword VERA_L1_TILEBASE = VERA_BASE + $16 &ubyte VERA_L1_TILEBASE = VERA_BASE + $16
&uword VERA_L1_HSCROLL_L = VERA_BASE + $17 &ubyte VERA_L1_HSCROLL_L = VERA_BASE + $17
&uword VERA_L1_HSCROLL_H = VERA_BASE + $18 &ubyte VERA_L1_HSCROLL_H = VERA_BASE + $18
&uword VERA_L1_VSCROLL_L = VERA_BASE + $19 &ubyte VERA_L1_VSCROLL_L = VERA_BASE + $19
&uword VERA_L1_VSCROLL_H = VERA_BASE + $1A &ubyte VERA_L1_VSCROLL_H = VERA_BASE + $1A
&uword VERA_AUDIO_CTRL = VERA_BASE + $1B &ubyte VERA_AUDIO_CTRL = VERA_BASE + $1B
&uword VERA_AUDIO_RATE = VERA_BASE + $1C &ubyte VERA_AUDIO_RATE = VERA_BASE + $1C
&uword VERA_AUDIO_DATA = VERA_BASE + $1D &ubyte VERA_AUDIO_DATA = VERA_BASE + $1D
&uword VERA_SPI_DATA = VERA_BASE + $1E &ubyte VERA_SPI_DATA = VERA_BASE + $1E
&uword VERA_SPI_CTRL = VERA_BASE + $1F &ubyte VERA_SPI_CTRL = VERA_BASE + $1F
; VERA_PSG_BASE = $1F9C0 ; VERA_PSG_BASE = $1F9C0
; VERA_PALETTE_BASE = $1FA00 ; VERA_PALETTE_BASE = $1FA00
; VERA_SPRITES_BASE = $1FC00 ; 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 ; supported C128 additions
romsub $ff4a = close_all() romsub $ff4a = close_all() clobbers(A,X,Y)
romsub $ff59 = lkupla() romsub $ff59 = lkupla() clobbers(A,X,Y)
romsub $ff5c = lkupsa() romsub $ff5c = lkupsa() clobbers(A,X,Y)
romsub $ff5f = screen_set_mode(ubyte mode @A) clobbers(A, X, Y) -> ubyte @Pc 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 $ff62 = screen_set_charset(ubyte charset @A, uword charsetptr @XY) clobbers(A,X,Y) ; incompatible with C128 dlchr()
romsub $ff65 = pfkey() romsub $ff65 = pfkey() clobbers(A,X,Y)
romsub $ff6e = jsrfar() romsub $ff6e = jsrfar() clobbers(A,X,Y)
romsub $ff74 = fetch() romsub $ff74 = fetch() clobbers(A,X,Y)
romsub $ff77 = stash() romsub $ff77 = stash() clobbers(A,X,Y)
romsub $ff7a = cmpare() romsub $ff7a = cmpare() clobbers(A,X,Y)
romsub $ff7d = primm() romsub $ff7d = primm() clobbers(A,X,Y)
; X16 additions ; X16 additions
romsub $ff44 = macptr() romsub $ff44 = macptr() clobbers(A,X,Y)
romsub $ff47 = enter_basic(ubyte cold_or_warm @Pc) 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 $ff68 = mouse_config(ubyte shape @A, ubyte scale @X) clobbers (A, X, Y)
romsub $ff6b = mouse_get(ubyte zpdataptr @X) clobbers(A) romsub $ff6b = mouse_get(ubyte zpdataptr @X) clobbers(A)
romsub $ff71 = mouse_scan() clobbers(A, X, Y) romsub $ff71 = mouse_scan() clobbers(A, X, Y)
romsub $ff53 = joystick_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 $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 $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 $ff50 = clock_get_date_time() clobbers(A) ; outout args: r0, r1, r2, r3L
; high level graphics & fonts ; high level graphics & fonts
romsub $ff20 = GRAPH_init() ; uses vectors=r0 romsub $ff20 = GRAPH_init() clobbers(A,X,Y) ; uses vectors=r0
romsub $ff23 = GRAPH_clear() romsub $ff23 = GRAPH_clear() clobbers(A,X,Y)
romsub $ff26 = GRAPH_set_window() ; uses x=r0, y=r1, width=r2, height=r3 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) romsub $ff29 = GRAPH_set_colors(ubyte stroke @A, ubyte fill @X, ubyte background @Y) clobbers (A,X,Y)
romsub $ff2c = GRAPH_draw_line() ; uses x1=r0, y1=r1, x2=r2, y2=r3 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) ; uses x=r0, y=r1, width=r2, height=r3, cornerradius=r4 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() ; uses sx=r0, sy=r1, tx=r2, ty=r3, width=r4, height=r5 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) ; uses x=r0, y=r1, width=r2, height=r3 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() ; uses x=r0, y=r1, ptr=r2, width=r3, height=r4 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() ; uses ptr=r0 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) 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) ; uses x=r0, y=r1 romsub $ff41 = GRAPH_put_char(ubyte char @A) clobbers(A,X,Y) ; uses x=r0, y=r1
; framebuffer ; framebuffer
romsub $fef6 = FB_init() romsub $fef6 = FB_init() clobbers(A,X,Y)
romsub $fef9 = FB_get_info() -> byte @A ; also outputs width=r0, height=r1 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) ; also uses pointer=r0 romsub $fefc = FB_set_palette(ubyte index @A, ubyte bytecount @X) clobbers(A,X,Y) ; also uses pointer=r0
romsub $feff = FB_cursor_position() ; uses x=r0, y=r1 romsub $feff = FB_cursor_position() clobbers(A,X,Y) ; uses x=r0, y=r1
romsub $ff02 = FB_cursor_next_line() ; uses x=r0 romsub $ff02 = FB_cursor_next_line() clobbers(A,X,Y) ; uses x=r0
romsub $ff05 = FB_get_pixel() -> ubyte @A romsub $ff05 = FB_get_pixel() clobbers(X,Y) -> ubyte @A
romsub $ff08 = FB_get_pixels() ; uses ptr=r0, count=r1 romsub $ff08 = FB_get_pixels() clobbers(A,X,Y) ; uses ptr=r0, count=r1
romsub $ff0b = FB_set_pixel(ubyte color @A) romsub $ff0b = FB_set_pixel(ubyte color @A) clobbers(A,X,Y)
romsub $ff0e = FB_set_pixels() ; uses ptr=r0, count=r1 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) 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) ; also uses mask=r0L 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) ; also uses count=r0, step=r1 romsub $ff17 = FB_fill_pixels(ubyte color @A) clobbers(A,X,Y) ; also uses count=r0, step=r1
romsub $ff1a = FB_filter_pixels() ; uses ptr=r0, count=r1 romsub $ff1a = FB_filter_pixels() clobbers(A,X,Y) ; uses ptr=r0, count=r1
romsub $ff1d = FB_move_pixels() ; uses sx=r0, sy=r1, tx=r2, ty=r3, count=r4 romsub $ff1d = FB_move_pixels() clobbers(A,X,Y) ; uses sx=r0, sy=r1, tx=r2, ty=r3, count=r4
; misc ; 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 $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) ; also uses x=r0 and y=r1 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) ; uses address=r0, num_bytes=r1 romsub $fee4 = memory_fill(ubyte value @A) clobbers(A,X,Y) ; uses address=r0, num_bytes=r1
romsub $fee7 = memory_copy() ; uses source=r0, target=r1, num_bytes=r2 romsub $fee7 = memory_copy() clobbers(A,X,Y) ; uses source=r0, target=r1, num_bytes=r2
romsub $feea = memory_crc() ; uses address=r0, num_bytes=r1 result->r2 romsub $feea = memory_crc() clobbers(A,X,Y) ; uses address=r0, num_bytes=r1 result->r2
romsub $feed = memory_decompress() ; uses input=r0, output=r1 result->r1 romsub $feed = memory_decompress() clobbers(A,X,Y) ; uses input=r0, output=r1 result->r1
romsub $fedb = console_init() ; uses x=r0, y=r1, width=r2, height=r3 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) romsub $fede = console_put_char(ubyte char @A, ubyte wrapping @Pc) clobbers(A,X,Y)
romsub $fee1 = console_get_char() -> ubyte @A romsub $fee1 = console_get_char() clobbers(X,Y) -> ubyte @A
romsub $fed8 = console_put_image() ; uses ptr=r0, width=r1, height=r2 romsub $fed8 = console_put_image() clobbers(A,X,Y) ; uses ptr=r0, width=r1, height=r2
romsub $fed5 = console_set_paging_message() ; uses messageptr=r0 romsub $fed5 = console_set_paging_message() clobbers(A,X,Y) ; uses messageptr=r0
romsub $fed2 = kbdbuf_put(ubyte key @A) romsub $fed2 = kbdbuf_put(ubyte key @A) clobbers(A,X,Y)
romsub $fecf = entropy_get() -> ubyte @A, ubyte @X, ubyte @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 {{ %asm {{
sei sei
cld cld
stz $00 ;stz $00
stz $01 ;stz $01
;stz d1prb ; select rom bank 0
lda #$80
sta VERA_CTRL
jsr c64.IOINIT jsr c64.IOINIT
jsr c64.RESTOR jsr c64.RESTOR
jsr c64.CINT jsr c64.CINT

View File

@ -4,7 +4,7 @@
; ;
; indent format: TABS, size=8 ; indent format: TABS, size=8
%target cx16
%import cx16lib %import cx16lib
%import conv %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] 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) { sub color (ubyte txtcol) {

View File

@ -11,6 +11,10 @@
; http://codebase64.org/doku.php?id=base:6502_6510_maths ; http://codebase64.org/doku.php?id=base:6502_6510_maths
; ;
math_store_reg .byte 0 ; temporary storage
multiply_bytes .proc multiply_bytes .proc
; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned) ; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned)
sta P8ZP_SCRATCH_B1 ; num1 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) ; -- multiply 2 bytes A and Y, result as word in A/Y (unsigned)
sta P8ZP_SCRATCH_B1 sta P8ZP_SCRATCH_B1
sty P8ZP_SCRATCH_REG sty P8ZP_SCRATCH_REG
stx P8ZP_SCRATCH_REG_X stx math_store_reg
lda #0 lda #0
ldx #8 ldx #8
lsr P8ZP_SCRATCH_B1 lsr P8ZP_SCRATCH_B1
@ -44,7 +48,7 @@ multiply_bytes_16 .proc
bne - bne -
tay tay
lda P8ZP_SCRATCH_B1 lda P8ZP_SCRATCH_B1
ldx P8ZP_SCRATCH_REG_X ldx math_store_reg
rts rts
.pend .pend
@ -57,7 +61,7 @@ multiply_words .proc
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1 sty P8ZP_SCRATCH_W2+1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
mult16 lda #0 mult16 lda #0
sta result+2 ; clear upper bits of product sta result+2 ; clear upper bits of product
@ -79,7 +83,7 @@ mult16 lda #0
ror result ror result
dex dex
bne - bne -
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
result .byte 0,0,0,0 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 ; division by zero will result in quotient = 255 and remainder = original number
sty P8ZP_SCRATCH_REG sty P8ZP_SCRATCH_REG
sta P8ZP_SCRATCH_B1 sta P8ZP_SCRATCH_B1
stx P8ZP_SCRATCH_REG_X stx math_store_reg
lda #0 lda #0
ldx #8 ldx #8
@ -137,7 +141,7 @@ divmod_ub_asm .proc
dex dex
bne - bne -
ldy P8ZP_SCRATCH_B1 ldy P8ZP_SCRATCH_B1
ldx P8ZP_SCRATCH_REG_X ldx math_store_reg
rts rts
.pend .pend
@ -197,7 +201,7 @@ result = dividend ;save memory by reusing divident to store the result
sta _divisor sta _divisor
sty _divisor+1 sty _divisor+1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda #0 ;preset remainder to 0 lda #0 ;preset remainder to 0
sta remainder sta remainder
sta remainder+1 sta remainder+1
@ -224,7 +228,7 @@ result = dividend ;save memory by reusing divident to store the result
lda result lda result
ldy result+1 ldy result+1
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
rts rts
_divisor .word 0 _divisor .word 0
.pend .pend
@ -308,7 +312,8 @@ _seed .word $2c9e
.pend .pend
mul_byte_3 .proc ; ----------- optimized multiplications (stack) : ---------
stack_mul_byte_3 .proc
; X + X*2 ; X + X*2
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -318,7 +323,7 @@ mul_byte_3 .proc
rts rts
.pend .pend
mul_word_3 .proc stack_mul_word_3 .proc
; W*2 + W ; W*2 + W
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -335,7 +340,7 @@ mul_word_3 .proc
.pend .pend
mul_byte_5 .proc stack_mul_byte_5 .proc
; X*4 + X ; X*4 + X
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -346,7 +351,7 @@ mul_byte_5 .proc
rts rts
.pend .pend
mul_word_5 .proc stack_mul_word_5 .proc
; W*4 + W ; W*4 + W
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -365,7 +370,7 @@ mul_word_5 .proc
.pend .pend
mul_byte_6 .proc stack_mul_byte_6 .proc
; (X*2 + X)*2 ; (X*2 + X)*2
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -376,7 +381,7 @@ mul_byte_6 .proc
rts rts
.pend .pend
mul_word_6 .proc stack_mul_word_6 .proc
; (W*2 + W)*2 ; (W*2 + W)*2
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -394,7 +399,7 @@ mul_word_6 .proc
rts rts
.pend .pend
mul_byte_7 .proc stack_mul_byte_7 .proc
; X*8 - X ; X*8 - X
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -406,7 +411,7 @@ mul_byte_7 .proc
rts rts
.pend .pend
mul_word_7 .proc stack_mul_word_7 .proc
; W*8 - W ; W*8 - W
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -426,7 +431,7 @@ mul_word_7 .proc
rts rts
.pend .pend
mul_byte_9 .proc stack_mul_byte_9 .proc
; X*8 + X ; X*8 + X
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -438,7 +443,7 @@ mul_byte_9 .proc
rts rts
.pend .pend
mul_word_9 .proc stack_mul_word_9 .proc
; W*8 + W ; W*8 + W
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -458,7 +463,7 @@ mul_word_9 .proc
rts rts
.pend .pend
mul_byte_10 .proc stack_mul_byte_10 .proc
; (X*4 + X)*2 ; (X*4 + X)*2
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -470,7 +475,7 @@ mul_byte_10 .proc
rts rts
.pend .pend
mul_word_10 .proc stack_mul_word_10 .proc
; (W*4 + W)*2 ; (W*4 + W)*2
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -490,7 +495,7 @@ mul_word_10 .proc
rts rts
.pend .pend
mul_byte_11 .proc stack_mul_byte_11 .proc
; (X*2 + X)*4 - X ; (X*2 + X)*4 - X
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -506,7 +511,7 @@ mul_byte_11 .proc
; mul_word_11 is skipped (too much code) ; mul_word_11 is skipped (too much code)
mul_byte_12 .proc stack_mul_byte_12 .proc
; (X*2 + X)*4 ; (X*2 + X)*4
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -518,7 +523,7 @@ mul_byte_12 .proc
rts rts
.pend .pend
mul_word_12 .proc stack_mul_word_12 .proc
; (W*2 + W)*4 ; (W*2 + W)*4
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -538,7 +543,7 @@ mul_word_12 .proc
rts rts
.pend .pend
mul_byte_13 .proc stack_mul_byte_13 .proc
; (X*2 + X)*4 + X ; (X*2 + X)*4 + X
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -554,7 +559,7 @@ mul_byte_13 .proc
; mul_word_13 is skipped (too much code) ; mul_word_13 is skipped (too much code)
mul_byte_14 .proc stack_mul_byte_14 .proc
; (X*8 - X)*2 ; (X*8 - X)*2
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -569,7 +574,7 @@ mul_byte_14 .proc
; mul_word_14 is skipped (too much code) ; mul_word_14 is skipped (too much code)
mul_byte_15 .proc stack_mul_byte_15 .proc
; X*16 - X ; X*16 - X
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -582,7 +587,7 @@ mul_byte_15 .proc
rts rts
.pend .pend
mul_word_15 .proc stack_mul_word_15 .proc
; W*16 - W ; W*16 - W
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -604,7 +609,7 @@ mul_word_15 .proc
rts rts
.pend .pend
mul_byte_20 .proc stack_mul_byte_20 .proc
; (X*4 + X)*4 ; (X*4 + X)*4
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -617,7 +622,7 @@ mul_byte_20 .proc
rts rts
.pend .pend
mul_word_20 .proc stack_mul_word_20 .proc
; (W*4 + W)*4 ; (W*4 + W)*4
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -639,7 +644,7 @@ mul_word_20 .proc
rts rts
.pend .pend
mul_byte_25 .proc stack_mul_byte_25 .proc
; (X*2 + X)*8 + X ; (X*2 + X)*8 + X
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
@ -654,27 +659,26 @@ mul_byte_25 .proc
rts rts
.pend .pend
mul_word_25 .proc stack_mul_word_25 .proc
; W + W*8 + W*16 ; W = (W*2 + W) *8 + W
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_W1+1 sta P8ZP_SCRATCH_W1+1
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a asl a
rol P8ZP_SCRATCH_W1+1 rol P8ZP_SCRATCH_W1+1
asl a
rol P8ZP_SCRATCH_W1+1
asl a
rol P8ZP_SCRATCH_W1+1
sta P8ZP_SCRATCH_W1
clc clc
adc P8ESTACK_LO+1,x adc P8ESTACK_LO+1,x
sta P8ESTACK_LO+1,x sta P8ZP_SCRATCH_W1
lda P8ZP_SCRATCH_W1+1 lda P8ZP_SCRATCH_W1+1
adc P8ESTACK_HI+1,x adc P8ESTACK_HI+1,x
sta P8ESTACK_HI+1,x sta P8ZP_SCRATCH_W1+1
lda P8ZP_SCRATCH_W1 lda P8ZP_SCRATCH_W1
asl a asl a
rol P8ZP_SCRATCH_W1+1 rol P8ZP_SCRATCH_W1+1
asl a
rol P8ZP_SCRATCH_W1+1
asl a
rol P8ZP_SCRATCH_W1+1
clc clc
adc P8ESTACK_LO+1,x adc P8ESTACK_LO+1,x
sta P8ESTACK_LO+1,x sta P8ESTACK_LO+1,x
@ -684,21 +688,16 @@ mul_word_25 .proc
rts rts
.pend .pend
mul_byte_40 .proc stack_mul_byte_40 .proc
; (X*4 + X)*8
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
asl a and #7
asl a tay
clc lda mul_byte_40._forties,y
adc P8ESTACK_LO+1,x
asl a
asl a
asl a
sta P8ESTACK_LO+1,x sta P8ESTACK_LO+1,x
rts rts
.pend .pend
mul_word_40 .proc stack_mul_word_40 .proc
; (W*4 + W)*8 ; (W*4 + W)*8
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -722,6 +721,529 @@ mul_word_40 .proc
rts rts
.pend .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 sign_b .proc
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
beq _sign_zero beq _sign_zero

View File

@ -686,7 +686,7 @@ func_sqrt16 .proc
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
lda P8ESTACK_HI+1,x lda P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_W2+1 sta P8ZP_SCRATCH_W2+1
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
ldy #$00 ; r = 0 ldy #$00 ; r = 0
ldx #$07 ldx #$07
clc ; clear bit 16 of m clc ; clear bit 16 of m
@ -721,7 +721,7 @@ _skip1
_skip2 _skip2
iny ; r = r or d (d is 1 here) iny ; r = r or d (d is 1 here)
_skip3 _skip3
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
tya tya
sta P8ESTACK_LO+1,x sta P8ESTACK_LO+1,x
lda #0 lda #0
@ -1216,7 +1216,7 @@ func_rndw .proc
func_memcopy .proc func_memcopy .proc
; note: clobbers A,Y ; note: clobbers A,Y
inx inx
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda P8ESTACK_LO+2,x lda P8ESTACK_LO+2,x
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda P8ESTACK_HI+2,x lda P8ESTACK_HI+2,x
@ -1233,7 +1233,7 @@ func_memcopy .proc
iny iny
dex dex
bne - bne -
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
inx inx
inx inx
rts rts
@ -1242,7 +1242,7 @@ func_memcopy .proc
func_memset .proc func_memset .proc
; note: clobbers A,Y ; note: clobbers A,Y
inx inx
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda P8ESTACK_LO+2,x lda P8ESTACK_LO+2,x
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda P8ESTACK_HI+2,x lda P8ESTACK_HI+2,x
@ -1253,7 +1253,7 @@ func_memset .proc
lda P8ESTACK_LO,x lda P8ESTACK_LO,x
ldx P8ZP_SCRATCH_B1 ldx P8ZP_SCRATCH_B1
jsr memset jsr memset
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
inx inx
inx inx
rts rts
@ -1264,7 +1264,7 @@ func_memsetw .proc
; -- fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY. ; -- fill memory from (SCRATCH_ZPWORD1) number of words in SCRATCH_ZPWORD2, with word value in AY.
inx inx
stx P8ZP_SCRATCH_REG_X stx P8ZP_SCRATCH_REG
lda P8ESTACK_LO+2,x lda P8ESTACK_LO+2,x
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda P8ESTACK_HI+2,x lda P8ESTACK_HI+2,x
@ -1276,7 +1276,7 @@ func_memsetw .proc
lda P8ESTACK_LO,x lda P8ESTACK_LO,x
ldy P8ESTACK_HI,x ldy P8ESTACK_HI,x
jsr memsetw jsr memsetw
ldx P8ZP_SCRATCH_REG_X ldx P8ZP_SCRATCH_REG
inx inx
inx inx
rts rts
@ -1328,9 +1328,9 @@ memset .proc
; -- fill memory from (SCRATCH_ZPWORD1), length XY, with value in A. ; -- fill memory from (SCRATCH_ZPWORD1), length XY, with value in A.
; clobbers X, Y ; clobbers X, Y
stx P8ZP_SCRATCH_B1 stx P8ZP_SCRATCH_B1
sty P8ZP_SCRATCH_REG sty _save_reg
ldy #0 ldy #0
ldx P8ZP_SCRATCH_REG ldx _save_reg
beq _lastpage beq _lastpage
_fullpage sta (P8ZP_SCRATCH_W1),y _fullpage sta (P8ZP_SCRATCH_W1),y
@ -1347,6 +1347,7 @@ _lastpage ldy P8ZP_SCRATCH_B1
bne - bne -
+ rts + rts
_save_reg .byte 0
.pend .pend

View File

@ -1 +1 @@
4.1 4.2

View File

@ -4,13 +4,10 @@ import kotlinx.cli.*
import prog8.ast.base.AstException import prog8.ast.base.AstException
import prog8.compiler.CompilationResult import prog8.compiler.CompilationResult
import prog8.compiler.compileProgram import prog8.compiler.compileProgram
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8.compiler.target.CompilationTarget 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 prog8.parser.ParsingFailedError
import java.io.IOException
import java.nio.file.FileSystems import java.nio.file.FileSystems
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.StandardWatchEventKinds 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 dontWriteAssembly by cli.flagArgument("-noasm", "don't create assembly code")
val dontOptimize by cli.flagArgument("-noopt", "don't perform any optimizations") 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 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) val moduleFiles by cli.positionalArgumentsList("modules", "main module file(s) to compile", minArgs = 1)
try { try {
@ -50,39 +48,6 @@ private fun compileMain(args: Array<String>) {
exitProcess(1) 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) val outputPath = pathFrom(outputDir)
if(!outputPath.toFile().isDirectory) { if(!outputPath.toFile().isDirectory) {
System.err.println("Output path doesn't exist") 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") println("Continuous watch mode active. Main module: $filepath")
try { try {
val compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, outputDir=outputPath) val compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, compilationTarget, outputPath)
println("Imported files (now watching:)") println("Imported files (now watching:)")
for (importedFile in compilationResult.importedFiles) { for (importedFile in compilationResult.importedFiles) {
print(" ") print(" ")
@ -122,7 +87,7 @@ private fun compileMain(args: Array<String>) {
val filepath = pathFrom(filepathRaw).normalize() val filepath = pathFrom(filepathRaw).normalize()
val compilationResult: CompilationResult val compilationResult: CompilationResult
try { try {
compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, outputDir=outputPath) compilationResult = compileProgram(filepath, !dontOptimize, !dontWriteAssembly, compilationTarget, outputPath)
if(!compilationResult.success) if(!compilationResult.success)
exitProcess(1) exitProcess(1)
} catch (x: ParsingFailedError) { } catch (x: ParsingFailedError) {
@ -135,7 +100,7 @@ private fun compileMain(args: Array<String>) {
if (compilationResult.programName.isEmpty()) if (compilationResult.programName.isEmpty())
println("\nCan't start emulator because no program was assembled.") println("\nCan't start emulator because no program was assembled.")
else if(startEmulator) { else if(startEmulator) {
CompilationTarget.machine.launchEmulator(compilationResult.programName) CompilationTarget.instance.machine.launchEmulator(compilationResult.programName)
} }
} }
} }

View File

@ -140,7 +140,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
param.second.stack -> "stack" param.second.stack -> "stack"
param.second.registerOrPair!=null -> param.second.registerOrPair.toString() param.second.registerOrPair!=null -> param.second.registerOrPair.toString()
param.second.statusflag!=null -> param.second.statusflag.toString() param.second.statusflag!=null -> param.second.statusflag.toString()
else -> "?????1" else -> "?????"
} }
output("${datatypeString(param.first.type)} ${param.first.name} @$reg") output("${datatypeString(param.first.type)} ${param.first.name} @$reg")
if(param.first!==subroutine.parameters.last()) if(param.first!==subroutine.parameters.last())

View File

@ -254,7 +254,7 @@ private fun prog8Parser.Asmsub_declContext.toAst(): AsmsubDecl {
val clobbers = asmsub_clobbers()?.clobber()?.toAst() ?: emptySet() val clobbers = asmsub_clobbers()?.clobber()?.toAst() ?: emptySet()
val normalParameters = params.map { SubroutineParameter(it.name, it.type, it.position) } val normalParameters = params.map { SubroutineParameter(it.name, it.type, it.position) }
val normalReturntypes = returns.map { it.type } 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) } val returnRegisters = returns.map { RegisterOrStatusflag(it.registerOrPair, it.statusflag, it.stack) }
return AsmsubDecl(name, normalParameters, normalReturntypes, paramRegisters, returnRegisters, clobbers) return AsmsubDecl(name, normalParameters, normalReturntypes, paramRegisters, returnRegisters, clobbers)
} }
@ -263,7 +263,7 @@ private class AsmSubroutineParameter(name: String,
type: DataType, type: DataType,
val registerOrPair: RegisterOrPair?, val registerOrPair: RegisterOrPair?,
val statusflag: Statusflag?, val statusflag: Statusflag?,
val stack: Boolean, // TODO implement: val stack: Boolean,
position: Position) : SubroutineParameter(name, type, position) position: Position) : SubroutineParameter(name, type, position)
private class AsmSubroutineReturn(val type: DataType, 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'") else -> throw FatalAstException("invalid register or status flag '$name'")
} }
} }
AsmSubroutineParameter(vardecl.varname.text, datatype, registerorpair, statusregister, AsmSubroutineParameter(vardecl.varname.text, datatype, registerorpair, statusregister, toPosition())
!it.stack?.text.isNullOrEmpty(), toPosition())
} }
private fun prog8Parser.Functioncall_stmtContext.toAst(): Statement { private fun prog8Parser.Functioncall_stmtContext.toAst(): Statement {
@ -472,7 +471,7 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression {
litval.charliteral()!=null -> { litval.charliteral()!=null -> {
try { try {
val cc=litval.charliteral() val cc=litval.charliteral()
NumericLiteralValue(DataType.UBYTE, CompilationTarget.encodeString( NumericLiteralValue(DataType.UBYTE, CompilationTarget.instance.encodeString(
unescape(litval.charliteral().SINGLECHAR().text, litval.toPosition()), unescape(litval.charliteral().SINGLECHAR().text, litval.toPosition()),
litval.charliteral().ALT_STRING_ENCODING()!=null)[0], litval.toPosition()) litval.charliteral().ALT_STRING_ENCODING()!=null)[0], litval.toPosition())
} catch (ce: CharConversionException) { } catch (ce: CharConversionException) {

View File

@ -56,8 +56,8 @@ enum class DataType {
return when(this) { return when(this) {
in ByteDatatypes -> 1 in ByteDatatypes -> 1
in WordDatatypes -> 2 in WordDatatypes -> 2
FLOAT -> CompilationTarget.machine.FLOAT_MEM_SIZE FLOAT -> CompilationTarget.instance.machine.FLOAT_MEM_SIZE
in PassByReferenceDatatypes -> CompilationTarget.machine.POINTER_MEM_SIZE in PassByReferenceDatatypes -> CompilationTarget.instance.machine.POINTER_MEM_SIZE
else -> -9999999 else -> -9999999
} }
} }

View File

@ -671,8 +671,8 @@ class RangeExpr(var from: Expression,
val toString = to as? StringLiteralValue val toString = to as? StringLiteralValue
if(fromString!=null && toString!=null ) { if(fromString!=null && toString!=null ) {
// string range -> int range over character values // string range -> int range over character values
fromVal = CompilationTarget.encodeString(fromString.value, fromString.altEncoding)[0].toInt() fromVal = CompilationTarget.instance.encodeString(fromString.value, fromString.altEncoding)[0].toInt()
toVal = CompilationTarget.encodeString(toString.value, fromString.altEncoding)[0].toInt() toVal = CompilationTarget.instance.encodeString(toString.value, fromString.altEncoding)[0].toInt()
} else { } else {
val fromLv = from as? NumericLiteralValue val fromLv = from as? NumericLiteralValue
val toLv = to as? NumericLiteralValue val toLv = to as? NumericLiteralValue

View File

@ -7,7 +7,9 @@ import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.CompilationOptions import prog8.compiler.CompilationOptions
import prog8.compiler.target.C64Target
import prog8.compiler.target.CompilationTarget import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.Cx16Target
import prog8.functions.BuiltinFunctions import prog8.functions.BuiltinFunctions
import java.io.File import java.io.File
@ -471,14 +473,11 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(decl: VarDecl) { override fun visit(decl: VarDecl) {
fun err(msg: String, position: Position?=null) { fun err(msg: String, position: Position?=null) = errors.err(msg, position ?: decl.position)
errors.err(msg, position ?: decl.position)
}
// the initializer value can't refer to the variable itself (recursive definition) // 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") err("recursive var declaration")
}
// CONST can only occur on simple types (byte, word, float) // CONST can only occur on simple types (byte, word, float)
if(decl.type== VarDeclType.CONST) { 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)") err("const modifier can only be used on numeric types (byte, word, float)")
} }
// FLOATS // FLOATS enabled?
if(!compilerOptions.floats && decl.datatype in setOf(DataType.FLOAT, DataType.ARRAY_F) && decl.type!= VarDeclType.MEMORY) { 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") 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 // ARRAY without size specifier MUST have an iterable initializer value
if(decl.isArray && decl.arraysize==null) { if(decl.isArray && decl.arraysize==null) {
@ -558,9 +559,11 @@ internal class AstChecker(private val program: Program,
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue) checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
} }
else -> { else -> {
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}") if(decl.type==VarDeclType.CONST) {
super.visit(decl) err("const declaration needs a compile-time constant initializer value, or range")
return 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 }) else if(directive.args.map{it.name in setOf("enable_floats", "force_output")}.any { !it })
err("invalid option directive argument(s)") 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) else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position)
} }
super.visit(directive) super.visit(directive)
@ -1156,7 +1167,7 @@ internal class AstChecker(private val program: Program,
// check if the floating point values are all within range // check if the floating point values are all within range
val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray() 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 err("floating point value overflow")
return true return true
} }

View File

@ -22,7 +22,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
} }
override fun visit(block: Block) { 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) errors.err("can't use a cpu opcode name as a symbol: '${block.name}'", block.position)
val existing = blocks[block.name] val existing = blocks[block.name]
@ -40,7 +40,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
if(decl.name in BuiltinFunctions) if(decl.name in BuiltinFunctions)
errors.err("builtin function cannot be redefined", decl.position) 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) errors.err("can't use a cpu opcode name as a symbol: '${decl.name}'", decl.position)
if(decl.datatype==DataType.STRUCT) { if(decl.datatype==DataType.STRUCT) {
@ -74,7 +74,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
} }
override fun visit(subroutine: Subroutine) { 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) errors.err("can't use a cpu opcode name as a symbol: '${subroutine.name}'", subroutine.position)
} else if(subroutine.name in BuiltinFunctions) { } else if(subroutine.name in BuiltinFunctions) {
// the builtin functions can't be redefined // 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) { 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) errors.err("can't use a cpu opcode name as a symbol: '${label.name}'", label.position)
if(label.name in BuiltinFunctions) { if(label.name in BuiltinFunctions) {

View File

@ -12,6 +12,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> { override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
if(functionCallStatement.target.nameInSource == listOf("swap")) { 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) // if x and y are both just identifiers, do not rewrite (there should be asm generation for that)
// otherwise: // otherwise:
// rewrite swap(x,y) as follows: // rewrite swap(x,y) as follows:

View File

@ -71,23 +71,6 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
return noModifications 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> { override fun after(whenStatement: WhenStatement, parent: Node): Iterable<IAstModification> {
val choices = whenStatement.choiceValues(program).sortedBy { val choices = whenStatement.choiceValues(program).sortedBy {

View File

@ -18,6 +18,21 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
private val noModifications = emptyList<IAstModification>() 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> { override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
val leftDt = expr.left.inferType(program) val leftDt = expr.left.inferType(program)
val rightDt = expr.right.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], call.args[arg.second.index],
TypecastExpression(arg.second.value, possibleType, true, arg.second.value.position), TypecastExpression(arg.second.value, possibleType, true, arg.second.value.position),
call as Node) call as Node)
break
} }
} }
} }

View File

@ -1,5 +1,6 @@
package prog8.compiler package prog8.compiler
import prog8.ast.IFunctionCall
import prog8.ast.Node import prog8.ast.Node
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
@ -14,7 +15,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
private val noModifications = emptyList<IAstModification>() private val noModifications = emptyList<IAstModification>()
override fun after(decl: VarDecl, parent: Node): Iterable<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. // a numeric vardecl without an initial value is initialized with zero.
decl.value = decl.zeroElementValue() decl.value = decl.zeroElementValue()
} }
@ -54,7 +55,8 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
} }
} }
if (!conflicts) { 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 { return numericVarsWithValue.map {
val initValue = it.value!! // assume here that value has always been set by now 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) 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, // 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. // 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. // 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(sourceDt in PassByReferenceDatatypes) {
if(typecast.type==DataType.UWORD) { if(typecast.type==DataType.UWORD) {

View File

@ -27,7 +27,8 @@ data class CompilationOptions(val output: OutputType,
val launcher: LauncherType, val launcher: LauncherType,
val zeropage: ZeropageType, val zeropage: ZeropageType,
val zpReserved: List<IntRange>, val zpReserved: List<IntRange>,
val floats: Boolean) val floats: Boolean,
val compilationTarget: String?)
class CompilerException(message: String?) : Exception(message) class CompilerException(message: String?) : Exception(message)

View File

@ -4,7 +4,9 @@ import prog8.ast.AstToSourceCode
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.statements.Directive import prog8.ast.statements.Directive
import prog8.compiler.target.C64Target
import prog8.compiler.target.CompilationTarget import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.Cx16Target
import prog8.optimizer.UnusedCodeRemover import prog8.optimizer.UnusedCodeRemover
import prog8.optimizer.constantFold import prog8.optimizer.constantFold
import prog8.optimizer.optimizeStatements import prog8.optimizer.optimizeStatements
@ -13,6 +15,7 @@ import prog8.parser.ModuleImporter
import prog8.parser.ParsingFailedError import prog8.parser.ParsingFailedError
import prog8.parser.moduleName import prog8.parser.moduleName
import java.nio.file.Path import java.nio.file.Path
import kotlin.system.exitProcess
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
@ -25,12 +28,22 @@ class CompilationResult(val success: Boolean,
fun compileProgram(filepath: Path, fun compileProgram(filepath: Path,
optimize: Boolean, optimize: Boolean,
writeAssembly: Boolean, writeAssembly: Boolean,
compilationTarget: String,
outputDir: Path): CompilationResult { outputDir: Path): CompilationResult {
var programName = "" var programName = ""
lateinit var programAst: Program lateinit var programAst: Program
lateinit var importedFiles: List<Path> lateinit var importedFiles: List<Path>
val errors = ErrorReporter() 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 { try {
val totalTime = measureTimeMillis { val totalTime = measureTimeMillis {
// import main module and everything it needs // 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) if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG)
throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type 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 // depending on the machine and compiler options we may have to include some libraries
CompilationTarget.machine.importLibs(compilerOptions, importer, programAst) CompilationTarget.instance.machine.importLibs(compilerOptions, importer, programAst)
// always import prog8lib and math // always import prog8lib and math
importer.importLibraryModule(programAst, "math") importer.importLibraryModule(programAst, "math")
@ -129,16 +142,26 @@ private fun determineCompilationOptions(program: Program): CompilationOptions {
.map { it[0].int!!..it[1].int!! } .map { it[0].int!!..it[1].int!! }
.toList() .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( return CompilationOptions(
if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType), if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType),
if (launcherType == null) LauncherType.BASIC else LauncherType.valueOf(launcherType), 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) { private fun processAst(programAst: Program, errors: ErrorReporter, compilerOptions: CompilationOptions) {
// perform initial syntax checks and processings // perform initial syntax checks and processings
println("Processing...") println("Processing for target ${CompilationTarget.instance.name}...")
programAst.checkIdentifiers(errors) programAst.checkIdentifiers(errors)
errors.handle() errors.handle()
programAst.constantFold(errors) programAst.constantFold(errors)
@ -191,11 +214,14 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir:
// printAst(programAst) // printAst(programAst)
CompilationTarget.machine.initializeZeropage(compilerOptions) if(compilerOptions.compilationTarget!=null && compilerOptions.compilationTarget != CompilationTarget.instance.name)
val assembly = CompilationTarget.asmGenerator( throw AssemblyError("program's compilation target differs from configured target")
CompilationTarget.instance.machine.initializeZeropage(compilerOptions)
val assembly = CompilationTarget.instance.asmGenerator(
programAst, programAst,
errors, errors,
CompilationTarget.machine.zeropage, CompilationTarget.instance.machine.zeropage,
compilerOptions, compilerOptions,
outputDir).compileToAssembly(optimize) outputDir).compileToAssembly(optimize)
assembly.assemble(compilerOptions) assembly.assemble(compilerOptions)

View File

@ -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_B1 : Int // temp storage for a single byte
abstract val SCRATCH_REG : Int // temp storage for a register 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_W1 : Int // temp storage 1 for a word $fb+$fc
abstract val SCRATCH_W2 : Int // temp storage 2 for a word $fb+$fc abstract val SCRATCH_W2 : Int // temp storage 2 for a word $fb+$fc

View File

@ -4,15 +4,50 @@ import prog8.ast.Program
import prog8.ast.base.ErrorReporter import prog8.ast.base.ErrorReporter
import prog8.compiler.CompilationOptions import prog8.compiler.CompilationOptions
import prog8.compiler.Zeropage 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 import java.nio.file.Path
internal interface CompilationTarget { 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 { companion object {
lateinit var name: String lateinit var instance: CompilationTarget
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
} }
} }
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"
}

View File

@ -28,7 +28,6 @@ internal interface IMachineDefinition {
val opcodeNames: Set<String> val opcodeNames: Set<String>
var zeropage: Zeropage var zeropage: Zeropage
val initSystemProcname: String
val cpu: CpuType val cpu: CpuType
fun initializeZeropage(compilerOptions: CompilationOptions) fun initializeZeropage(compilerOptions: CompilationOptions)

View File

@ -2,6 +2,7 @@ package prog8.compiler.target.c64
import prog8.compiler.CompilationOptions import prog8.compiler.CompilationOptions
import prog8.compiler.OutputType import prog8.compiler.OutputType
import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.IAssemblyProgram import prog8.compiler.target.IAssemblyProgram
import prog8.compiler.target.generatedLabelPrefix import prog8.compiler.target.generatedLabelPrefix
import java.nio.file.Path import java.nio.file.Path
@ -22,12 +23,12 @@ class AssemblyProgram(override val name: String, outputDir: Path) : IAssemblyPro
val outFile = when (options.output) { val outFile = when (options.output) {
OutputType.PRG -> { OutputType.PRG -> {
command.add("--cbm-prg") command.add("--cbm-prg")
println("\nCreating prg.") println("\nCreating prg for target ${CompilationTarget.instance.name}.")
prgFile prgFile
} }
OutputType.RAW -> { OutputType.RAW -> {
command.add("--nostart") command.add("--nostart")
println("\nCreating raw binary.") println("\nCreating raw binary for target ${CompilationTarget.instance.name}.")
binFile binFile
} }
} }

View File

@ -29,7 +29,6 @@ internal object C64MachineDefinition: IMachineDefinition {
override val ESTACK_HI = 0xcf00 // $ce00-$ceff inclusive override val ESTACK_HI = 0xcf00 // $ce00-$ceff inclusive
override lateinit var zeropage: Zeropage override lateinit var zeropage: Zeropage
override val initSystemProcname = "c64.init_system"
override fun getFloat(num: Number) = Mflpt5.fromNumber(num) 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_B1 = 0x02 // temp storage for a single byte
override val SCRATCH_REG = 0x03 // temp storage for a register 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_W1 = 0xfb // temp storage 1 for a word $fb+$fc
override val SCRATCH_W2 = 0xfd // temp storage 2 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) { if (options.zeropage == ZeropageType.FULL) {
free.addAll(0x04..0xf9) free.addAll(0x04..0xf9)
free.add(0xff) 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 free.removeAll(listOf(0xa0, 0xa1, 0xa2, 0x91, 0xc0, 0xc5, 0xcb, 0xf5, 0xf6)) // these are updated by IRQ
} else { } else {
if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) { if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
@ -170,7 +168,6 @@ internal object C64MachineDefinition: IMachineDefinition {
} }
require(SCRATCH_B1 !in free) require(SCRATCH_B1 !in free)
require(SCRATCH_REG !in free) require(SCRATCH_REG !in free)
require(SCRATCH_REG_X !in free)
require(SCRATCH_W1 !in free) require(SCRATCH_W1 !in free)
require(SCRATCH_W2 !in free) require(SCRATCH_W2 !in free)

View File

@ -35,6 +35,10 @@ internal class AsmGen(private val program: Program,
val options: CompilationOptions, val options: CompilationOptions,
private val outputDir: Path): IAssemblyGenerator { 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 assemblyLines = mutableListOf<String>()
private val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname) private val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
private val allocatedZeropageVariables = mutableMapOf<String, Pair<Int, DataType>>() private val allocatedZeropageVariables = mutableMapOf<String, Pair<Int, DataType>>()
@ -79,7 +83,7 @@ internal class AsmGen(private val program: Program,
private fun header() { private fun header() {
val ourName = this.javaClass.name val ourName = this.javaClass.name
val cpu = when(CompilationTarget.machine.cpu) { val cpu = when(CompilationTarget.instance.machine.cpu) {
CpuType.CPU6502 -> "6502" CpuType.CPU6502 -> "6502"
CpuType.CPU65c02 -> "65c02" CpuType.CPU65c02 -> "65c02"
else -> "unsupported" else -> "unsupported"
@ -94,18 +98,16 @@ internal class AsmGen(private val program: Program,
program.actualLoadAddress = program.definedLoadAddress program.actualLoadAddress = program.definedLoadAddress
if (program.actualLoadAddress == 0) // fix load address if (program.actualLoadAddress == 0) // fix load address
program.actualLoadAddress = if (options.launcher == LauncherType.BASIC) 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 // the global prog8 variables needed
val zp = CompilationTarget.machine.zeropage val zp = CompilationTarget.instance.machine.zeropage
val initproc = CompilationTarget.machine.initSystemProcname
out("P8ZP_SCRATCH_B1 = ${zp.SCRATCH_B1}") out("P8ZP_SCRATCH_B1 = ${zp.SCRATCH_B1}")
out("P8ZP_SCRATCH_REG = ${zp.SCRATCH_REG}") 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_W1 = ${zp.SCRATCH_W1} ; word")
out("P8ZP_SCRATCH_W2 = ${zp.SCRATCH_W2} ; word") out("P8ZP_SCRATCH_W2 = ${zp.SCRATCH_W2} ; word")
out("P8ESTACK_LO = ${CompilationTarget.machine.ESTACK_LO.toHex()}") out("P8ESTACK_LO = ${CompilationTarget.instance.machine.ESTACK_LO.toHex()}")
out("P8ESTACK_HI = ${CompilationTarget.machine.ESTACK_HI.toHex()}") out("P8ESTACK_HI = ${CompilationTarget.instance.machine.ESTACK_HI.toHex()}")
when { when {
options.launcher == LauncherType.BASIC -> { 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("_prog8_entrypoint\t; assembly code starts here\n")
out(" tsx") out(" tsx")
out(" stx prog8_lib.orig_stackpointer") out(" stx prog8_lib.orig_stackpointer")
if(!initproc.isNullOrEmpty()) if(!CompilationTarget.instance.initProcName.isNullOrEmpty())
out(" jsr $initproc") out(" jsr ${CompilationTarget.instance.initProcName}")
} }
options.output == OutputType.PRG -> { options.output == OutputType.PRG -> {
out("; ---- program without basic sys call ----") out("; ---- program without basic sys call ----")
out("* = ${program.actualLoadAddress.toHex()}\n") out("* = ${program.actualLoadAddress.toHex()}\n")
out(" tsx") out(" tsx")
out(" stx prog8_lib.orig_stackpointer") out(" stx prog8_lib.orig_stackpointer")
if(!initproc.isNullOrEmpty()) if(!CompilationTarget.instance.initProcName.isNullOrEmpty())
out(" jsr $initproc") out(" jsr ${CompilationTarget.instance.initProcName}")
} }
options.output == OutputType.RAW -> { options.output == OutputType.RAW -> {
out("; ---- raw assembler program ----") out("; ---- raw assembler program ----")
@ -161,7 +163,7 @@ internal class AsmGen(private val program: Program,
} }
Zeropage.ExitProgramStrategy.SYSTEM_RESET -> { Zeropage.ExitProgramStrategy.SYSTEM_RESET -> {
out(" jsr main.start\t; call program entrypoint") 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 // the global list of all floating point constants for the whole program
out("; global float constants") out("; global float constants")
for (flt in globalFloatConsts) { 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 val floatvalue = flt.key
out("${flt.value}\t.byte $floatFill ; float $floatvalue") out("${flt.value}\t.byte $floatFill ; float $floatvalue")
} }
@ -340,7 +342,7 @@ internal class AsmGen(private val program: Program,
} }
val floatFills = array.map { val floatFills = array.map {
val number = (it as NumericLiteralValue).number val number = (it as NumericLiteralValue).number
CompilationTarget.machine.getFloat(number).makeFloatFillAsm() CompilationTarget.instance.machine.getFloat(number).makeFloatFillAsm()
} }
out(name) out(name)
for (f in array.zip(floatFills)) for (f in array.zip(floatFills))
@ -474,7 +476,7 @@ internal class AsmGen(private val program: Program,
} }
internal fun getFloatAsmConst(number: Double): String { internal fun getFloatAsmConst(number: Double): String {
var asmName = CompilationTarget.machine.getFloatRomConst(number) var asmName = CompilationTarget.instance.machine.getFloatRomConst(number)
if(asmName.isNullOrEmpty()) { if(asmName.isNullOrEmpty()) {
// no ROM float const for this value, create our own // no ROM float const for this value, create our own
asmName = globalFloatConsts[number] 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 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) { internal fun saveRegister(register: CpuRegister) {
when(register) { when(register) {
CpuRegister.A -> out(" pha") CpuRegister.A -> out(" pha")
CpuRegister.X -> { CpuRegister.X -> {
if(CompilationTarget.machine.cpu == CpuType.CPU65c02) if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phx")
out(" phx") else {
else val save = makeLabel("saveX")
out(" stx P8ZP_SCRATCH_REG_X") 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) { when(register) {
CpuRegister.A -> out(" pla") CpuRegister.A -> out(" pla")
CpuRegister.X -> { CpuRegister.X -> {
if(CompilationTarget.machine.cpu == CpuType.CPU65c02) if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" plx")
out(" plx") else {
else val save = saveRegisterLabels.pop()
out(" ldx P8ZP_SCRATCH_REG_X") 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) { internal fun translate(stmt: Statement) {
outputSourceLine(stmt) outputSourceLine(stmt)
when(stmt) { when(stmt) {
@ -684,7 +713,7 @@ internal class AsmGen(private val program: Program,
+""") +""")
when(register) { when(register) {
CpuRegister.A -> out(" inx | lda P8ESTACK_LO,x") 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") CpuRegister.Y -> out(" inx | ldy P8ESTACK_LO,x")
} }
} }
@ -722,7 +751,7 @@ internal class AsmGen(private val program: Program,
expressionsAsmGen.translateExpression(index) expressionsAsmGen.translateExpression(index)
when(register) { when(register) {
CpuRegister.A -> out(" inx | lda P8ESTACK_LO,x") 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") CpuRegister.Y -> out(" inx | ldy P8ESTACK_LO,x")
} }
} }
@ -792,16 +821,38 @@ internal class AsmGen(private val program: Program,
} }
private fun translate(stmt: IfStatement) { private fun translate(stmt: IfStatement) {
expressionsAsmGen.translateExpression(stmt.condition) when {
translateTestStack(stmt.condition.inferType(program).typeOrElse(DataType.STRUCT)) stmt.elsepart.containsNoCodeNorVars() -> {
val elseLabel = makeLabel("if_else") // empty else
val endLabel = makeLabel("if_end") expressionsAsmGen.translateExpression(stmt.condition)
out(" beq $elseLabel") translateTestStack(stmt.condition.inferType(program).typeOrElse(DataType.STRUCT))
translate(stmt.truepart) val endLabel = makeLabel("if_end")
out(" jmp $endLabel") out(" beq $endLabel")
out(elseLabel) translate(stmt.truepart)
translate(stmt.elsepart) out(endLabel)
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) { private fun translateTestStack(dataType: DataType) {

View File

@ -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.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
RegisterOrPair.X -> { RegisterOrPair.X -> {
// return value in X register has been discarded, just push a zero // 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") asmgen.out(" stz P8ESTACK_LO,x")
else else
asmgen.out(" lda #0 | sta P8ESTACK_LO,x") asmgen.out(" lda #0 | sta P8ESTACK_LO,x")
@ -56,7 +56,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
RegisterOrPair.AX -> { RegisterOrPair.AX -> {
// return value in X register has been discarded, just push a zero in this place // return value in X register has been discarded, just push a zero in this place
asmgen.out(" sta P8ESTACK_LO,x") 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") asmgen.out(" stz P8ESTACK_HI,x")
else else
asmgen.out(" lda #0 | sta P8ESTACK_HI,x") asmgen.out(" lda #0 | sta P8ESTACK_HI,x")
@ -64,7 +64,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
} }
RegisterOrPair.XY -> { RegisterOrPair.XY -> {
// return value in X register has been discarded, just push a zero in this place // 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") asmgen.out(" stz P8ESTACK_LO,x")
else else
asmgen.out(" lda #0 | sta P8ESTACK_LO,x") 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) { when(expr.type) {
DataType.UBYTE, DataType.BYTE -> {} DataType.UBYTE, DataType.BYTE -> {}
DataType.UWORD, DataType.WORD -> { DataType.UWORD, DataType.WORD -> {
if(CompilationTarget.machine.cpu==CpuType.CPU65c02) if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
asmgen.out(" stz P8ESTACK_HI+1,x") asmgen.out(" stz P8ESTACK_HI+1,x")
else else
asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x") 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(""" asmgen.out("""
lda P8ESTACK_LO+1,x lda P8ESTACK_LO+1,x
ora #$7f ora #$7f
bmi +""") bmi +
if(CompilationTarget.machine.cpu==CpuType.CPU65c02) lda #0
asmgen.out(""" + sta P8ESTACK_HI+1,x""")
+ stz P8ESTACK_HI+1,x""")
else
asmgen.out("""
lda #0
+ sta P8ESTACK_HI+1,x""")
} }
DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_b2float") DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_b2float")
in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") 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) { private fun translateExpression(expr: BinaryExpression) {
val leftIDt = expr.left.inferType(program) val leftIDt = expr.left.inferType(program)
val rightIDt = expr.right.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() val amount = value.number.toInt()
when(rightDt) { when(rightDt) {
DataType.UBYTE -> { DataType.UBYTE -> {
if(amount in optimizedByteMultiplications) { if(amount in asmgen.optimizedByteMultiplications) {
translateExpression(expr.left) translateExpression(expr.left)
asmgen.out(" jsr math.mul_byte_$amount") asmgen.out(" jsr math.stack_mul_byte_$amount")
return return
} }
} }
DataType.BYTE -> { DataType.BYTE -> {
if(amount in optimizedByteMultiplications) { if(amount in asmgen.optimizedByteMultiplications) {
translateExpression(expr.left) translateExpression(expr.left)
asmgen.out(" jsr math.mul_byte_$amount") asmgen.out(" jsr math.stack_mul_byte_$amount")
return return
} }
if(amount.absoluteValue in optimizedByteMultiplications) { if(amount.absoluteValue in asmgen.optimizedByteMultiplications) {
translateExpression(expr.left) 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 return
} }
} }
DataType.UWORD -> { DataType.UWORD -> {
if(amount in optimizedWordMultiplications) { if(amount in asmgen.optimizedWordMultiplications) {
translateExpression(expr.left) translateExpression(expr.left)
asmgen.out(" jsr math.mul_word_$amount") asmgen.out(" jsr math.stack_mul_word_$amount")
return return
} }
} }
DataType.WORD -> { DataType.WORD -> {
if(amount in optimizedWordMultiplications) { if(amount in asmgen.optimizedWordMultiplications) {
translateExpression(expr.left) translateExpression(expr.left)
asmgen.out(" jsr math.mul_word_$amount") asmgen.out(" jsr math.stack_mul_word_$amount")
return return
} }
if(amount.absoluteValue in optimizedWordMultiplications) { if(amount.absoluteValue in asmgen.optimizedWordMultiplications) {
translateExpression(expr.left) 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 return
} }
} }

View File

@ -4,6 +4,7 @@ import prog8.ast.IFunctionCall
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.RegisterOrStatusflag
import prog8.ast.statements.Subroutine import prog8.ast.statements.Subroutine
import prog8.ast.statements.SubroutineParameter import prog8.ast.statements.SubroutineParameter
import prog8.compiler.AssemblyError 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 sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
val saveX = CpuRegister.X in sub.asmClobbers || sub.regXasResult() || sub.regXasParam() val saveX = CpuRegister.X in sub.asmClobbers || sub.regXasResult() || sub.regXasParam()
if(saveX) 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) val subName = asmgen.asmSymbolName(stmt.target)
if(stmt.args.isNotEmpty()) { 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) { private fun registerArgsViaStackEvaluation(stmt: IFunctionCall, sub: Subroutine) {
// this is called when one or more of the arguments are 'complex' and // 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. // 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()) for (arg in stmt.args.reversed())
asmgen.translateExpression(arg) 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 { when {
regparam.statusflag==Statusflag.Pc -> { argi.value.second.stack -> TODO("asmsub @stack parameter")
asmgen.out(""" argi.value.second.statusflag == Statusflag.Pc -> {
inx require(argForCarry == null)
pha argForCarry = argi
lda P8ESTACK_LO,x
beq +
sec
bcs ++
+ clc
+ pla""")
} }
regparam.statusflag!=null -> { argi.value.second.statusflag != null -> throw AssemblyError("can only use Carry as status flag parameter")
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 -> { argi.value.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.AY) -> {
val tgt = AsmAssignTarget.fromRegisters(regparam.registerOrPair, program, asmgen) require(argForAregister == null)
val source = AsmAssignSource(SourceStorageKind.STACK, program, tgt.datatype) argForAregister = argi
val asgn = AsmAssignment(source, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(asgn)
} }
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) { private fun argumentViaVariable(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression) {

View File

@ -159,6 +159,7 @@ internal class AsmAssignment(val source: AsmAssignSource,
val position: Position) { val position: Position) {
init { 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" }
} }
} }

View File

@ -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 IdentifierReference -> throw AssemblyError("source kind should have been variable")
is ArrayIndexedExpression -> throw AssemblyError("source kind should have been array") is ArrayIndexedExpression -> throw AssemblyError("source kind should have been array")
is DirectMemoryRead -> throw AssemblyError("source kind should have been memory") is DirectMemoryRead -> throw AssemblyError("source kind should have been memory")
// is TypecastExpression -> { is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, assign)
// 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 FunctionCall -> { // is FunctionCall -> {
// if (assign.target.kind == TargetStorageKind.STACK) { // if (assign.target.kind == TargetStorageKind.STACK) {
// asmgen.translateExpression(value) // 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) { private fun assignStackValue(target: AsmAssignTarget) {
when(target.kind) { when(target.kind) {
TargetStorageKind.VARIABLE -> { TargetStorageKind.VARIABLE -> {
@ -260,16 +296,18 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
when(target.register!!) { when(target.register!!) {
RegisterOrPair.A -> asmgen.out(" inx | lda P8ESTACK_LO,x") 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") 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 -> { DataType.UWORD, DataType.WORD, in PassByReferenceDatatypes -> {
when(target.register!!) { 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.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") 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) { private fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister) {
require(target.datatype in ByteDatatypes) require(target.datatype in ByteDatatypes)
when(target.kind) { when(target.kind) {
@ -571,19 +662,25 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.A -> {} RegisterOrPair.A -> {}
RegisterOrPair.X -> { asmgen.out(" tax") } RegisterOrPair.X -> { asmgen.out(" tax") }
RegisterOrPair.Y -> { asmgen.out(" tay") } 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!!) { CpuRegister.X -> when(target.register!!) {
RegisterOrPair.A -> { asmgen.out(" txa") } RegisterOrPair.A -> { asmgen.out(" txa") }
RegisterOrPair.X -> { } RegisterOrPair.X -> { }
RegisterOrPair.Y -> { asmgen.out(" txy") } 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!!) { CpuRegister.Y -> when(target.register!!) {
RegisterOrPair.A -> { asmgen.out(" tya") } RegisterOrPair.A -> { asmgen.out(" tya") }
RegisterOrPair.X -> { asmgen.out(" tyx") } RegisterOrPair.X -> { asmgen.out(" tyx") }
RegisterOrPair.Y -> { } 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.A -> asmgen.out(" lda #${byte.toHex()}")
RegisterOrPair.X -> asmgen.out(" ldx #${byte.toHex()}") RegisterOrPair.X -> asmgen.out(" ldx #${byte.toHex()}")
RegisterOrPair.Y -> asmgen.out(" ldy #${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 -> { TargetStorageKind.STACK -> {
asmgen.out(""" asmgen.out("""
@ -708,7 +807,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
// optimized case for float zero // optimized case for float zero
when(target.kind) { when(target.kind) {
TargetStorageKind.VARIABLE -> { TargetStorageKind.VARIABLE -> {
if(CompilationTarget.machine.cpu == CpuType.CPU65c02) if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(""" asmgen.out("""
stz ${target.asmVarname} stz ${target.asmVarname}
stz ${target.asmVarname}+1 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.A -> asmgen.out(" lda ${address.toHex()}")
RegisterOrPair.X -> asmgen.out(" ldx ${address.toHex()}") RegisterOrPair.X -> asmgen.out(" ldx ${address.toHex()}")
RegisterOrPair.Y -> asmgen.out(" ldy ${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 -> { TargetStorageKind.STACK -> {
asmgen.out(""" asmgen.out("""
@ -875,7 +976,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.A -> {} RegisterOrPair.A -> {}
RegisterOrPair.X -> asmgen.out(" tax") RegisterOrPair.X -> asmgen.out(" tax")
RegisterOrPair.Y -> asmgen.out(" tay") 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 -> { 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) { private fun storeByteViaRegisterAInMemoryAddress(ldaInstructionArg: String, memoryAddress: DirectMemoryWrite) {
val addressExpr = memoryAddress.addressExpression val addressExpr = memoryAddress.addressExpression
val addressLv = addressExpr as? NumericLiteralValue val addressLv = addressExpr as? NumericLiteralValue

View File

@ -8,6 +8,7 @@ import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.CpuType import prog8.compiler.target.CpuType
import prog8.compiler.target.c64.codegen.AsmGen import prog8.compiler.target.c64.codegen.AsmGen
import prog8.compiler.toHex import prog8.compiler.toHex
import kotlin.math.absoluteValue
internal class AugmentableAssignmentAsmGen(private val program: Program, internal class AugmentableAssignmentAsmGen(private val program: Program,
private val assignmentAsmGen: AssignmentAsmGen, private val assignmentAsmGen: AssignmentAsmGen,
@ -22,8 +23,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// A = -A , A = +A, A = ~A, A = not A // A = -A , A = +A, A = ~A, A = not A
val type = value.inferType(program).typeOrElse(DataType.STRUCT) val type = value.inferType(program).typeOrElse(DataType.STRUCT)
when (value.operator) { when (value.operator) {
"+" -> { "+" -> {}
}
"-" -> inplaceNegate(assign.target, type) "-" -> inplaceNegate(assign.target, type)
"~" -> inplaceInvert(assign.target, type) "~" -> inplaceInvert(assign.target, type)
"not" -> inplaceBooleanNot(assign.target, type) "not" -> inplaceBooleanNot(assign.target, type)
@ -193,7 +193,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.translateExpression(memory.addressExpression) asmgen.translateExpression(memory.addressExpression)
// TODO buggy?: // TODO buggy?:
asmgen.out(" jsr prog8_lib.read_byte_from_address_on_stack | sta P8ZP_SCRATCH_B1") 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 { when {
valueLv != null -> inplaceModification_byte_litval_to_variable(zp.SCRATCH_B1.toHex(), DataType.UBYTE, operator, valueLv.toInt()) 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) 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 else
asmgen.out(" sta (P8ZP_SCRATCH_W1),y") 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("div mem byte")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
"%" -> { "%" -> {
TODO("mem byte remainder") TODO("mem byte remainder")
@ -309,7 +311,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
else else
asmgen.out(" sta (P8ZP_SCRATCH_W1),y") 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 div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b")
"%" -> { "%" -> {
TODO("mem byte remainder") TODO("mem byte remainder")
@ -367,8 +371,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
asmgen.out(" sta (P8ZP_SCRATCH_W1),y") asmgen.out(" sta (P8ZP_SCRATCH_W1),y")
} }
"*" -> { "*" -> {
TODO("mem mul byte litval") if(value in asmgen.optimizedByteMultiplications) {
// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier TODO("optimized mem mul ubyte litval $value")
} else {
TODO("mem mul ubyte litval $value")
// asmgen.out(" jsr prog8_lib.mul_byte")
}
} }
"/" -> { "/" -> {
if(value==0) 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") "-" -> asmgen.out(" lda $name | sec | sbc P8ESTACK_LO+1,x | sta $name")
"*" -> { "*" -> {
TODO("var mul byte expr") 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") 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 | clc | adc #$value | sta $name")
"-" -> asmgen.out(" lda $name | sec | sbc #$value | sta $name") "-" -> asmgen.out(" lda $name | sec | sbc #$value | sta $name")
"*" -> { "*" -> {
// TODO what about the optimized mul_5 etc routines? if(dt == DataType.UBYTE) {
TODO("var byte mul litval") if(value in asmgen.optimizedByteMultiplications) {
// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier 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) { if (dt == DataType.UBYTE) {
@ -669,19 +689,32 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
} }
"*" -> { "*" -> {
// TODO what about the optimized mul_5 etc routines? if(dt == DataType.UWORD){
asmgen.out(""" if(value in asmgen.optimizedWordMultiplications) {
lda $name asmgen.out(" lda $name | ldy $name+1 | jsr math.mul_word_$value | sta $name | sty $name+1")
sta P8ZP_SCRATCH_W1 } else {
lda $name+1 TODO("var uword mul litval $value")
sta P8ZP_SCRATCH_W1+1 }
lda #<$value } else {
ldy #>$value if(value.absoluteValue in asmgen.optimizedWordMultiplications) {
jsr math.multiply_words asmgen.out(" lda $name | ldy $name+1 | jsr math.mul_word_$value | sta $name | sty $name+1")
lda math.multiply_words.result } else {
sta $name // TODO don't use stack here
lda math.multiply_words.result+1 // TODO does this work for signed words?
sta $name+1""") 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) if(value==0)
@ -747,13 +780,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
"&" -> { "&" -> {
when { when {
value == 0 -> { value == 0 -> {
if(CompilationTarget.machine.cpu == CpuType.CPU65c02) if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(" stz $name | stz $name+1") asmgen.out(" stz $name | stz $name+1")
else else
asmgen.out(" lda #0 | sta $name | sta $name+1") asmgen.out(" lda #0 | sta $name | sta $name+1")
} }
value and 255 == 0 -> { value and 255 == 0 -> {
if(CompilationTarget.machine.cpu == CpuType.CPU65c02) if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(" stz $name") asmgen.out(" stz $name")
else else
asmgen.out(" lda #0 | sta $name") asmgen.out(" lda #0 | sta $name")
@ -761,7 +794,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
value < 0x0100 -> { value < 0x0100 -> {
asmgen.out(" lda $name | and #$value | sta $name") 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") asmgen.out(" stz $name+1")
else else
asmgen.out(" lda #0 | sta $name+1") 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). // 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 println("warning: slow stack evaluation used (2): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
asmgen.translateExpression(value) asmgen.translateExpression(value)
asmgen.out(" jsr c64flt.pop_float_fac1")
asmgen.saveRegister(CpuRegister.X) asmgen.saveRegister(CpuRegister.X)
when (operator) { when (operator) {
"**" -> { "**" -> {
asmgen.out(""" asmgen.out("""
jsr c64flt.pop_float_fac1
lda #<$name lda #<$name
ldy #>$name ldy #>$name
jsr c64flt.CONUPK jsr c64flt.CONUPK
@ -1101,7 +1134,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
"+" -> { "+" -> {
asmgen.out(""" asmgen.out("""
jsr c64flt.pop_float_fac1
lda #<$name lda #<$name
ldy #>$name ldy #>$name
jsr c64flt.FADD jsr c64flt.FADD
@ -1109,7 +1141,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
"-" -> { "-" -> {
asmgen.out(""" asmgen.out("""
jsr c64flt.pop_float_fac1
lda #<$name lda #<$name
ldy #>$name ldy #>$name
jsr c64flt.FSUB jsr c64flt.FSUB
@ -1117,7 +1148,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
"*" -> { "*" -> {
asmgen.out(""" asmgen.out("""
jsr c64flt.pop_float_fac1
lda #<$name lda #<$name
ldy #>$name ldy #>$name
jsr c64flt.FMULT jsr c64flt.FMULT
@ -1125,7 +1155,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
"/" -> { "/" -> {
asmgen.out(""" asmgen.out("""
jsr c64flt.pop_float_fac1
lda #<$name lda #<$name
ldy #>$name ldy #>$name
jsr c64flt.FDIV 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") else -> throw AssemblyError("invalid operator for in-place float modification $operator")
} }
// store Fac1 back into memory
asmgen.out(""" asmgen.out("""
ldx #<$name ldx #<$name
ldy #>$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(""" asmgen.out("""
lda #<$name lda #<$name
ldy #>$name ldy #>$name
@ -1285,7 +1314,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
private fun inplaceCast(target: AsmAssignTarget, cast: TypecastExpression, position: Position) { private fun inplaceCast(target: AsmAssignTarget, cast: TypecastExpression, position: Position) {
val outerCastDt = cast.type val outerCastDt = cast.type
val innerCastDt = (cast.expression as? TypecastExpression)?.type val innerCastDt = (cast.expression as? TypecastExpression)?.type
if (innerCastDt == null) { if (innerCastDt == null) {
// simple typecast where the value is the target // simple typecast where the value is the target
when (target.datatype) { when (target.datatype) {
@ -1295,20 +1323,20 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
DataType.UBYTE, DataType.BYTE -> { DataType.UBYTE, DataType.BYTE -> {
when(target.kind) { when(target.kind) {
TargetStorageKind.VARIABLE -> { TargetStorageKind.VARIABLE -> {
if(CompilationTarget.machine.cpu == CpuType.CPU65c02) if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(" stz ${target.asmVarname}+1") asmgen.out(" stz ${target.asmVarname}+1")
else else
asmgen.out(" lda #0 | sta ${target.asmVarname}+1") asmgen.out(" lda #0 | sta ${target.asmVarname}+1")
} }
TargetStorageKind.ARRAY -> { TargetStorageKind.ARRAY -> {
asmgen.loadScaledArrayIndexIntoRegister(target.array!!, target.datatype, CpuRegister.Y, true) 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") asmgen.out(" stz ${target.asmVarname},y")
else else
asmgen.out(" lda #0 | sta ${target.asmVarname},y") asmgen.out(" lda #0 | sta ${target.asmVarname},y")
} }
TargetStorageKind.STACK -> { TargetStorageKind.STACK -> {
if(CompilationTarget.machine.cpu == CpuType.CPU65c02) if(CompilationTarget.instance.machine.cpu == CpuType.CPU65c02)
asmgen.out(" stz P8ESTACK_HI+1,x") asmgen.out(" stz P8ESTACK_HI+1,x")
else else
asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x") asmgen.out(" lda #0 | sta P8ESTACK_HI+1,x")

View File

@ -26,7 +26,6 @@ internal object CX16MachineDefinition: IMachineDefinition {
override val ESTACK_HI = 0x0500 // $0500-$05ff inclusive override val ESTACK_HI = 0x0500 // $0500-$05ff inclusive
override lateinit var zeropage: Zeropage override lateinit var zeropage: Zeropage
override val initSystemProcname = "cx16.init_system"
override fun getFloat(num: Number) = C64MachineDefinition.Mflpt5.fromNumber(num) 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_B1 = 0x79 // temp storage for a single byte
override val SCRATCH_REG = 0x7a // temp storage for a register 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_W1 = 0x7c // temp storage 1 for a word $7c+$7d
override val SCRATCH_W2 = 0x7e // temp storage 2 for a word $7e+$7f override val SCRATCH_W2 = 0x7e // temp storage 2 for a word $7e+$7f
@ -96,16 +94,16 @@ internal object CX16MachineDefinition: IMachineDefinition {
when (options.zeropage) { when (options.zeropage) {
ZeropageType.FULL -> { ZeropageType.FULL -> {
free.addAll(0x22..0xff) 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 -> { ZeropageType.KERNALSAFE -> {
free.addAll(0x22..0x7f) free.addAll(0x22..0x7f)
free.addAll(0xa9..0xff) 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 -> { ZeropageType.BASICSAFE -> {
free.addAll(0x22..0x7f) 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 -> { ZeropageType.DONTUSE -> {
free.clear() // don't use zeropage at all free.clear() // don't use zeropage at all
@ -115,7 +113,6 @@ internal object CX16MachineDefinition: IMachineDefinition {
require(SCRATCH_B1 !in free) require(SCRATCH_B1 !in free)
require(SCRATCH_REG !in free) require(SCRATCH_REG !in free)
require(SCRATCH_REG_X !in free)
require(SCRATCH_W1 !in free) require(SCRATCH_W1 !in free)
require(SCRATCH_W2 !in free) require(SCRATCH_W2 !in free)

View File

@ -150,7 +150,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
if(rangeExpr==null && litval!=null) { if(rangeExpr==null && litval!=null) {
// arraysize initializer is a single int, and we know the size. // arraysize initializer is a single int, and we know the size.
val fillvalue = litval.number.toDouble() 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) errors.err("float value overflow", litval.position)
else { else {
// create the array itself, filled with the fillvalue. // create the array itself, filled with the fillvalue.

View File

@ -297,6 +297,49 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
return noModifications 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? { private fun determineY(x: Expression, subBinExpr: BinaryExpression): Expression? {
return when { return when {
subBinExpr.left isSameAs x -> subBinExpr.right subBinExpr.left isSameAs x -> subBinExpr.right

View File

@ -104,7 +104,7 @@ internal class StatementOptimizer(private val program: Program,
if(string!=null) { if(string!=null) {
val pos = functionCallStatement.position val pos = functionCallStatement.position
if (string.value.length == 1) { 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( val chrout = FunctionCallStatement(
IdentifierReference(listOf("c64", "CHROUT"), pos), IdentifierReference(listOf("c64", "CHROUT"), pos),
mutableListOf(NumericLiteralValue(DataType.UBYTE, firstCharEncoded.toInt(), 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)) return listOf(IAstModification.ReplaceNode(functionCallStatement, chrout, parent))
} else if (string.value.length == 2) { } 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( val chrout1 = FunctionCallStatement(
IdentifierReference(listOf("c64", "CHROUT"), pos), IdentifierReference(listOf("c64", "CHROUT"), pos),
mutableListOf(NumericLiteralValue(DataType.UBYTE, firstTwoCharsEncoded[0].toInt(), 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 val size = sv.value.length
if(size==1) { if(size==1) {
// loop over string of length 1 -> just assign the single character // 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 byte = NumericLiteralValue(DataType.UBYTE, character, iterable.position)
val scope = AnonymousScope(mutableListOf(), forLoop.position) val scope = AnonymousScope(mutableListOf(), forLoop.position)
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, forLoop.position), byte, forLoop.position)) scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, forLoop.position), byte, forLoop.position))

View File

@ -129,7 +129,7 @@ class TestC64Zeropage {
@Test @Test
fun testNames() { 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)
zp.allocate("", DataType.UBYTE, null, errors) zp.allocate("", DataType.UBYTE, null, errors)
@ -142,37 +142,37 @@ class TestC64Zeropage {
@Test @Test
fun testZpFloatEnable() { 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> { assertFailsWith<CompilerException> {
zp.allocate("", DataType.FLOAT, null, errors) 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> { assertFailsWith<CompilerException> {
zp2.allocate("", DataType.FLOAT, null, errors) 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) zp3.allocate("", DataType.FLOAT, null, errors)
} }
@Test @Test
fun testZpModesWithFloats() { fun testZpModesWithFloats() {
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, "c64"))
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), true, "c64"))
assertFailsWith<CompilerException> { 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> { assertFailsWith<CompilerException> {
C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true)) C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), true, "c64"))
} }
} }
@Test @Test
fun testZpDontuse() { 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) println(zp.free)
assertEquals(0, zp.available()) assertEquals(0, zp.available())
assertFailsWith<CompilerException> { assertFailsWith<CompilerException> {
@ -182,19 +182,19 @@ class TestC64Zeropage {
@Test @Test
fun testFreeSpaces() { 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()) 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()) 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()) 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()) assertEquals(238, zp4.available())
} }
@Test @Test
fun testReservedSpace() { 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()) assertEquals(238, zp1.available())
assertTrue(50 in zp1.free) assertTrue(50 in zp1.free)
assertTrue(100 in zp1.free) assertTrue(100 in zp1.free)
@ -203,7 +203,7 @@ class TestC64Zeropage {
assertTrue(200 in zp1.free) assertTrue(200 in zp1.free)
assertTrue(255 in zp1.free) assertTrue(255 in zp1.free)
assertTrue(199 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()) assertEquals(139, zp2.available())
assertFalse(50 in zp2.free) assertFalse(50 in zp2.free)
assertFalse(100 in zp2.free) assertFalse(100 in zp2.free)
@ -216,7 +216,7 @@ class TestC64Zeropage {
@Test @Test
fun testBasicsafeAllocation() { 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()) assertEquals(16, zp.available())
assertFailsWith<ZeropageDepletedError> { assertFailsWith<ZeropageDepletedError> {
@ -239,7 +239,7 @@ class TestC64Zeropage {
@Test @Test
fun testFullAllocation() { 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()) assertEquals(238, zp.available())
val loc = zp.allocate("", DataType.UWORD, null, errors) val loc = zp.allocate("", DataType.UWORD, null, errors)
assertTrue(loc > 3) assertTrue(loc > 3)
@ -269,7 +269,7 @@ class TestC64Zeropage {
@Test @Test
fun testEfficientAllocation() { 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(16, zp.available())
assertEquals(0x04, zp.allocate("", DataType.WORD, null, errors)) assertEquals(0x04, zp.allocate("", DataType.WORD, null, errors))
assertEquals(0x06, zp.allocate("", DataType.UBYTE, null, errors)) assertEquals(0x06, zp.allocate("", DataType.UBYTE, null, errors))

View File

@ -33,6 +33,14 @@ This makes it easier to understand and relate the generated code. Examples::
Directives 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> .. data:: %output <type>
Level: module. 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. 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. 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 like this:: 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 {{ %asm {{
lda $62 ldy #0
eor #$ff _loop sta c64.Screen,y
asl a sta c64.Screen+$0100,y
lda #0 sta c64.Screen+$0200,y
ldx #$a0 sta c64.Screen+$02e8,y
jmp $bc4f iny
}} bne _loop
rts
}}
} }
the statement body of such a subroutine should consist of just an inline assembly block. the statement body of such a subroutine should consist of just an inline assembly block.

View File

@ -2,12 +2,15 @@
TODO TODO
==== ====
- optimize assignment codegeneration - get rid of all other TODO's in the code ;-)
- get rid of all TODO's ;-) - 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 '_' - 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) - 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' ? - 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 - see if we can group some errors together for instance the (now single) errors about unidentified symbols

View File

@ -57,7 +57,7 @@ main {
float Azy = cosb*sinc float Azy = cosb*sinc
float Azz = cosb*cosc float Azz = cosb*cosc
ubyte i ubyte @zp i
for i in 0 to len(xcoor)-1 { for i in 0 to len(xcoor)-1 {
rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i] rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*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 ; plot the points of the 3d cube
; first the points on the back, then the points on the front (painter algorithm) ; first the points on the back, then the points on the front (painter algorithm)
ubyte i ubyte @zp i
float rz float rz
float persp float persp
ubyte sx ubyte sx

View File

@ -1,12 +1,8 @@
%import c64lib %import c64lib
%import c64graphics %import c64graphics
main { main {
const uword width = 255
const uword height = 200
; vertices ; vertices
word[] xcoor = [ -100, -100, -100, -100, 100, 100, 100, 100 ] word[] xcoor = [ -100, -100, -100, -100, 100, 100, 100, 100 ]
word[] ycoor = [ -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 Azy = wcosb*wsinc / 128
word Azz = wcosb*wcosc / 128 word Azz = wcosb*wcosc / 128
ubyte i ubyte @zp i
for i in 0 to len(xcoor)-1 { for i in 0 to len(xcoor)-1 {
; don't normalize by dividing by 128, instead keep some precision for perspective calc later ; 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]) 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() { sub draw_lines() {
ubyte i ubyte @zp i
for i in len(edgesFrom) -1 downto 0 { for i in len(edgesFrom) -1 downto 0 {
ubyte vFrom = edgesFrom[i] ubyte @zp vFrom = edgesFrom[i]
ubyte vTo = edgesTo[i] ubyte @zp vTo = edgesTo[i] ; TODO need compiler error for double declaration if also declared outside the for loop!
word persp1 = 256 + rotatedz[vFrom]/256 word @zp persp1 = 256 + rotatedz[vFrom]/256
word persp2 = 256 + rotatedz[vTo]/256 word @zp persp2 = 256 + rotatedz[vTo]/256
graphics.line(rotatedx[vFrom] / persp1 + 160.w as uword, graphics.line(rotatedx[vFrom] / persp1 + screen_width/2 as uword,
rotatedy[vFrom] / persp1 + 100 as ubyte, rotatedy[vFrom] / persp1 + screen_height/2 as ubyte,
rotatedx[vTo] / persp2 + 160.w as uword, rotatedx[vTo] / persp2 + screen_width/2 as uword,
rotatedy[vTo] / persp2 + 100 as ubyte) rotatedy[vTo] / persp2 + screen_height/2 as ubyte)
} }
} }
} }

View File

@ -122,7 +122,7 @@ main {
word Azy = wcosb*wsinc / 128 word Azy = wcosb*wsinc / 128
word Azz = wcosb*wcosc / 128 word Azz = wcosb*wcosc / 128
ubyte i ubyte @zp i
for i in 0 to len(xcoor)-1 { for i in 0 to len(xcoor)-1 {
; don't normalize by dividing by 128, instead keep some precision for perspective calc later ; 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]) 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 ; 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) ; (simple bubble sort as it's only 8 items to sort)
ubyte i ubyte @zp i
ubyte i1 ubyte @zp i1
for i in 6 downto 0 { for i in 6 downto 0 {
for i1 in 0 to i { for i1 in 0 to i {
ubyte i2 = i1+1 ubyte i2 = i1+1
@ -154,7 +154,7 @@ main {
ubyte[] spritecolors = [1,1,7,15,12,11,9,9] ubyte[] spritecolors = [1,1,7,15,12,11,9,9]
for i in 0 to 7 { for i in 0 to 7 {
word zc = rotatedz[i] word @zp zc = rotatedz[i]
word persp = 300+zc/256 word persp = 300+zc/256
ubyte sx = rotatedx[i] / persp + width/2 as ubyte + 20 ubyte sx = rotatedx[i] / persp + width/2 as ubyte + 20
ubyte sy = rotatedy[i] / persp + height/2 as ubyte + 40 ubyte sy = rotatedy[i] / persp + height/2 as ubyte + 40

View File

@ -62,7 +62,7 @@ main {
word Azy = wcosb*wsinc / 128 word Azy = wcosb*wsinc / 128
word Azz = wcosb*wcosc / 128 word Azz = wcosb*wcosc / 128
ubyte i ubyte @zp i
for i in 0 to len(xcoor)-1 { for i in 0 to len(xcoor)-1 {
; don't normalize by dividing by 128, instead keep some precision for perspective calc later ; 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] rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
@ -76,9 +76,9 @@ main {
; plot the points of the 3d cube ; plot the points of the 3d cube
; first the points on the back, then the points on the front (painter algorithm) ; first the points on the back, then the points on the front (painter algorithm)
ubyte i ubyte @zp i
word rz word @zp rz
word persp word @zp persp
byte sx byte sx
byte sy byte sy

View 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).")
}
}

View 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
}
}

View 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')
}
}

View 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')
}
}

View 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')
}
}

View 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')
}
}

View 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')
}
}

View 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')
}
}

View 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")
}
}

View 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
]
}

View 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
View 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)
}
}
}
}

View File

@ -1,6 +1,7 @@
; CommanderX16 text clock example! ; CommanderX16 text datetime example!
; make sure to compile with the cx16 compiler target. ; make sure to compile with the cx16 compiler target.
%target cx16
%import cx16textio %import cx16textio
%zeropage basicsafe %zeropage basicsafe
@ -8,28 +9,6 @@ main {
sub start() { 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.r0 = mkword(8, 2020 - 1900)
cx16.r1 = mkword(19, 27) cx16.r1 = mkword(19, 27)
cx16.r2 = mkword(0, 16) cx16.r2 = mkword(0, 16)

View File

@ -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')
}
}

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio %import cx16textio
%import cx16flt %import cx16flt
%zeropage basicsafe %zeropage basicsafe
@ -5,7 +6,7 @@
main { main {
const uword width = 256 const uword width = 256
const uword height = 200 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() { sub start() {
initialize() initialize()

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio %import cx16textio
%import cx16flt %import cx16flt
%zeropage basicsafe %zeropage basicsafe

View File

@ -1,6 +1,7 @@
; CommanderX16 text clock example! ; CommanderX16 simple graphics example!
; make sure to compile with the cx16 compiler target. ; make sure to compile with the cx16 compiler target.
%target cx16
%zeropage basicsafe %zeropage basicsafe
main { main {

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16textio %import cx16textio
%import cx16flt %import cx16flt
%zeropage basicsafe %zeropage basicsafe

View File

@ -1,3 +1,4 @@
%target cx16
%import cx16lib %import cx16lib
%import cx16textio %import cx16textio
%zeropage basicsafe %zeropage basicsafe

View File

@ -38,9 +38,7 @@ main {
} }
if iter & 1 if iter & 1
; TODO fix plot() so we don't have to use separate internal variable graphics.plot(pixelx, pixely)
graphics.internal_plotx = pixelx
graphics.internal_plot(pixely)
} }
} }

View File

@ -385,9 +385,9 @@ waitkey:
} }
sub drawBlock(ubyte x, ubyte y, ubyte character) { sub drawBlock(ubyte x, ubyte y, ubyte character) {
ubyte i ubyte @zp i
for i in 15 downto 0 { for i in 15 downto 0 {
ubyte c=blocklogic.currentBlock[i] ubyte @zp c=blocklogic.currentBlock[i]
if c if c
txt.setcc((i&3)+x, (i/4)+y, character, c) txt.setcc((i&3)+x, (i/4)+y, character, c)
} }
@ -534,7 +534,7 @@ blocklogic {
} }
sub noCollision(ubyte xpos, ubyte ypos) -> ubyte { sub noCollision(ubyte xpos, ubyte ypos) -> ubyte {
ubyte i ubyte @zp i
for i in 15 downto 0 { for i in 15 downto 0 {
if currentBlock[i] and txt.getchr(xpos + (i&3), ypos+i/4)!=32 if currentBlock[i] and txt.getchr(xpos + (i&3), ypos+i/4)!=32
return false return false

View File

@ -1,8 +1,12 @@
%import c64lib
%import c64graphics
%import c64textio %import c64textio
;%import c64flt
;%option enable_floats
%zeropage basicsafe %zeropage basicsafe
main { main {
sub start() {
;asmsub clear_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) { ...} ;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. ; 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 color(...) {}
; sub other(ubyte color) {} ; TODO don't cause name conflict ; sub other(ubyte color) {} ; TODO don't cause name conflict
c64.CHROUT('\n')
sub start() {
} }
} }

View File

@ -126,7 +126,7 @@ unconditionaljump : 'goto' (integerliteral | scoped_identifier) ;
directive : directive :
directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' | directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' |
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option') '%breakpoint' | '%asminclude' | '%asmbinary' | '%option' | '%target' )
(directivearg? | directivearg (',' directivearg)*) (directivearg? | directivearg (',' directivearg)*)
; ;
@ -273,7 +273,7 @@ asmsub_decl : identifier '(' asmsub_params? ')' asmsub_clobbers? asmsub_returns?
asmsub_params : asmsub_param (',' EOL? asmsub_param)* ; 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? ')' ; asmsub_clobbers : 'clobbers' '(' clobber? ')' ;