Compare commits

...
53 Commits
Author SHA1 Message Date
Irmen de Jong 513ee25432 beta5 2025-10-15 18:29:36 +02:00
Irmen de Jong be74290ddc many more TODO messages now log proper source positions 2025-10-15 17:58:40 +02:00
Irmen de Jong a36501a9ed fix long bitwise expressions temp register usage 2025-10-14 02:57:48 +02:00
Irmen de Jong ee5d33a230 fix long if-expressions temp register usage 2025-10-14 02:16:42 +02:00
Irmen de Jong a8fd66cfdb fix long==0 long!=0 register usage 2025-10-14 01:49:42 +02:00
Irmen de Jong f5ce744748 undo the math crc param optimization that now causes the footgun warning when you import math. + doc fix about arithmetic expressions 2025-10-14 00:31:29 +02:00
Irmen de Jong 68066acdec changed (and fixed) msb(long) and lsb(long) 2025-10-13 21:34:03 +02:00
Irmen de Jong 6286035d89 support long +/- number in expressions 2025-10-13 02:50:48 +02:00
Irmen de Jong 9a37eb9146 save A and Y when storing longs 2025-10-13 02:12:07 +02:00
Irmen de Jong 307796f115 fixed some bugs in optimizing long values 2025-10-12 23:15:42 +02:00
Irmen de Jong e962431139 added bcd.addtol()/subfroml() for in-place long calculations
fix long overflow messages, IR register type error
2025-10-12 22:08:10 +02:00
Irmen de Jong b7620abc9a longs: fix msw() and lsw() 2025-10-12 19:49:36 +02:00
Irmen de Jong d2719d23f5 C128: adjust MEMTOP value to $C000 during runtime (41 Kb of available space because Basic ROM is banked out) 2025-10-12 15:02:36 +02:00
Irmen de Jong d69eead6d8 fix abs(long), mklong(), mklong2(), peekl(), pokel() 2025-10-12 14:17:27 +02:00
Irmen de Jong 6db3611d93 fix typecast error when assigning pointer to long 2025-10-12 12:44:28 +02:00
Irmen de Jong a84320c7e2 add sgn(long) support, fix sgn() result type in IR 2025-10-12 12:22:32 +02:00
Irmen de Jong dfc720557c fix some more long hex value comparisons 2025-10-12 04:40:50 +02:00
Irmen de Jong 32149d073a bitwise long exprs now use R12-R13 instead of R2-R3 2025-10-12 03:02:09 +02:00
Irmen de Jong fc38be6376 fix a const long value hex asm mistake, fix conv.str_l(0) empty output 2025-10-12 01:52:35 +02:00
Irmen de Jong 13f6efc1d1 long +/- long now use R12-R15 instead of R0-R3 2025-10-12 01:35:02 +02:00
Irmen de Jong 8296002887 fix combined reg asm name 2025-10-12 01:34:00 +02:00
Irmen de Jong 424b89f357 longs now returned in R14+R15 instead of R0+R1 2025-10-12 00:27:17 +02:00
Irmen de Jong 4f5590fbff doc 2025-10-11 21:37:59 +02:00
Irmen de Jong 598e70c49a allow negative values on poke and pokew without an explicit cast 2025-10-11 16:39:36 +02:00
Irmen de Jong a6d051b496 update syntax files 2025-10-11 16:15:34 +02:00
Irmen de Jong 796d3242e1 optimize word pointer indexing and fix long pointer indexing assignment (pokel) 2025-10-11 15:59:27 +02:00
Irmen de Jong 1e8ff6f82a warning in doc about problems when using long + R0/R1 together 2025-10-11 15:36:57 +02:00
Irmen de Jong 07bb5c36bd avoid fallback JSR peek for common case pointer+offset 2025-10-11 04:45:03 +02:00
Irmen de Jong 7e26ecb0b6 allow 'then' in if-expressions to separate condition and result value 2025-10-10 23:26:53 +02:00
Irmen de Jong 0c59ad70d4 fix aliased pointer deref problem 2025-10-10 22:13:24 +02:00
Irmen de Jong 53ce688cc5 fix pointer type check for R0-R15 subroutine arg 2025-10-10 00:54:52 +02:00
Irmen de Jong bb8b44d9d0 fix missing byte to long assignment, add c-bench-64 comparison 2025-10-10 00:01:54 +02:00
Irmen de Jong 51ae32d23e fix up todo 2025-10-09 21:14:06 +02:00
markjreed c873fac0dc feat: point doc source links to matching version (#179)
* feat: point doc source links to matching version

* fix: formatting, remove debug
2025-10-09 20:03:46 +02:00
Irmen de Jong f0a67fff8a added missing byte to long type assignment 2025-10-09 02:52:33 +02:00
Irmen de Jong f85ccd837d tweak conv.str_l() so that it properly reuses the conv.string_out buffer 2025-10-08 22:33:03 +02:00
Irmen de Jong 396fcbc927 implement missing long typecasts 2025-10-07 17:46:10 +02:00
Irmen de Jong 0f564b301d implement peekl() and pokel() 2025-10-07 00:53:00 +02:00
Irmen de Jong f4f34fc2ed added symboltable into CompilationResult because it might be useful to inspect in tests 2025-10-07 00:26:43 +02:00
Irmen de Jong f7639cb78f implement long comparisons > and <= 2025-10-06 23:42:40 +02:00
Irmen de Jong f5f5aef722 implement long comparisons < and >= 2025-10-06 22:30:17 +02:00
Irmen de Jong d6e30d8468 fix signed word and long cmp() 2025-10-06 22:05:34 +02:00
Irmen de Jong 37afdf5a18 tweak antlr grammar to improve parsing performance 2025-10-06 01:28:33 +02:00
Irmen de Jong 5eb7074172 fix gfx_lores and gfx_hires disc() inaccurracy 2025-10-05 23:21:19 +02:00
Irmen de Jong 9aff280d10 fix monogfx.disc() inaccurracy 2025-10-05 23:03:53 +02:00
Irmen de Jong 44741a8e32 fix c64 graphics.disc() inaccurracy 2025-10-05 22:57:39 +02:00
Irmen de Jong 37535f2913 optimize charfade example, added textspotlight example 2025-10-05 21:18:47 +02:00
Irmen de Jong ec9475c308 use pointer arithmetic instead of raw peeks and pokes 2025-10-05 18:38:01 +02:00
Irmen de Jong b961ce97d6 add -libdump and -libsearch compiler options 2025-10-05 17:07:55 +02:00
Irmen de Jong 4ed92d71a7 remove "@split" tag
The default is to split word arrays. If you need your word array to not be split, use @nosplit on the array.
2025-10-05 17:06:21 +02:00
Irmen de Jong 3e1386a987 remove the -dontsplitarrays compiler option
it was still there for backward compatibility reasons with really old prog8 code. If you need a word array to be not split, just use @nosplit on the array.
2025-10-05 14:44:29 +02:00
Irmen de Jong 4195e3968a remove needless library module imports in unit tests 2025-10-05 13:10:02 +02:00
Irmen de Jong 961095bfec fix output path for shadow jar 2025-10-04 23:31:52 +02:00
116 changed files with 3451 additions and 1884 deletions

No files matched your search

+9
View File
@@ -193,3 +193,12 @@ For instance here's a well known space ship animated in 3D with hidden line remo
in the CommanderX16 emulator:
![cobra3d](docs/source/_static/cobra3d.png)
Performance comparison with various C compilers
-----------------------------------------------
Here is a performance comparison with various C compilers for the 6502/C64 so you can get
an idea of how Prog8 stacks up.
[comparison](benchmark-c/benchmark.md)
+26
View File
@@ -0,0 +1,26 @@
# C-Bench-64 comparison
Several benchmarks of https://thred.github.io/c-bench-64/
have been ported to equivalent Prog8 code and the benchmark results have been penciled in in the graphs below.
Maybe one day I'll try to integrate the prog8 data properly but their benchmark site is comparing C compilers, which Prog8 clearly is not.
However conclusions so far (note: these are micro benchmarks so interpret the results as you will!)
* Prog8 program size is consistently the smallest by a fair bit.
* Prog8 execution speed places it more or less in the middle of the stack.
Measured with Prog8 V12.0 .
![crc8](result-crc8.png)
![crc16](result-crc16.png)
![crc32](result-crc32.png)
![pow](result-pow.png)
![sieve](result-sieve.png)
![sieve-bit](result-sieve-bit.png)
+71
View File
@@ -0,0 +1,71 @@
%import textio
%import floats
; note: Prog8 has a complete CRC16 routine in its library: math.crc16
main {
sub start() {
txt.lowercase()
test.benchmark_name()
cbm.SETTIM(0,0,0)
test.benchmark()
txt.print_f(floats.time() / 60)
txt.print(" seconds\n")
void test.benchmark_check()
repeat {}
}
}
test {
const uword EXPECTED = $ffd0
uword crc_result
sub benchmark_name()
{
txt.print("crc16.p8\n")
txt.print("Calculates the CRC16 of the C64 Kernal\n")
}
sub benchmark()
{
crc_result = CRC16($e000, $2000)
}
sub benchmark_check() -> bool
{
txt.print("CRC=")
txt.print_uwhex(crc_result, true)
if crc_result == EXPECTED
{
txt.print(" [OK]")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_uwhex(EXPECTED, true)
return true
}
sub CRC16(^^ubyte data, uword length) -> uword {
; CRC-16/XMODEM
uword crc
repeat length
{
crc ^= mkword(@(data),0) ; currently there's no easy way to affect only the MSB of the variable
repeat 8
{
crc <<=1
if_cs
crc ^= $1021
}
data++
}
return crc
}
}
+72
View File
@@ -0,0 +1,72 @@
%import textio
%import floats
; note: Prog8 has a complete CRC32 routine in its library: math.crc32
main {
sub start() {
txt.lowercase()
test.benchmark_name()
cbm.SETTIM(0,0,0)
test.benchmark()
txt.print_f(floats.time() / 60)
txt.print(" seconds\n")
void test.benchmark_check()
repeat {}
}
}
test {
const long EXPECTED = $e1fa84c6
long crc_result
sub benchmark_name()
{
txt.print("crc32.p8\n")
txt.print("Calculates the CRC32 of the C64 Kernal\n")
}
sub benchmark()
{
crc_result = CRC32($e000, $2000)
}
sub benchmark_check() -> bool
{
txt.print("CRC=")
txt.print_ulhex(crc_result, true)
if crc_result == EXPECTED
{
txt.print(" [OK]")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_ulhex(EXPECTED, true)
return true
}
sub CRC32(^^ubyte data, uword length) -> long {
; CRC-32/CKSUM
long crc
repeat length
{
crc ^= (@(data) as long)<<24 ; currently there's no easy way to affect only the MSB of the variable
repeat 8
{
crc <<=1
if_cs
crc ^= $04c11db7
}
data++
}
crc ^= $ffffffff
return crc
}
}
+72
View File
@@ -0,0 +1,72 @@
%import textio
%import floats
main {
sub start() {
txt.lowercase()
test.benchmark_name()
cbm.SETTIM(0,0,0)
test.benchmark()
txt.print_f(floats.time() / 60)
txt.print(" seconds\n")
void test.benchmark_check()
repeat {}
}
}
test {
sub benchmark_name()
{
txt.print("crc8.p8\n")
txt.print("Calculates the CRC8 of the C64 Kernal\n")
}
sub benchmark()
{
crc_result = CRC8($e000, $2000)
}
sub benchmark_check() -> bool
{
txt.print("CRC=")
txt.print_ubhex(crc_result, true)
if crc_result == EXPECTED
{
txt.print(" [OK]")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_ubhex(EXPECTED, true)
return true
}
const ubyte EXPECTED = $a2
ubyte crc_result
sub CRC8(^^ubyte data, uword length) -> ubyte
{
; CRC-8/GSM-A
ubyte crc
repeat length
{
crc ^= @(data)
repeat 8
{
if (crc & $80) != 0
crc = (crc << 1) ^ $1d
else
crc <<= 1
}
data++
}
return crc
}
}
+93
View File
@@ -0,0 +1,93 @@
%import textio
%import floats
main {
sub start() {
txt.lowercase()
test.benchmark_name()
cbm.SETTIM(0,0,0)
test.benchmark()
txt.print_f(floats.time() / 60)
txt.print(" seconds\n")
void test.benchmark_check()
repeat {}
}
}
test {
const ubyte N_ITER = 10
const ubyte SIZE = 32
float[SIZE] array
const float expected = 3614007361536.000000
const float epsilon = 10000000
float res
sub benchmark_name()
{
txt.print("pow.p8\n")
txt.print("Calculates floating point exponential (")
txt.print_uw(N_ITER)
txt.print(" iterations)\n")
}
sub benchmark()
{
ubyte i,j
res = 0
for j in 0 to SIZE-1 {
array[j]=0
}
for i in 0 to N_ITER-1 {
for j in 0 to SIZE-1 {
array[j] += testpow(2.5 / ((i + 1) as float), j)
}
}
for j in 0 to SIZE-1 {
res += array[j]
}
}
sub testpow(float x, ubyte y) -> float
{
float tmp = x
if y == 0
return 1
repeat y-1
tmp *= x
return tmp
}
sub benchmark_check() -> bool
{
txt.print("res = ")
txt.print_f(res)
float diff = expected - res;
txt.print("\nexpected = ")
txt.print_f(expected)
txt.print("\nepsilon = ")
txt.print_f(epsilon)
txt.print("\ndiff = ")
txt.print_f(diff)
if (diff < epsilon and diff > -epsilon)
{
txt.print(" [OK]\n")
return false
}
txt.print("[FAIL]\n")
return true
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

+85
View File
@@ -0,0 +1,85 @@
%import textio
%import floats
main {
sub start() {
txt.lowercase()
test.benchmark_name()
cbm.SETTIM(0,0,0)
test.benchmark()
txt.print_f(floats.time() / 60)
txt.print(" seconds\n")
void test.benchmark_check()
repeat {}
}
}
test {
const ubyte N_ITER = 10
const uword SIZE = 8191
const uword EXPECTED = 1900
uword prime_count
^^bool @zp flags = memory("flags", SIZE, 0)
sub benchmark_name()
{
txt.print("sieve.c\n")
txt.print("Calculates the primes from 1 to ")
txt.print_uw(SIZE * 2 + 2)
txt.print(" (")
txt.print_ub(N_ITER)
txt.print(" iterations)\n")
}
sub benchmark()
{
repeat N_ITER
prime_count = sieve(SIZE)
}
sub benchmark_check() -> bool
{
txt.print("count=")
txt.print_uw(prime_count)
if prime_count == EXPECTED
{
txt.print(" [OK]")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_uw(EXPECTED)
return true
}
sub sieve(uword size) -> uword
{
uword i, prime, k
uword count = 1
for i in 0 to size-1
flags[i] = true
for i in 0 to size-1
{
if flags[i]
{
prime = i + i + 3
k = i + prime
while k < size
{
flags[k] = false
k += prime
}
count++
}
}
return count
}
}
+107
View File
@@ -0,0 +1,107 @@
%import textio
%import floats
main {
sub start() {
txt.lowercase()
test.benchmark_name()
cbm.SETTIM(0,0,0)
test.benchmark()
txt.print_f(floats.time() / 60)
txt.print(" seconds\n")
void test.benchmark_check()
repeat {}
}
}
test {
const ubyte N_ITER = 4
const uword SIZE = 16000
const uword EXPECTED = 3432
uword prime_count
^^ubyte @zp flags = memory("flags", SIZE/8+1, 0)
sub benchmark_name()
{
txt.print("sieve_bit.p8\n")
txt.print("Calculates the primes from 1 to ")
txt.print_uw(SIZE * 2 + 2)
txt.print(" (")
txt.print_ub(N_ITER)
txt.print(" iterations)\n")
}
sub benchmark()
{
repeat N_ITER
prime_count = sieve(SIZE)
}
sub benchmark_check() -> bool
{
txt.print("count=")
txt.print_uw(prime_count)
if prime_count == EXPECTED
{
txt.print(" [OK]")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_uw(EXPECTED)
return true
}
ubyte[] bitv = [
$01,
$02,
$04,
$08,
$10,
$20,
$40,
$80
]
sub check_flag(uword idx) -> bool
{
return flags[idx / 8] & bitv[lsb(idx) & 7] != 0
}
sub clear_flag(uword idx)
{
flags[idx / 8] &= ~(bitv[lsb(idx) & 7])
}
sub sieve(uword size) -> uword
{
uword i, prime, k
uword count=1
for i in 0 to (size / 8)
flags[i] = $ff
for i in 0 to size-1
{
if check_flag(i)
{
prime = i + i + 3
k = i + prime;
while k < size
{
clear_flag(k)
k += prime
}
count++
}
}
return count
}
}
+3 -3
View File
@@ -35,7 +35,7 @@ main {
txt.color2(1, 6)
txt.clear_screen()
txt.print("\n\n\n prog8 compiler benchmark tests.\n")
txt.print("\n\n\n prog8 compiler benchmark tests.\n\n benchmark version v12\n\n")
sys.wait(60)
benchmark_number = 0
@@ -65,7 +65,7 @@ main {
benchmark_number++
announce_benchmark("circles with gfx_lores")
benchmark_score[benchmark_number] = circles.draw(false, 300)
benchmark_score[benchmark_number] = circles.draw(false, 400)
benchmark_number++
announce_benchmark("text-elite")
@@ -88,7 +88,7 @@ main {
txt.color2(1, 6)
uword total_score
benchmark_number = 0
txt.print("\nscore benchmark\n\n")
txt.print("\nscore benchmark (v12)\n\n")
do {
txt.spc()
txt.print_uw(benchmark_score[benchmark_number])
@@ -37,7 +37,7 @@ class FSignature(val pure: Boolean, // does it have side effects?
val returns: ReturnConvention = when (returnType) {
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A)
BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY)
BaseDataType.LONG -> ReturnConvention(returnType, RegisterOrPair.R0R1_32)
BaseDataType.LONG -> ReturnConvention(returnType, RegisterOrPair.R14R15_32)
BaseDataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1)
in IterableDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY)
null -> ReturnConvention(null, null)
@@ -46,7 +46,7 @@ class FSignature(val pure: Boolean, // does it have side effects?
when (val paramType = actualParamTypes.first()) {
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A)
BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY)
BaseDataType.LONG -> ReturnConvention(returnType, RegisterOrPair.R0R1_32)
BaseDataType.LONG -> ReturnConvention(returnType, RegisterOrPair.R14R15_32)
BaseDataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1)
in IterableDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY)
else -> ReturnConvention(paramType, null)
@@ -63,7 +63,7 @@ class FSignature(val pure: Boolean, // does it have side effects?
val paramConv = when(val paramType = actualParamTypes[0]) {
BaseDataType.UBYTE, BaseDataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
BaseDataType.UWORD, BaseDataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
BaseDataType.LONG -> ParamConvention(paramType, RegisterOrPair.R0R1_32, false)
BaseDataType.LONG -> ParamConvention(paramType, RegisterOrPair.R14R15_32, false)
BaseDataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY)
in IterableDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
else -> ParamConvention(paramType, null, false)
@@ -95,7 +95,7 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
"ror" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
"rol2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
"ror2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
"cmp" to FSignature(false, null, FParam("value1", *IntegerDatatypes), FParam("value2", *NumericDatatypes)), // cmp returns a status in the carry flag, but not a proper return value
"cmp" to FSignature(false, null, FParam("value1", *IntegerDatatypes), FParam("value2", *NumericDatatypes)), // cmp returns result in the cpu status flags, but not asa proper return value
"prog8_lib_stringcompare" to FSignature(true, BaseDataType.BYTE, FParam("str1", BaseDataType.STR), FParam("str2", BaseDataType.STR)),
"prog8_lib_square_byte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
"prog8_lib_square_word" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.WORD, BaseDataType.UWORD)),
@@ -117,8 +117,10 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
"divmod__ubyte" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE), FParam("divisor", BaseDataType.UBYTE), FParam("quotient", BaseDataType.UBYTE), FParam("remainder", BaseDataType.UBYTE)),
"divmod__uword" to FSignature(false, null, FParam("dividend", BaseDataType.UWORD), FParam("divisor", BaseDataType.UWORD), FParam("quotient", BaseDataType.UWORD), FParam("remainder", BaseDataType.UWORD)),
"lsb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"lsw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"lsb__long" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.LONG)),
"msb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"msb__long" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.LONG)),
"lsw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"msw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"mkword" to FSignature(true, BaseDataType.UWORD, FParam("msb", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
"mklong" to FSignature(true, BaseDataType.LONG, FParam("msb", BaseDataType.UBYTE), FParam("b2", BaseDataType.UBYTE), FParam("b1", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
@@ -146,10 +148,10 @@ val BuiltinFunctions: Map<String, FSignature> = mapOf(
"peekw" to FSignature(true, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
"peekl" to FSignature(true, BaseDataType.LONG, FParam("address", BaseDataType.UWORD)),
"peekf" to FSignature(true, BaseDataType.FLOAT, FParam("address", BaseDataType.UWORD)),
"poke" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
"poke" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE, BaseDataType.BYTE)),
"pokebool" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.BOOL)),
"pokebowl" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.BOOL)),
"pokew" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UWORD)),
"pokew" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UWORD, BaseDataType.WORD)),
"pokel" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.LONG)),
"pokef" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.FLOAT)),
"pokemon" to FSignature(false, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
@@ -29,7 +29,6 @@ class CompilationOptions(val output: OutputType,
var varsGolden: Boolean = false,
var slabsHighBank: Int? = null,
var slabsGolden: Boolean = false,
var dontSplitWordArrays: Boolean = false,
var breakpointCpuInstruction: String? = null,
var ignoreFootguns: Boolean = false,
var outputDir: Path = Path(""),
+1 -1
View File
@@ -13,7 +13,7 @@ fun Number.toHex(): String {
// 256..65536 -> "$0100".."$ffff"
// larger -> "$12345678"
// negative values are prefixed with '-'.
val integer = this.toInt()
val integer = this.toLong()
if(integer<0)
return '-' + abs(integer).toHex()
return when (integer) {
+1 -2
View File
@@ -440,7 +440,7 @@ enum class RegisterOrPair {
BaseDataType.UBYTE, BaseDataType.BOOL -> "L"
BaseDataType.BYTE -> "sL"
BaseDataType.WORD -> "s"
BaseDataType.UWORD, null -> ""
BaseDataType.UWORD, BaseDataType.POINTER, null -> ""
else -> throw IllegalArgumentException("invalid register param type for cx16 virtual reg")
}
return listOf("cx16", name.lowercase()+suffix)
@@ -530,6 +530,5 @@ enum class ZeropageWish {
enum class SplitWish {
DONTCARE,
SPLIT,
NOSPLIT
}
@@ -870,19 +870,19 @@ class AsmGen6502Internal (
when(target.kind) {
TargetStorageKind.VARIABLE -> {
out("""
lda #${hex.substring(6,8)}
lda #$${hex.substring(6,8)}
sta ${target.asmVarname}
lda #${hex.substring(4, 6)}
lda #$${hex.substring(4, 6)}
sta ${target.asmVarname}+1
lda #${hex.substring(2, 4)}
lda #$${hex.substring(2, 4)}
sta ${target.asmVarname}+2
lda #${hex.take(2)}
lda #$${hex.take(2)}
sta ${target.asmVarname}+3""")
}
TargetStorageKind.ARRAY -> TODO("assign long to array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.REGISTER -> assignExpressionToRegister(value, target.register!!, true)
TargetStorageKind.POINTER -> throw AssemblyError("assign long into pointer ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
} else if(value is PtIdentifier && value.type.isLong) {
@@ -904,8 +904,8 @@ class AsmGen6502Internal (
TargetStorageKind.ARRAY -> TODO("assign long to array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.REGISTER -> assignExpressionToRegister(value, target.register!!, true)
TargetStorageKind.POINTER -> throw AssemblyError("assign long into pointer ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
} else if(value is PtTypeCast && value.type.isLong) {
@@ -917,10 +917,10 @@ class AsmGen6502Internal (
out(" lda $valuesym | sta ${target.asmVarname}")
signExtendLongVariable(target.asmVarname, value.value.type.base)
}
TargetStorageKind.ARRAY -> TODO("assign long to array ${target.position}")
TargetStorageKind.ARRAY -> TODO("assign typecasted long to array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.REGISTER -> assignExpressionToRegister(value, target.register!!, true)
TargetStorageKind.POINTER -> throw AssemblyError("assign long into pointer ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
} else if(value.value.type.isWord) {
@@ -933,11 +933,11 @@ class AsmGen6502Internal (
sta ${target.asmVarname}+1""")
signExtendLongVariable(target.asmVarname, value.value.type.base)
}
TargetStorageKind.ARRAY -> TODO("assign long to array ${target.position}")
TargetStorageKind.ARRAY -> TODO("assign typecasted long to array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> {
require(target.register in combinedLongRegisters)
val startreg = target.register.toString().take(2).lowercase()
val startreg = target.register!!.startregname()
out("""
lda $valuesym
sta cx16.$startreg
@@ -945,15 +945,19 @@ class AsmGen6502Internal (
sta cx16.$startreg+1""")
signExtendLongVariable("cx16.$startreg", value.value.type.base)
}
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.POINTER -> {
throw AssemblyError("assign typecasted long into pointer ${target.position}")
}
TargetStorageKind.VOID -> { /* do nothing */ }
}
} else throw AssemblyError("weird casted type")
} else {
TODO("assign typecasted expression $value to a long target ${target.position} - use simple expressions and temporary variables for now")
TODO("assign typecasted expression $value to a long target ${target.kind} at ${target.position} - use simple expressions and temporary variables for now")
}
} else if(target.kind == TargetStorageKind.REGISTER) {
assignExpressionToRegister(value, target.register!!, true)
} else {
TODO("assign long expression $value to a target ${target.position} - use simple expressions and temporary variables for now")
TODO("assign long expression $value to a target ${target.kind} at ${target.position} - use simple expressions and temporary variables for now")
}
}
target.datatype.isFloat -> {
@@ -1261,12 +1265,12 @@ $repeatLabel""")
// print a message when more optimal code is possible for 65C02 cpu
val variable = symbolTable.lookup(arrayVariable.name)!!
if(variable is StStaticVariable && variable.length!!<=128u)
errors.info("the jump address array is @split, but @nosplit would create more efficient code here", jump.position)
errors.info("the jump address array is split, but @nosplit would create more efficient code here", jump.position)
}
} else {
// print a message when more optimal code is possible for 6502 cpu
if(!arrayIdx.splitWords)
errors.info("the jump address array is @nosplit, but @split would create more efficient code here", jump.position)
errors.info("the jump address array is @nosplit, but split would create more efficient code here", jump.position)
}
}
// we can do the address evaluation right now and just use a temporary pointer variable
@@ -1512,7 +1516,7 @@ $repeatLabel""")
val constOffset = (ptrAndIndex.second as? PtNumber)?.number?.toInt()
if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
TODO("address-of array element ${addrOf.position}")
} else if(addrOf.dereference!=null) {
throw AssemblyError("write &dereference, makes no sense at ${addrOf.position}")
} else {
@@ -1554,9 +1558,9 @@ $repeatLabel""")
val constOffset = (ptrAndIndex.second as? PtNumber)?.number?.toInt()
if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
TODO("address-of array element ${addrOf.position}")
} else if(addrOf.dereference!=null) {
TODO("read &dereference")
TODO("read &dereference ${addrOf.position}")
} else {
out(" lda ${asmSymbolName(addrOf.identifier!!)}+${constOffset}")
return true
@@ -1604,7 +1608,7 @@ $repeatLabel""")
val constOffset = (ptrAndIndex.second as? PtNumber)?.number?.toInt()
if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
TODO("address-of array element ${addrOf.position}")
} else if(addrOf.dereference!=null) {
throw AssemblyError("write &dereference, makes no sense at ${addrOf.position}")
} else {
@@ -1637,9 +1641,9 @@ $repeatLabel""")
val constOffset = (ptrAndIndex.second as? PtNumber)?.number?.toInt()
if(addrOf!=null && constOffset!=null) {
if(addrOf.isFromArrayElement) {
TODO("address-of array element $addrOf")
TODO("address-of array element ${addrOf.position}")
} else if(addrOf.dereference!=null) {
TODO("read &dereference")
TODO("read &dereference ${addrOf.position}")
} else {
out(" lda ${asmSymbolName(addrOf.identifier!!)}-${constOffset}")
return true
@@ -2417,6 +2421,69 @@ $repeatLabel""")
}
}
}
internal fun pushLongRegisters(startreg: RegisterOrPair, numberOfLongs: Int) {
if(numberOfLongs==0) return
val startregName = startreg.startregname()
if(numberOfLongs==1) {
out("""
sta P8ZP_SCRATCH_REG
lda cx16.$startregName
pha
lda cx16.$startregName+1
pha
lda cx16.$startregName+2
pha
lda cx16.$startregName+3
pha
lda P8ZP_SCRATCH_REG""")
return
}
val numbytes = numberOfLongs * options.compTarget.memorySize(BaseDataType.LONG)
out("""
sta P8ZP_SCRATCH_REG
sty P8ZP_SCRATCH_B1
ldy #0
- lda cx16.$startregName,y
pha
iny
cpy #$numbytes
bne -
ldy P8ZP_SCRATCH_B1
lda P8ZP_SCRATCH_REG""")
}
internal fun popLongRegisters(startreg: RegisterOrPair, numberOfLongs: Int) {
if(numberOfLongs==0) return
val startregName = startreg.startregname()
if(numberOfLongs==1) {
out("""
sta P8ZP_SCRATCH_REG
pla
sta cx16.$startregName+3
pla
sta cx16.$startregName+2
pla
sta cx16.$startregName+1
pla
sta cx16.$startregName
lda P8ZP_SCRATCH_REG""")
return
}
val numbytes = numberOfLongs * options.compTarget.memorySize(BaseDataType.LONG)
out("""
sta P8ZP_SCRATCH_REG
sty P8ZP_SCRATCH_B1
ldy #$numbytes-1
- pla
sta cx16.$startregName,y
dey
bpl -
ldy P8ZP_SCRATCH_B1
lda P8ZP_SCRATCH_REG""")
}
}
/**
@@ -30,9 +30,11 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
"msw" -> funcMsw(fcall, resultRegister)
"lsw" -> funcLsw(fcall, resultRegister)
"msb" -> funcMsb(fcall, resultRegister)
"lsb" -> funcLsb(fcall, resultRegister)
"msb__long" -> funcMsbLong(fcall, resultRegister)
"lsb" -> funcLsb(fcall, resultRegister, false)
"lsb__long" -> funcLsb(fcall, resultRegister, true)
"mkword" -> funcMkword(fcall, resultRegister)
"mklong", "mklong2" -> funcMklong(fcall) // result is in R0:R1
"mklong", "mklong2" -> funcMklong(fcall) // result is in R14:R15
"clamp__byte", "clamp__ubyte", "clamp__word", "clamp__uword", "clamp__long" -> funcClamp(fcall, resultRegister)
"min__byte", "min__ubyte", "min__word", "min__uword", "min__long" -> funcMin(fcall, resultRegister)
"max__byte", "max__ubyte", "max__word", "max__uword", "max__long" -> funcMax(fcall, resultRegister)
@@ -351,31 +353,61 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
throw AssemblyError("args for cmp() should have same dt")
} else if(arg1.type.isWord) {
if(arg2.type.isWord) {
when (arg2) {
is PtIdentifier -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
cpy ${asmgen.asmVariableName(arg2)}+1
bne +
cmp ${asmgen.asmVariableName(arg2)}
+""")
if(arg1.type.isSigned) {
when (arg2) {
is PtIdentifier -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
sec
sbc ${asmgen.asmVariableName(arg2)}
tya
sbc ${asmgen.asmVariableName(arg2)}+1""")
}
is PtBool -> TODO("word compare against bool ${arg2.position}")
is PtNumber -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
sec
sbc #<${arg2.number.toInt()}
tya
sbc #>${arg2.number.toInt()}""")
}
else -> {
asmgen.assignWordOperandsToAYAndVar(arg1, arg2, "P8ZP_SCRATCH_W1")
asmgen.out("""
sec
sbc P8ZP_SCRATCH_W1
tya
sbc P8ZP_SCRATCH_W1+1""")
}
}
is PtBool -> TODO("word compare against bool ${arg2.position}")
is PtNumber -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
cpy #>${arg2.number.toInt()}
bne +
cmp #<${arg2.number.toInt()}
} else {
when (arg2) {
is PtIdentifier -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
cpy ${asmgen.asmVariableName(arg2)}+1
bne +
cmp ${asmgen.asmVariableName(arg2)}
+""")
}
else -> {
asmgen.assignWordOperandsToAYAndVar(arg1, arg2, "P8ZP_SCRATCH_W1")
asmgen.out("""
cpy P8ZP_SCRATCH_W1+1
bne +
cmp P8ZP_SCRATCH_W1
}
is PtBool -> TODO("word compare against bool ${arg2.position}")
is PtNumber -> {
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
asmgen.out("""
cpy #>${arg2.number.toInt()}
bne +
cmp #<${arg2.number.toInt()}
+""")
}
else -> {
asmgen.assignWordOperandsToAYAndVar(arg1, arg2, "P8ZP_SCRATCH_W1")
asmgen.out("""
cpy P8ZP_SCRATCH_W1+1
bne +
cmp P8ZP_SCRATCH_W1
+""")
}
}
}
} else
@@ -386,52 +418,43 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
val var1 = asmgen.asmVariableName(arg1)
val hex = arg2.number.toUInt().toString(16).padStart(8, '0')
asmgen.out("""
sec
lda $var1
cmp #${hex.substring(6, 8)}
bne +
sbc #$${hex.substring(6, 8)}
lda $var1+1
cmp #${hex.substring(4, 6)}
bne +
sbc #$${hex.substring(4, 6)}
lda $var1+2
cmp #${hex.substring(2, 4)}
bne +
sbc #$${hex.substring(2, 4)}
lda $var1+3
cmp #${hex.take(2)}
+""")
sbc #$${hex.take(2)}""")
} else if(arg1 is PtIdentifier && arg2 is PtIdentifier) {
val var1 = asmgen.asmVariableName(arg1)
val var2 = asmgen.asmVariableName(arg2)
asmgen.out("""
sec
lda $var1
cmp $var2
bne +
sbc $var2
lda $var1+1
cmp $var2+1
bne +
sbc $var2+1
lda $var1+2
cmp $var2+2
bne +
sbc $var2+2
lda $var1+3
cmp $var2+3
+""")
sbc $var2+3""")
} else {
assignAsmGen.assignExpressionToRegister(arg2, RegisterOrPair.R2R3_32, true)
assignAsmGen.assignExpressionToRegister(arg1, RegisterOrPair.R0R1_32, true)
// cmp() doesn't return a value and as such can't be used in an expression, so no need to save the temp registers' original values
assignAsmGen.assignExpressionToRegister(arg2, RegisterOrPair.R14R15_32, true)
assignAsmGen.assignExpressionToRegister(arg1, RegisterOrPair.R12R13_32, true)
asmgen.out("""
lda cx16.r0
cmp cx16.r2
bne +
lda cx16.r0+1
cmp cx16.r2+1
bne +
lda cx16.r0+2
cmp cx16.r2+2
bne +
lda cx16.r0+3
cmp cx16.r2+3
+""")
sec
lda cx16.r12
sbc cx16.r14
lda cx16.r12+1
sbc cx16.r14+1
lda cx16.r12+2
sbc cx16.r14+2
lda cx16.r12+3
sbc cx16.r14+3""")
}
// TODO: carry flag is not correct......
} else
throw AssemblyError("args for cmp() should have same dt")
}
@@ -480,7 +503,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.out(" jsr prog8_lib.func_sqrt16_into_A")
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, fcall.position, scope, asmgen), CpuRegister.A, false, false)
}
BaseDataType.LONG -> TODO("sqrt LONG")
BaseDataType.LONG -> TODO("sqrt LONG ${fcall.position}")
BaseDataType.FLOAT -> {
asmgen.out(" jsr floats.func_sqrt_into_FAC1")
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, fcall.position, scope, asmgen))
@@ -846,7 +869,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
BaseDataType.BYTE -> asmgen.out(" jsr prog8_lib.func_sign_b_into_A")
BaseDataType.UWORD -> asmgen.out(" jsr prog8_lib.func_sign_uw_into_A")
BaseDataType.WORD -> asmgen.out(" jsr prog8_lib.func_sign_w_into_A")
BaseDataType.LONG -> TODO("sgn LONG")
BaseDataType.LONG -> asmgen.out(" jsr prog8_lib.func_sign_l_r14r15_into_A") // note: long arg is stored in R14:R15
BaseDataType.FLOAT -> asmgen.out(" jsr floats.func_sign_f_into_A")
else -> throw AssemblyError("weird type $dt")
}
@@ -866,8 +889,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, scope, asmgen), RegisterOrPair.AY)
}
BaseDataType.LONG -> {
asmgen.out(" jsr prog8_lib.abs_l_into_R0R1")
assignAsmGen.assignRegisterLong(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.R0R1_32, true, fcall.position, scope, asmgen), RegisterOrPair.R0R1_32)
asmgen.out(" jsr prog8_lib.abs_l_into_R14R15")
assignAsmGen.assignRegisterLong(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.R14R15_32, true, fcall.position, scope, asmgen), RegisterOrPair.R14R15_32)
}
BaseDataType.FLOAT -> {
asmgen.out(" jsr floats.func_abs_f_into_FAC1")
@@ -946,6 +969,19 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.restoreRegisterStack(CpuRegister.Y, true)
asmgen.out(" sta ($varname),y")
return
} else if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier) {
asmgen.assignExpressionToRegister(addrExpr.right, RegisterOrPair.AY, false)
val ptrName = asmgen.asmVariableName(addrExpr.left as PtIdentifier)
asmgen.out("""
clc
adc $ptrName
sta P8ZP_SCRATCH_W2
tya
adc $ptrName+1
sta P8ZP_SCRATCH_W2+1""")
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.A) // TODO *could* overwerite SCRATCH_W2 if it's a compliated expression...
asmgen.storeIndirectByteReg(CpuRegister.A, "P8ZP_SCRATCH_W2", 0u, false, false)
return
}
}
else -> { /* fall through */ }
@@ -996,6 +1032,20 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
iny
sta ($varname),y""")
return
} else if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier) {
asmgen.assignExpressionToRegister(addrExpr.right, RegisterOrPair.AY, false)
val ptrName = asmgen.asmVariableName(addrExpr.left as PtIdentifier)
asmgen.out("""
clc
adc $ptrName
sta P8ZP_SCRATCH_W2
tya
adc $ptrName+1
sta P8ZP_SCRATCH_W2+1""")
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AY) // TODO *could* overwerite SCRATCH_W2 if it's a compliated expression...
asmgen.out(" jsr prog8_lib.func_pokew_scratchW2")
//asmgen.storeIndirectWordReg(RegisterOrPair.AY, "P8ZP_SCRATCH_W2", 0u)
return
}
}
else -> { /* fall through */ }
@@ -1007,9 +1057,15 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
private fun funcPokeL(fcall: PtBuiltinFunctionCall) {
val addrExpr = fcall.args[0]
val value = fcall.args[1]
TODO("pokel $addrExpr, $value")
// TODO optimize for the simple cases
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
asmgen.saveRegisterStack(CpuRegister.A, false)
asmgen.saveRegisterStack(CpuRegister.Y, false)
// it's a statement so no need to preserve R14:R15
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.R14R15_32, true)
asmgen.restoreRegisterStack(CpuRegister.Y, false)
asmgen.restoreRegisterStack(CpuRegister.A, false)
asmgen.out(" jsr prog8_lib.func_pokel")
}
private fun funcPeekF(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
@@ -1046,6 +1102,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
val varname = asmgen.asmVariableName(pointer)
asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y)
asmgen.out(" lda ($varname),y")
} else if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier) {
readValueFromPointerPlusOffset(addrExpr.left as PtIdentifier, addrExpr.right, BaseDataType.BOOL)
} else fallback()
}
else -> fallback()
@@ -1091,6 +1149,8 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
lda ($varname),y
tay
txa""")
} else if(addrExpr.operator=="+" && addrExpr.left is PtIdentifier) {
readValueFromPointerPlusOffset(addrExpr.left as PtIdentifier, addrExpr.right, BaseDataType.UWORD)
} else fallback()
}
else -> fallback()
@@ -1108,10 +1168,33 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
}
private fun readValueFromPointerPlusOffset(ptr: PtIdentifier, offset: PtExpression, dt: BaseDataType) {
val varname = asmgen.asmVariableName(ptr)
asmgen.assignExpressionToRegister(offset, RegisterOrPair.AY)
asmgen.out("""
clc
adc $varname
sta P8ZP_SCRATCH_W1
tya
adc $varname+1
sta P8ZP_SCRATCH_W1+1""")
if (dt.isByteOrBool) {
if(asmgen.isTargetCpu(CpuType.CPU65C02)) {
asmgen.out(" lda (P8ZP_SCRATCH_W1)")
} else {
asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W1),y")
}
} else if(dt.isWord) {
asmgen.out(" jsr prog8_lib.func_peekw.from_scratchW1")
} else throw AssemblyError("unsupported type for peek $dt")
}
private fun funcPeekL(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
val addrExpr = fcall.args[0]
val value = fcall.args[1]
TODO("peekl $addrExpr, $value")
// TODO optimize for the simple cases
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY)
asmgen.out(" jsr prog8_lib.func_peekl")
val targetReg = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.R14R15_32, true, fcall.position, fcall.definingISub(), asmgen)
assignAsmGen.assignRegisterLong(targetReg, RegisterOrPair.R14R15_32)
}
@@ -1277,7 +1360,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
private fun funcMklong(fcall: PtBuiltinFunctionCall) {
// result long in R0:R1 (r0=lsw, r1=msw)
// result long in R14:R15 (r14=lsw, r15=msw)
fun isArgRegister(expression: PtExpression, reg: RegisterOrPair): Boolean {
if(expression !is PtIdentifier)
@@ -1287,25 +1370,25 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
if(fcall.args.size==2) {
// mklong2(msw, lsw)
if(isArgRegister(fcall.args[0], RegisterOrPair.R0) || isArgRegister(fcall.args[0], RegisterOrPair.R1) ||
isArgRegister(fcall.args[1], RegisterOrPair.R0) || isArgRegister(fcall.args[1], RegisterOrPair.R1)) {
error("cannot use R0 and/or R1 as arguments for mklong2 because the result should go into R0:R1 ${fcall.position}")
if(isArgRegister(fcall.args[0], RegisterOrPair.R14) || isArgRegister(fcall.args[0], RegisterOrPair.R15) ||
isArgRegister(fcall.args[1], RegisterOrPair.R14) || isArgRegister(fcall.args[1], RegisterOrPair.R15)) {
error("cannot use R14 and/or R15 as arguments for mklong2 because the result should go into R0:R1 ${fcall.position}")
} else {
assignAsmGen.assignExpressionToVariable(fcall.args[0], "cx16.r1", DataType.UWORD)
assignAsmGen.assignExpressionToVariable(fcall.args[1], "cx16.r0", DataType.UWORD)
assignAsmGen.assignExpressionToVariable(fcall.args[0], "cx16.r15", DataType.UWORD)
assignAsmGen.assignExpressionToVariable(fcall.args[1], "cx16.r14", DataType.UWORD)
}
} else {
// mklong(msb, b2, b1, lsb)
if(isArgRegister(fcall.args[0], RegisterOrPair.R0) || isArgRegister(fcall.args[0], RegisterOrPair.R1) ||
isArgRegister(fcall.args[1], RegisterOrPair.R0) || isArgRegister(fcall.args[1], RegisterOrPair.R1) ||
isArgRegister(fcall.args[2], RegisterOrPair.R0) || isArgRegister(fcall.args[2], RegisterOrPair.R1) ||
isArgRegister(fcall.args[3], RegisterOrPair.R0) || isArgRegister(fcall.args[3], RegisterOrPair.R1)) {
error("cannot use R0 and/or R1 as arguments for mklong because the result should go into R0:R1 ${fcall.position}")
if(isArgRegister(fcall.args[0], RegisterOrPair.R14) || isArgRegister(fcall.args[0], RegisterOrPair.R15) ||
isArgRegister(fcall.args[1], RegisterOrPair.R14) || isArgRegister(fcall.args[1], RegisterOrPair.R15) ||
isArgRegister(fcall.args[2], RegisterOrPair.R14) || isArgRegister(fcall.args[2], RegisterOrPair.R15) ||
isArgRegister(fcall.args[3], RegisterOrPair.R14) || isArgRegister(fcall.args[3], RegisterOrPair.R15)) {
error("cannot use R14 and/or R15 as arguments for mklong because the result should go into R14:R15 ${fcall.position}")
} else {
assignAsmGen.assignExpressionToVariable(fcall.args[0], "cx16.r1H", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[1], "cx16.r1L", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[2], "cx16.r0H", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[3], "cx16.r0L", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[0], "cx16.r15H", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[1], "cx16.r15L", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[2], "cx16.r14H", DataType.UBYTE)
assignAsmGen.assignExpressionToVariable(fcall.args[3], "cx16.r14L", DataType.UBYTE)
}
}
}
@@ -1377,6 +1460,39 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
}
private fun funcMsbLong(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
val arg = fcall.args.single()
if (!arg.type.isLong)
throw AssemblyError("msb__long requires long argument")
if (arg is PtNumber)
throw AssemblyError("msb(const) should have been const-folded away")
if (arg is PtIdentifier) {
val sourceName = asmgen.asmVariableName(arg)
when(resultRegister) {
null, RegisterOrPair.A -> asmgen.out(" lda $sourceName+3")
RegisterOrPair.X -> asmgen.out(" ldx $sourceName+3")
RegisterOrPair.Y -> asmgen.out(" ldy $sourceName+3")
RegisterOrPair.AX -> asmgen.out(" lda $sourceName+3 | ldx #0")
RegisterOrPair.AY -> asmgen.out(" lda $sourceName+3 | ldy #0")
RegisterOrPair.XY -> asmgen.out(" ldx $sourceName+3 | ldy #0")
in Cx16VirtualRegisters -> {
val regname = resultRegister.name.lowercase()
if(asmgen.isTargetCpu(CpuType.CPU65C02))
asmgen.out(" lda $sourceName+3 | sta cx16.$regname | stz cx16.$regname+1")
else
asmgen.out(" lda $sourceName+3 | sta cx16.$regname | lda #0 | sta cx16.$regname+1")
}
in combinedLongRegisters -> {
TODO("msb__long into long register ${fcall.position}")
}
else -> throw AssemblyError("invalid reg")
}
} else {
TODO("msb__long from $arg ${fcall.position}")
}
}
private fun funcMsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
val arg = fcall.args.single()
if (!arg.type.isWord)
@@ -1399,6 +1515,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
else
asmgen.out(" lda $sourceName+1 | sta cx16.$regname | lda #0 | sta cx16.$regname+1")
}
in combinedLongRegisters -> {
TODO("msb into long register ${fcall.position}")
}
else -> throw AssemblyError("invalid reg")
}
} else {
@@ -1475,15 +1594,21 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
asmgen.out(" sty ${reg}L | lda #0 | sta ${reg}H | lda ${reg}L")
}
in combinedLongRegisters -> {
TODO("msb into long register ${fcall.position}")
}
else -> throw AssemblyError("invalid reg")
}
}
}
private fun funcLsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
private fun funcLsb(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?, fromLong: Boolean) {
val arg = fcall.args.single()
if (!arg.type.isWord)
throw AssemblyError("lsb required word argument")
if(fromLong) {
if (!arg.type.isLong) throw AssemblyError("lsb__long requires long")
} else {
if (!arg.type.isWord) throw AssemblyError("lsb requires word")
}
if (arg is PtNumber)
throw AssemblyError("lsb(const) should have been const-folded away")
@@ -1503,6 +1628,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
else
asmgen.out(" lda $sourceName | sta cx16.$regname | lda #0 | sta cx16.$regname+1")
}
in combinedLongRegisters -> {
TODO("lsb into long register ${fcall.position}")
}
else -> throw AssemblyError("invalid reg")
}
} else {
@@ -1561,6 +1689,9 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.assignExpressionToRegister(arg, RegisterOrPair.AY)
asmgen.out(" sta ${reg}L | ldy #0 | sty ${reg}H | cmp #0")
}
in combinedLongRegisters -> {
TODO("lsb into long register ${fcall.position}")
}
else -> throw AssemblyError("invalid reg")
}
}
@@ -1585,7 +1716,19 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
else -> throw AssemblyError("invalid reg")
}
} else {
TODO("msw(expression) ${fcall.position} - use a temporary variable for now")
// TODO can't efficiently preserve R14:R15 on the stack because the result of the routine is likely to be in CPU registers,
// which in turn would be clobbered by popping stuff from the stack...
asmgen.assignExpressionToRegister(arg, RegisterOrPair.R14R15_32, true)
when(resultRegister) {
RegisterOrPair.AX -> asmgen.out(" lda cx16.r15 | ldx cx16.r15+1")
null, RegisterOrPair.AY -> asmgen.out(" lda cx16.r15 | ldy cx16.r15+1")
RegisterOrPair.XY -> asmgen.out(" ldx cx16.r15 | ldy cx16.r15+1")
in Cx16VirtualRegisters -> {
val regname = resultRegister.name.lowercase()
asmgen.out(" lda cx16.r15 | sta cx16.$regname | lda cx16.r15+1 | sta cx16.$regname+1")
}
else -> throw AssemblyError("invalid reg")
}
}
}
@@ -1608,7 +1751,21 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
else -> throw AssemblyError("invalid reg")
}
} else {
TODO("lsw(expression) ${fcall.position} - use a temporary variable for now")
// TODO can't efficiently preserve R14:R15 on the stack because the result of the routine is likely to be in CPU registers,
// which in turn would be clobbered by popping stuff from the stack...
asmgen.assignExpressionToRegister(arg, RegisterOrPair.R14R15_32, true)
when(resultRegister) {
RegisterOrPair.AX -> asmgen.out(" lda cx16.r14 | ldx cx16.r14+1")
null, RegisterOrPair.AY -> asmgen.out(" lda cx16.r14 | ldy cx16.r14+1")
RegisterOrPair.XY -> asmgen.out(" ldx cx16.r14 | ldy cx16.r14+1")
in Cx16VirtualRegisters -> {
if(resultRegister!=RegisterOrPair.R14) {
val regname = resultRegister.name.lowercase()
asmgen.out(" lda cx16.r14 | sta cx16.$regname | lda cx16.r14+1 | sta cx16.$regname+1")
}
}
else -> throw AssemblyError("invalid reg")
}
}
}
@@ -1655,7 +1812,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
val varname = "prog8_lib.func_${call.name}._arg_${paramName}"
val src = when {
conv.dt==BaseDataType.FLOAT -> getSourceForFloat(value)
conv.dt==BaseDataType.LONG -> TODO("LONG argument for builtin func")
conv.dt==BaseDataType.LONG -> TODO("LONG argument for builtin func ${call.position}")
conv.dt.isPassByRef -> {
// put the address of the argument in AY
val addr = PtAddressOf(DataType.forDt(conv.dt).typeForAddressOf(false), false, value.position)
@@ -594,10 +594,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
return when (condition.operator) {
"==" -> longEqualsValue(condition.left, condition.right, false, jumpAfterIf, stmt)
"!=" -> longEqualsValue(condition.left, condition.right, true, jumpAfterIf, stmt)
"<" -> TODO("long < 0")
"<=" -> TODO("long <= 0")
">" -> TODO("long > 0")
">=" -> TODO("long >= 0")
"<", "<=", ">", ">=" -> compareLongValues(condition.left, condition.operator, condition.right, jumpAfterIf, stmt)
else -> throw AssemblyError("expected comparison operator")
}
}
@@ -1263,12 +1260,25 @@ _jump jmp (${target.asmLabel})
}
private fun longEqualsZero(value: PtExpression, notEquals: Boolean, jump: PtJump?, stmt: PtIfElse) {
asmgen.assignExpressionToRegister(value, RegisterOrPair.R0R1_32, value.type.isSigned)
asmgen.out("""
lda cx16.r0
ora cx16.r0+1
ora cx16.r0+2
ora cx16.r0+3""")
if(value is PtIdentifier) {
val varname = asmgen.asmVariableName(value)
asmgen.out("""
lda $varname
ora $varname+1
ora $varname+2
ora $varname+3""")
} else {
asmgen.pushLongRegisters(RegisterOrPair.R14R15_32, 1)
asmgen.assignExpressionToRegister(value, RegisterOrPair.R14R15_32, value.type.isSigned)
asmgen.out("""
lda cx16.r14
ora cx16.r14+1
ora cx16.r14+2
ora cx16.r14+3
sta P8ZP_SCRATCH_REG""")
asmgen.popLongRegisters(RegisterOrPair.R14R15_32, 1)
asmgen.out(" lda P8ZP_SCRATCH_REG ; restore flags")
}
if(notEquals) {
if (jump != null)
translateJumpElseBodies("bne", "beq", jump, stmt.elseScope)
@@ -1284,7 +1294,7 @@ _jump jmp (${target.asmLabel})
private fun longLessZero(value: PtExpression, lessEquals: Boolean, jump: PtJump?, stmt: PtIfElse) {
if(lessEquals) {
TODO("long <= 0")
TODO("long <= 0 ${value.position}")
} else {
loadAndCmp0MSB(value, true)
if (jump != null)
@@ -1296,7 +1306,7 @@ _jump jmp (${target.asmLabel})
private fun longGreaterZero(value: PtExpression, lessEquals: Boolean, jump: PtJump?, stmt: PtIfElse) {
if(lessEquals) {
TODO("long >= 0")
TODO("long >= 0 ${value.position}")
} else {
loadAndCmp0MSB(value, true)
if (jump != null)
@@ -1390,71 +1400,75 @@ _jump jmp (${target.asmLabel})
jump: PtJump?,
stmt: PtIfElse
) {
// TODO this can be optimized somewhat more when the left operand is a variable as well
// we only optimize for a const right value for now
val constRight = right.asConstInteger()
val variableRight = (right as? PtIdentifier)?.name
if(constRight!=null) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.R0R1_32, left.type.isSigned)
val hex = constRight.toUInt().toString(16).padStart(8, '0')
asmgen.out("""
lda cx16.r0
cmp #$${hex.substring(6,8)}
bne +
lda cx16.r0+1
cmp #$${hex.substring(4, 6)}
bne +
lda cx16.r0+2
cmp #$${hex.substring(2, 4)}
bne +
lda cx16.r0+3
cmp #$${hex.take(2)}
+""")
} else if(variableRight!=null) {
require(right.type.isLong)
val variableLeft = (left as? PtIdentifier)?.name
if(variableLeft!=null) {
if(left is PtIdentifier) {
val leftvar = asmgen.asmVariableName(left)
if(constRight!=null) {
val hex = constRight.toUInt().toString(16).padStart(8, '0')
asmgen.out("""
lda #<$variableLeft
ldy #>$variableLeft
lda $leftvar
cmp #$${hex.substring(6,8)}
bne +
lda $leftvar+1
cmp #$${hex.substring(4, 6)}
bne +
lda $leftvar+2
cmp #$${hex.substring(2, 4)}
bne +
lda $leftvar+3
cmp #$${hex.take(2)}
+""")
} else if(variableRight!=null) {
require(right.type.isLong)
asmgen.out("""
lda #<$leftvar
ldy #>$leftvar
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #<$variableRight
ldy #>$variableRight
jsr prog8_lib.long_not_equals""")
} else {
asmgen.assignExpressionToRegister(left, RegisterOrPair.R0R1_32, left.type.isSigned)
}
}
else
{
// TODO cannot easily preserve R14:R15 on stack because we need the status flags of the comparison in between...
asmgen.assignExpressionToRegister(left, RegisterOrPair.R14R15_32, left.type.isSigned)
if(constRight!=null) {
val hex = constRight.toUInt().toString(16).padStart(8, '0')
asmgen.out("""
lda cx16.r0
lda cx16.r14
cmp #$${hex.substring(6,8)}
bne +
lda cx16.r14+1
cmp #$${hex.substring(4, 6)}
bne +
lda cx16.r14+2
cmp #$${hex.substring(2, 4)}
bne +
lda cx16.r14+3
cmp #$${hex.take(2)}
+""")
} else if(variableRight!=null) {
require(right.type.isLong)
asmgen.out("""
lda cx16.r14
cmp $variableRight
bne +
lda cx16.r0+1
lda cx16.r14+1
cmp $variableRight+1
bne +
lda cx16.r0+2
lda cx16.r14+2
cmp $variableRight+2
bne +
lda cx16.r0+3
lda cx16.r14+3
cmp $variableRight+3
+""")
} else {
TODO("long == value expression ${right.position}")
}
} else {
asmgen.assignExpressionToRegister(left, RegisterOrPair.R2R3_32, left.type.isSigned)
asmgen.assignExpressionToRegister(right, RegisterOrPair.R0R1_32, right.type.isSigned)
asmgen.out("""
lda cx16.r0
cmp cx16.r2
bne +
lda cx16.r0+1
cmp cx16.r2+1
bne +
lda cx16.r0+2
cmp cx16.r2+2
bne +
lda cx16.r0+3
cmp cx16.r2+3
+""")
}
if(notEquals) {
@@ -1470,6 +1484,49 @@ _jump jmp (${target.asmLabel})
}
}
private fun compareLongValues(
left: PtExpression,
operator: String,
right: PtExpression,
jump: PtJump?,
stmt: PtIfElse
) {
// this comparison is not part of an expression but part of an if statement, there's no need to save the previous values of the temp registers
if(operator=="<" || operator ==">=") {
assignmentAsmGen.assignExpressionToRegister(right, RegisterOrPair.R14R15_32, left.type.isSigned)
assignmentAsmGen.assignExpressionToRegister(left, RegisterOrPair.R12R13_32, left.type.isSigned)
} else {
// flip operands
assignmentAsmGen.assignExpressionToRegister(left, RegisterOrPair.R14R15_32, left.type.isSigned)
assignmentAsmGen.assignExpressionToRegister(right, RegisterOrPair.R12R13_32, left.type.isSigned)
}
asmgen.out("""
sec
lda cx16.r12
sbc cx16.r14
lda cx16.r12+1
sbc cx16.r14+1
lda cx16.r12+2
sbc cx16.r14+2
lda cx16.r12+3
sbc cx16.r14+3""")
when(operator) {
"<", ">" -> {
if (jump != null)
translateJumpElseBodies("bmi", "bpl", jump, stmt.elseScope)
else
translateIfElseBodies("bpl", stmt)
}
">=", "<=" -> {
if (jump != null)
translateJumpElseBodies("bpl", "bmi", jump, stmt.elseScope)
else
translateIfElseBodies("bmi", stmt)
}
else -> throw RuntimeException("invalid operator $operator")
}
}
private fun wordEqualsValue(
left: PtExpression,
right: PtExpression,
@@ -15,40 +15,27 @@ internal class IfExpressionAsmGen(private val asmgen: AsmGen6502Internal, privat
val falseLabel = asmgen.makeLabel("ifexpr_false")
val endLabel = asmgen.makeLabel("ifexpr_end")
evalIfExpressionConditonAndBranchWhenFalse(expr.condition, falseLabel)
when {
expr.type.isByteOrBool -> {
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.A)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A)
asmgen.out(endLabel)
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, false, false)
}
expr.type.isWord || expr.type.isString -> {
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.AY)
asmgen.out(endLabel)
assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY)
}
expr.type.isLong -> {
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.R0R1_32, true)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.R0R1_32, true)
asmgen.out(endLabel)
assignmentAsmGen.assignRegisterLong(target, RegisterOrPair.R0R1_32)
}
expr.type.isFloat -> {
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.FAC1, true)
asmgen.out(endLabel)
asmgen.assignRegister(RegisterOrPair.FAC1, target)
}
else -> throw AssemblyError("weird dt")
if(expr.type.isByteOrBool) {
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.A)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A)
asmgen.out(endLabel)
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A, false, false)
} else if(expr.type.isFloat) {
asmgen.assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
asmgen.assignExpressionToRegister(expr.falsevalue, RegisterOrPair.FAC1, true)
asmgen.out(endLabel)
asmgen.assignRegister(RegisterOrPair.FAC1, target)
} else {
asmgen.assignExpressionTo(expr.truevalue, target)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
asmgen.assignExpressionTo(expr.falsevalue, target)
asmgen.out(endLabel)
}
}
@@ -386,31 +373,32 @@ internal class IfExpressionAsmGen(private val asmgen: AsmGen6502Internal, privat
val varname = asmgen.asmVariableName(expr)
asmgen.out("""
lda $varname
cmp #${hex.substring(6, 8)}
cmp #$${hex.substring(6, 8)}
bne $falseLabel
lda $varname+1
cmp #${hex.substring(4, 6)}
cmp #$${hex.substring(4, 6)}
bne $falseLabel
lda $varname+2
cmp #${hex.substring(2, 4)}
cmp #$${hex.substring(2, 4)}
bne $falseLabel
lda $varname+3
cmp #${hex.take(2)}
cmp #$${hex.take(2)}
bne $falseLabel""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.R0R1_32)
// TODO cannot easily preserve R14:R15 on stack because we need the status flags of the comparison in between...
asmgen.assignExpressionToRegister(expr, RegisterOrPair.R14R15_32)
asmgen.out("""
lda cx16.r0
cmp #${hex.substring(6, 8)}
lda cx16.r14
cmp #$${hex.substring(6, 8)}
bne $falseLabel
lda cx16.r0+1
cmp #${hex.substring(4, 6)}
lda cx16.r14+1
cmp #$${hex.substring(4, 6)}
bne $falseLabel
lda cx16.r0+2
cmp #${hex.substring(2, 4)}
lda cx16.r14+2
cmp #$${hex.substring(2, 4)}
bne $falseLabel
lda cx16.r0+3
cmp #${hex.take(2)}
lda cx16.r14+3
cmp #$${hex.take(2)}
bne $falseLabel""")
}
}
@@ -435,18 +423,19 @@ internal class IfExpressionAsmGen(private val asmgen: AsmGen6502Internal, privat
cmp $varname2+3
bne $falseLabel""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.R0R1_32)
// TODO cannot easily preserve R14:R15 on stack because we need the status flags of the comparison in between...
asmgen.assignExpressionToRegister(expr, RegisterOrPair.R14R15_32)
asmgen.out("""
lda cx16.r0
lda cx16.r14
cmp $varname2
bne $falseLabel
lda cx16.r0+1
lda cx16.r14+1
cmp $varname2+1
bne $falseLabel
lda cx16.r0+2
lda cx16.r14+2
cmp $varname2+2
bne $falseLabel
lda cx16.r0+3
lda cx16.r14+3
cmp $varname2+3
bne $falseLabel""")
}
@@ -503,13 +492,16 @@ internal class IfExpressionAsmGen(private val asmgen: AsmGen6502Internal, privat
ora $varname+3
bne $falseLabel""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.R0R1_32)
asmgen.pushLongRegisters(RegisterOrPair.R14R15_32, 1)
asmgen.assignExpressionToRegister(expr, RegisterOrPair.R14R15_32)
asmgen.out("""
lda cx16.r0
ora cx16.r0+1
ora cx16.r0+2
ora cx16.r0+3
bne $falseLabel""")
lda cx16.r14
ora cx16.r14+1
ora cx16.r14+2
ora cx16.r14+3
sta P8ZP_SCRATCH_REG""")
asmgen.popLongRegisters(RegisterOrPair.R14R15_32, 1)
asmgen.out(" lda P8ZP_SCRATCH_REG | bne $falseLabel")
}
}
@@ -525,13 +517,16 @@ internal class IfExpressionAsmGen(private val asmgen: AsmGen6502Internal, privat
ora $varname+3
beq $falseLabel""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.R0R1_32)
asmgen.pushLongRegisters(RegisterOrPair.R14R15_32, 1)
asmgen.assignExpressionToRegister(expr, RegisterOrPair.R14R15_32)
asmgen.out("""
lda cx16.r0
ora cx16.r0+1
ora cx16.r0+2
ora cx16.r0+3
beq $falseLabel""")
lda cx16.r14
ora cx16.r14+1
ora cx16.r14+2
ora cx16.r14+3
sta P8ZP_SCRATCH_REG""")
asmgen.popLongRegisters(RegisterOrPair.R14R15_32, 1)
asmgen.out(" lda P8ZP_SCRATCH_REG | beq $falseLabel")
}
}
@@ -791,7 +791,7 @@ internal class ProgramAndVarsGen(
}
dt.isPointer -> asmgen.out("${variable.name}\t.word ?") // a pointer is just an uword address
dt.isPointerArray -> {
TODO("pointers are not supported yet")
TODO("pointers are not supported yet for uninitialized array ${variable.astNode?.position}")
}
else -> {
throw AssemblyError("weird dt")
@@ -185,7 +185,7 @@ internal class AnyExprAsmGen(
asmgen.assignRegister(RegisterOrPair.A, assign.target)
return true
}
else -> TODO("float expression operator ${expr.operator}")
else -> TODO("float expression operator ${expr.operator} ${expr.position}")
}
}
@@ -43,7 +43,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
variableAsmName!!
else {
if(array.variable==null)
TODO("asmVarname for array with pointer")
TODO("asmVarname for array with pointer $position")
asmgen.asmVariableName(array.variable!!)
}
}
@@ -121,7 +121,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
in combinedLongRegisters -> {
val dt = if(signed) DataType.LONG
else
TODO("unsigned long")
TODO("unsigned long $pos")
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
}
else -> throw AssemblyError("weird register $registers")
@@ -516,7 +516,7 @@ internal class AssignmentAsmGen(
asmgen.assignRegister(RegisterOrPair.FAC1, assign.target)
}
dt.isLong -> {
TODO("read long")
TODO("read long ${value.position}")
}
else -> throw AssemblyError("unsupported dereference type ${dt} ${value.position}")
}
@@ -655,8 +655,8 @@ internal class AssignmentAsmGen(
}
}
returnDt== BaseDataType.LONG -> {
// longs are in R0:R1 (r0=lsw, r1=msw)
assignRegisterLong(target, RegisterOrPair.R0R1_32)
// longs are in R14:R15 (r14=lsw, r15=msw)
assignRegisterLong(target, RegisterOrPair.R14R15_32)
}
returnDt==BaseDataType.FLOAT -> {
// float result from function sits in FAC1
@@ -1262,10 +1262,11 @@ internal class AssignmentAsmGen(
return true
}
assignExpressionToRegister(expr.left, RegisterOrPair.R0R1_32, signed)
// TODO: cannot preserve R14:R15 on the stack here because the stack already contains a value that we need to pop
assignExpressionToRegister(expr.left, RegisterOrPair.R14R15_32, signed)
asmgen.out(" pla | sta P8ZP_SCRATCH_REG")
augmentableAsmGen.inplacemodificationLongWithVariable("cx16.r0", expr.operator, "P8ZP_SCRATCH_REG")
assignRegisterLong(target, RegisterOrPair.R0R1_32)
augmentableAsmGen.inplacemodificationLongWithVariable("cx16.r14", expr.operator, "P8ZP_SCRATCH_REG")
assignRegisterLong(target, RegisterOrPair.R14R15_32)
return true
}
}
@@ -1401,9 +1402,13 @@ internal class AssignmentAsmGen(
return true
}
assignExpressionToRegister(expr.left, RegisterOrPair.R0R1_32, signed)
augmentableAsmGen.inplacemodificationLongWithLiteralval("cx16.r0", expr.operator, shifts)
assignRegisterLong(target, RegisterOrPair.R0R1_32)
if(target.register!=RegisterOrPair.R14R15_32)
asmgen.pushLongRegisters(RegisterOrPair.R14R15_32, 1)
assignExpressionToRegister(expr.left, RegisterOrPair.R14R15_32, signed)
augmentableAsmGen.inplacemodificationLongWithLiteralval("cx16.r14", expr.operator, shifts)
assignRegisterLong(target, RegisterOrPair.R14R15_32)
if(target.register!=RegisterOrPair.R14R15_32)
asmgen.popLongRegisters(RegisterOrPair.R14R15_32, 1)
return true
}
}
@@ -1559,7 +1564,7 @@ internal class AssignmentAsmGen(
if(right.isFromArrayElement) {
TODO("address-of array element at ${right.position}")
} else if(right.dereference!=null) {
TODO("read &dereference")
TODO("read &dereference ${right.position}")
} else {
var symbol = asmgen.asmVariableName(right.identifier!!)
if(right.identifier!!.type.isSplitWordArray) {
@@ -1753,14 +1758,33 @@ internal class AssignmentAsmGen(
asmgen.out(" jsr prog8_lib.long_sub_inplace")
}
return true
} else if(target.kind == TargetStorageKind.REGISTER) {
val startreg = target.register!!.startregname()
asmgen.assignExpressionTo(left, target)
val rightsym = asmgen.asmVariableName(right)
asmgen.out(
"""
lda #<$rightsym
ldy #>$rightsym
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #<cx16.$startreg
ldy #>cx16.$startreg"""
)
if (expr.operator == "+") {
asmgen.out(" jsr prog8_lib.long_add_inplace")
} else {
asmgen.out(" jsr prog8_lib.long_sub_inplace")
}
return true
} else {
TODO("add/subtract long ${target.position} - use simple expressions and temporary variables for now")
TODO("add/subtract long into ${target.kind} at ${target.position} - use simple expressions and temporary variables for now")
}
}
is PtNumber -> {
asmgen.assignExpressionTo(left, target)
val hex = right.number.toInt().toString(16).padStart(8, '0')
if (target.kind == TargetStorageKind.VARIABLE) {
asmgen.assignExpressionTo(left, target)
if (expr.operator == "+") {
asmgen.out("""
lda ${target.asmVarname}
@@ -1793,15 +1817,58 @@ internal class AssignmentAsmGen(
sta ${target.asmVarname}+3""")
}
return true
} else if(target.kind == TargetStorageKind.REGISTER) {
val startreg = target.register!!.startregname()
if(expr.operator=="+") {
asmgen.out("""
lda cx16.$startreg
clc
adc #$${hex.substring(6,8)}
sta cx16.$startreg
lda cx16.$startreg+1
adc #$${hex.substring(4, 6)}
sta cx16.$startreg+1
lda cx16.$startreg+2
adc #$${hex.substring(2, 4)}
sta cx16.$startreg+2
lda cx16.$startreg+3
adc #$${hex.take(2)}
sta cx16.$startreg+3""")
} else {
asmgen.out("""
lda cx16.$startreg
sec
sbc #$${hex.substring(6,8)}
sta cx16.$startreg
lda cx16.$startreg+1
sbc #$${hex.substring(4, 6)}
sta cx16.$startreg+1
lda cx16.$startreg+2
sbc #$${hex.substring(2, 4)}
sta cx16.$startreg+2
lda cx16.$startreg+3
sbc #$${hex.take(2)}
sta cx16.$startreg+3""")
}
return true
} else {
TODO("add/subtract long ${target.position} - use simple expressions and temporary variables for now")
TODO("add/subtract long const into ${target.kind} ${target.position} - use simple expressions and temporary variables for now")
}
}
else -> {
assignExpressionToRegister(expr.left, RegisterOrPair.R2R3_32, expr.left.type.isSigned)
assignExpressionToRegister(expr.right, RegisterOrPair.R0R1_32, expr.right.type.isSigned)
augmentableAsmGen.inplacemodificationLongWithVariable("cx16.r2", expr.operator, "cx16.r0")
assignRegisterLong(target, RegisterOrPair.R2R3_32)
val targetreg = target.register
if(targetreg==RegisterOrPair.R14R15_32)
asmgen.pushLongRegisters(RegisterOrPair.R12R13_32, 1)
else
asmgen.pushLongRegisters(RegisterOrPair.R12R13_32, 2)
assignExpressionToRegister(expr.left, RegisterOrPair.R14R15_32, expr.left.type.isSigned)
assignExpressionToRegister(expr.right, RegisterOrPair.R12R13_32, expr.right.type.isSigned)
augmentableAsmGen.inplacemodificationLongWithVariable("cx16.r14", expr.operator, "cx16.r12")
assignRegisterLong(target, RegisterOrPair.R14R15_32)
if(targetreg==RegisterOrPair.R14R15_32)
asmgen.popLongRegisters(RegisterOrPair.R12R13_32, 1)
else
asmgen.popLongRegisters(RegisterOrPair.R14R15_32, 2)
return true
}
}
@@ -1967,16 +2034,25 @@ internal class AssignmentAsmGen(
}
}
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.R2R3_32, expr.left.type.isSigned)
val targetreg = target.register
if(targetreg!=RegisterOrPair.R14R15_32) {
asmgen.pushLongRegisters(RegisterOrPair.R14R15_32, 1)
}
asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.R14R15_32, expr.left.type.isSigned)
val constval = expr.right.asConstInteger()
val varname = (expr.right as? PtIdentifier)?.name
if(constval!=null)
augmentableAsmGen.inplacemodificationLongWithLiteralval("cx16.r2", expr.operator, constval)
augmentableAsmGen.inplacemodificationLongWithLiteralval("cx16.r14", expr.operator, constval)
else if(varname!=null)
augmentableAsmGen.inplacemodificationLongWithVariable("cx16.r2", expr.operator, varname)
else
augmentableAsmGen.inplacemodificationLongWithExpression("cx16.r2", expr.operator, expr.right)
assignRegisterLong(target, RegisterOrPair.R2R3_32)
augmentableAsmGen.inplacemodificationLongWithVariable("cx16.r14", expr.operator, varname)
else {
// TODO: preserve R14:R15 on stack here? (the function does't do it for us)
augmentableAsmGen.inplacemodificationLongWithExpression("cx16.r14", expr.operator, expr.right)
}
assignRegisterLong(target, RegisterOrPair.R14R15_32)
if(targetreg!=RegisterOrPair.R14R15_32) {
asmgen.popLongRegisters(RegisterOrPair.R14R15_32, 1)
}
return true
}
return false
@@ -2455,7 +2531,7 @@ $endLabel""")
is PtArrayIndexer -> {
if(targetDt.isByte && valueDt.isWord) {
// just assign the lsb from the array value
return assignCastViaLsbFunc(value, target)
return assignCastWordViaLsbFunc(value, target)
} else if(targetDt.isBool && valueDt.isWord) {
return assignWordToBool(value, target)
}
@@ -2481,7 +2557,7 @@ $endLabel""")
)
assignExpression(assignDirect, target.scope)
} else {
TODO("assign bool to non-integer type $targetDt")
TODO("assign bool to non-integer type $targetDt ${value.position}")
}
}
valueDt.isByte -> {
@@ -2489,7 +2565,8 @@ $endLabel""")
assignTypeCastedRegisters(target.asmVarname, targetDt.base, RegisterOrPair.A, valueDt.base)
}
valueDt.isLong -> {
TODO("assign typecasted long to $targetDt ${value.position}")
assignExpressionToRegister(value, RegisterOrPair.R14R15_32, valueDt.isSigned)
assignTypeCastedRegisters(target.asmVarname, targetDt.base, RegisterOrPair.R14R15_32, valueDt.base)
}
valueDt.isWord || valueDt.isPointer -> {
assignExpressionToRegister(value, RegisterOrPair.AY, valueDt.isSigned)
@@ -2513,7 +2590,7 @@ $endLabel""")
if(parentTc!=null && parentTc.type.isUnsignedWord) {
// typecast a word value to ubyte and directly back to uword
// generate code for lsb(value) here instead of the ubyte typecast
return assignCastViaLsbFunc(value, target)
return assignCastWordViaLsbFunc(value, target)
}
}
@@ -2533,6 +2610,11 @@ $endLabel""")
assignRegisterByte(target, CpuRegister.A, valueDt.isSigned, true)
return
}
in combinedLongRegisters -> {
assignExpressionToRegister(value, RegisterOrPair.A, false)
assignRegisterByte(target, CpuRegister.A, valueDt.isSigned, true)
return
}
else -> {}
}
} else if(valueDt.isUnsignedWord) {
@@ -2545,7 +2627,7 @@ $endLabel""")
else
// cast an uword to a byte register, do this via lsb(value)
// generate code for lsb(value) here instead of the ubyte typecast
assignCastViaLsbFunc(value, target)
assignCastWordViaLsbFunc(value, target)
}
RegisterOrPair.AX,
RegisterOrPair.AY,
@@ -2554,6 +2636,7 @@ $endLabel""")
// 'cast' uword into a 16 bits register, just assign it
return assignExpressionToRegister(value, target.register!!, targetDt.isSigned)
}
in combinedLongRegisters -> TODO("assign wprd to long reg ${value.position}")
else -> {}
}
}
@@ -2569,7 +2652,7 @@ $endLabel""")
if(!(valueDt isAssignableTo targetDt)) {
return if(valueDt.isWord && targetDt.isByte) {
// word to byte, just take the lsb
assignCastViaLsbFunc(value, target)
assignCastWordViaLsbFunc(value, target)
} else if(valueDt.isWord && targetDt.isBool) {
// word to bool
assignWordToBool(value, target)
@@ -2582,6 +2665,12 @@ $endLabel""")
} else if(valueDt.isByteOrBool && targetDt.isWord) {
// byte to word, just assign
assignExpressionToRegister(value, target.register!!, valueDt.isSigned)
} else if(valueDt.isLong && targetDt.isByte) {
// long to byte, just take the lsb
assignCastLongToByte(value, target)
} else if(valueDt.isLong && targetDt.isWord) {
// long to word, just take the lsw
assignCastViaLswFunc(value, target)
} else
throw AssemblyError("can't cast $valueDt to $targetDt, this should have been checked in the astchecker")
}
@@ -2664,7 +2753,26 @@ $endLabel""")
asmgen.assignExpressionTo(origTypeCastExpression, target)
}
private fun assignCastViaLsbFunc(value: PtExpression, target: AsmAssignTarget) {
private fun assignCastLongToByte(value: PtExpression, target: AsmAssignTarget) {
// long to byte, can't use lsb() because that only works on words
when(value) {
is PtIdentifier -> {
val longvar = asmgen.asmVariableName(value)
asmgen.out(" lda $longvar")
assignRegisterByte(target, CpuRegister.A, true, false)
}
is PtNumber -> throw AssemblyError("casting a long number to byte should have been const-folded away ${value.position}")
else -> {
asmgen.pushLongRegisters(RegisterOrPair.R14R15_32, 1)
assignExpressionToRegister(value, RegisterOrPair.R14R15_32, true)
asmgen.out(" lda cx16.r14")
assignRegisterByte(target, CpuRegister.A, true, false)
asmgen.popLongRegisters(RegisterOrPair.R14R15_32, 1)
}
}
}
private fun assignCastWordViaLsbFunc(value: PtExpression, target: AsmAssignTarget) {
val lsb = PtBuiltinFunctionCall("lsb", false, true, DataType.UBYTE, value.position)
lsb.parent = value.parent
lsb.add(value)
@@ -2673,6 +2781,15 @@ $endLabel""")
translateNormalAssignment(assign, value.definingISub())
}
private fun assignCastViaLswFunc(value: PtExpression, target: AsmAssignTarget) {
val lsb = PtBuiltinFunctionCall("lsw", false, true, DataType.UWORD, value.position)
lsb.parent = value.parent
lsb.add(value)
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = lsb)
val assign = AsmAssignment(src, listOf(target), program.memsizer, value.position)
translateNormalAssignment(assign, value.definingISub())
}
private fun assignWordToBool(value: PtExpression, target: AsmAssignTarget) {
assignExpressionToRegister(value, RegisterOrPair.AY, false)
asmgen.out("""
@@ -2725,7 +2842,15 @@ $endLabel""")
else
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
}
BaseDataType.LONG -> TODO("assign typecasted to LONG")
BaseDataType.LONG -> {
asmgen.out("""
lda $sourceAsmVarName
sta $targetAsmVarName
lda #0
sta $targetAsmVarName+1
sta $targetAsmVarName+2
sta $targetAsmVarName+3""")
}
BaseDataType.FLOAT -> {
asmgen.out("""
lda #<$targetAsmVarName
@@ -2786,7 +2911,16 @@ $endLabel""")
BaseDataType.WORD -> {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1")
}
BaseDataType.LONG -> TODO("assign typecasted to LONG")
BaseDataType.LONG -> {
asmgen.out("""
lda $sourceAsmVarName
sta $targetAsmVarName
lda $sourceAsmVarName+1
sta $targetAsmVarName+1
lda #0
sta $targetAsmVarName+2
sta $targetAsmVarName+3""")
}
BaseDataType.FLOAT -> {
asmgen.out("""
lda #<$targetAsmVarName
@@ -2849,6 +2983,14 @@ $endLabel""")
}
}
sourceDt.isString -> throw AssemblyError("cannot typecast a string value")
sourceDt.isLong -> {
if(targetDt.isByteOrBool) {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName")
} else if(targetDt.isWord || targetDt.isPointer) {
asmgen.out(" lda $sourceAsmVarName | sta $targetAsmVarName | lda $sourceAsmVarName+1 | sta $targetAsmVarName+1")
} else
throw AssemblyError("weird type")
}
else -> throw AssemblyError("weird type")
}
}
@@ -2884,7 +3026,14 @@ $endLabel""")
else
asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1")
}
BaseDataType.LONG -> TODO("assign typecasted to LONG")
BaseDataType.LONG -> {
asmgen.out("""
st${regs.toString().lowercase()} $targetAsmVarName
lda #0
sta $targetAsmVarName+1
sta $targetAsmVarName+2
sta $targetAsmVarName+3""")
}
BaseDataType.FLOAT -> {
when(regs) {
RegisterOrPair.A -> asmgen.out(" tay")
@@ -2924,7 +3073,10 @@ $endLabel""")
asmgen.signExtendAYlsb(sourceDt)
asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
}
BaseDataType.LONG -> TODO("assign typecasted to LONG")
BaseDataType.LONG -> {
asmgen.out(" st${regs.toString().lowercase()} $targetAsmVarName")
asmgen.signExtendLongVariable(targetAsmVarName, sourceDt)
}
BaseDataType.FLOAT -> {
when(regs) {
RegisterOrPair.A -> {}
@@ -2956,7 +3108,15 @@ $endLabel""")
else -> throw AssemblyError("non-word regs")
}
}
BaseDataType.LONG -> TODO("assign typecasted to LONG")
BaseDataType.LONG -> {
when(regs) {
RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1")
RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1")
else -> throw AssemblyError("non-word regs")
}
asmgen.out(" lda #0 | sta $targetAsmVarName+2 | sta $targetAsmVarName+3")
}
BaseDataType.FLOAT -> {
if(regs!=RegisterOrPair.AY)
throw AssemblyError("only supports AY here")
@@ -3019,10 +3179,27 @@ $endLabel""")
RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1")
else -> throw AssemblyError("non-word regs")
}
} else if(targetDt.isLong) {
when(regs) {
RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1")
RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1")
RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1")
else -> throw AssemblyError("non-word regs")
}
asmgen.out(" lda #0 | sta $targetAsmVarName+2 | sta $targetAsmVarName+3")
} else {
throw AssemblyError("cannot assign pointer to $targetDt")
}
}
BaseDataType.LONG -> {
val startreg = regs.startregname()
if(targetDt.isByteOrBool) {
asmgen.out(" lda cx16.$startreg | sta $targetAsmVarName")
} else if(targetDt.isWord || targetDt.isPointer) {
asmgen.out(" lda cx16.$startreg | sta $targetAsmVarName | lda cx16.$startreg+1 | sta $targetAsmVarName+1")
} else
throw AssemblyError("weird type")
}
else -> throw AssemblyError("weird type")
}
}
@@ -3165,7 +3342,7 @@ $endLabel""")
sta cx16.${target.register.toString().lowercase()}
sty cx16.${target.register.toString().lowercase()}+1""")
}
else -> throw AssemblyError("can't load address in a single 8-bit register")
else -> throw AssemblyError("can only load address into 16 bit register")
}
}
TargetStorageKind.POINTER -> pointergen.assignAddressOf(PtrTarget(target), sourceName)
@@ -3209,16 +3386,16 @@ $endLabel""")
TargetStorageKind.VARIABLE -> {
when(sourceDt) {
DataType.BYTE -> {
TODO("signed byte to long var")
TODO("signed byte to long var ${target.position}")
}
DataType.UBYTE -> {
TODO("ubyte to long var")
TODO("ubyte to long var ${target.position}")
}
DataType.WORD -> {
TODO("signed word to long var")
TODO("signed word to long var ${target.position}")
}
DataType.UWORD -> {
TODO("ubyte to long var")
TODO("ubyte to long var ${target.position}")
}
DataType.LONG -> {
asmgen.out("""
@@ -3255,7 +3432,7 @@ $endLabel""")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> {
require(target.register in combinedLongRegisters)
val regstart = target.register.toString().take(2).lowercase()
val regstart = target.register!!.startregname()
when(sourceDt) {
DataType.BYTE -> {
asmgen.out(" lda $varName | sta cx16.$regstart")
@@ -3404,6 +3581,7 @@ $endLabel""")
else
asmgen.out(" lda #0 | sta cx16.${target.register.toString().lowercase()}+1")
}
in combinedLongRegisters -> TODO("assign byte to long reg ${target.position}")
else -> throw AssemblyError("can't load word in a single 8-bit register")
}
} else {
@@ -3418,6 +3596,7 @@ $endLabel""")
lda $varName+1
sta cx16.${target.register.toString().lowercase()}+1""")
}
in combinedLongRegisters -> TODO("assign byte to long reg ${target.position}")
else -> throw AssemblyError("can't load word in a single 8-bit register")
}
}
@@ -3595,6 +3774,7 @@ $endLabel""")
lda #0
sta cx16.${target.register.toString().lowercase()}+1""")
}
in combinedLongRegisters -> TODO("assign byte to long reg ${target.position}")
else -> throw AssemblyError("weird register")
}
}
@@ -3804,7 +3984,7 @@ $endLabel""")
else throw AssemblyError("only combined vreg allowed as long target ${target.position}")
}
TargetStorageKind.ARRAY -> {
TODO("assign 32 bits int in R0:R1 into array ${target.position}")
TODO("assign 32 bits int into array ${target.position}")
}
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> {
@@ -3829,13 +4009,13 @@ $endLabel""")
}
}
internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister, signed: Boolean, extendWord: Boolean) {
internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister, signed: Boolean, extendSignedBits: Boolean) {
val assignAsWord = target.datatype.isWord
when(target.kind) {
TargetStorageKind.VARIABLE -> {
asmgen.out(" st${register.name.lowercase()} ${target.asmVarname}")
if(assignAsWord && extendWord) {
if(assignAsWord && extendSignedBits) {
if(target.datatype.isSigned) {
if(register!=CpuRegister.A)
asmgen.out(" t${register.name.lowercase()}a")
@@ -3864,7 +4044,7 @@ $endLabel""")
CpuRegister.X -> asmgen.out(" txa")
CpuRegister.Y -> asmgen.out(" tya")
}
if(extendWord) {
if(extendSignedBits) {
asmgen.signExtendAYlsb(if(target.datatype.isSigned) BaseDataType.BYTE else BaseDataType.UBYTE)
} else {
asmgen.out(" ldy #0")
@@ -3881,7 +4061,7 @@ $endLabel""")
RegisterOrPair.X -> { asmgen.out(" tax") }
RegisterOrPair.Y -> { asmgen.out(" tay") }
RegisterOrPair.AY -> {
require(extendWord) {
require(extendSignedBits) {
"no extend but byte target is registerpair"
}
if(signed)
@@ -3895,7 +4075,7 @@ $endLabel""")
asmgen.out(" ldy #0")
}
RegisterOrPair.AX -> {
require(extendWord)
require(extendSignedBits)
if(signed)
asmgen.out("""
ldx #0
@@ -3907,7 +4087,7 @@ $endLabel""")
asmgen.out(" ldx #0")
}
RegisterOrPair.XY -> {
require(extendWord)
require(extendSignedBits)
if(signed)
asmgen.out("""
tax
@@ -3923,9 +4103,16 @@ $endLabel""")
in Cx16VirtualRegisters -> {
val reg = "cx16.${target.register.toString().lowercase()}"
asmgen.out(" sta $reg")
if(extendWord)
if(extendSignedBits)
extendToMSBofVirtualReg(CpuRegister.A, reg, signed)
}
in combinedLongRegisters -> {
val reg = target.register.startregname()
asmgen.out(" sta cx16.$reg")
if(extendSignedBits) {
asmgen.signExtendLongVariable("cx16.$reg", if(signed) BaseDataType.BYTE else BaseDataType.UBYTE)
}
}
else -> throw AssemblyError("weird register")
}
CpuRegister.X -> when(target.register!!) {
@@ -3933,7 +4120,7 @@ $endLabel""")
RegisterOrPair.X -> { }
RegisterOrPair.Y -> { asmgen.out(" stx P8ZP_SCRATCH_REG | ldy P8ZP_SCRATCH_REG") }
RegisterOrPair.AY -> {
require(extendWord)
require(extendSignedBits)
if(signed)
asmgen.out("""
txa
@@ -3946,7 +4133,7 @@ $endLabel""")
asmgen.out(" txa | ldy #0")
}
RegisterOrPair.AX -> {
require(extendWord)
require(extendSignedBits)
if(signed)
asmgen.out("""
txa
@@ -3959,7 +4146,7 @@ $endLabel""")
asmgen.out(" txa | ldx #0")
}
RegisterOrPair.XY -> {
require(extendWord)
require(extendSignedBits)
if(signed)
asmgen.out("""
ldy #0
@@ -3974,9 +4161,10 @@ $endLabel""")
in Cx16VirtualRegisters -> {
val reg = "cx16.${target.register.toString().lowercase()}"
asmgen.out(" stx $reg")
if(extendWord)
if(extendSignedBits)
extendToMSBofVirtualReg(CpuRegister.X, reg, signed)
}
in combinedLongRegisters -> TODO("assign byte to long reg ${target.position}")
else -> throw AssemblyError("weird register")
}
CpuRegister.Y -> when(target.register!!) {
@@ -3984,7 +4172,7 @@ $endLabel""")
RegisterOrPair.X -> { asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") }
RegisterOrPair.Y -> { }
RegisterOrPair.AY -> {
require(extendWord)
require(extendSignedBits)
if(signed)
asmgen.out("""
tya
@@ -3997,7 +4185,7 @@ $endLabel""")
asmgen.out(" tya | ldy #0")
}
RegisterOrPair.AX -> {
require(extendWord)
require(extendSignedBits)
if(signed)
asmgen.out("""
tya
@@ -4010,7 +4198,7 @@ $endLabel""")
asmgen.out(" tya | ldx #0")
}
RegisterOrPair.XY -> {
require(extendWord)
require(extendSignedBits)
if(signed)
asmgen.out("""
tya
@@ -4027,14 +4215,15 @@ $endLabel""")
in Cx16VirtualRegisters -> {
val reg = "cx16.${target.register.toString().lowercase()}"
asmgen.out(" sty $reg")
if(extendWord)
if(extendSignedBits)
extendToMSBofVirtualReg(CpuRegister.Y, reg, signed)
}
in combinedLongRegisters -> TODO("assign byte to long reg ${target.position}")
else -> throw AssemblyError("weird register")
}
}
}
TargetStorageKind.POINTER -> pointergen.assignByteReg(PtrTarget(target), register, signed, extendWord)
TargetStorageKind.POINTER -> pointergen.assignByteReg(PtrTarget(target), register, signed, extendSignedBits)
TargetStorageKind.VOID -> { /* do nothing */ }
}
}
@@ -4302,7 +4491,14 @@ $endLabel""")
sta ${target.asmVarname}+3,y""")
}
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.REGISTER -> {
val startreg = target.register!!.startregname()
asmgen.out("""
stz $startreg
stz $startreg+1
stz $startreg+2
stz $startreg+3""")
}
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
@@ -4694,6 +4890,7 @@ $endLabel""")
lda #0
sta cx16.${target.register.toString().lowercase()}+1""")
}
in combinedLongRegisters -> TODO("assign memory byte into long ${target.position}")
else -> throw AssemblyError("weird register")
}
TargetStorageKind.POINTER -> pointergen.assignByteMemory(PtrTarget(target), address)
@@ -4729,6 +4926,15 @@ $endLabel""")
lda #0
sta cx16.${target.register.toString().lowercase()}+1""")
}
in combinedLongRegisters -> {
val startreg = target.register.startregname()
asmgen.out("""
sta cx16.$startreg
lda #0
sta cx16.$startreg+1
sta cx16.$startreg+2
sta cx16.$startreg+3""")
}
else -> throw AssemblyError("weird register")
}
}
@@ -4943,6 +5149,7 @@ $endLabel""")
RegisterOrPair.AY -> asmgen.out(" pha | tya | eor #255 | tay | pla | eor #255")
RegisterOrPair.XY -> asmgen.out(" txa | eor #255 | tax | tya | eor #255 | tay")
in Cx16VirtualRegisters -> throw AssemblyError("cx16 virtual regs should be variables, not real registers")
in combinedLongRegisters -> TODO("in place negate long invert ${target.position}")
else -> throw AssemblyError("invalid reg dt for word invert")
}
}
@@ -5071,6 +5278,7 @@ $endLabel""")
tay""")
}
in Cx16VirtualRegisters -> throw AssemblyError("cx16 virtual regs should be variables, not real registers")
in combinedLongRegisters -> TODO("in place negate long reg ${target.position}")
else -> throw AssemblyError("invalid reg dt for word neg")
}
}
@@ -5100,7 +5308,7 @@ $endLabel""")
}
TargetStorageKind.ARRAY -> TODO(" - long array ${target.position}")
TargetStorageKind.MEMORY -> throw AssemblyError("memory is bytes not long ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register assign? (we have no 32 bits registers right now) ${target.position}")
TargetStorageKind.REGISTER -> TODO("32 bits register negate ${target.position}")
TargetStorageKind.POINTER -> throw AssemblyError("can't assign long to pointer, pointers are 16 bits ${target.position}")
TargetStorageKind.VOID -> { /* do nothing */ }
}
@@ -123,7 +123,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(target.asmVarname, operator, value.number!!.number)
SourceStorageKind.VARIABLE -> inplacemodificationFloatWithVariable(target.asmVarname, operator, value.asmVarname)
SourceStorageKind.REGISTER -> inplacemodificationFloatWithVariable(target.asmVarname, operator, regName(value))
SourceStorageKind.MEMORY -> TODO("memread into float")
SourceStorageKind.MEMORY -> TODO("memread into float ${target.position}")
SourceStorageKind.ARRAY -> inplacemodificationFloatWithValue(target.asmVarname, operator, value.array!!)
SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
@@ -167,7 +167,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
SourceStorageKind.LITERALNUMBER -> inplacemodificationBytePointerWithLiteralval(pointer, operator, value.number!!.number.toInt())
SourceStorageKind.VARIABLE -> inplacemodificationBytePointerWithVariable(pointer, operator, value.asmVarname)
SourceStorageKind.REGISTER -> inplacemodificationBytePointerWithVariable(pointer, operator, regName(value))
SourceStorageKind.MEMORY -> TODO("memread into pointer")
SourceStorageKind.MEMORY -> TODO("memread into pointer ${target.position}")
SourceStorageKind.ARRAY -> inplacemodificationBytePointerWithValue(pointer, operator, value.array!!)
SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
@@ -327,7 +327,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(targetVarName, operator, value.number!!.number)
SourceStorageKind.VARIABLE -> inplacemodificationFloatWithVariable(targetVarName, operator, value.asmVarname)
SourceStorageKind.REGISTER -> inplacemodificationFloatWithVariable(targetVarName, operator, regName(value))
SourceStorageKind.MEMORY -> TODO("memread into float array")
SourceStorageKind.MEMORY -> TODO("memread into float array ${target.position}")
SourceStorageKind.ARRAY -> inplacemodificationFloatWithValue(targetVarName, operator, value.array!!)
SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
@@ -518,7 +518,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
SourceStorageKind.LITERALNUMBER -> inplacemodificationFloatWithLiteralval(tempvar, operator, value.number!!.number)
SourceStorageKind.VARIABLE -> inplacemodificationFloatWithVariable(tempvar, operator, value.asmVarname)
SourceStorageKind.REGISTER -> inplacemodificationFloatWithVariable(tempvar, operator, regName(value))
SourceStorageKind.MEMORY -> TODO("memread into float")
SourceStorageKind.MEMORY -> TODO("memread into float ${target.position}")
SourceStorageKind.ARRAY -> inplacemodificationFloatWithValue(tempvar, operator, value.array!!)
SourceStorageKind.EXPRESSION -> {
if(value.expression is PtTypeCast) {
@@ -554,8 +554,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
}
internal fun inplacemodificationLongWithExpression(targetVar: String, operator: String, value: PtExpression) {
assignmentAsmGen.assignExpressionToRegister(value, RegisterOrPair.R0R1_32, value.type.isSigned)
inplacemodificationLongWithVariable(targetVar, operator, "cx16.r0")
// it's not an expression so no need to preserve R14:R15
assignmentAsmGen.assignExpressionToRegister(value, RegisterOrPair.R14R15_32, value.type.isSigned)
inplacemodificationLongWithVariable(targetVar, operator, "cx16.r14")
}
internal fun inplacemodificationLongWithVariable(targetVar: String, operator: String, sourceVar: String) {
@@ -1438,7 +1439,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
+""")
}
// pretty uncommon, who's going to assign a comparison boolean expression to a pointer?
"<", "<=", ">", ">=" -> TODO("byte-var-to-pointer comparisons")
"<", "<=", ">", ">=" -> TODO("byte-var-to-pointer comparisons ${pointervar.position}")
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
asmgen.storeAIntoZpPointerVar(sourceName, false)
@@ -1561,7 +1562,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.storeAIntoZpPointerVar(sourceName, false)
}
// pretty uncommon, who's going to assign a comparison boolean expression to a pointer?:
"<", "<=", ">", ">=" -> TODO("byte-litval-to-pointer comparisons")
"<", "<=", ">", ">=" -> TODO("byte-litval-to-pointer comparisons ${pointervar.position}")
else -> throw AssemblyError("invalid operator for in-place modification $operator")
}
}
@@ -249,7 +249,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
asmgen.assignRegister(RegisterOrPair.FAC1, target)
}
else if(value.type.isLong)
TODO("load long")
TODO("load long ${value.position}")
else
throw AssemblyError("weird dt ${value.type} in pointer deref assignment ${target.position}")
}
@@ -264,6 +264,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
if (target.dt.isByte) inplaceByteAdd(target, value)
else if (target.dt.isWord) inplaceWordAdd(target, value)
else if (target.dt.isFloat) inplaceFloatAddOrMul(target, "FADD", value)
else if (target.dt.isLong) inplaceLongAdd(target, value)
else throw AssemblyError("weird dt ${target.dt} ${target.position}")
}
}
@@ -275,6 +276,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
if (target.dt.isByte) inplaceByteSub(target, value)
else if (target.dt.isWord) inplaceWordSub(target, value)
else if (target.dt.isFloat) inplaceFloatSubOrDiv(target, "FSUB", value)
else if (target.dt.isLong) inplaceLongSub(target, value)
else throw AssemblyError("weird dt ${target.position}")
}
}
@@ -282,15 +284,17 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
if(target.dt.isByte) TODO("inplaceByteMul(target, value) ${target.position}")
else if(target.dt.isWord) inplaceWordMul(target, value)
else if(target.dt.isFloat) inplaceFloatAddOrMul(target, "FMULT", value)
else if(target.dt.isLong) TODO("inplace long mul ${target.position}")
else throw AssemblyError("weird dt ${target.position}")
}
"/" -> {
if(target.dt.isByte) TODO("inplaceByteDiv(target, value) ${target.position}")
else if(target.dt.isWord) inplaceWordDiv(target, value)
else if(target.dt.isFloat) inplaceFloatSubOrDiv(target, "FDIV", value)
else if(target.dt.isLong) TODO("inplace long div ${target.position}")
else throw AssemblyError("weird dt ${target.position}")
}
"%" -> TODO("inplace ptr %")
"%" -> TODO("inplace ptr % ${target.position}")
"<<" -> {
if(target.dt.isByte) inplaceByteShiftLeft(target, value)
else if(target.dt.isWord) inplaceWordShiftLeft(target, value)
@@ -467,7 +471,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
if(left.variable!=null) {
asmgen.assignExpressionToRegister(left.variable!!, RegisterOrPair.AY)
} else if(left.pointerderef!=null) {
TODO("get pointer from deref $left")
TODO("get pointer from deref $left ${left.position}")
} else {
throw AssemblyError("weird arrayindexer $left")
}
@@ -943,6 +947,24 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
}
}
private fun inplaceLongAdd(target: PtrTarget, value: AsmAssignSource) {
when(value.kind) {
SourceStorageKind.LITERALNUMBER -> TODO("inplace long add with ${value.number} ${target.position}")
SourceStorageKind.VARIABLE -> TODO("inplace long add with ${value.asmVarname} ${target.position}")
SourceStorageKind.EXPRESSION -> TODO("inplace long add with ${value.expression} ${target.position}")
else -> TODO("inplace long add with ${value.kind} ${target.position}")
}
}
private fun inplaceLongSub(target: PtrTarget, value: AsmAssignSource) {
when(value.kind) {
SourceStorageKind.LITERALNUMBER -> TODO("inplace long sub with ${value.number} ${target.position}")
SourceStorageKind.VARIABLE -> TODO("inplace long sub with ${value.asmVarname} ${target.position}")
SourceStorageKind.EXPRESSION -> TODO("inplace long sub with ${value.expression} ${target.position}")
else -> TODO("inplace long sub with ${value.kind} ${target.position}")
}
}
private fun inplaceWordAdd(target: PtrTarget, value: AsmAssignSource) {
val (zpPtrVar, offset) = deref(target.pointer)
when(value.kind) {
@@ -1024,9 +1046,9 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
ldy $zpPtrVar+1
jsr floats.MOVMF""")
}
SourceStorageKind.VARIABLE -> TODO("variable + * float")
SourceStorageKind.EXPRESSION -> TODO("expression + * float")
SourceStorageKind.REGISTER -> TODO("register + * float")
SourceStorageKind.VARIABLE -> TODO("variable + * float ${target.position}")
SourceStorageKind.EXPRESSION -> TODO("expression + * float ${target.position}")
SourceStorageKind.REGISTER -> TODO("register + * float ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1075,7 +1097,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
sbc P8ZP_SCRATCH_W1+1
sta ($zpPtrVar),y""")
}
SourceStorageKind.REGISTER -> TODO("register - word")
SourceStorageKind.REGISTER -> TODO("register - word ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1127,7 +1149,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
asmgen.assignRegister(register, multiplyArg)
multiply()
}
SourceStorageKind.EXPRESSION -> TODO("ptr * expr (word)")
SourceStorageKind.EXPRESSION -> TODO("ptr * expr (word) ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1165,14 +1187,14 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
SourceStorageKind.VARIABLE -> {
require(value.datatype.isWord)
val varname = value.asmVarname
TODO("inplace variable word divide")
TODO("inplace variable word divide ${target.position}")
}
SourceStorageKind.REGISTER -> {
val register = value.register!!
require(register.isWord())
TODO("inplace register word divide")
TODO("inplace register word divide ${target.position}")
}
SourceStorageKind.EXPRESSION -> TODO("ptr / expr (word)")
SourceStorageKind.EXPRESSION -> TODO("ptr / expr (word) ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1194,9 +1216,9 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
ldy $zpPtrVar+1
jsr floats.MOVMF""")
}
SourceStorageKind.VARIABLE -> TODO("variable - / float")
SourceStorageKind.EXPRESSION -> TODO("expression - / float")
SourceStorageKind.REGISTER -> TODO("register - / float")
SourceStorageKind.VARIABLE -> TODO("variable - / float ${target.position}")
SourceStorageKind.EXPRESSION -> TODO("expression - / float ${target.position}")
SourceStorageKind.REGISTER -> TODO("register - / float ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1376,7 +1398,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
eor ($zpPtrVar),y
sta ($zpPtrVar),y""")
}
SourceStorageKind.REGISTER -> TODO("register ^ byte")
SourceStorageKind.REGISTER -> TODO("register ^ byte ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1420,7 +1442,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
eor ($zpPtrVar),y
sta ($zpPtrVar),y""")
}
SourceStorageKind.REGISTER -> TODO("register ^ word")
SourceStorageKind.REGISTER -> TODO("register ^ word ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1463,7 +1485,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
ora ($zpPtrVar),y
sta ($zpPtrVar),y""")
}
SourceStorageKind.REGISTER -> TODO("register | byte")
SourceStorageKind.REGISTER -> TODO("register | byte ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1507,7 +1529,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
ora ($zpPtrVar),y
sta ($zpPtrVar),y""")
}
SourceStorageKind.REGISTER -> TODO("register | word")
SourceStorageKind.REGISTER -> TODO("register | word ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1550,7 +1572,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
and ($zpPtrVar),y
sta ($zpPtrVar),y""")
}
SourceStorageKind.REGISTER -> TODO("register & byte")
SourceStorageKind.REGISTER -> TODO("register & byte ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1594,7 +1616,7 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
and ($zpPtrVar),y
sta ($zpPtrVar),y""")
}
SourceStorageKind.REGISTER -> TODO("register & word")
SourceStorageKind.REGISTER -> TODO("register & word ${target.position}")
else -> throw AssemblyError("weird source value $value")
}
}
@@ -1669,6 +1691,9 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
lda $regname+1
pha""")
}
in combinedLongRegisters -> {
TODO("save on stack long register pair")
}
else -> asmgen.saveRegisterStack(regs.asCpuRegister(), false)
}
}
@@ -1701,6 +1726,9 @@ internal class PointerAssignmentsGen(private val asmgen: AsmGen6502Internal, pri
pla
sta $regname""")
}
in combinedLongRegisters -> {
TODO("restore from stack long register")
}
else -> asmgen.restoreRegisterStack(regs.asCpuRegister(), false)
}
}
@@ -24,7 +24,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
if(extsub!=null) {
require(funcCall.multipleResultRegs.size + funcCall.multipleResultFpRegs.size >= 2)
if (funcCall.multipleResultFpRegs.isNotEmpty())
TODO("deal with (multiple?) FP return registers")
TODO("deal with (multiple?) FP return registers ${assignment.position}")
if (extsub.returns.size == assignmentTargets.size) {
// Targets and values match. Assign all the things. Skip 'void' targets.
extsub.returns.zip(assignmentTargets).zip(funcCall.multipleResultRegs).forEach {
@@ -702,9 +702,9 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
val chunk = IRCodeChunk(null, null).also {
if(targetArray.splitWords) {
val lsbmsbReg = codeGen.registers.next(IRDataType.BYTE)
it += IRInstruction(Opcode.LSIG, IRDataType.BYTE, reg1 = lsbmsbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1 = lsbmsbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = lsbmsbReg, immediate = arrayLength, labelSymbol = "${variable}_lsb", symbolOffset = fixedIndex)
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = lsbmsbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.MSIGB, IRDataType.WORD, reg1 = lsbmsbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = lsbmsbReg, immediate = arrayLength, labelSymbol = "${variable}_msb", symbolOffset = fixedIndex)
}
else
@@ -717,9 +717,9 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
result += IRCodeChunk(null, null).also {
if(targetArray.splitWords) {
val lsbmsbReg = codeGen.registers.next(IRDataType.BYTE)
it += IRInstruction(Opcode.LSIG, IRDataType.BYTE, reg1 = lsbmsbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1 = lsbmsbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = lsbmsbReg, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = lsbmsbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.MSIGB, IRDataType.WORD, reg1 = lsbmsbReg, reg2 = valueRegister)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = lsbmsbReg, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
}
else
@@ -969,7 +969,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
private fun operatorDivideInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): IRCodeChunks? {
if(array!=null) {
TODO("/ in array")
TODO("/ in array ${array.position}")
}
if(constAddress==null && memory!=null)
return null // TODO("optimized memory in-place /"")
@@ -1312,11 +1312,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} else {
val shiftTr = expressionEval.translateExpression(operand)
addToResult(result, shiftTr, shiftTr.resultReg, -1)
var shiftReg = shiftTr.resultReg
if(vmDt==IRDataType.WORD && shiftTr.dt==IRDataType.BYTE) {
shiftReg = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=shiftReg, reg2=shiftTr.resultReg), null)
}
val shiftReg = shiftTr.resultReg
val opc = if (signed) Opcode.ASRNM else Opcode.LSRNM
val ins = if(constAddress!=null)
IRInstruction(opc, vmDt, reg1 = shiftReg, address = constAddress)
@@ -1374,11 +1370,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} else {
val shiftTr = expressionEval.translateExpression(operand)
addToResult(result, shiftTr, shiftTr.resultReg, -1)
var shiftReg = shiftTr.resultReg
if(vmDt==IRDataType.WORD && shiftTr.dt==IRDataType.BYTE) {
shiftReg = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=shiftReg, reg2=shiftTr.resultReg), null)
}
val shiftReg = shiftTr.resultReg
addInstr(result, if(constAddress!=null)
IRInstruction(Opcode.LSLNM, vmDt, reg1=shiftReg, address = constAddress)
else
@@ -1433,7 +1425,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
private fun operatorModuloInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks? {
if(array!=null) {
TODO("% in array")
TODO("% in array ${array.position}")
}
if(constAddress==null && memory!=null)
return null // TODO("optimized memory in-place %"")
@@ -26,8 +26,10 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
"call" -> funcCall(call)
"msw" -> funcMsw(call)
"lsw" -> funcLsw(call)
"msb" -> funcMsb(call)
"lsb" -> funcLsb(call)
"msb" -> funcMsb(call, false)
"msb__long" -> funcMsb(call, true)
"lsb" -> funcLsb(call, false)
"lsb__long" -> funcLsb(call, true)
"memory" -> funcMemory(call)
"peek" -> funcPeek(call, IRDataType.BYTE)
"peekbool" -> funcPeek(call, IRDataType.BYTE)
@@ -230,7 +232,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcSgn(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val tr = exprGen.translateExpression(call.args.single())
val resultReg = codeGen.registers.next(tr.dt)
val resultReg = codeGen.registers.next(IRDataType.BYTE)
if(tr.dt==IRDataType.FLOAT) {
addToResult(result, tr, -1, tr.resultFpReg)
@@ -267,7 +269,14 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
}
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
BaseDataType.LONG -> TODO("SQRT LONG")
BaseDataType.LONG -> {
addToResult(result, tr, tr.resultReg, -1)
val resultReg = codeGen.registers.next(IRDataType.WORD) // sqrt of a long still produces just a word result
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.SQRT, IRDataType.LONG, reg1=resultReg, reg2=tr.resultReg)
}
return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1)
}
BaseDataType.FLOAT -> {
addToResult(result, tr, -1, tr.resultFpReg)
val resultFpReg = codeGen.registers.next(IRDataType.FLOAT)
@@ -577,12 +586,15 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
return ExpressionCodeResult(code, IRDataType.WORD, resultReg, -1)
}
private fun funcLsb(call: PtBuiltinFunctionCall): ExpressionCodeResult {
private fun funcLsb(call: PtBuiltinFunctionCall, fromLong: Boolean): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val tr = exprGen.translateExpression(call.args.single())
addToResult(result, tr, tr.resultReg, -1)
val resultReg = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.LSIG, IRDataType.BYTE, reg1 = resultReg, reg2 = tr.resultReg), null)
if(fromLong)
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.LONG, reg1 = resultReg, reg2 = tr.resultReg), null)
else
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1 = resultReg, reg2 = tr.resultReg), null)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
@@ -592,16 +604,19 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val tr = exprGen.translateExpression(call.args.single())
addToResult(result, tr, tr.resultReg, -1)
val resultReg = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.LSIG, IRDataType.WORD, reg1 = resultReg, reg2 = tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.LSIGW, IRDataType.LONG, reg1 = resultReg, reg2 = tr.resultReg), null)
return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1)
}
private fun funcMsb(call: PtBuiltinFunctionCall): ExpressionCodeResult {
private fun funcMsb(call: PtBuiltinFunctionCall, fromLong: Boolean): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val tr = exprGen.translateExpression(call.args.single())
addToResult(result, tr, tr.resultReg, -1)
val resultReg = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = resultReg, reg2 = tr.resultReg), null)
if(fromLong)
addInstr(result, IRInstruction(Opcode.MSIGB, IRDataType.LONG, reg1 = resultReg, reg2 = tr.resultReg), null)
else
addInstr(result, IRInstruction(Opcode.MSIGB, IRDataType.WORD, reg1 = resultReg, reg2 = tr.resultReg), null)
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
@@ -611,7 +626,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
val tr = exprGen.translateExpression(call.args.single())
addToResult(result, tr, tr.resultReg, -1)
val resultReg = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.MSIG, IRDataType.WORD, reg1 = resultReg, reg2 = tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.MSIGW, IRDataType.LONG, reg1 = resultReg, reg2 = tr.resultReg), null)
return ExpressionCodeResult(result, IRDataType.WORD, resultReg, -1)
}
@@ -99,7 +99,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
var pointerReg: Int
if(deref.startpointer.type.isStructInstance) {
TODO("translate structinstance deref???")
TODO("translate structinstance deref??? ${deref.position}")
/*
val arrayIndexer = deref.startpointer as? PtArrayIndexer
if(arrayIndexer==null)
@@ -686,7 +686,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.WORD, reg1=tr.resultReg, immediate = 0), null)
actualResultReg2 = loadStatusAsBooleanResult(Opcode.BSTNE, result)
}
valueDt.isLong -> TODO("typecast long ${cast.position}")
valueDt.isLong -> {
addInstr(result, IRInstruction(Opcode.CMPI, IRDataType.LONG, reg1=tr.resultReg, immediate = 0), null)
actualResultReg2 = loadStatusAsBooleanResult(Opcode.BSTNE, result)
}
valueDt.isFloat -> {
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
result += IRCodeChunk(null, null).also {
@@ -704,9 +707,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
BaseDataType.UWORD, BaseDataType.WORD -> {
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.LSIG, IRDataType.BYTE, reg1=actualResultReg2, reg2=tr.resultReg, immediate = 0), null)
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1=actualResultReg2, reg2=tr.resultReg, immediate = 0), null)
}
BaseDataType.LONG -> {
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.LONG, reg1=actualResultReg2, reg2=tr.resultReg, immediate = 0), null)
}
BaseDataType.LONG -> TODO("cast UBYTE to LONG ${cast.position}")
BaseDataType.FLOAT -> {
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.FTOUB, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
@@ -721,9 +727,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
BaseDataType.UWORD, BaseDataType.WORD -> {
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.LSIG, IRDataType.BYTE, reg1=actualResultReg2, reg2=tr.resultReg, immediate = 0), null)
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1=actualResultReg2, reg2=tr.resultReg, immediate = 0), null)
}
BaseDataType.LONG -> {
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.LONG, reg1=actualResultReg2, reg2=tr.resultReg, immediate = 0), null)
}
BaseDataType.LONG -> TODO("cast BYTE to LONG ${cast.position}")
BaseDataType.FLOAT -> {
actualResultReg2 = codeGen.registers.next(IRDataType.BYTE)
addInstr(result, IRInstruction(Opcode.FTOSB, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
@@ -746,7 +755,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
BaseDataType.WORD -> {
actualResultReg2 = tr.resultReg
}
BaseDataType.LONG -> TODO("cast UWORD to LONG ${cast.position}")
BaseDataType.LONG -> {
actualResultReg2 = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.LSIGW, IRDataType.LONG, reg1=actualResultReg2, reg2=tr.resultReg, immediate = 0), null)
}
BaseDataType.FLOAT -> {
actualResultReg2 = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.FTOUW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
@@ -772,7 +784,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
BaseDataType.UWORD -> {
actualResultReg2 = tr.resultReg
}
BaseDataType.LONG -> TODO("cast WORD to LONG ${cast.position}}")
BaseDataType.LONG -> {
actualResultReg2 = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.LSIGW, IRDataType.LONG, reg1=actualResultReg2, reg2=tr.resultReg, immediate = 0), null)
}
BaseDataType.FLOAT -> {
actualResultReg2 = codeGen.registers.next(IRDataType.WORD)
addInstr(result, IRInstruction(Opcode.FTOSW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null)
@@ -796,7 +811,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.BYTE, reg1 = wordreg, reg2=tr.resultReg), null)
addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.WORD, reg1 = actualResultReg2, reg2=wordreg), null)
}
BaseDataType.UWORD -> {
BaseDataType.UWORD, BaseDataType.POINTER -> {
actualResultReg2 = codeGen.registers.next(IRDataType.LONG)
addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.WORD, reg1 = actualResultReg2, reg2=tr.resultReg), null)
}
@@ -804,7 +819,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
actualResultReg2 = codeGen.registers.next(IRDataType.LONG)
addInstr(result, IRInstruction(Opcode.EXTS, type = IRDataType.WORD, reg1 = actualResultReg2, reg2=tr.resultReg), null)
}
else -> throw AssemblyError("weird cast value type ${cast.position}")
else -> throw AssemblyError("weird cast $valueDt to long ${cast.position}")
}
}
BaseDataType.FLOAT -> {
@@ -831,7 +846,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
// no further conversion required, pointers are all just uwords
}
BaseDataType.ARRAY_POINTER -> {
TODO("typecast to array of pointers $valueDt -> ${cast.type}")
TODO("typecast to array of pointers $valueDt -> ${cast.type} ${cast.position}")
}
else -> throw AssemblyError("weird cast value type ${cast.position}")
}
@@ -1169,7 +1184,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
fcallArgs = FunctionCallArgs(argRegisters, returnRegisters)
)
}
else TODO("extsub with banked address got called ${callTarget.name}")
else TODO("extsub with banked address got called ${callTarget.name} ${fcall.position}")
}
addInstr(result, call, null)
val resultRegs = returnRegisters.filter{it.dt!=IRDataType.FLOAT}.map{it.registerNum}
@@ -1747,9 +1762,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
result += pointerTr.chunks
pointerReg = pointerTr.resultReg
} else if(left.pointerderef!=null) {
TODO("get pointer from deref $left")
TODO("get pointer from deref $left ${left.position}")
} else {
throw AssemblyError("weird arrayindexer $left")
throw AssemblyError("weird arrayindexer $left ${left.position}")
}
val struct = left.type.subType!! as StStruct
val constindex = left.index as? PtNumber
@@ -272,7 +272,7 @@ class IRCodeGen(
is PtSub -> throw AssemblyError("nested subroutines should have been flattened $node")
is PtStructDecl -> emptyList()
is PtSubSignature -> emptyList()
else -> TODO("missing codegen for $node")
else -> TODO("missing codegen for $node ${node.position}")
}
val nonEmptyChunks = chunks.filter { it.isNotEmpty() || it.label != null }
@@ -1142,7 +1142,7 @@ class IRCodeGen(
if(identifier!=null && !isIndirectJump(goto))
IRInstruction(branchOpcode, labelSymbol = identifier.name)
else
TODO("JUMP to expression address ${goto.target}")
TODO("JUMP to expression address ${goto.target} ${goto.position}")
}
}
@@ -1860,7 +1860,7 @@ class IRCodeGen(
is PtNop -> { /* nothing */ }
is PtAssignment, is PtAugmentedAssign -> { /* global variable initialization is done elsewhere */ }
is PtVariable, is PtConstant, is PtMemMapped -> { /* vars should be looked up via symbol table */ }
is PtAlign -> TODO("ir support for inline %align")
is PtAlign -> TODO("ir support for inline %align ${child.position}")
is PtSub -> {
val sub = IRSubroutine(child.name, translateParameters(child.signature.children), child.signature.returns, child.position)
for (subchild in child.children) {
@@ -1912,7 +1912,7 @@ class IRCodeGen(
}
}
is PtStructDecl -> { /* do nothing, should be found in the symbol table */ }
else -> TODO("weird block child node $child")
else -> TODO("weird block child node $child ${child.position}")
}
}
return irBlock
@@ -415,13 +415,19 @@ jump p8_label_gen_2
chunk.instructions.removeAt(idx)
changed = true
}
-1 if ins.type == IRDataType.LONG -> {
chunk.instructions.removeAt(idx)
changed = true
}
}
}
Opcode.OR -> {
if (ins.immediate == 0) {
chunk.instructions.removeAt(idx)
changed = true
} else if ((ins.immediate == 255 && ins.type == IRDataType.BYTE) || (ins.immediate == 65535 && ins.type == IRDataType.WORD)) {
} else if ((ins.immediate == 255 && ins.type == IRDataType.BYTE) ||
(ins.immediate == 65535 && ins.type == IRDataType.WORD) ||
(ins.immediate == -1 && ins.type == IRDataType.LONG)) {
chunk.instructions[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, immediate = ins.immediate)
changed = true
}
+11 -5
View File
@@ -205,21 +205,27 @@ class TestIRPeepholeOpt: FunSpec({
val irProg = makeIRProgram(listOf(
IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=42, immediate = 0),
IRInstruction(Opcode.AND, IRDataType.WORD, reg1=42, immediate = 0),
IRInstruction(Opcode.AND, IRDataType.LONG, reg1=42, immediate = 0),
IRInstruction(Opcode.OR, IRDataType.BYTE, reg1=42, immediate = 255),
IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, immediate = 65535)
IRInstruction(Opcode.OR, IRDataType.WORD, reg1=42, immediate = 65535),
IRInstruction(Opcode.OR, IRDataType.LONG, reg1=42, immediate = -1)
))
irProg.chunks().single().instructions.size shouldBe 4
irProg.chunks().single().instructions.size shouldBe 6
val opt = IRPeepholeOptimizer(irProg)
opt.optimize(true, ErrorReporterForTests())
val instr = irProg.chunks().single().instructions
instr.size shouldBe 4
instr.size shouldBe 6
instr[0].opcode shouldBe Opcode.LOAD
instr[1].opcode shouldBe Opcode.LOAD
instr[2].opcode shouldBe Opcode.LOAD
instr[3].opcode shouldBe Opcode.LOAD
instr[4].opcode shouldBe Opcode.LOAD
instr[5].opcode shouldBe Opcode.LOAD
instr[0].immediate shouldBe 0
instr[1].immediate shouldBe 0
instr[2].immediate shouldBe 255
instr[3].immediate shouldBe 65535
instr[2].immediate shouldBe 0
instr[3].immediate shouldBe 255
instr[4].immediate shouldBe 65535
instr[5].immediate shouldBe -1
}
})
@@ -349,7 +349,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
}
}
} else if(arrayIndexedExpression.pointerderef!=null) {
TODO("constant fold pointer[i]")
TODO("constant fold pointer[i] ${arrayIndexedExpression.position}")
}
}
}
@@ -254,6 +254,15 @@ class VarConstantValueTypeAdjuster(
functionCallExpr))
}
}
else if(func==listOf("lsb") || func==listOf("msb")) {
val t1 = functionCallExpr.args[0].inferType(program)
if(t1.isLong) {
val replaceFunc = func[0]+"__long"
return listOf(IAstModification.SetExpression({functionCallExpr.target = it as IdentifierReference},
IdentifierReference(listOf(replaceFunc), functionCallExpr.target.position),
functionCallExpr))
}
}
return noModifications
}
+62
View File
@@ -38,6 +38,36 @@ bcd {
return a
}
sub addtol(^^long a, long b) {
; -- inplace long BCD addition (avoids copying long values by value)
setbcd()
;; NOT YET IMPLEMENTED IN PROG8: a^^ += b, so inline asm
%asm {{
lda p8v_a
ldy p8v_a+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy #0
clc
lda (P8ZP_SCRATCH_W1),y
adc p8v_b
sta (P8ZP_SCRATCH_W1),y
iny
lda (P8ZP_SCRATCH_W1),y
adc p8v_b+1
sta (P8ZP_SCRATCH_W1),y
iny
lda (P8ZP_SCRATCH_W1),y
adc p8v_b+2
sta (P8ZP_SCRATCH_W1),y
iny
lda (P8ZP_SCRATCH_W1),y
adc p8v_b+3
sta (P8ZP_SCRATCH_W1),y
}}
clearbcd()
}
sub subb(byte a, byte b) -> byte {
setbcd()
a -= b
@@ -66,7 +96,39 @@ bcd {
return a
}
sub subfroml(^^long a, long b) {
; -- inplace long BCD subtraction (avoids copying long values by value)
setbcd()
;; NOT YET IMPLEMENTED IN PROG8: a^^ -= b, so inline asm
%asm {{
lda p8v_a
ldy p8v_a+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy #0
sec
lda (P8ZP_SCRATCH_W1),y
sbc p8v_b
sta (P8ZP_SCRATCH_W1),y
iny
lda (P8ZP_SCRATCH_W1),y
sbc p8v_b+1
sta (P8ZP_SCRATCH_W1),y
iny
lda (P8ZP_SCRATCH_W1),y
sbc p8v_b+2
sta (P8ZP_SCRATCH_W1),y
iny
lda (P8ZP_SCRATCH_W1),y
sbc p8v_b+3
sta (P8ZP_SCRATCH_W1),y
}}
clearbcd()
}
inline asmsub setbcd() {
; be safe and 6502 compatible and prohibit interrupts during BCD mode
%asm {{
php
sei
+9
View File
@@ -1302,6 +1302,11 @@ asmsub init_system() {
lda #0
sta c64.BGCOL0
jsr disable_runstop_and_charsetswitch
; basic is not banked in, adjust MEMTOP
ldx #<$c000
ldy #>$c000
clc
jsr cbm.MEMTOP
cli
rts
}}
@@ -1323,6 +1328,10 @@ asmsub cleanup_at_exit() {
sta $ff00 ; default bank 15
jsr cbm.CLRCHN ; reset i/o channels
jsr enable_runstop_and_charsetswitch
ldx #<$ff00
ldy #>$ff00
clc
jsr cbm.MEMTOP ; adjust MEMTOP to original value again
lda _exitcarry
lsr a
lda _exitcode
+3 -20
View File
@@ -288,29 +288,16 @@ hline_filled_right .byte 0, %10000000, %11000000, %11100000, %11110000, %1111
sub disc(uword xcenter, ubyte ycenter, ubyte radius) {
; Warning: NO BOUNDS CHECKS. Make sure circle fits in the screen.
; Midpoint algorithm, filled.
; Overdraws horizontal lines unfortunately.
if radius==0
return
ubyte @zp yy = 0
word decisionOver2 = (1 as word)-radius
ubyte last_y3 = ycenter+radius
ubyte last_y4 = ycenter-radius
ubyte new_y3, new_y4
while radius>=yy {
horizontal_line(xcenter-radius, ycenter+yy, radius*2+1)
horizontal_line(xcenter-radius, ycenter-yy, radius*2+1)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
horizontal_line(xcenter-yy, last_y3, yy*2+1)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
horizontal_line(xcenter-yy, last_y4, yy*2+1)
last_y4 = new_y4
}
horizontal_line(xcenter-yy, ycenter+radius, yy*2+1)
horizontal_line(xcenter-yy, ycenter-radius, yy*2+1)
yy++
if decisionOver2>=0 {
radius--
@@ -319,10 +306,6 @@ hline_filled_right .byte 0, %10000000, %11000000, %11100000, %11110000, %1111
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
horizontal_line(xcenter-yy, last_y3, yy*2+1)
horizontal_line(xcenter-yy, last_y4, yy*2+1)
}
+41 -45
View File
@@ -6,8 +6,6 @@ conv {
; ----- number conversions to decimal strings ----
ubyte[16] @shared string_out ; result buffer for the string conversion routines (note: uses uninitialized ARRAY instead of STR, to force it to be allocated in BSS area so it's ROM-compatible)
asmsub str_ub0(ubyte value @A) clobbers(X) -> str @AY {
; ---- convert the ubyte in A in decimal string form, with left padding 0s (3 positions total)
%asm {{
@@ -257,53 +255,56 @@ sub str_l (long value) -> str {
; source: https://codebase64.net/doku.php?id=base:32_bit_hexadecimal_to_decimal_conversion
; NOTE: this is a pretty slow conversion, don't use for time critical displays!
bool negative
string_out[0] = '0'
if value<0 {
negative = true
value = -value
}
%asm {{
jsr hex2dec
jsr hex2dec
ldx #0
- lda string_out+1,x
cmp #'0'
bne +
inx
bne -
+ cpx #10 ; just all 0? keep one
bne +
dex
ldx #0
- lda result,x
bne +
inx ; skip leading zeros
cpx #9
bne -
+ ; x points at the rightmost leading 0
lda negative
beq +
lda #'-' ; sign in front
sta string_out,x
dex
bmi _done
+ ; x still points at rightmost leading 0
; remove leading 0's (there is at least one if we're here)
ldy #0
- lda string_out+1,x
sta string_out,y
iny
inx
cpx #10
bne -
lda #0
sta string_out,y
_done
; convert to petscii numbers and return ptr to first nonzero
+ stx P8ZP_SCRATCH_B1
inc P8ZP_SCRATCH_B1
- lda result,x
ora #$30
sta result,x
inx
cpx #10
bne -
lda #0
sta result,x
; sign needed?
lda negative
beq +
dec P8ZP_SCRATCH_B1
ldx P8ZP_SCRATCH_B1
lda #'-'
sta result_sign,x
+ lda #<result_sign
ldy #>result_sign
clc
adc P8ZP_SCRATCH_B1
bcc +
iny
+ rts
lda #<string_out
ldy #>string_out
rts
hex2dec:
; converts 10 digits (32 bit values have max. 10 decimal digits)
hex2dec
ldx #9
ldx #9+1
l3 jsr div10
sta result,x
ora #$30
sta string_out,x
dex
bpl l3
bne l3
rts
; divides a 32 bit value by 10
@@ -323,13 +324,6 @@ skip rol value
dey
bpl l4
rts
.section BSS
result_sign .byte ? ; room for the '-' sign
result .fill 10
.byte ? ; string 0 terminator
.send
}}
}
@@ -865,4 +859,6 @@ output .fill 5 ; 0-terminated output buffer (to make printing easier)
}}
}
ubyte[16] @shared string_out ; internal result buffer for the string conversion routines (note: uses uninitialized ARRAY instead of STR, to force it to be allocated in BSS area so it's ROM-compatible)
}
+4 -37
View File
@@ -433,25 +433,12 @@ gfx_hires {
return
ubyte @zp yy = 0
word @zp decisionOver2 = (1 as word)-radius
uword last_y3 = ycenter+radius
uword last_y4 = ycenter-radius
uword new_y3, new_y4
while radius>=yy {
horizontal_line(xcenter-radius, ycenter+yy, radius*$0002+1, color)
horizontal_line(xcenter-radius, ycenter-yy, radius*$0002+1, color)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
horizontal_line(xcenter-yy, last_y3, yy*$0002+1, color)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
horizontal_line(xcenter-yy, last_y4, yy*$0002+1, color)
last_y4 = new_y4
}
horizontal_line(xcenter-yy, ycenter+radius, yy*$0002+1, color)
horizontal_line(xcenter-yy, ycenter-radius, yy*$0002+1, color)
yy++
if decisionOver2>=0 {
radius--
@@ -460,11 +447,6 @@ gfx_hires {
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
horizontal_line(xcenter-yy, last_y3, yy*$0002+1, color)
horizontal_line(xcenter-yy, last_y4, yy*$0002+1, color)
}
sub safe_disc(uword @zp xcenter, uword @zp ycenter, ubyte @zp radius, ubyte color) {
@@ -474,23 +456,12 @@ gfx_hires {
return
ubyte @zp yy = 0
word @zp decisionOver2 = (1 as word)-radius
uword last_y3 = ycenter+radius
uword last_y4 = ycenter-radius
uword new_y3, new_y4
while radius>=yy {
safe_horizontal_line(xcenter-radius, ycenter+yy, radius*$0002+1, color)
safe_horizontal_line(xcenter-radius, ycenter-yy, radius*$0002+1, color)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
safe_horizontal_line(xcenter-yy, last_y3, yy*$0002+1, color)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
safe_horizontal_line(xcenter-yy, last_y4, yy*$0002+1, color)
last_y4 = new_y4
}
safe_horizontal_line(xcenter-yy, ycenter+radius, yy*$0002+1, color)
safe_horizontal_line(xcenter-yy, ycenter-radius, yy*$0002+1, color)
yy++
if decisionOver2>=0 {
radius--
@@ -499,10 +470,6 @@ gfx_hires {
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
safe_horizontal_line(xcenter-yy, last_y3, yy*$0002+1, color)
safe_horizontal_line(xcenter-yy, last_y4, yy*$0002+1, color)
}
sub plot(uword @zp xx, uword @zp yy, ubyte @zp color) {
+12 -44
View File
@@ -505,25 +505,11 @@ gfx_lores {
return
ubyte @zp yy = 0
word @zp decisionOver2 = (1 as word)-radius
ubyte last_y3 = ycenter+radius
ubyte last_y4 = ycenter-radius
ubyte new_y3, new_y4
while radius>=yy {
horizontal_line(xcenter-radius, ycenter+yy, radius*$0002+1, color)
horizontal_line(xcenter-radius, ycenter-yy, radius*$0002+1, color)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
horizontal_line(xcenter-yy, last_y3, yy*$0002+1, color)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
horizontal_line(xcenter-yy, last_y4, yy*$0002+1, color)
last_y4 = new_y4
}
horizontal_line(xcenter-yy, ycenter+radius, yy*$0002+1, color)
horizontal_line(xcenter-yy, ycenter-radius, yy*$0002+1, color)
yy++
if decisionOver2>=0 {
radius--
@@ -532,11 +518,6 @@ gfx_lores {
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
horizontal_line(xcenter-yy, last_y3, yy*$0002+1, color)
horizontal_line(xcenter-yy, last_y4, yy*$0002+1, color)
}
sub safe_disc(uword @zp xcenter, uword @zp ycenter, ubyte @zp radius, ubyte color) {
@@ -546,29 +527,22 @@ gfx_lores {
return
ubyte @zp yy = 0
word @zp decisionOver2 = (1 as word)-radius
uword last_y3 = ycenter+radius
uword last_y4 = ycenter-radius
uword new_y3, new_y4
while radius>=yy {
uword liney = ycenter+yy
if msb(liney)==0
safe_horizontal_line(xcenter-radius, lsb(ycenter+yy), radius*$0002+1, color)
safe_horizontal_line(xcenter-radius, lsb(liney), radius*$0002+1, color)
liney = ycenter-yy
if msb(liney)==0
safe_horizontal_line(xcenter-radius, lsb(ycenter-yy), radius*$0002+1, color)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
if msb(last_y3)==0
safe_horizontal_line(xcenter-yy, lsb(last_y3), yy*$0002+1, color)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
if msb(last_y4)==0
safe_horizontal_line(xcenter-yy, lsb(last_y4), yy*$0002+1, color)
last_y4 = new_y4
}
safe_horizontal_line(xcenter-radius, lsb(liney), radius*$0002+1, color)
liney = ycenter+radius
if msb(liney)==0
safe_horizontal_line(xcenter-yy, lsb(liney), yy*$0002+1, color)
liney = ycenter-radius
if msb(liney)==0
safe_horizontal_line(xcenter-yy, lsb(liney), yy*$0002+1, color)
yy++
if decisionOver2>=0 {
radius--
@@ -577,12 +551,6 @@ gfx_lores {
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
if msb(last_y3)==0
safe_horizontal_line(xcenter-yy, lsb(last_y3), yy*$0002+1, color)
if msb(last_y4)==0
safe_horizontal_line(xcenter-yy, lsb(last_y4), yy*$0002+1, color)
}
asmsub plot(uword x @AX, ubyte y @Y, ubyte color @R0) {
+5 -35
View File
@@ -595,23 +595,12 @@ drawmode: ora cx16.r15L
return
ubyte @zp yy = 0
word @zp decisionOver2 = (1 as word)-radius
uword last_y3 = ycenter+radius
uword last_y4 = ycenter-radius
uword new_y3, new_y4
while radius>=yy {
horizontal_line(xcenter-radius, ycenter+yy, radius*$0002+1, draw)
horizontal_line(xcenter-radius, ycenter-yy, radius*$0002+1, draw)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
horizontal_line(xcenter-yy, last_y3, yy*$0002+1, draw)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
horizontal_line(xcenter-yy, last_y4, yy*$0002+1, draw)
last_y4 = new_y4
}
horizontal_line(xcenter-yy, ycenter+radius, yy*$0002+1, draw)
horizontal_line(xcenter-yy, ycenter-radius, yy*$0002+1, draw)
yy++
if decisionOver2>=0 {
radius--
@@ -620,10 +609,6 @@ drawmode: ora cx16.r15L
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
horizontal_line(xcenter-yy, last_y3, yy*$0002+1, draw)
horizontal_line(xcenter-yy, last_y4, yy*$0002+1, draw)
}
sub safe_disc(uword @zp xcenter, uword @zp ycenter, ubyte @zp radius, bool draw) {
@@ -634,23 +619,12 @@ drawmode: ora cx16.r15L
return
ubyte @zp yy = 0
word @zp decisionOver2 = (1 as word)-radius
uword last_y3 = ycenter+radius
uword last_y4 = ycenter-radius
uword new_y3, new_y4
while radius>=yy {
safe_horizontal_line(xcenter-radius, ycenter+yy, radius*$0002+1, draw)
safe_horizontal_line(xcenter-radius, ycenter-yy, radius*$0002+1, draw)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
safe_horizontal_line(xcenter-yy, last_y3, yy*$0002+1, draw)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
safe_horizontal_line(xcenter-yy, last_y4, yy*$0002+1, draw)
last_y4 = new_y4
}
safe_horizontal_line(xcenter-yy, ycenter+radius, yy*$0002+1, draw)
safe_horizontal_line(xcenter-yy, ycenter-radius, yy*$0002+1, draw)
yy++
if decisionOver2>=0 {
radius--
@@ -659,10 +633,6 @@ drawmode: ora cx16.r15L
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
safe_horizontal_line(xcenter-yy, last_y3, yy*$0002+1, draw)
safe_horizontal_line(xcenter-yy, last_y4, yy*$0002+1, draw)
}
sub plot(uword @zp xx, uword @zp yy, bool @zp draw) {
@@ -1038,7 +1008,7 @@ _doplot beq +
; y*40 lookup table. Pretty compact because it all fits in a word and we only need 240 y positions.
; a y*80 lookup table would be very large (lo,mid,hi for 480 values...)
uword[240] @split @shared times40 = [
uword[240] @shared times40 = [
0, 40, 80, 120, 160, 200, 240, 280, 320, 360, 400, 440, 480, 520, 560, 600,
640, 680, 720, 760, 800, 840, 880, 920, 960, 1000, 1040, 1080, 1120, 1160,
1200, 1240, 1280, 1320, 1360, 1400, 1440, 1480, 1520, 1560, 1600, 1640, 1680,
+10 -12
View File
@@ -554,14 +554,13 @@ log2_tab
}
sub crc16(^^ubyte data, uword length) -> uword {
; calculates the CRC16 (XMODEM) checksum of the buffer.
; calculates the CRC16 (XMODEM) checksum of the buffer. Clobbers R14 and R15.
; There are also "streaming" crc16_start/update/end routines below, that allow you to calculate crc16 for data that doesn't fit in a single memory block.
cx16.r14 = data
crc16_start()
cx16.r13 = data
cx16.r14 = data+length
while cx16.r13!=cx16.r14 {
crc16_update(@(cx16.r13))
cx16.r13++
repeat length {
crc16_update(@(cx16.r14))
cx16.r14++
}
return crc16_end()
}
@@ -610,14 +609,13 @@ log2_tab
sub crc32(^^ubyte data, uword length) -> long {
; Calculates the CRC-32 (ISO-HDLC/PKZIP) checksum of the buffer.
; Clobbers R12 through R15, returns the 32 bits result as long
; Clobbers R13 through R15, returns the 32 bits result as long
; There are also "streaming" crc32_start/update/end routines below, that allow you to calculate crc32 for data that doesn't fit in a single memory block.
cx16.r13 = data
crc32_start()
cx16.r12 = data
cx16.r13 = data+length
while cx16.r12!=cx16.r13 {
crc32_update(@(cx16.r12))
cx16.r12++
repeat length {
crc32_update(@(cx16.r13))
cx16.r13++
}
return crc32_end()
}
+96 -23
View File
@@ -29,33 +29,33 @@ abs_w_into_AY .proc
+ rts
.pend
abs_l_into_R0R1 .proc
; -- R0:R1 = abs(R0:R1)
lda cx16.r1H
abs_l_into_R14R15 .proc
; -- R14:R15 = abs(R14:R15)
lda cx16.r15H
bmi + ; Negative if high bit of highest byte is set
rts
+
; Invert all four bytes
lda cx16.r0L
lda cx16.r14L
eor #$FF
sta cx16.r0L
lda cx16.r0H
sta cx16.r14L
lda cx16.r14H
eor #$FF
sta cx16.r0H
lda cx16.r1L
sta cx16.r14H
lda cx16.r15L
eor #$FF
sta cx16.r1L
lda cx16.r1H
sta cx16.r15L
lda cx16.r15H
eor #$FF
sta cx16.r1H
sta cx16.r15H
; Add 1 to whole 32-bit value
inc cx16.r0L
inc cx16.r14L
bne +
inc cx16.r0H
inc cx16.r14H
bne +
inc cx16.r1L
inc cx16.r15L
bne +
inc cx16.r1H
inc cx16.r15H
+ rts
.pend
@@ -89,17 +89,39 @@ _possibly_zero cmp #0
func_sign_w_into_A .proc
cpy #0
beq _possibly_zero
bmi _neg
_pos lda #1
rts
_neg lda #-1
rts
_possibly_zero cmp #0
bne _pos
bmi _negative
bne _positive
cmp #0
beq _zero
_positive lda #1
_zero rts
_negative lda #-1
rts
.pend
func_sign_l_r14r15_into_A .proc
lda cx16.r14+3 ; msb
bmi _negative
bne _positive
lda cx16.r14+2
bne _positive
lda cx16.r14+1
bne _positive
lda cx16.r14
beq _zero
lda #1
_zero
rts
_negative
lda #-1
rts
_positive
lda #1
rts
.pend
func_sqrt16_into_A .proc
; integer square root
@@ -435,6 +457,7 @@ func_peek .proc
; -- read the byte value on the address in AY, into A
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
from_scratchW1
ldy #0
lda (P8ZP_SCRATCH_W1),y
rts
@@ -444,6 +467,7 @@ func_peekw .proc
; -- read the word value on the address in AY, into AY
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
from_scratchW1
ldy #0
lda (P8ZP_SCRATCH_W1),y
pha
@@ -454,6 +478,26 @@ func_peekw .proc
rts
.pend
func_peekl .proc
; -- read the ;pmg value on the address in AY, into R14:R15
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
from_scratchW1
ldy #0
lda (P8ZP_SCRATCH_W1),y
sta cx16.r14
iny
lda (P8ZP_SCRATCH_W1),y
sta cx16.r14+1
iny
lda (P8ZP_SCRATCH_W1),y
sta cx16.r14+2
iny
lda (P8ZP_SCRATCH_W1),y
sta cx16.r14+3
rts
.pend
func_pokew .proc
; -- store the word value in AY in the address in P8ZP_SCRATCH_W1
@@ -466,6 +510,35 @@ func_pokew .proc
rts
.pend
func_pokew_scratchW2 .proc
; -- store the word value in AY in the address in P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_REG
ldy #0
sta (P8ZP_SCRATCH_W2),y
iny
lda P8ZP_SCRATCH_REG
sta (P8ZP_SCRATCH_W2),y
rts
.pend
func_pokel .proc
; -- store the long value in R14:R15 in the address in AY
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy #0
lda cx16.r14
sta (P8ZP_SCRATCH_W1),y
iny
lda cx16.r14+1
sta (P8ZP_SCRATCH_W1),y
iny
lda cx16.r14+2
sta (P8ZP_SCRATCH_W1),y
iny
lda cx16.r14+3
sta (P8ZP_SCRATCH_W1),y
rts
.pend
func_clamp_byte .proc
; signed value in A, result in A
+17 -20
View File
@@ -138,31 +138,29 @@ _done
}
}
; TODO convert to ^^uword once code size regression is fixed
sub shellsort_uw(uword @requirezp values, ubyte num_elements) {
sub shellsort_uw(^^uword @requirezp values, ubyte num_elements) {
; sorts the values array (no-split unsigned words).
num_elements--
ubyte gap
for gap in [132, 57, 23, 10, 4, 1] {
ubyte i
for i in gap to num_elements {
uword @zp temp = peekw(values+i*$0002)
uword @zp temp = values[i]
ubyte @zp j = i
ubyte @zp k = j-gap
while j>=gap {
uword @zp v = peekw(values+k*$0002)
uword @zp v = values[k]
if v <= temp break
pokew(values+j*$0002, v)
values[j] = v
j = k
k -= gap
}
pokew(values+j*$0002, temp)
values[j] = temp
}
}
}
; TODO convert to ^^uword once code size regression is fixed
sub shellsort_by_ub(^^ubyte @requirezp ub_keys, uword @requirezp wordvalues, ubyte num_elements) {
sub shellsort_by_ub(^^ubyte @requirezp ub_keys, ^^uword @requirezp wordvalues, ubyte num_elements) {
; sorts the 'wordvalues' array (no-split array of words) according to the 'ub_keys' array (which also gets sorted ofcourse).
num_elements--
ubyte @zp gap
@@ -170,7 +168,7 @@ _done
ubyte i
for i in gap to num_elements {
ubyte @zp temp = ub_keys[i]
uword temp_wv = peekw(wordvalues + i*$0002)
uword temp_wv = wordvalues[i]
ubyte @zp j = i
ubyte @zp k = j-gap
repeat {
@@ -178,18 +176,17 @@ _done
if v <= temp break
if j < gap break
ub_keys[j] = v
pokew(wordvalues + j*$0002, peekw(wordvalues + k*$0002))
wordvalues[j] = wordvalues[k]
j = k
k -= gap
}
ub_keys[j] = temp
pokew(wordvalues + j*$0002, temp_wv)
wordvalues[j] = temp_wv
}
}
}
; TODO convert to ^^uword once code size regression is fixed
sub shellsort_by_uw(uword @requirezp uw_keys, uword @requirezp wordvalues, ubyte num_elements) {
sub shellsort_by_uw(^^uword @requirezp uw_keys, ^^uword @requirezp wordvalues, ubyte num_elements) {
; sorts the 'wordvalues' array according to the 'uw_keys' array (which also gets sorted ofcourse).
; both arrays should be no-split array of words. uw_keys are unsigned.
num_elements--
@@ -197,20 +194,20 @@ _done
for gap in [132, 57, 23, 10, 4, 1] {
ubyte i
for i in gap to num_elements {
uword @zp temp = peekw(uw_keys+i*$0002)
uword temp_wv = peekw(wordvalues + i*$0002)
uword @zp temp = uw_keys[i]
uword temp_wv = wordvalues[i]
ubyte @zp j = i
ubyte @zp k = j-gap
while j>=gap {
uword @zp v = peekw(uw_keys+k*2)
uword @zp v = uw_keys[k]
if v <= temp break
pokew(uw_keys+j*2, v)
pokew(wordvalues + j*$0002, peekw(wordvalues + k*$0002))
uw_keys[j] = v
wordvalues[j] = wordvalues[k]
j = k
k -= gap
}
pokew(uw_keys+j*2, temp)
pokew(wordvalues + j*$0002, temp_wv)
uw_keys[j] = temp
wordvalues[j] = temp_wv
}
}
}
+3
View File
@@ -0,0 +1,3 @@
bcd {
; virtual machine does not support BCD
}
+4 -36
View File
@@ -302,23 +302,11 @@ monogfx {
return
ubyte @zp yy = 0
word @zp decisionOver2 = (1 as word)-radius
uword last_y3 = ycenter+radius
uword last_y4 = ycenter-radius
uword new_y3, new_y4
while radius>=yy {
horizontal_line(xcenter-radius, ycenter+yy, radius*$0002+1, draw)
horizontal_line(xcenter-radius, ycenter-yy, radius*$0002+1, draw)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
horizontal_line(xcenter-yy, last_y3, yy*$0002+1, draw)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
horizontal_line(xcenter-yy, last_y4, yy*$0002+1, draw)
last_y4 = new_y4
}
horizontal_line(xcenter-yy, ycenter+radius, yy*$0002+1, draw)
horizontal_line(xcenter-yy, ycenter-radius, yy*$0002+1, draw)
yy++
if decisionOver2>=0 {
radius--
@@ -327,10 +315,6 @@ monogfx {
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
horizontal_line(xcenter-yy, last_y3, yy*$0002+1, draw)
horizontal_line(xcenter-yy, last_y4, yy*$0002+1, draw)
}
sub safe_disc(uword @zp xcenter, uword @zp ycenter, ubyte @zp radius, bool draw) {
@@ -340,23 +324,11 @@ monogfx {
return
ubyte @zp yy = 0
word @zp decisionOver2 = (1 as word)-radius
uword last_y3 = ycenter+radius
uword last_y4 = ycenter-radius
uword new_y3, new_y4
while radius>=yy {
safe_horizontal_line(xcenter-radius, ycenter+yy, radius*$0002+1, draw)
safe_horizontal_line(xcenter-radius, ycenter-yy, radius*$0002+1, draw)
new_y3 = ycenter+radius
if new_y3 != last_y3 {
safe_horizontal_line(xcenter-yy, last_y3, yy*$0002+1, draw)
last_y3 = new_y3
}
new_y4 = ycenter-radius
if new_y4 != last_y4 {
safe_horizontal_line(xcenter-yy, last_y4, yy*$0002+1, draw)
last_y4 = new_y4
}
safe_horizontal_line(xcenter-yy, ycenter+radius, yy*$0002+1, draw)
safe_horizontal_line(xcenter-yy, ycenter-radius, yy*$0002+1, draw)
yy++
if decisionOver2>=0 {
radius--
@@ -365,10 +337,6 @@ monogfx {
decisionOver2 += yy*$0002
decisionOver2++
}
; draw the final two spans
yy--
safe_horizontal_line(xcenter-yy, last_y3, yy*$0002+1, draw)
safe_horizontal_line(xcenter-yy, last_y4, yy*$0002+1, draw)
}
sub plot(uword @zp xx, uword @zp yy, bool @zp draw) {
+2 -2
View File
@@ -8,7 +8,7 @@ txt {
sub width() -> ubyte {
%ir {{
syscall 46 (): r99000.w
lsig.b r99100,r99000
lsigb.w r99100,r99000
returnr.b r99100
}}
}
@@ -16,7 +16,7 @@ sub width() -> ubyte {
sub height() -> ubyte {
%ir {{
syscall 46 (): r99000.w
msig.b r99100,r99000
msigb.w r99100,r99000
returnr.b r99100
}}
}
+75 -9
View File
@@ -2,6 +2,7 @@ package prog8
import kotlinx.cli.*
import prog8.ast.AstException
import prog8.buildversion.VERSION
import prog8.code.source.ImportFileSystem.expandTilde
import prog8.code.target.CompilationTargets
import prog8.code.target.Cx16Target
@@ -12,13 +13,10 @@ import prog8.compiler.CompilerArguments
import prog8.compiler.ErrorReporter
import prog8.compiler.compileProgram
import java.io.File
import java.nio.file.FileSystems
import java.nio.file.Path
import java.nio.file.StandardWatchEventKinds
import java.nio.file.WatchKey
import java.net.URI
import java.nio.file.*
import java.time.LocalDateTime
import kotlin.io.path.Path
import kotlin.io.path.isReadable
import kotlin.io.path.*
import kotlin.system.exitProcess
@@ -46,6 +44,8 @@ private fun compileMain(args: Array<String>): Boolean {
val symbolDefs by cli.option(ArgType.String, fullName = "D", description = "define assembly symbol(s) with -D SYMBOL=VALUE").multiple()
val dumpSymbols by cli.option(ArgType.Boolean, fullName = "dumpsymbols", description = "print a dump of the variable declarations and subroutine signatures")
val dumpVariables by cli.option(ArgType.Boolean, fullName = "dumpvars", description = "print a dump of the variables in the program")
val libSearch by cli.option(ArgType.String, fullName = "libsearch", description = "search for a regex pattern in the embedded library files")
val libDump by cli.option(ArgType.String, fullName = "libdump", description = "dump all the embedded library files into the specified output directory")
val startEmulator1 by cli.option(ArgType.Boolean, fullName = "emu", description = "auto-start emulator after successful compilation")
val startEmulator2 by cli.option(ArgType.Boolean, fullName = "emu2", description = "auto-start alternative emulator after successful compilation")
val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental/alternative codegen")
@@ -62,7 +62,6 @@ private fun compileMain(args: Array<String>): Boolean {
val slabsGolden by cli.option(ArgType.Boolean, fullName = "slabsgolden", description = "put memory() slabs in 'golden ram' memory area instead of at the end of the program. On the cx16 target this is $0400-07ff. This is unavailable on other systems.")
val slabsHighBank by cli.option(ArgType.Int, fullName = "slabshigh", description = "put memory() slabs in high memory area instead of at the end of the program. On the cx16 target the value specifies the HiRAM bank to use, on other systems this value is ignored.")
val dontIncludeSourcelines by cli.option(ArgType.Boolean, fullName = "nosourcelines", description = "do not include original Prog8 source lines in generated asm code")
val dontSplitWordArrays by cli.option(ArgType.Boolean, fullName = "dontsplitarrays", description = "don't store any word array as split lsb/msb in memory, as if all of those have @nosplit")
val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator)
val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of ${CompilationTargets.joinToString(",")} or a custom target properties file) (required)")
val showTimings by cli.option(ArgType.Boolean, fullName = "timings", description = "show internal compiler timings (for performance analysis)")
@@ -90,6 +89,16 @@ private fun compileMain(args: Array<String>): Boolean {
if(quietAll!=true)
banner()
if(libDump!=null) {
scanLibraryFiles(libDump, null)
return true
}
if(libSearch!=null) {
scanLibraryFiles(null, libSearch)
return true
}
val outputPath = pathFrom(outputDir)
if(!outputPath.toFile().isDirectory) {
System.err.println("Output path doesn't exist")
@@ -193,7 +202,6 @@ private fun compileMain(args: Array<String>): Boolean {
slabsHighBank,
slabsGolden == true,
compilationTarget!!,
dontSplitWordArrays == true,
breakpointCpuInstruction,
printAst1 == true,
printAst2 == true,
@@ -278,7 +286,6 @@ private fun compileMain(args: Array<String>): Boolean {
slabsHighBank,
slabsGolden == true,
compilationTarget!!,
dontSplitWordArrays == true,
breakpointCpuInstruction,
printAst1 == true,
printAst2 == true,
@@ -363,3 +370,62 @@ fun runVm(irFilename: String, quiet: Boolean) {
val vmdef = VMTarget()
vmdef.launchEmulator(0, irFile, quiet)
}
private fun scanLibraryFiles(dump: String?, searchPattern: String?) {
val library_prefix = "/prog8lib"
val dumpPath = if(dump!=null) pathFrom(dump) else null
val pattern = searchPattern?.toRegex(RegexOption.IGNORE_CASE)
if(pattern!=null) {
println("You can also have a look in the documentation for the libraries at https://prog8.readthedocs.io/en/latest/libraries.html")
println("The library source files are available in the Github repository at https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib")
println("Searching for pattern '$pattern' in embedded library files.\n")
}
if(dumpPath!=null) {
println("Dumping embedded library files into $dumpPath\n")
dumpPath.createDirectories()
val license = dumpPath / "${library_prefix.drop(1)}-$VERSION/LICENSE.txt"
license.parent.createDirectories()
license.writeText("These library files belong to the Prog8 compiler project, see https://github.com/irmen/prog8/\n" +
"They are licensed under the GNU GPL 3.0 software license, see https://www.gnu.org/licenses/gpl.html\n")
}
fun search(path: Path) {
val hits = mutableListOf<String>()
path.useLines { lines ->
lines.forEachIndexed { index, line ->
if (pattern!!.containsMatchIn(line)) {
hits.add("${(index + 1).toString().padStart(6)}: ${line.trimStart()}")
}
}
}
if(hits.isNotEmpty()) {
println("Found in Library file '${path.absolutePathString().drop(library_prefix.length+1)}':")
hits.forEach(::println)
println()
}
}
fun dump(path: Path) {
val targetfolder = dumpPath!! / (path.first().pathString + "-$VERSION")
val target = targetfolder / path.pathString.drop(library_prefix.length+1)
target.parent.createDirectories()
target.writeBytes(path.readBytes())
}
// Get the location of the current JAR
val jarUrl = object {}.javaClass.protectionDomain.codeSource.location
FileSystems.newFileSystem(URI.create("jar:$jarUrl"), emptyMap<String, String>()).use { fs ->
val dir = fs.getPath(library_prefix)
Files.walk(dir).use { paths ->
paths.filter { Files.isRegularFile(it) }.forEach { path ->
if(pattern!=null)
search(path)
else
dump(path)
}
}
}
}
@@ -22,8 +22,10 @@ internal val constEvaluatorsForBuiltinFuncs: Map<String, ConstExpressionCaller>
"sqrt__uword" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, false) { sqrt(it.toDouble()) } },
"sqrt__float" to { a, p, prg -> oneFloatArgOutputFloat(a, p, prg) { sqrt(it) } },
"lsb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x and 255).toDouble() } },
"lsb__long" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x and 255).toDouble() } },
"lsw" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x and 65535).toDouble() } },
"msb" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 8 and 255).toDouble()} },
"msb__long" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 24 and 255).toDouble()} },
"msw" to { a, p, prg -> oneIntArgOutputInt(a, p, prg, true) { x: Int -> (x ushr 16 and 65535).toDouble()} },
"mkword" to ::builtinMkword,
"mklong" to ::builtinMklong,
+7 -8
View File
@@ -35,6 +35,7 @@ import kotlin.time.measureTimedValue
class CompilationResult(val compilerAst: Program, // deprecated, use codegenAst instead
val codegenAst: PtProgram?,
val codegenSymboltable: SymbolTable?,
val compilationOptions: CompilationOptions,
val importedFiles: List<Path>)
@@ -55,7 +56,6 @@ class CompilerArguments(val filepath: Path,
val slabsHighBank: Int?,
val slabsGolden: Boolean,
val compilationTarget: String,
val dontSplitWordArrays: Boolean,
val breakpointCpuInstruction: String?,
val printAst1: Boolean,
val printAst2: Boolean,
@@ -88,6 +88,8 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
}
try {
var symbolTable: SymbolTable? = null
val totalTime = measureTime {
val libraryDirs = if(compTarget.libraryPath!=null) listOf(compTarget.libraryPath.toString()) else emptyList()
val (parseresult, parseDuration) = measureTimedValue {
@@ -120,7 +122,6 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
varsGolden = args.varsGolden
slabsHighBank = args.slabsHighBank
slabsGolden = args.slabsGolden
dontSplitWordArrays = args.dontSplitWordArrays
outputDir = args.outputDir.normalize()
symbolDefs = args.symbolDefs
}
@@ -178,19 +179,17 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
println("*********** COMPILER AST END *************\n")
}
var symbolTable: SymbolTable
val (intermediateAst, simplifiedAstDuration2) = measureTimedValue {
val intermediateAst = SimplifiedAstMaker(program, args.errors).transform()
val stMaker = SymbolTableMaker(intermediateAst, compilationOptions)
symbolTable = stMaker.make()
postprocessSimplifiedAst(intermediateAst, symbolTable, compilationOptions, args.errors)
postprocessSimplifiedAst(intermediateAst, symbolTable!!, compilationOptions, args.errors)
args.errors.report()
symbolTable = stMaker.make() // need an updated ST because the postprocessing changes stuff
if (compilationOptions.optimize) {
optimizeSimplifiedAst(intermediateAst, compilationOptions, symbolTable, args.errors)
optimizeSimplifiedAst(intermediateAst, compilationOptions, symbolTable!!, args.errors)
args.errors.report()
symbolTable = stMaker.make() // need an updated ST because the optimization changes stuff
}
@@ -210,7 +209,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
createAssemblyDuration = measureTime {
if (!createAssemblyAndAssemble(
intermediateAst,
symbolTable,
symbolTable!!,
args.errors,
compilationOptions,
program.generatedLabelSequenceNumber
@@ -251,7 +250,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
if(!args.quietAll) {
println("\nTotal compilation+assemble time: ${totalTime.toString(DurationUnit.SECONDS, 3)}.")
}
return CompilationResult(resultingProgram!!, ast, compilationOptions, importedFiles)
return CompilationResult(resultingProgram!!, ast, symbolTable, compilationOptions, importedFiles)
} catch (px: ParseError) {
args.errors.printSingleError("${px.position.toClickableStr()} parse error: ${px.message}".trim())
} catch (ac: ErrorsReportedException) {
@@ -588,8 +588,8 @@ internal class AstChecker(private val program: Program,
else {
if(!compilerOptions.ignoreFootguns)
errors.warn("\uD83D\uDCA3 footgun: reusing R0-R15 as parameters risks overwriting due to clobbering or no callstack", subroutine.position)
if(!p.type.isWord && !p.type.isByteOrBool) {
errors.err("can only use register param when type is boolean, byte or word", p.position)
if(!p.type.isWordOrByteOrBool && !p.type.isPointer) {
errors.err("can only use register param when type is boolean, byte, word or pointer", p.position)
}
}
}
@@ -1090,8 +1090,8 @@ internal class AstChecker(private val program: Program,
}
if(decl.datatype.isPointerArray) {
if(decl.splitwordarray!= SplitWish.SPLIT)
errors.err("pointer arrays can only be @split", decl.position)
if(decl.splitwordarray==SplitWish.NOSPLIT)
errors.err("pointer arrays can only be split", decl.position)
}
if(decl.datatype.isStructInstance && decl.origin!=VarDeclOrigin.SUBROUTINEPARAM) {
@@ -1452,7 +1452,7 @@ internal class AstChecker(private val program: Program,
} else if(rightIndexer!=null) {
val leftDt = expr.left.inferType(program)
if(leftDt.isStructInstance) {
TODO("pointer[x].field[y] ??")
TODO("pointer[x].field[y] ?? ${expr.left.position}")
// // pointer[x].field[y] --> type is the dt of 'field'
// var struct = leftDt.getOrUndef().subType
// if (struct==null) {
@@ -1639,6 +1639,10 @@ internal class AstChecker(private val program: Program,
errors.err("invalid type cast", typecast.position)
}
if(typecast.implicit && typecast.type.isLong && typecast.expression.inferType(program).isPointer) {
errors.err("cannot use a pointer as a long, a pointer is an unsigned word", typecast.position)
}
super.visit(typecast)
}
@@ -2061,6 +2065,8 @@ internal class AstChecker(private val program: Program,
!iterableEltDt.isByte
} else if (elementDt.isWords) {
!iterableEltDt.isWord
} else if (elementDt.isLong) {
!iterableEltDt.isLong
} else {
false
}
@@ -2088,6 +2094,12 @@ internal class AstChecker(private val program: Program,
super.visit(memread)
}
override fun visit(numLiteral: NumericLiteral) {
super.visit(numLiteral)
if(numLiteral.type== BaseDataType.LONG) // other smaller types have already been validated
checkValueTypeAndRange(DataType.forDt(numLiteral.type), numLiteral)
}
private fun allowedMemoryAccessAddressExpression(addressExpression: Expression, program: Program): Boolean {
val dt = addressExpression.inferType(program)
if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub?.isByteOrBool==true))
@@ -2347,7 +2359,7 @@ internal class AstChecker(private val program: Program,
if(value.type==BaseDataType.FLOAT)
err("integer value expected instead of float; possible loss of precision")
val number=value.number
if (number < -2147483647 || number > 2147483647)
if (number < -2147483647.0 || number > 2147483647.0)
return err("value '$number' out of range for long")
}
targetDt.isArray -> {
@@ -2459,7 +2471,7 @@ internal class AstChecker(private val program: Program,
val sourceIsBitwiseOperatorExpression = (sourceValue as? BinaryExpression)?.operator in BitwiseOperators
if(sourceDatatype.isWord && targetDatatype.isByte)
errors.err("cannot assign word to byte, maybe use msb() or lsb()", position)
else if(sourceDatatype.isFloat&& targetDatatype.isInteger)
else if(sourceDatatype.isFloat && targetDatatype.isInteger)
errors.err("cannot assign float to ${targetDatatype}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position)
else if(targetDatatype.isUnsignedWord && (sourceDatatype.isPassByRef || sourceDatatype.isPointer)) {
// this is allowed: a pass-by-reference or pointer datatype into an uword (untyped pointer value).
@@ -113,8 +113,6 @@ class AstPreprocessor(val program: Program,
val replacements = mutableListOf<IAstModification>()
for(decl in vars) {
if(shouldUnSplitArray(decl))
continue // unsplitting must be done first
if(decl.type != VarDeclType.VAR) {
movements.add(IAstModification.InsertFirst(decl, parentscope))
replacements.add(IAstModification.Remove(decl, scope))
@@ -198,10 +196,6 @@ class AstPreprocessor(val program: Program,
}
}
if(shouldUnSplitArray(decl)) {
return makeUnSplitArray(decl)
}
// convert all antlr names to structs
val antlrTypeName = decl.datatype.subTypeFromAntlr
if(antlrTypeName!=null) {
@@ -232,18 +226,6 @@ class AstPreprocessor(val program: Program,
return noModifications
}
private fun shouldUnSplitArray(decl: VarDecl): Boolean =
options.dontSplitWordArrays && decl.datatype.isSplitWordArray
private fun makeUnSplitArray(decl: VarDecl): Iterable<IAstModification> {
val splitDt = DataType.arrayFor(decl.datatype.sub!!, false)
val newDecl = VarDecl(
decl.type, decl.origin, splitDt, decl.zeropage, decl.splitwordarray, decl.arraysize, decl.name, emptyList(),
decl.value?.copy(), decl.sharedWithAsm, decl.alignment, false, decl.position
)
return listOf(IAstModification.ReplaceNode(decl, newDecl, decl.parent))
}
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
// For non-kernal subroutines and non-asm parameters:
// inject subroutine params as local variables (if they're not there yet).
@@ -269,7 +251,7 @@ class AstPreprocessor(val program: Program,
.filter { it.name !in namesInSub && it.name !in existingAliases }
.forEach {
if (it.registerOrPair in Cx16VirtualRegisters) {
if(it.type.isWordOrByteOrBool) {
if(it.type.isWordOrByteOrBool || it.type.isPointer) {
val mappedParamVar = VarDecl.fromParameter(it)
mods += IAstModification.InsertFirst(mappedParamVar, subroutine)
} else {
@@ -297,6 +297,17 @@ _after:
val peek = FunctionCallExpression(IdentifierReference(listOf("peekbool"), arrayIndexedExpression.position), mutableListOf(address), arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, peek, parent))
}
} else if(arrayVar.datatype.sub==BaseDataType.LONG) {
// use peekl/pokel
if(parent is AssignTarget) {
val assignment = parent.parent as Assignment
val args = mutableListOf(address, assignment.value)
val poke = FunctionCallStatement(IdentifierReference(listOf("pokel"), arrayIndexedExpression.position), args, false, arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(assignment, poke, assignment.parent))
} else {
val peek = FunctionCallExpression(IdentifierReference(listOf("peekl"), arrayIndexedExpression.position), mutableListOf(address), arrayIndexedExpression.position)
return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, peek, parent))
}
} else if(arrayVar.datatype.sub==BaseDataType.FLOAT) {
// use peekf/pokef
if(parent is AssignTarget) {
@@ -313,7 +324,7 @@ _after:
return noModifications
} else if(arrayVar!=null) {
// it could be a pointer dereference instead of a simple array variable
TODO("deref[word] rewrite ???? $arrayIndexedExpression")
TODO("deref[word] rewrite ???? ${arrayIndexedExpression.position}")
// val dt = arrayIndexedExpression.plainarrayvar!!.traverseDerefChainForDt(null)
// if(dt.isUnsignedWord) {
// // ptr.field[index] --> @(ptr.field + index)
@@ -364,7 +375,8 @@ _after:
if(expr.operator=="*" && expr.inferType(program).isInteger && expr.left isSameAs expr.right) {
// replace squaring with call to builtin function to do this in a more optimized way
val function = if(expr.left.inferType(program).isBytes) "prog8_lib_square_byte" else "prog8_lib_square_word"
val leftDt = expr.left.inferType(program)
val function = if(leftDt.isBytes) "prog8_lib_square_byte" else if(leftDt.isWords) "prog8_lib_square_word" else "prog8_lib_square_long"
val squareCall = FunctionCallExpression(
IdentifierReference(listOf(function), expr.position),
mutableListOf(expr.left.copy()), expr.position)
@@ -651,7 +663,7 @@ _after:
val indexer = ArrayIndexedExpression(null, ptrDeref, idx.indexer, idx.position)
return listOf(IAstModification.ReplaceNode(expr, indexer, expr.parent))
} else {
TODO("convert ptr.p[idx]")
TODO("convert ptr.p[idx] ${idx.position}")
}
}
}
@@ -129,6 +129,7 @@ internal class LiteralsToAutoVarsAndRecombineIdentifiers(private val program: Pr
override fun after(alias: Alias, parent: Node): Iterable<IAstModification> {
val target = alias.target.targetStatement()
if(target is Alias) {
// shortcut the alias that refers to another alias
val newAlias = Alias(alias.alias, target.target, alias.position)
return listOf(IAstModification.ReplaceNode(alias, newAlias, parent))
}
@@ -212,8 +213,8 @@ internal class LiteralsToAutoVarsAndRecombineIdentifiers(private val program: Pr
val tgt2 = deref.definingScope.lookup(deref.chain.take(1)) as? Alias
if(tgt2!=null && parent !is Alias) {
if(tgt2.target.targetStatement() !is Alias) {
val actual = IdentifierReference(tgt2.target.nameInSource + deref.chain.drop(1), deref.position)
return listOf(IAstModification.ReplaceNode(deref, actual, parent))
val unaliased = PtrDereference(tgt2.target.nameInSource + deref.chain.drop(1), deref.derefLast, deref.position)
return listOf(IAstModification.ReplaceNode(deref, unaliased, parent))
}
}
return noModifications
@@ -90,7 +90,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
if(leftDt.isKnown && rightDt.isKnown) {
if(expr.operator=="<<" && leftDt.isBytes) {
// uword ww = 1 << shift --> make the '1' a word constant
// uword/ulong ww = 1 << shift --> make the '1' a word (or long) constant
val leftConst = expr.left.constValue(program)
if(leftConst!=null) {
val leftConstAsWord =
@@ -98,19 +98,22 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
NumericLiteral(BaseDataType.UWORD, leftConst.number, leftConst.position)
else
NumericLiteral(BaseDataType.WORD, leftConst.number, leftConst.position)
val leftConstAsLong = NumericLiteral(BaseDataType.LONG, leftConst.number, leftConst.position)
val modifications = mutableListOf<IAstModification>()
if (parent is Assignment) {
if (parent.target.inferType(program).isWords) {
modifications += IAstModification.ReplaceNode(expr.left, leftConstAsWord, expr)
// if(rightDt.isBytes)
// modifications += IAstModification.ReplaceNode(expr.right, TypecastExpression(expr.right, leftConstAsWord.type, true, expr.right.position), expr)
}
else if (parent.target.inferType(program).isLong) {
modifications += IAstModification.ReplaceNode(expr.left, leftConstAsLong, expr)
}
} else if (parent is TypecastExpression && parent.type.isUnsignedWord && parent.parent is Assignment) {
val assign = parent.parent as Assignment
if (assign.target.inferType(program).isWords) {
modifications += IAstModification.ReplaceNode(expr.left, leftConstAsWord, expr)
// if(rightDt.isBytes)
// modifications += IAstModification.ReplaceNode(expr.right, TypecastExpression(expr.right, leftConstAsWord.type, true, expr.right.position), expr)
}
else if (assign.target.inferType(program).isLong) {
modifications += IAstModification.ReplaceNode(expr.left, leftConstAsLong, expr)
}
}
if(modifications.isNotEmpty())
@@ -129,7 +132,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
expr))
}
if(rightCv!=null && rightCv.number<0) {
val value = if(leftDt.isBytes) 256+rightCv.number else 65536+rightCv.number
val value = if(leftDt.isBytes) 256+rightCv.number else if(leftDt.isWords) 65536+rightCv.number else 0xffffffffL+rightCv.number
return listOf(IAstModification.ReplaceNode(
expr.right,
NumericLiteral(leftDt.getOrUndef().base, value, expr.right.position),
@@ -268,7 +271,18 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
}
val cvalue = assignment.value.constValue(program)
if(cvalue!=null) {
return castLiteral(cvalue)
val castResult = castLiteral(cvalue)
if(castResult.isNotEmpty())
return castResult
// exception for @(...) = -byte (direct memory write) it's just convenient to be able to write negative numbers too (like pokew also allows)
if(assignment.target.memoryAddress!=null) {
if(valuetype.isByteOrBool && targettype.isUnsignedByte) {
require(cvalue.number.toInt() in -128..127)
val asUByte = NumericLiteral(BaseDataType.UBYTE, cvalue.number.toInt().toUByte().toDouble(), assignment.value.position)
return listOf(IAstModification.ReplaceNode(assignment.value, asUByte, assignment))
}
}
}
}
}
@@ -71,34 +71,17 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
// check splitting of word arrays
if(decl.splitwordarray != SplitWish.DONTCARE && !decl.datatype.isWordArray && !decl.datatype.isPointerArray) {
if(decl.origin != VarDeclOrigin.ARRAYLITERAL)
errors.err("@split and @nosplit are for word or pointer arrays only", decl.position)
errors.err("@nosplit is for word or pointer arrays only", decl.position)
}
if(decl.datatype.isWordArray) {
var changeDataType: DataType?
var changeSplit: SplitWish = decl.splitwordarray
when(decl.splitwordarray) {
SplitWish.DONTCARE -> {
if(options.dontSplitWordArrays) {
changeDataType = if(decl.datatype.isSplitWordArray) DataType.arrayFor(decl.datatype.elementType().base, false) else null
changeSplit = SplitWish.NOSPLIT
}
else {
changeDataType = if(decl.datatype.isSplitWordArray) null else {
val eltDt = decl.datatype.elementType()
if(eltDt.isPointer)
TODO("convert array of pointers to split words array type")
else
DataType.arrayFor(eltDt.base)
}
changeSplit = SplitWish.SPLIT
}
}
SplitWish.SPLIT -> {
changeDataType = if(decl.datatype.isSplitWordArray) null else {
val eltDt = decl.datatype.elementType()
if(eltDt.isPointer)
TODO("convert array of pointers to split words array type")
TODO("convert array of pointers to split words array type ${decl.position}")
else
DataType.arrayFor(eltDt.base)
}
@@ -115,7 +98,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
value = ArrayLiteral(InferredTypes.knownFor(changeDataType), value.value, value.position)
}
val newDecl = VarDecl(decl.type, decl.origin, changeDataType, decl.zeropage,
changeSplit, decl.arraysize, decl.name, decl.names,
decl.splitwordarray, decl.arraysize, decl.name, decl.names,
value, decl.sharedWithAsm, decl.alignment, decl.dirty, decl.position)
return listOf(IAstModification.ReplaceNode(decl, newDecl, parent))
}
@@ -225,17 +208,17 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
}
if(expr.operator=="<<") {
// << X --> X (X is word or byte)
// << X --> X (X is long or word or byte)
val valueDt = expr.expression.inferType(program)
if(valueDt.isBytes || valueDt.isWords) {
if(valueDt.isInteger) {
return listOf(IAstModification.ReplaceNode(expr, expr.expression, parent))
}
}
if(expr.operator=="^") {
// ^ X --> 0 (X is word or byte)
// ^ X --> 0 (X is long word or byte)
val valueDt = expr.expression.inferType(program)
if(valueDt.isBytes || valueDt.isWords) {
if(valueDt.isInteger) {
val zero = NumericLiteral(BaseDataType.UBYTE, 0.0, expr.expression.position)
return listOf(IAstModification.ReplaceNode(expr, zero, parent))
}
@@ -450,7 +433,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
newIndex.linkParents(arrayIndexedExpression.indexer)
}
} else if(arrayIndexedExpression.pointerderef!=null) {
TODO("cleanup pointer indexing")
TODO("cleanup pointer indexing ${arrayIndexedExpression.position}")
}
}
return noModifications
@@ -145,7 +145,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila
if(addrOf!=null) {
val identType = addrOf.identifier?.inferType(program)?.getOrUndef()
if(identType?.isSplitWordArray==true) {
return Pair("argument ${mismatch + 1} type mismatch, was: $actual (because arg is a @split word array) expected: $expected", call.args[mismatch].position)
return Pair("argument ${mismatch + 1} type mismatch, was: $actual (because arg is a split word array) expected: $expected", call.args[mismatch].position)
}
}
}
+19 -1
View File
@@ -58,7 +58,7 @@ class TestBuiltinFunctions: FunSpec({
func.parameters[0].name shouldBe "address"
func.parameters[0].possibleDatatypes shouldBe arrayOf(BaseDataType.UWORD)
func.parameters[1].name shouldBe "value"
func.parameters[1].possibleDatatypes shouldBe arrayOf(BaseDataType.UBYTE)
func.parameters[1].possibleDatatypes shouldBe arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
func.pure shouldBe false
func.returnType shouldBe null
}
@@ -184,5 +184,23 @@ main {
compileText(Cx16Target(), false, src, outputDir, writeAssembly = true) shouldNotBe null
compileText(C64Target(), false, src, outputDir, writeAssembly = true) shouldNotBe null
}
test("sgn") {
val src="""
main {
sub start() {
byte @shared b1 = -100
word @shared w1 = -1000
long @shared l1 = -1000000
cx16.r0sL = sgn(b1)
cx16.r1sL = sgn(w1)
cx16.r2sL = sgn(l1)
}
}"""
compileText(Cx16Target(), false, src, outputDir, writeAssembly = true) shouldNotBe null
compileText(C64Target(), false, src, outputDir, writeAssembly = true) shouldNotBe null
compileText(VMTarget(), false, src, outputDir, writeAssembly = true) shouldNotBe null
}
})
+1 -1
View File
@@ -47,7 +47,6 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
slabsHighBank = null,
slabsGolden = false,
compilationTarget = target.name,
dontSplitWordArrays = false,
breakpointCpuInstruction = null,
printAst1 = false,
printAst2 = false,
@@ -178,6 +177,7 @@ class TestCompilerOnExamplesCx16: FunSpec({
"test_gfx_lores",
"test_gfx_hires",
"testmonogfx",
"textspotlight",
),
listOf(false, true)
)
@@ -39,7 +39,6 @@ class TestCompilerOptionSourcedirs: FunSpec({
slabsHighBank = null,
slabsGolden = false,
compilationTarget = Cx16Target.NAME,
dontSplitWordArrays = false,
breakpointCpuInstruction = null,
printAst1 = false,
printAst2 = false,
+56 -13
View File
@@ -1564,33 +1564,34 @@ main {
test("hoist variable decl and initializer correctly in case of pointer type variable as well") {
val src="""
%import textio
main {
sub start() {
txt.print("one\n")
stuff()
if true {
txt.print("two\n")
stuff()
^^bool @shared successor = find_successor() ; testcase here
}
txt.print("four\n")
stuff()
sub find_successor() -> uword {
txt.print("three\n")
stuff()
cx16.r0++
return 0
}
}
sub stuff() {
}
}"""
compileText(C64Target(), false, src, outputDir) shouldNotBe null
val result = compileText(VMTarget(), false, src, outputDir)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 6
st[0] shouldBe instanceOf<VarDecl>()
(st[1] as FunctionCallStatement).target.nameInSource shouldBe listOf("txt", "print")
(st[1] as FunctionCallStatement).target.nameInSource shouldBe listOf("stuff")
st[2] shouldBe instanceOf<IfElse>()
(st[3] as FunctionCallStatement).target.nameInSource shouldBe listOf("txt", "print")
(st[3] as FunctionCallStatement).target.nameInSource shouldBe listOf("stuff")
st[4] shouldBe instanceOf<Return>()
st[5] shouldBe instanceOf<Subroutine>()
}
@@ -1950,7 +1951,7 @@ main {
val src="""
main {
sub start() {
uword[10] @split @shared splitarray
uword[10] @shared splitarray
uword[10] @nosplit @shared nosplitarray
^^uword ptr1 = &&splitarray
@@ -1991,9 +1992,9 @@ main {
errors.errors.size shouldBe 3
errors.warnings.size shouldBe 0
errors.infos.size shouldBe 0
errors.errors[0] shouldContain "pointer arrays can only be @split"
errors.errors[1] shouldContain "was: ^^ubyte (because arg is a @split word array) expected: ^^main.Node"
errors.errors[2] shouldContain "was: ^^ubyte (because arg is a @split word array) expected: ^^main.Node"
errors.errors[0] shouldContain "pointer arrays can only be split"
errors.errors[1] shouldContain "was: ^^ubyte (because arg is a split word array) expected: ^^main.Node"
errors.errors[2] shouldContain "was: ^^ubyte (because arg is a split word array) expected: ^^main.Node"
}
test("passing split array of structpointers to a subroutine in various forms should be param type ptr to ubyte (the lsb part of the split array)") {
@@ -2004,7 +2005,7 @@ main {
}
sub start() {
^^Node[10] @split nodearray
^^Node[10] nodearray
func(&&nodearray)
func(&nodearray)
func(nodearray)
@@ -2437,6 +2438,48 @@ structdefs {
a6t.pointerDereference!!.chain shouldBe listOf("structdefs", "element", "value2")
}
test("pointer dereference aliasing") {
val src="""
main {
sub start() {
player.test()
}
}
cx16 {
%option merge
&^^word pword4 = &cx16.r4
}
player {
alias sxPtr = cx16.pword4
&^^word zxPtr = &cx16.r6
sub test() {
sxPtr^^ = -99 ; aliased assignment
if (zxPtr^^ - sxPtr^^) in -13 to 13 { ; aliased expression
cx16.r0++
}
}
}"""
val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!!
val st = result.compilerAst.allBlocks.single{it.name == "player"}.statements
st.size shouldBe 2
val test = (st[1] as Subroutine).statements
test.size shouldBe 3
val assignTgt = (test[0] as Assignment).target
val targetDeref = assignTgt.pointerDereference!!
targetDeref.chain shouldBe listOf("cx16", "pword4")
val ifCond = (test[1] as IfElse).condition as ContainmentCheck
val cond = ifCond.element as BinaryExpression
cond.left shouldBe instanceOf<PtrDereference>()
cond.right shouldBe instanceOf<PtrDereference>()
(cond.right as PtrDereference).chain shouldBe listOf("cx16", "pword4")
}
test("assigning field with same name should not confuse compiler") {
val src="""
main {
+24 -4
View File
@@ -193,17 +193,20 @@ main {
test("word to byte casts") {
val text = """
%import textio
main {
sub func(ubyte arg) -> word {
return arg-99
}
sub start() {
txt.print_ub(func(0) as ubyte)
txt.print_uw(func(0) as ubyte)
txt.print_w(func(0) as ubyte)
funcub(func(0) as ubyte)
funcuw(func(0) as ubyte)
funcw(func(0) as ubyte)
}
sub funcub(ubyte arg) { }
sub funcuw(uword arg) { }
sub funcw(word arg) { }
}"""
val result = compileText(C64Target(), false, text, outputDir, writeAssembly = false)!!
val stmts = result.compilerAst.entrypoint.statements
@@ -977,4 +980,21 @@ main {
compileText(VMTarget(), false, src, outputDir, writeAssembly = true) shouldNotBe null
compileText(C64Target(), false, src, outputDir, writeAssembly = true) shouldNotBe null
}
test("negative numbers okay for pokes") {
val src = """
main {
sub start() {
@(4000) = 100
@(4000) = -100
poke(4000, 100)
poke(4000, -100)
pokew(4000, 9999)
pokew(4000, -9999)
pokel(4000, 999999)
pokel(4000, -999999)
}
}"""
compileText(C64Target(), false, src, outputDir, writeAssembly = false) shouldNotBe null
}
})
+14 -10
View File
@@ -63,17 +63,19 @@ class TestAstChecks: FunSpec({
test("can't do str or array expression without using address-of") {
val text = """
%import textio
main {
sub start() {
ubyte[] array = [1,2,3,4]
str s1 = "test"
ubyte ff = 1
txt.print(s1+ff)
txt.print(array+ff)
txt.print_uwhex(s1+ff, true)
txt.print_uwhex(array+ff, true)
print(s1+ff)
print(array+ff)
print_uwhex(s1+ff, true)
print_uwhex(array+ff, true)
}
sub print(str s) { cx16.r0++ }
sub print_uwhex(uword w, bool prefix) { cx16.r0++ }
}
"""
val errors = ErrorReporterForTests()
@@ -83,21 +85,23 @@ class TestAstChecks: FunSpec({
test("str or array expression with address-of") {
val text = """
%import textio
main {
sub start() {
ubyte[] array = [1,2,3,4]
str s1 = "test"
bool bb1, bb2
ubyte ff = 1
txt.print(&s1+ff)
txt.print(&array+ff)
txt.print_uwhex(&s1+ff, true)
txt.print_uwhex(&array+ff, true)
print(&s1+ff)
print(&array+ff)
print_uwhex(&s1+ff, true)
print_uwhex(&array+ff, true)
; also good:
bb1 = (s1 == "derp")
bb2 = (s1 != "derp")
}
sub print(str s) { cx16.r0++ }
sub print_uwhex(uword w, bool prefix) { cx16.r0++ }
}
"""
compileText(C64Target(), false, text, outputDir, writeAssembly = false) shouldNotBe null
+24 -37
View File
@@ -407,7 +407,6 @@ main {
test("const evaluation of signed bitwise operations") {
val src="""
%import textio
main {
sub start() {
byte @shared a = -1
@@ -417,26 +416,16 @@ main {
const byte cb = -15
const ubyte cub = 2
txt.print_ub( a & b )
txt.spc()
txt.print_ub( a | b )
txt.spc()
txt.print_ub( a ^ b )
txt.spc()
txt.print_b( a << ub )
txt.spc()
txt.print_b( a >> ub )
txt.nl()
txt.print_ub( ca & cb )
txt.spc()
txt.print_ub( ca | cb )
txt.spc()
txt.print_ub( ca ^ cb )
txt.spc()
txt.print_b( ca << cub )
txt.spc()
txt.print_b( ca >> cub )
txt.nl()
print_ub( a & b )
print_ub( a | b )
print_ub( a ^ b )
print_b( a << ub )
print_b( a >> ub )
print_ub( ca & cb )
print_ub( ca | cb )
print_ub( ca ^ cb )
print_b( ca << cub )
print_b( ca >> cub )
word @shared aw = -1
word @shared bw = -15
@@ -445,23 +434,21 @@ main {
const word cbw = -15
const uword cuw = 2
txt.print_uw( aw & bw )
txt.spc()
txt.print_uw( aw | bw )
txt.spc()
txt.print_uw( aw ^ bw )
txt.nl()
txt.print_uw( caw & cbw )
txt.spc()
txt.print_uw( caw | cbw )
txt.spc()
txt.print_uw( caw ^ cbw )
txt.nl()
txt.print_w( cbw << cuw )
txt.spc()
txt.print_w( cbw >> cuw )
txt.nl()
print_uw( aw & bw )
print_uw( aw | bw )
print_uw( aw ^ bw )
print_uw( caw & cbw )
print_uw( caw | cbw )
print_uw( caw ^ cbw )
print_w( cbw << cuw )
print_w( cbw >> cuw )
}
sub print_ub(ubyte v) {}
sub print_b(byte v) {}
sub print_uw(uword v) {}
sub print_w(word v) {}
}"""
compileText(C64Target(), false, src, outputDir, writeAssembly = false) shouldNotBe null
-5
View File
@@ -970,9 +970,6 @@ class TestProg8Parser: FunSpec( {
test("line comment in array literal is ok") {
val src="""
%import textio
%zeropage basicsafe
main {
sub start() {
byte[] foo = [ 1, 2, ; this comment is ok
@@ -991,8 +988,6 @@ main {
test("various alternative curly brace styles are ok") {
val src="""
%zeropage dontuse
main {
; curly braces without newline
sub start () { foo() derp() other() }
+4 -9
View File
@@ -118,10 +118,10 @@ class TestProgram: FunSpec({
}
test("block sort order") {
val src="""
val src= """
%import textio
main ${'$'}0a00 {
main $0a00 {
sub start() {
otherblock1.foo()
otherblock2.foo()
@@ -132,16 +132,12 @@ otherblock1 {
sub foo() {
txt.print("main.start: ")
txt.print_uwhex(&main.start, true)
txt.nl()
txt.print("datablock1 array: ")
txt.print_uwhex(&datablock1.array1, true)
txt.nl()
txt.print("datablock2 array: ")
txt.print_uwhex(&datablock2.array2, true)
txt.nl()
txt.print("otherblock1.foo: ")
txt.print_uwhex(&foo, true)
txt.nl()
}
}
@@ -149,15 +145,14 @@ otherblock2 {
sub foo() {
txt.print("otherblock2.foo: ")
txt.print_uwhex(&otherblock2.foo, true)
txt.nl()
}
}
datablock1 ${'$'}9000 {
datablock1 $9000 {
ubyte[5] @shared array1 = [1,2,3,4,5]
}
datablock2 ${'$'}8000 {
datablock2 $8000 {
ubyte[5] @shared array2 = [1,2,3,4,5]
}
"""
+7 -11
View File
@@ -1129,30 +1129,26 @@ thing {
}
}
test("pointer arrays are always split") {
test("pointer arrays are split by default") {
val src="""
%option enable_floats
main {
sub start() {
^^bool[10] @split @shared barray
^^word[10] @split @shared warray
^^float[10] @split @shared farray
^^bool[10] @shared barrayns
^^word[10] @shared warrayns
^^float[10] @shared farrayns
^^bool[10] @shared barray
^^word[10] @shared warray
^^float[10] @shared farray
}
}"""
val result = compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 7
st.size shouldBe 4
val decls = st.filterIsInstance<VarDecl>()
decls.size shouldBe 6
decls.size shouldBe 3
decls.all { it.datatype.sub!=null } shouldBe true
decls.all { it.datatype.isPointerArray } shouldBe true
decls.all { it.datatype.isPointerArray } shouldBe true
decls.all { it.datatype.isSplitWordArray } shouldBe true
}
test("on..call in nested scope compiles correctly with temp variable introduced") {
@@ -413,8 +413,6 @@ main {
test("various array indexed assignment scenarios") {
val src="""
%import floats
%import textio
%zeropage basicsafe
main {
bool[10] barray
@@ -456,14 +454,10 @@ main {
dump()
sub dump() {
txt.print_bool(barray[2])
txt.spc()
txt.print_uw(warrayns[2])
txt.spc()
txt.print_uw(warray[2])
txt.spc()
txt.print_f(farray[2])
txt.nl()
bool @shared bb = barray[2]
uword @shared ww = warrayns[2]
uword @shared ww2 = warray[2]
float @shared ff = farray[2]
}
}
}"""
@@ -197,8 +197,6 @@ main {
"identifiers can have the names of cpu instructions" {
val text="""
%import textio
nop {
sub lda(ubyte sec) -> ubyte {
asl:
@@ -223,13 +221,15 @@ main {
sub start() {
ubyte col = 10
ubyte row = 20
txt.print_ub(nop.lda(42))
txt.nl()
txt.print_uw(nop.lda.asl)
print_ub(nop.lda(42))
print_uw(nop.lda.asl)
void ffalse(99)
void ftrue(99)
}
sub print_ub(ubyte v) {}
sub print_uw(uword v) {}
}
"""
val result = compileText(C64Target(), false, text, outputDir, writeAssembly = true)
+9 -15
View File
@@ -19,14 +19,11 @@ class TestLibrary: FunSpec({
val outputDir = tempdir().toPath()
test("library compilation (x16)") {
val src="""
%address ${'$'}A050
%memtop ${'$'}C000
val src= $$"""
%address $A050
%memtop $C000
%output library
%import textio
main {
; Create a jump table as first thing in the library.
uword[] @shared @nosplit jumptable = [
@@ -105,23 +102,20 @@ library {
}
test("library compilation (c64)") {
val src="""
%address ${'$'}8050
%memtop ${'$'}a000
val src= $$"""
%address $8050
%memtop $a000
%output library
%import textio
main {
; Create a jump table as first thing in the library.
uword[] @shared @nosplit jumptable = [
; NOTE: the compiler has inserted a single JMP instruction at the start of the 'main' block, that jumps to the start() routine.
; This is convenient because the rest of the jump table simply follows it,
; making the first jump neatly be the required initialization routine for the library (initializing variables and BSS region).
; btw, ${'$'}4c = opcode for JMP.
${'$'}4c00, &library.func1,
${'$'}4c00, &library.func2,
; btw, $4c = opcode for JMP.
$4c00, &library.func1,
$4c00, &library.func2,
]
sub start() {
@@ -8,6 +8,7 @@ import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.string.shouldStartWith
import io.kotest.matchers.types.instanceOf
import prog8.code.StNodeType
import prog8.code.ast.*
import prog8.code.core.BaseDataType
import prog8.code.core.DataType
@@ -81,6 +82,12 @@ main {
val assign = start.children[2] as PtAssignment
assign.target.identifier!!.name shouldBe "cx16.r0"
assign.value shouldBe instanceOf<PtBinaryExpression>()
val st = result.codegenSymboltable!!
st.flat.size shouldBeGreaterThan 100
st.flat["cbm.CHROUT"]?.type shouldBe StNodeType.EXTSUB
st.lookup("cbm.CHROUT")?.type shouldBe StNodeType.EXTSUB
st.lookupUnscoped("sizeof")?.type shouldBe StNodeType.BUILTINFUNC
}
test("peek and poke argument types") {
@@ -80,8 +80,8 @@ def make_test_array(datatype, comparison: C):
numbers = testnumbers[datatype]
print(" sub test_cmp_array() {")
print(f""" {datatype} @shared x
{datatype}[] @split values = [0, 0]
{datatype}[] @split sources = [0, 0]
{datatype}[] values = [0, 0]
{datatype}[] sources = [0, 0]
success = 0""")
expected = 0
test_index = 0
@@ -36,9 +36,9 @@ main {{
test_is_var()
txt.print("\\n!=var: ")
test_not_var()
txt.print("\\n==array[] @split: ")
txt.print("\\n==array[] split: ")
test_is_array_splitw()
txt.print("\\n!=array[] @split: ")
txt.print("\\n!=array[] split: ")
test_not_array_splitw()
txt.print("\\n==expr: ")
test_is_expr()
@@ -97,7 +97,7 @@ nonzero_values = {
def make_test_is_zero(datatype):
print(f"""
sub test_is_zero() {{
{datatype}[] @split sources = [9999, 9999]
{datatype}[] sources = [9999, 9999]
success = 0
sources[1]={zero_values[datatype]}
@@ -155,7 +155,7 @@ skip4:
def make_test_not_zero(datatype):
print(f"""
sub test_not_zero() {{
{datatype}[] @split sources = [9999, 9999]
{datatype}[] sources = [9999, 9999]
success = 0
sources[1]={nonzero_values[datatype]}
@@ -229,7 +229,7 @@ testnumbers = {
def make_test_is_number(datatype, equals):
numbers = testnumbers[datatype]
print(" sub test_is_number() {" if equals else " sub test_not_number() {")
print(f""" {datatype}[] @split sources = [9999, 9999]
print(f""" {datatype}[] sources = [9999, 9999]
success = 0""")
expected = 0
test_index = 0
@@ -286,8 +286,8 @@ skip{test_index}b:
def make_test_is_var(datatype, equals):
numbers = testnumbers[datatype]
print(" sub test_is_var() {" if equals else " sub test_not_var() {")
print(f""" {datatype}[] @split sources = [9999, 9999]
{datatype}[] @split values = [8888,8888]
print(f""" {datatype}[] sources = [9999, 9999]
{datatype}[] values = [8888,8888]
success = 0""")
expected = 0
test_index = 0
@@ -346,8 +346,8 @@ def make_test_is_array(datatype, equals):
numbers = testnumbers[datatype]
print(" sub test_is_array_splitw() {" if equals else " sub test_not_array_splitw() {")
print(f"""
{datatype}[] @split values = [9999, 8888]
{datatype}[] @split sources = [9999, 8888]
{datatype}[] values = [9999, 8888]
{datatype}[] sources = [9999, 8888]
success = 0""")
expected = 0
test_index = 0
@@ -441,7 +441,7 @@ skip{test_index}d:
def make_test_is_expr(datatype, equals):
numbers = testnumbers[datatype]
print(" sub test_is_expr() {" if equals else " sub test_not_expr() {")
print(f""" {datatype}[] @split sources = [9999, 9999]
print(f""" {datatype}[] sources = [9999, 9999]
cx16.r4 = 1
cx16.r5 = 1
success = 0""")
-1
View File
@@ -43,7 +43,6 @@ internal fun compileFile(
symbolDefs = emptyMap(),
outputDir = outputDir,
errors = errors ?: ErrorReporterForTests(),
dontSplitWordArrays = false,
breakpointCpuInstruction = null,
printAst1 = false,
printAst2 = false,
@@ -320,7 +320,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
when (numLiteral.type) {
BaseDataType.BOOL -> output(if(numLiteral.number==0.0) "false" else "true")
BaseDataType.FLOAT -> output(numLiteral.number.toString())
else -> output(numLiteral.number.toInt().toString())
else -> output(numLiteral.number.toLong().toString())
}
}
@@ -137,7 +137,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
override fun visitVardecl(ctx: VardeclContext): VarDecl {
val tags = ctx.TAG().map { it.text }
val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@split", "@nosplit", "@shared", "@alignword", "@alignpage", "@align64", "@dirty")
val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@nosplit", "@shared", "@alignword", "@alignpage", "@align64", "@dirty")
for(tag in tags) {
if(tag !in validTags)
throw SyntaxError("invalid variable tag '$tag'", ctx.toPosition())
@@ -167,17 +167,12 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
DataType.arrayFor(baseDt.base, split!=SplitWish.NOSPLIT)
}
val splitWords = if(split==SplitWish.DONTCARE) {
if(dt.isPointerArray) SplitWish.SPLIT // pointer arrays are always @split by default
else split
} else split
return VarDecl(
VarDeclType.VAR, // can be changed to MEMORY or CONST as required
VarDeclOrigin.USERCODE,
dt,
zp,
splitWords,
split,
arrayIndex,
name,
if(identifiers.size==1) emptyList() else identifiers,
@@ -337,12 +332,12 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
fun makeLiteral(literalTextWithGrouping: String, radix: Int): Pair<Double, BaseDataType> {
val literalText = literalTextWithGrouping.replace("_", "")
val integer: Int
val integer: Long
var datatype = BaseDataType.UBYTE
when (radix) {
10 -> {
integer = try {
literalText.toInt()
literalText.toLong()
} catch(x: NumberFormatException) {
throw SyntaxError("invalid decimal literal ${x.message}", ctx.toPosition())
}
@@ -361,7 +356,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
else if(literalText.length>8)
datatype = BaseDataType.UWORD
try {
integer = literalText.toInt(2)
integer = literalText.toLong(2)
} catch(x: NumberFormatException) {
throw SyntaxError("invalid binary literal ${x.message}", ctx.toPosition())
}
@@ -372,7 +367,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
else if(literalText.length>2)
datatype = BaseDataType.UWORD
try {
integer = literalText.lowercase().toLong(16).toInt()
integer = literalText.lowercase().toLong(16)
} catch(x: NumberFormatException) {
throw SyntaxError("invalid hexadecimal literal ${x.message}", ctx.toPosition())
}
@@ -486,7 +481,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
override fun visitSub_param(pctx: Sub_paramContext): SubroutineParameter {
val decl = pctx.vardecl()
val tags = decl.TAG().map { t -> t.text }
val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@split", "@nosplit", "@shared")
val validTags = arrayOf("@zp", "@requirezp", "@nozp", "@nosplit", "@shared")
for(tag in tags) {
if(tag !in validTags)
throw SyntaxError("invalid parameter tag '$tag'", pctx.toPosition())
@@ -724,7 +719,6 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
private fun getSplitOption(tags: List<String>): SplitWish {
return when {
"@nosplit" in tags -> SplitWish.NOSPLIT
"@split" in tags -> SplitWish.SPLIT
else -> SplitWish.DONTCARE
}
}
@@ -650,7 +650,7 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed
BaseDataType.BYTE -> require(number in -128.0..127.0)
BaseDataType.UWORD -> require(number in 0.0..65535.0)
BaseDataType.WORD -> require(number in -32768.0..32767.0)
BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0)
BaseDataType.LONG -> { /*no hard requirement, the range will be checked later to give a proper error message instead of a crash */ }
BaseDataType.BOOL -> require(number==0.0 || number==1.0)
BaseDataType.POINTER -> throw FatalAstException("pointer literals should not be created, should have been UWORD $position")
else -> require(type.isNumericOrBool) {
@@ -699,8 +699,7 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed
in -128..127 -> NumericLiteral(BaseDataType.BYTE, dvalue, position)
in 0..65535 -> NumericLiteral(BaseDataType.UWORD, dvalue, position)
in -32768..32767 -> NumericLiteral(BaseDataType.WORD, dvalue, position)
in -2147483647..2147483647 -> NumericLiteral(BaseDataType.LONG, dvalue, position)
else -> throw FatalAstException("integer overflow: $dvalue")
else -> NumericLiteral(BaseDataType.LONG, dvalue, position)
}
}
@@ -305,7 +305,7 @@ class VarDecl(
fun createAutoOptionalSplit(array: ArrayLiteral): VarDecl {
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
val arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") }
val split = if(arrayDt.isSplitWordArray) SplitWish.SPLIT else if(arrayDt.isWordArray) SplitWish.NOSPLIT else SplitWish.DONTCARE
val split = if(arrayDt.isSplitWordArray) SplitWish.DONTCARE else if(arrayDt.isWordArray) SplitWish.NOSPLIT else SplitWish.DONTCARE
val arraysize = ArrayIndex.forArray(array)
return VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, arrayDt, ZeropageWish.NOT_IN_ZEROPAGE,
split, arraysize, autoVarName, emptyList(), array,
+161 -130
View File
@@ -1,12 +1,31 @@
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit c04908a9 in branch structs6502
Prog8 compiler v12.0 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c128.p8
Compiler target: c128
LIBRARY MODULE NAME: bcd
------------------------
bcd {
addb (byte a, byte b) -> byte
addl (long a, long b) -> long
addtol (^^long a, long b)
addub (ubyte a, ubyte b) -> ubyte
adduw (uword a, uword b) -> uword
addw (word a, word b) -> word
clearbcd ()
setbcd ()
subb (byte a, byte b) -> byte
subfroml (^^long a, long b)
subl (long a, long b) -> long
subub (ubyte a, ubyte b) -> ubyte
subuw (uword a, uword b) -> uword
}
LIBRARY MODULE NAME: buffers
----------------------------
@@ -63,11 +82,11 @@ LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_tscrunch (uword compressed @R0, uword target @R1) -> clobbers (A,X,Y)
decode_tscrunch_inplace (uword compressed @R0) -> clobbers (A,X,Y)
decode_zx0 (uword compressed @R0, uword target @R1) -> clobbers (A,X,Y)
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) clobbers (X) -> uword @AY
decode_tscrunch (uword compressed @R0, uword target @R1) clobbers (A,X,Y)
decode_tscrunch_inplace (uword compressed @R0) clobbers (A,X,Y)
decode_zx0 (uword compressed @R0, uword target @R1) clobbers (A,X,Y)
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)
}
@@ -78,28 +97,30 @@ LIBRARY MODULE NAME: conv
conv {
ubyte[] @shared string_out
any2uword (str string @AY) -> clobbers (Y) -> ubyte @A
any2uword (str string @AY) -> uword @AY, ubyte @X
bin2uword (str string @AY) -> uword @AY
hex2uword (str string @AY) -> uword @AY
internal_byte2decimal (byte value @A) -> ubyte @Y, ubyte @A, ubyte @X
internal_ubyte2decimal (ubyte value @A) -> ubyte @Y, ubyte @X, ubyte @A
internal_ubyte2hex (ubyte value @A) -> clobbers (X) -> ubyte @A, ubyte @Y
internal_ubyte2hex (ubyte value @A) clobbers (X) -> ubyte @A, ubyte @Y
internal_uword2decimal (uword value @AY) -> ubyte @Y, ubyte @A, ubyte @X
internal_uword2hex (uword value @AY) -> clobbers (A,Y)
str2byte (str string @AY) -> clobbers (Y) -> byte @A
str2ubyte (str string @AY) -> clobbers (Y) -> ubyte @A
internal_uword2hex (uword value @AY) clobbers (A,Y)
str2byte (str string @AY) clobbers (Y) -> byte @A
str2ubyte (str string @AY) clobbers (Y) -> ubyte @A
str2uword (str string @AY) -> uword @AY
str2word (str string @AY) -> word @AY
str_b (byte value @A) -> clobbers (X) -> str @AY
str_ub (ubyte value @A) -> clobbers (X) -> str @AY
str_ub0 (ubyte value @A) -> clobbers (X) -> str @AY
str_ubbin (ubyte value @A) -> clobbers (X) -> str @AY
str_ubhex (ubyte value @A) -> clobbers (X) -> str @AY
str_uw (uword value @AY) -> clobbers (X) -> str @AY
str_uw0 (uword value @AY) -> clobbers (X) -> str @AY
str_uwbin (uword value @AY) -> clobbers (X) -> str @AY
str_b (byte value @A) clobbers (X) -> str @AY
str_l (long value) -> str
str_ub (ubyte value @A) clobbers (X) -> str @AY
str_ub0 (ubyte value @A) clobbers (X) -> str @AY
str_ubbin (ubyte value @A) clobbers (X) -> str @AY
str_ubhex (ubyte value @A) clobbers (X) -> str @AY
str_ulhex (long value) -> str
str_uw (uword value @AY) clobbers (X) -> str @AY
str_uw0 (uword value @AY) clobbers (X) -> str @AY
str_uwbin (uword value @AY) clobbers (X) -> str @AY
str_uwhex (uword value @AY) -> str @AY
str_w (word value @AY) -> clobbers (X) -> str @AY
str_w (word value @AY) clobbers (X) -> str @AY
}
@@ -159,7 +180,7 @@ diskio {
f_open_w (str filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (^^ubyte bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_readline (^^ubyte bufptr @AY) clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
get_loadaddress (str filename) -> uword
lf_end_list ()
@@ -186,17 +207,17 @@ LIBRARY MODULE NAME: math
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
cos8 (ubyte angle @A) clobbers (Y) -> byte @A
cos8u (ubyte angle @A) clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) clobbers (Y) -> ubyte @A
crc16 (^^ubyte data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (^^ubyte data, uword length)
crc32_end ()
crc32_end_result () -> uword @R15, uword @R14
crc32 (^^ubyte data, uword length) -> long
crc32_end () -> long
crc32_end_result () -> long @R14R15_32
crc32_start ()
crc32_update (ubyte value)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
@@ -210,20 +231,21 @@ math {
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
mul32 (uword a, uword b) -> long
randrange (ubyte n) -> ubyte
randrange_rom (ubyte n) -> ubyte
randrangew (uword n) -> uword
randrangew_rom (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rnd_rom () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndseed_rom (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rnd () clobbers (Y) -> ubyte @A
rnd_rom () clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) clobbers (A,Y)
rndseed_rom (uword seed1 @AY, uword seed2 @R0) clobbers (A,Y)
rndw () -> uword @AY
rndw_rom () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
sin8 (ubyte angle @A) clobbers (Y) -> byte @A
sin8u (ubyte angle @A) clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) clobbers (Y) -> ubyte @A
}
@@ -235,11 +257,11 @@ sorting {
gnomesort_by_uw (uword uw_keys, uword wordvalues, ubyte num_elements)
gnomesort_ub (^^ubyte bytearray @AY, ubyte num_elements @X)
gnomesort_uw (uword wordvalues, ubyte num_elements)
shellsort_by_ub (^^ubyte ub_keys, uword wordvalues, ubyte num_elements)
shellsort_by_uw (uword uw_keys, uword wordvalues, ubyte num_elements)
shellsort_by_ub (^^ubyte ub_keys, ^^uword wordvalues, ubyte num_elements)
shellsort_by_uw (^^uword uw_keys, ^^uword wordvalues, ubyte num_elements)
shellsort_pointers (uword pointers, ubyte num_elements, uword comparefunc)
shellsort_ub (^^ubyte values, ubyte num_elements)
shellsort_uw (uword values, ubyte num_elements)
shellsort_uw (^^uword values, ubyte num_elements)
string_comparator (str string1 @R0, str string2 @R1) -> bool @Pc
}
@@ -248,10 +270,10 @@ LIBRARY MODULE NAME: strings
----------------------------
strings {
append (str target @R0, str suffix @R1) -> clobbers (Y) -> ubyte @A
compare (str string1 @R0, str string2 @AY) -> clobbers (Y) -> byte @A
append (str target @R0, str suffix @R1) clobbers (Y) -> ubyte @A
compare (str string1 @R0, str string2 @AY) clobbers (Y) -> byte @A
contains (str string @AY, ubyte character @X) -> bool @Pc
copy (str source @R0, str target @AY) -> clobbers (A) -> ubyte @Y
copy (str source @R0, str target @AY) clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (str string @AY, ubyte character @X) -> ubyte @A, bool @Pc
find_eol (str string @AY) -> ubyte @A, bool @Pc
@@ -263,21 +285,21 @@ strings {
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (str source @AX, ubyte length @Y, str target @R1) -> clobbers (A,Y)
length (str string @AY) -> clobbers (A) -> ubyte @Y
left (str source @AX, ubyte length @Y, str target @R1) clobbers (A,Y)
length (str string @AY) clobbers (A) -> ubyte @Y
lower (str st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
ncompare (str string1 @R0, str string2 @AY, ubyte length @X) -> clobbers (X,Y) -> byte @A
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
ncompare (str string1 @R0, str string2 @AY, ubyte length @X) clobbers (X,Y) -> byte @A
pattern_match (str string @AY, str pattern @R0) clobbers (Y) -> bool @A
rfind (str string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (str source @AY, ubyte length @X, str target @R1) -> clobbers (A,Y)
right (str source @AY, ubyte length @X, str target @R1) clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (str source @R0, ubyte start @A, ubyte length @Y, str target @R1) -> clobbers (A,Y)
slice (str source @R0, ubyte start @A, ubyte length @Y, str target @R1) clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
@@ -329,51 +351,53 @@ cbm {
&ubyte TIME_LO
&ubyte TIME_MID
ACPTR () -> ubyte @A = $ffa5
CHKIN (ubyte logical @X) -> clobbers (A,X) -> bool @Pc = $ffc6
CHKOUT (ubyte logical @X) -> clobbers (A,X) = $ffc9
CHRIN () -> clobbers (X,Y) -> ubyte @A = $ffcf
CHKIN (ubyte logical @X) clobbers (A,X) -> bool @Pc = $ffc6
CHKOUT (ubyte logical @X) clobbers (A,X) = $ffc9
CHRIN () clobbers (X,Y) -> ubyte @A = $ffcf
CHROUT (ubyte character @A) = $ffd2
CINT () -> clobbers (A,X,Y) = $ff81
CINT () clobbers (A,X,Y) = $ff81
CIOUT (ubyte databyte @A) = $ffa8
CLALL () -> clobbers (A,X) = $ffe7
CLALL () clobbers (A,X) = $ffe7
CLEARST ()
CLOSE (ubyte logical @A) -> clobbers (A,X,Y) = $ffc3
CLRCHN () -> clobbers (A,X) = $ffcc
GETIN () -> clobbers (X,Y) -> bool @Pc, ubyte @A = $ffe4
GETIN2 () -> clobbers (X,Y) -> ubyte @A
CLOSE (ubyte logical @A) clobbers (A,X,Y) = $ffc3
CLRCHN () clobbers (A,X) = $ffcc
GETIN () clobbers (X,Y) -> bool @Pc, ubyte @A = $ffe4
GETIN2 () clobbers (X,Y) -> ubyte @A
IOBASE () -> uword @XY = $fff3
IOINIT () -> clobbers (A,X) = $ff84
IRQDFEND () -> clobbers (A,X,Y) = $ff33
IRQDFRT () -> clobbers (A,X,Y) = $fa65
LISTEN (ubyte device @A) -> clobbers (A) = $ffb1
IOINIT () clobbers (A,X) = $ff84
IRQDFEND () clobbers (A,X,Y) = $ff33
IRQDFRT () clobbers (A,X,Y) = $fa65
LISTEN (ubyte device @A) clobbers (A) = $ffb1
LOAD (ubyte verify @A, uword address @XY) -> bool @Pc, ubyte @A, uword @XY = $ffd5
MEMBOT (uword address @XY, bool dir @Pc) -> uword @XY = $ff9c
MEMTOP (uword address @XY, bool dir @Pc) -> uword @XY = $ff99
OPEN () -> clobbers (X,Y) -> bool @Pc, ubyte @A = $ffc0
PLOT (ubyte col @Y, ubyte row @X, bool dir @Pc) -> clobbers (A) -> ubyte @Y, ubyte @X = $fff0
RAMTAS () -> clobbers (A,X,Y) = $ff87
OPEN () clobbers (X,Y) -> bool @Pc, ubyte @A = $ffc0
PLOT (ubyte col @Y, ubyte row @X, bool dir @Pc) clobbers (A) -> ubyte @Y, ubyte @X = $fff0
RAMTAS () clobbers (A,X,Y) = $ff87
RDTIM () -> ubyte @A, ubyte @X, ubyte @Y = $ffde
RDTIM16 () -> clobbers (X) -> uword @AY
RDTIM16 () clobbers (X) -> uword @AY
RDTIML () clobbers (X) -> long @R0R1_32
READST () -> ubyte @A = $ffb7
RESTOR () -> clobbers (A,X,Y) = $ff8a
RESTOR () clobbers (A,X,Y) = $ff8a
SAVE (ubyte zp_startaddr @A, uword endaddr @XY) -> bool @Pc, ubyte @A = $ffd8
SCNKEY () -> clobbers (A,X,Y) = $ff9f
SCNKEY () clobbers (A,X,Y) = $ff9f
SCREEN () -> ubyte @X, ubyte @Y = $ffed
SCRORG () -> ubyte @X, ubyte @Y = $ffed
SECOND (ubyte address @A) -> clobbers (A) = $ff93
SECOND (ubyte address @A) clobbers (A) = $ff93
SETLFS (ubyte logical @A, ubyte device @X, ubyte secondary @Y) = $ffba
SETMSG (ubyte value @A) = $ff90
SETNAM (ubyte namelen @A, str filename @XY) = $ffbd
SETTIM (ubyte low @A, ubyte middle @X, ubyte high @Y) = $ffdb
SETTIML (long jiffies @R0R1_32)
SETTMO (ubyte timeout @A) = $ffa2
STOP () -> clobbers (X) -> bool @Pz, ubyte @A = $ffe1
STOP2 () -> clobbers (A,X) -> bool @Pz
TALK (ubyte device @A) -> clobbers (A) = $ffb4
TKSA (ubyte address @A) -> clobbers (A) = $ff96
UDTIM () -> clobbers (A,X) = $ffea
UNLSN () -> clobbers (A) = $ffae
UNTLK () -> clobbers (A) = $ffab
VECTOR (uword userptr @XY, bool dir @Pc) -> clobbers (A,Y) = $ff8d
STOP () clobbers (X) -> bool @Pz, ubyte @A = $ffe1
STOP2 () clobbers (A,X) -> bool @Pz
TALK (ubyte device @A) clobbers (A) = $ffb4
TKSA (ubyte address @A) clobbers (A) = $ff96
UDTIM () clobbers (A,X) = $ffea
UNLSN () clobbers (A) = $ffae
UNTLK () clobbers (A) = $ffab
VECTOR (uword userptr @XY, bool dir @Pc) clobbers (A,Y) = $ff8d
kbdbuf_clear ()
}
@@ -512,27 +536,27 @@ c128 {
&ubyte VM2
&ubyte VM3
&ubyte VM4
BOOT_CALL (ubyte device @X, ubyte drive @A) -> clobbers (A,X,Y) = $ff53
BOOT_CALL (ubyte device @X, ubyte drive @A) clobbers (A,X,Y) = $ff53
C64_MODE () = $ff4d
CLOSE_ALL (ubyte device @X) -> clobbers (X) = $ff4a
DLCHR () -> clobbers (A,X,Y) = $ff62
DMA_CALL (ubyte bank @X, ubyte command @Y) -> clobbers (A,X) = $ff50
CLOSE_ALL (ubyte device @X) clobbers (X) = $ff4a
DLCHR () clobbers (A,X,Y) = $ff62
DMA_CALL (ubyte bank @X, ubyte command @Y) clobbers (A,X) = $ff50
GETCFG (ubyte bank @X) -> ubyte @A = $ff6b
INDCMP (ubyte value @A, ubyte bank @X, ubyte offset @Y) -> clobbers (X) -> bool @Pz, bool @Pc, bool @Pv = $ff7a
INDFET (ubyte zpaddr @A, ubyte bank @X, ubyte offset @Y) -> clobbers (X) -> ubyte @A = $ff74
INDSTA (ubyte value @A, ubyte bank @X, ubyte offset @Y) -> clobbers (X) = $ff77
JMPFAR () -> clobbers (A,X) = $ff71
JSRFAR () -> clobbers (A,X) = $ff6e
INDCMP (ubyte value @A, ubyte bank @X, ubyte offset @Y) clobbers (X) -> bool @Pz, bool @Pc, bool @Pv = $ff7a
INDFET (ubyte zpaddr @A, ubyte bank @X, ubyte offset @Y) clobbers (X) -> ubyte @A = $ff74
INDSTA (ubyte value @A, ubyte bank @X, ubyte offset @Y) clobbers (X) = $ff77
JMPFAR () clobbers (A,X) = $ff71
JSRFAR () clobbers (A,X) = $ff6e
LKUPLA (ubyte lfn @A) -> bool @Pc, ubyte @X = $ff59
LKUPSA (ubyte sa @Y) -> bool @Pc, ubyte @A, ubyte @X = $ff5c
PFKEY (ubyte zpaddr @A, ubyte key @X, ubyte length @Y) = $ff65
PHOENIX () -> clobbers (A,X,Y) = $ff56
PHOENIX () clobbers (A,X,Y) = $ff56
PRIMM () = $ff7d
SETBNK (ubyte data_bank @A, ubyte filename_bank @X) = $ff68
SPIN_SPOUT () -> clobbers (A) = $ff47
SWAPPER () -> clobbers (A,X,Y) = $ff5f
SPIN_SPOUT () clobbers (A) = $ff47
SWAPPER () clobbers (A,X,Y) = $ff5f
banks (ubyte banks @A)
disable_basic () -> clobbers (A)
disable_basic () clobbers (A)
getbanks () -> ubyte @A
x16jsrfar ()
}
@@ -557,6 +581,7 @@ sys {
const ubyte target
clear_carry ()
clear_irqd ()
cpu_is_65816 () -> bool
disable_caseswitch ()
disable_runstop_and_charsetswitch ()
enable_caseswitch ()
@@ -565,32 +590,37 @@ sys {
exit2 (ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y)
exit3 (ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc)
get_as_returnaddress (uword address @XY) -> uword @AX
internal_stringcopy (str source @R0, str target @AY) -> clobbers (A,Y)
internal_stringcopy (str source @R0, str target @AY) clobbers (A,Y)
irqsafe_clear_irqd ()
irqsafe_set_irqd ()
memcmp (uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A
memcopy (uword source @R0, uword target @R1, uword count @AY) -> clobbers (A,X,Y)
memset (uword mem @R0, uword numbytes @R1, ubyte value @A) -> clobbers (A,X,Y)
memsetw (uword mem @R0, uword numwords @R1, uword value @AY) -> clobbers (A,X,Y)
memcopy (uword source @R0, uword target @R1, uword count @AY) clobbers (A,X,Y)
memset (uword mem @R0, uword numbytes @R1, ubyte value @A) clobbers (A,X,Y)
memsetw (uword mem @R0, uword numwords @R1, uword value @AY) clobbers (A,X,Y)
pop () -> ubyte @A
popl () -> long @R0R1_32
popw () -> uword @AY
progend () -> uword @AY
progstart () -> uword @AY
push (ubyte value @A)
push_returnaddress (uword address @XY)
pushl (long value @R0R1_32)
pushw (uword value @AY)
read_flags () -> ubyte @A
reset_system ()
restore_irq () -> clobbers (A)
restore_irq () clobbers (A)
restore_prog8_internals ()
save_prog8_internals ()
set_carry ()
set_irq (uword handler @AY) -> clobbers (A)
set_irq (uword handler @AY) clobbers (A)
set_irqd ()
set_rasterirq (uword handler @AY, uword rasterpos @R0) -> clobbers (A)
set_rasterirq (uword handler @AY, uword rasterpos @R0) clobbers (A)
set_rasterline (uword line @AY)
update_rasterirq (uword handler @AY, uword rasterpos @R0) clobbers (A)
wait (uword jiffies @AY)
waitrastborder ()
waitvsync () -> clobbers (A)
waitrasterline (uword line @AY)
waitvsync () clobbers (A)
}
cx16 {
@@ -722,15 +752,14 @@ cx16 {
&word r9s
&byte r9sH
&byte r9sL
cpu_is_65816 () -> bool
restore_virtual_registers () -> clobbers (A,Y)
save_virtual_registers () -> clobbers (A,Y)
restore_virtual_registers () clobbers (A,Y)
save_virtual_registers () clobbers (A,Y)
}
p8_sys_startup {
cleanup_at_exit ()
disable_runstop_and_charsetswitch () -> clobbers (A)
enable_runstop_and_charsetswitch () -> clobbers (A)
disable_runstop_and_charsetswitch () clobbers (A)
enable_runstop_and_charsetswitch () clobbers (A)
init_system ()
init_system_phase2 ()
}
@@ -753,51 +782,53 @@ txt {
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte char @A) -> clobbers (Y)
clear_screencolors (ubyte color @A) -> clobbers (Y)
clear_screenchars (ubyte char @A) clobbers (Y)
clear_screencolors (ubyte color @A) clobbers (Y)
cls ()
color (ubyte txtcol)
column (ubyte col @A) -> clobbers (A,X,Y)
fill_screen (ubyte char @A, ubyte color @Y) -> clobbers (A)
column (ubyte col @A) clobbers (A,X,Y)
fill_screen (ubyte char @A, ubyte color @Y) clobbers (A)
get_column () -> ubyte @Y
get_cursor () -> ubyte @X, ubyte @Y
get_row () -> ubyte @X
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
getchr (ubyte col @A, ubyte row @Y) clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) clobbers (Y) -> ubyte @A
height () clobbers (X,Y) -> ubyte @A
home ()
input_chars (^^ubyte buffer @AY) -> clobbers (A) -> ubyte @Y
input_chars (^^ubyte buffer @AY) clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print (str text @AY) clobbers (A,Y)
print_b (byte value @A) clobbers (A,X,Y)
print_bool (bool value)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum @A) -> clobbers (A,X,Y)
print_l (long value)
print_ub (ubyte value @A) clobbers (A,X,Y)
print_ub0 (ubyte value @A) clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) clobbers (A,X,Y)
print_ulhex (long value, bool prefix)
print_uw (uword value @AY) clobbers (A,X,Y)
print_uw0 (uword value @AY) clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) clobbers (A,X,Y)
print_w (word value @AY) clobbers (A,X,Y)
row (ubyte rownum @A) clobbers (A,X,Y)
rvs_off ()
rvs_on ()
scroll_down (bool alsocolors @Pc) -> clobbers (A,X)
scroll_left (bool alsocolors @Pc) -> clobbers (A,X,Y)
scroll_right (bool alsocolors @Pc) -> clobbers (A,X)
scroll_up (bool alsocolors @Pc) -> clobbers (A,X)
scroll_down (bool alsocolors @Pc) clobbers (A,X)
scroll_left (bool alsocolors @Pc) clobbers (A,X,Y)
scroll_right (bool alsocolors @Pc) clobbers (A,X)
scroll_up (bool alsocolors @Pc) clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A,Y)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) clobbers (A,Y)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
width () clobbers (X,Y) -> ubyte @A
}
+209 -178
View File
@@ -1,12 +1,31 @@
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit c04908a9 in branch structs6502
Prog8 compiler v12.0 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c64.p8
Compiler target: c64
LIBRARY MODULE NAME: bcd
------------------------
bcd {
addb (byte a, byte b) -> byte
addl (long a, long b) -> long
addtol (^^long a, long b)
addub (ubyte a, ubyte b) -> ubyte
adduw (uword a, uword b) -> uword
addw (word a, word b) -> word
clearbcd ()
setbcd ()
subb (byte a, byte b) -> byte
subfroml (^^long a, long b)
subl (long a, long b) -> long
subub (ubyte a, ubyte b) -> ubyte
subuw (uword a, uword b) -> uword
}
LIBRARY MODULE NAME: buffers
----------------------------
@@ -63,11 +82,11 @@ LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_tscrunch (uword compressed @R0, uword target @R1) -> clobbers (A,X,Y)
decode_tscrunch_inplace (uword compressed @R0) -> clobbers (A,X,Y)
decode_zx0 (uword compressed @R0, uword target @R1) -> clobbers (A,X,Y)
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) clobbers (X) -> uword @AY
decode_tscrunch (uword compressed @R0, uword target @R1) clobbers (A,X,Y)
decode_tscrunch_inplace (uword compressed @R0) clobbers (A,X,Y)
decode_zx0 (uword compressed @R0, uword target @R1) clobbers (A,X,Y)
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)
}
@@ -78,28 +97,30 @@ LIBRARY MODULE NAME: conv
conv {
ubyte[] @shared string_out
any2uword (str string @AY) -> clobbers (Y) -> ubyte @A
any2uword (str string @AY) -> uword @AY, ubyte @X
bin2uword (str string @AY) -> uword @AY
hex2uword (str string @AY) -> uword @AY
internal_byte2decimal (byte value @A) -> ubyte @Y, ubyte @A, ubyte @X
internal_ubyte2decimal (ubyte value @A) -> ubyte @Y, ubyte @X, ubyte @A
internal_ubyte2hex (ubyte value @A) -> clobbers (X) -> ubyte @A, ubyte @Y
internal_ubyte2hex (ubyte value @A) clobbers (X) -> ubyte @A, ubyte @Y
internal_uword2decimal (uword value @AY) -> ubyte @Y, ubyte @A, ubyte @X
internal_uword2hex (uword value @AY) -> clobbers (A,Y)
str2byte (str string @AY) -> clobbers (Y) -> byte @A
str2ubyte (str string @AY) -> clobbers (Y) -> ubyte @A
internal_uword2hex (uword value @AY) clobbers (A,Y)
str2byte (str string @AY) clobbers (Y) -> byte @A
str2ubyte (str string @AY) clobbers (Y) -> ubyte @A
str2uword (str string @AY) -> uword @AY
str2word (str string @AY) -> word @AY
str_b (byte value @A) -> clobbers (X) -> str @AY
str_ub (ubyte value @A) -> clobbers (X) -> str @AY
str_ub0 (ubyte value @A) -> clobbers (X) -> str @AY
str_ubbin (ubyte value @A) -> clobbers (X) -> str @AY
str_ubhex (ubyte value @A) -> clobbers (X) -> str @AY
str_uw (uword value @AY) -> clobbers (X) -> str @AY
str_uw0 (uword value @AY) -> clobbers (X) -> str @AY
str_uwbin (uword value @AY) -> clobbers (X) -> str @AY
str_b (byte value @A) clobbers (X) -> str @AY
str_l (long value) -> str
str_ub (ubyte value @A) clobbers (X) -> str @AY
str_ub0 (ubyte value @A) clobbers (X) -> str @AY
str_ubbin (ubyte value @A) clobbers (X) -> str @AY
str_ubhex (ubyte value @A) clobbers (X) -> str @AY
str_ulhex (long value) -> str
str_uw (uword value @AY) clobbers (X) -> str @AY
str_uw0 (uword value @AY) clobbers (X) -> str @AY
str_uwbin (uword value @AY) clobbers (X) -> str @AY
str_uwhex (uword value @AY) -> str @AY
str_w (word value @AY) -> clobbers (X) -> str @AY
str_w (word value @AY) clobbers (X) -> str @AY
}
@@ -159,7 +180,7 @@ diskio {
f_open_w (str filenameptr) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (^^ubyte bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_readline (^^ubyte bufptr @AY) clobbers (X) -> ubyte @Y, ubyte @A
f_write (uword bufferpointer, uword num_bytes) -> bool
get_loadaddress (str filename) -> uword
lf_end_list ()
@@ -191,61 +212,61 @@ floats {
const float TWOPI
const float π
ABS () = $bc58
ATN () -> clobbers (A,X,Y) = $e30e
AYINT () -> clobbers (A,X,Y) = $b1bf
AYINT2 () -> clobbers (X) -> word @AY
CONUPK (uword mflpt @AY) -> clobbers (A,Y) = $ba8c
COS () -> clobbers (A,X,Y) = $e264
DIV10 () -> clobbers (A,X,Y) = $bafe
EXP () -> clobbers (A,X,Y) = $bfed
FADD (uword mflpt @AY) -> clobbers (A,X,Y) = $b867
FADDH () -> clobbers (A,X,Y) = $b849
FADDT () -> clobbers (A,X,Y) = $b86a
FAREADMEM () -> clobbers (A,Y) = $ba90
FCOMP (uword mflpt @AY) -> clobbers (X,Y) -> ubyte @A = $bc5b
FDIV (uword mflpt @AY) -> clobbers (A,X,Y) = $bb0f
FDIVT () -> clobbers (A,X,Y) = $bb12
FINLOG (byte value @A) -> clobbers (A,X,Y) = $bd7e
FMULT (uword mflpt @AY) -> clobbers (A,X,Y) = $ba28
FMULTT () -> clobbers (A,X,Y) = $ba2b
FOUT () -> clobbers (X) -> uword @AY = $bddd
FPRINTLN () -> clobbers (A,X,Y) = $aabc
FPWR (uword mflpt @AY) -> clobbers (A,X,Y) = $bf78
FPWRT () -> clobbers (A,X,Y) = $bf7b
FREADMEM () -> clobbers (A,Y) = $bba6
FREADS24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) -> clobbers (A,X,Y)
FREADS32 () -> clobbers (A,X,Y)
FREADSA (byte value @A) -> clobbers (A,X,Y) = $bc3c
FREADSTR (ubyte length @A) -> clobbers (A,X,Y) = $b7b5
FREADU24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) -> clobbers (A,X,Y) -> float @FAC1
FREADUS32 () -> clobbers (A,X,Y)
FREADUY (ubyte value @Y) -> clobbers (A,X,Y) = $b3a2
FSUB (uword mflpt @AY) -> clobbers (A,X,Y) = $b850
FSUBT () -> clobbers (A,X,Y) = $b853
GETADR () -> clobbers (X) -> ubyte @Y, ubyte @A = $b7f7
GETADRAY () -> clobbers (X) -> uword @AY
GIVAYF (ubyte lo @Y, ubyte hi @A) -> clobbers (A,X,Y) = $b391
GIVAYFAY (uword value @AY) -> clobbers (A,X,Y)
GIVUAYFAY (uword value @AY) -> clobbers (A,X,Y)
INT () -> clobbers (A,X,Y) = $bccc
LOG () -> clobbers (A,X,Y) = $b9ea
MOVAF () -> clobbers (A,X) = $bc0c
MOVEF () -> clobbers (A,X) = $bc0f
MOVFA () -> clobbers (A,X) = $bbfc
MOVFM (uword mflpt @AY) -> clobbers (A,Y) = $bba2
MOVMF (uword mflpt @XY) -> clobbers (A,Y) = $bbd4
MUL10 () -> clobbers (A,X,Y) = $bae2
NEGOP () -> clobbers (A) = $bfb4
NORMAL () -> clobbers (A) = $b8d7
NOTOP () -> clobbers (A,X,Y) = $aed4
QINT () -> clobbers (A,X,Y) = $bc9b
RND () -> clobbers (A,X,Y) = $e097
SGN () -> clobbers (A,X,Y) = $bc39
ATN () clobbers (A,X,Y) = $e30e
AYINT () clobbers (A,X,Y) = $b1bf
AYINT2 () clobbers (X) -> word @AY
CONUPK (uword mflpt @AY) clobbers (A,Y) = $ba8c
COS () clobbers (A,X,Y) = $e264
DIV10 () clobbers (A,X,Y) = $bafe
EXP () clobbers (A,X,Y) = $bfed
FADD (uword mflpt @AY) clobbers (A,X,Y) = $b867
FADDH () clobbers (A,X,Y) = $b849
FADDT () clobbers (A,X,Y) = $b86a
FAREADMEM () clobbers (A,Y) = $ba90
FCOMP (uword mflpt @AY) clobbers (X,Y) -> ubyte @A = $bc5b
FDIV (uword mflpt @AY) clobbers (A,X,Y) = $bb0f
FDIVT () clobbers (A,X,Y) = $bb12
FINLOG (byte value @A) clobbers (A,X,Y) = $bd7e
FMULT (uword mflpt @AY) clobbers (A,X,Y) = $ba28
FMULTT () clobbers (A,X,Y) = $ba2b
FOUT () clobbers (X) -> uword @AY = $bddd
FPRINTLN () clobbers (A,X,Y) = $aabc
FPWR (uword mflpt @AY) clobbers (A,X,Y) = $bf78
FPWRT () clobbers (A,X,Y) = $bf7b
FREADMEM () clobbers (A,Y) = $bba6
FREADS24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) clobbers (A,X,Y)
FREADS32 () clobbers (A,X,Y)
FREADSA (byte value @A) clobbers (A,X,Y) = $bc3c
FREADSTR (ubyte length @A) clobbers (A,X,Y) = $b7b5
FREADU24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) clobbers (A,X,Y) -> float @FAC1
FREADUS32 () clobbers (A,X,Y)
FREADUY (ubyte value @Y) clobbers (A,X,Y) = $b3a2
FSUB (uword mflpt @AY) clobbers (A,X,Y) = $b850
FSUBT () clobbers (A,X,Y) = $b853
GETADR () clobbers (X) -> ubyte @Y, ubyte @A = $b7f7
GETADRAY () clobbers (X) -> uword @AY
GIVAYF (ubyte lo @Y, ubyte hi @A) clobbers (A,X,Y) = $b391
GIVAYFAY (uword value @AY) clobbers (A,X,Y)
GIVUAYFAY (uword value @AY) clobbers (A,X,Y)
INT () clobbers (A,X,Y) = $bccc
LOG () clobbers (A,X,Y) = $b9ea
MOVAF () clobbers (A,X) = $bc0c
MOVEF () clobbers (A,X) = $bc0f
MOVFA () clobbers (A,X) = $bbfc
MOVFM (uword mflpt @AY) clobbers (A,Y) = $bba2
MOVMF (uword mflpt @XY) clobbers (A,Y) = $bbd4
MUL10 () clobbers (A,X,Y) = $bae2
NEGOP () clobbers (A) = $bfb4
NORMAL () clobbers (A) = $b8d7
NOTOP () clobbers (A,X,Y) = $aed4
QINT () clobbers (A,X,Y) = $bc9b
RND () clobbers (A,X,Y) = $e097
SGN () clobbers (A,X,Y) = $bc39
SIGN () -> ubyte @A = $bc2b
SIN () -> clobbers (A,X,Y) = $e26b
SQR () -> clobbers (A,X,Y) = $bf71
SQRA () -> clobbers (A,X,Y) = $bf74
TAN () -> clobbers (A,X,Y) = $e2b4
SIN () clobbers (A,X,Y) = $e26b
SQR () clobbers (A,X,Y) = $bf71
SQRA () clobbers (A,X,Y) = $bf74
TAN () clobbers (A,X,Y) = $e2b4
atan (float value) -> float
atan2 (float y, float x) -> float
ceil (float value) -> float
@@ -266,7 +287,7 @@ floats {
parse (str value @AY) -> float @FAC1
pop () -> float @FAC1
pow (float value, float power) -> float
print (float value @FAC1) -> clobbers (A,X,Y)
print (float value @FAC1) clobbers (A,X,Y)
push (float value @FAC1)
rad (float angle) -> float
rnd () -> float
@@ -276,7 +297,7 @@ floats {
sin (float angle) -> float
tan (float value) -> float
time () -> float @FAC1
tostr (float value @FAC1) -> clobbers (X) -> str @AY
tostr (float value @FAC1) clobbers (X) -> str @AY
}
@@ -297,9 +318,9 @@ graphics {
fillrect (uword xx, ubyte yy, uword width, ubyte height)
get_y_lookup (ubyte yy @Y) -> uword @AY
horizontal_line (uword xx, ubyte yy, uword length)
internal_plot (ubyte ploty @Y) -> clobbers (A,X,Y)
internal_plot (ubyte ploty @Y) clobbers (A,X,Y)
line (uword x1, ubyte y1, uword x2, ubyte y2)
plot (uword plotx @AX, ubyte ploty @Y) -> clobbers (A,X,Y)
plot (uword plotx @AX, ubyte ploty @Y) clobbers (A,X,Y)
rect (uword xx, ubyte yy, uword width, ubyte height)
vertical_line (uword xx, ubyte yy, ubyte height)
}
@@ -310,17 +331,17 @@ LIBRARY MODULE NAME: math
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
cos8 (ubyte angle @A) clobbers (Y) -> byte @A
cos8u (ubyte angle @A) clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) clobbers (Y) -> ubyte @A
crc16 (^^ubyte data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (^^ubyte data, uword length)
crc32_end ()
crc32_end_result () -> uword @R15, uword @R14
crc32 (^^ubyte data, uword length) -> long
crc32_end () -> long
crc32_end_result () -> long @R14R15_32
crc32_start ()
crc32_update (ubyte value)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
@@ -337,20 +358,21 @@ math {
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
mul32 (uword a, uword b) -> long
randrange (ubyte n) -> ubyte
randrange_rom (ubyte n) -> ubyte
randrangew (uword n) -> uword
randrangew_rom (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rnd_rom () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndseed_rom (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rnd () clobbers (Y) -> ubyte @A
rnd_rom () clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) clobbers (A,Y)
rndseed_rom (uword seed1 @AY, uword seed2 @R0) clobbers (A,Y)
rndw () -> uword @AY
rndw_rom () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
sin8 (ubyte angle @A) clobbers (Y) -> byte @A
sin8u (ubyte angle @A) clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) clobbers (Y) -> ubyte @A
}
@@ -362,11 +384,11 @@ sorting {
gnomesort_by_uw (uword uw_keys, uword wordvalues, ubyte num_elements)
gnomesort_ub (^^ubyte bytearray @AY, ubyte num_elements @X)
gnomesort_uw (uword wordvalues, ubyte num_elements)
shellsort_by_ub (^^ubyte ub_keys, uword wordvalues, ubyte num_elements)
shellsort_by_uw (uword uw_keys, uword wordvalues, ubyte num_elements)
shellsort_by_ub (^^ubyte ub_keys, ^^uword wordvalues, ubyte num_elements)
shellsort_by_uw (^^uword uw_keys, ^^uword wordvalues, ubyte num_elements)
shellsort_pointers (uword pointers, ubyte num_elements, uword comparefunc)
shellsort_ub (^^ubyte values, ubyte num_elements)
shellsort_uw (uword values, ubyte num_elements)
shellsort_uw (^^uword values, ubyte num_elements)
string_comparator (str string1 @R0, str string2 @R1) -> bool @Pc
}
@@ -375,10 +397,10 @@ LIBRARY MODULE NAME: strings
----------------------------
strings {
append (str target @R0, str suffix @R1) -> clobbers (Y) -> ubyte @A
compare (str string1 @R0, str string2 @AY) -> clobbers (Y) -> byte @A
append (str target @R0, str suffix @R1) clobbers (Y) -> ubyte @A
compare (str string1 @R0, str string2 @AY) clobbers (Y) -> byte @A
contains (str string @AY, ubyte character @X) -> bool @Pc
copy (str source @R0, str target @AY) -> clobbers (A) -> ubyte @Y
copy (str source @R0, str target @AY) clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (str string @AY, ubyte character @X) -> ubyte @A, bool @Pc
find_eol (str string @AY) -> ubyte @A, bool @Pc
@@ -390,21 +412,21 @@ strings {
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (str source @AX, ubyte length @Y, str target @R1) -> clobbers (A,Y)
length (str string @AY) -> clobbers (A) -> ubyte @Y
left (str source @AX, ubyte length @Y, str target @R1) clobbers (A,Y)
length (str string @AY) clobbers (A) -> ubyte @Y
lower (str st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
ncompare (str string1 @R0, str string2 @AY, ubyte length @X) -> clobbers (X,Y) -> byte @A
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
ncompare (str string1 @R0, str string2 @AY, ubyte length @X) clobbers (X,Y) -> byte @A
pattern_match (str string @AY, str pattern @R0) clobbers (Y) -> bool @A
rfind (str string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (str source @AY, ubyte length @X, str target @R1) -> clobbers (A,Y)
right (str source @AY, ubyte length @X, str target @R1) clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (str source @R0, ubyte start @A, ubyte length @Y, str target @R1) -> clobbers (A,Y)
slice (str source @R0, ubyte start @A, ubyte length @Y, str target @R1) clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
@@ -459,53 +481,55 @@ cbm {
&uword USERCMD
&uword USRADD
ACPTR () -> ubyte @A = $ffa5
CHKIN (ubyte logical @X) -> clobbers (A,X) -> bool @Pc = $ffc6
CHKOUT (ubyte logical @X) -> clobbers (A,X) = $ffc9
CHRIN () -> clobbers (X,Y) -> ubyte @A = $ffcf
CHKIN (ubyte logical @X) clobbers (A,X) -> bool @Pc = $ffc6
CHKOUT (ubyte logical @X) clobbers (A,X) = $ffc9
CHRIN () clobbers (X,Y) -> ubyte @A = $ffcf
CHROUT (ubyte character @A) = $ffd2
CINT () -> clobbers (A,X,Y) = $ff81
CINT () clobbers (A,X,Y) = $ff81
CIOUT (ubyte databyte @A) = $ffa8
CLALL () -> clobbers (A,X) = $ffe7
CLEARSCR () -> clobbers (A,X,Y) = $e544
CLALL () clobbers (A,X) = $ffe7
CLEARSCR () clobbers (A,X,Y) = $e544
CLEARST ()
CLOSE (ubyte logical @A) -> clobbers (A,X,Y) = $ffc3
CLRCHN () -> clobbers (A,X) = $ffcc
GETIN () -> clobbers (X,Y) -> bool @Pc, ubyte @A = $ffe4
GETIN2 () -> clobbers (X,Y) -> ubyte @A
HOMECRSR () -> clobbers (A,X,Y) = $e566
CLOSE (ubyte logical @A) clobbers (A,X,Y) = $ffc3
CLRCHN () clobbers (A,X) = $ffcc
GETIN () clobbers (X,Y) -> bool @Pc, ubyte @A = $ffe4
GETIN2 () clobbers (X,Y) -> ubyte @A
HOMECRSR () clobbers (A,X,Y) = $e566
IOBASE () -> uword @XY = $fff3
IOINIT () -> clobbers (A,X) = $ff84
IRQDFEND () -> clobbers (A,X,Y) = $ea81
IRQDFRT () -> clobbers (A,X,Y) = $ea31
LISTEN (ubyte device @A) -> clobbers (A) = $ffb1
IOINIT () clobbers (A,X) = $ff84
IRQDFEND () clobbers (A,X,Y) = $ea81
IRQDFRT () clobbers (A,X,Y) = $ea31
LISTEN (ubyte device @A) clobbers (A) = $ffb1
LOAD (ubyte verify @A, uword address @XY) -> bool @Pc, ubyte @A, uword @XY = $ffd5
MEMBOT (uword address @XY, bool dir @Pc) -> uword @XY = $ff9c
MEMTOP (uword address @XY, bool dir @Pc) -> uword @XY = $ff99
OPEN () -> clobbers (X,Y) -> bool @Pc, ubyte @A = $ffc0
PLOT (ubyte col @Y, ubyte row @X, bool dir @Pc) -> clobbers (A) -> ubyte @Y, ubyte @X = $fff0
RAMTAS () -> clobbers (A,X,Y) = $ff87
OPEN () clobbers (X,Y) -> bool @Pc, ubyte @A = $ffc0
PLOT (ubyte col @Y, ubyte row @X, bool dir @Pc) clobbers (A) -> ubyte @Y, ubyte @X = $fff0
RAMTAS () clobbers (A,X,Y) = $ff87
RDTIM () -> ubyte @A, ubyte @X, ubyte @Y = $ffde
RDTIM16 () -> clobbers (X) -> uword @AY
RDTIM16 () clobbers (X) -> uword @AY
RDTIML () clobbers (X) -> long @R0R1_32
READST () -> ubyte @A = $ffb7
RESTOR () -> clobbers (A,X,Y) = $ff8a
RESTOR () clobbers (A,X,Y) = $ff8a
SAVE (ubyte zp_startaddr @A, uword endaddr @XY) -> bool @Pc, ubyte @A = $ffd8
SCNKEY () -> clobbers (A,X,Y) = $ff9f
SCNKEY () clobbers (A,X,Y) = $ff9f
SCREEN () -> ubyte @X, ubyte @Y = $ffed
SECOND (ubyte address @A) -> clobbers (A) = $ff93
SECOND (ubyte address @A) clobbers (A) = $ff93
SETLFS (ubyte logical @A, ubyte device @X, ubyte secondary @Y) = $ffba
SETMSG (ubyte value @A) = $ff90
SETNAM (ubyte namelen @A, str filename @XY) = $ffbd
SETTIM (ubyte low @A, ubyte middle @X, ubyte high @Y) = $ffdb
SETTIML (long jiffies @R0R1_32)
SETTMO (ubyte timeout @A) = $ffa2
STOP () -> clobbers (X) -> bool @Pz, ubyte @A = $ffe1
STOP2 () -> clobbers (A,X) -> bool @Pz
STROUT (str strptr @AY) -> clobbers (A,X,Y) = $ab1e
TALK (ubyte device @A) -> clobbers (A) = $ffb4
TKSA (ubyte address @A) -> clobbers (A) = $ff96
UDTIM () -> clobbers (A,X) = $ffea
UNLSN () -> clobbers (A) = $ffae
UNTLK () -> clobbers (A) = $ffab
VECTOR (uword userptr @XY, bool dir @Pc) -> clobbers (A,Y) = $ff8d
STOP () clobbers (X) -> bool @Pz, ubyte @A = $ffe1
STOP2 () clobbers (A,X) -> bool @Pz
STROUT (str strptr @AY) clobbers (A,X,Y) = $ab1e
TALK (ubyte device @A) clobbers (A) = $ffb4
TKSA (ubyte address @A) clobbers (A) = $ff96
UDTIM () clobbers (A,X) = $ffea
UNLSN () clobbers (A) = $ffae
UNTLK () clobbers (A) = $ffab
VECTOR (uword userptr @XY, bool dir @Pc) clobbers (A,Y) = $ff8d
kbdbuf_clear ()
}
@@ -669,6 +693,7 @@ sys {
const ubyte target
clear_carry ()
clear_irqd ()
cpu_is_65816 () -> bool
disable_caseswitch ()
disable_runstop_and_charsetswitch ()
enable_caseswitch ()
@@ -677,32 +702,37 @@ sys {
exit2 (ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y)
exit3 (ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc)
get_as_returnaddress (uword address @XY) -> uword @AX
internal_stringcopy (str source @R0, str target @AY) -> clobbers (A,Y)
internal_stringcopy (str source @R0, str target @AY) clobbers (A,Y)
irqsafe_clear_irqd ()
irqsafe_set_irqd ()
memcmp (uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A
memcopy (uword source @R0, uword target @R1, uword count @AY) -> clobbers (A,X,Y)
memset (uword mem @R0, uword numbytes @R1, ubyte value @A) -> clobbers (A,X,Y)
memsetw (uword mem @R0, uword numwords @R1, uword value @AY) -> clobbers (A,X,Y)
memcopy (uword source @R0, uword target @R1, uword count @AY) clobbers (A,X,Y)
memset (uword mem @R0, uword numbytes @R1, ubyte value @A) clobbers (A,X,Y)
memsetw (uword mem @R0, uword numwords @R1, uword value @AY) clobbers (A,X,Y)
pop () -> ubyte @A
popl () -> long @R0R1_32
popw () -> uword @AY
progend () -> uword @AY
progstart () -> uword @AY
push (ubyte value @A)
push_returnaddress (uword address @XY)
pushl (long value @R0R1_32)
pushw (uword value @AY)
read_flags () -> ubyte @A
reset_system ()
restore_irq () -> clobbers (A)
restore_irq () clobbers (A)
restore_prog8_internals ()
save_prog8_internals ()
set_carry ()
set_irq (uword handler @AY) -> clobbers (A)
set_irq (uword handler @AY) clobbers (A)
set_irqd ()
set_rasterirq (uword handler @AY, uword rasterpos @R0) -> clobbers (A)
set_rasterirq (uword handler @AY, uword rasterpos @R0) clobbers (A)
set_rasterline (uword line @AY)
update_rasterirq (uword handler @AY, uword rasterpos @R0) clobbers (A)
wait (uword jiffies @AY)
waitrastborder ()
waitvsync () -> clobbers (A)
waitrasterline (uword line @AY)
waitvsync () clobbers (A)
}
cx16 {
@@ -834,15 +864,14 @@ cx16 {
&word r9s
&byte r9sH
&byte r9sL
cpu_is_65816 () -> bool
restore_virtual_registers () -> clobbers (A,Y)
save_virtual_registers () -> clobbers (A,Y)
restore_virtual_registers () clobbers (A,Y)
save_virtual_registers () clobbers (A,Y)
}
p8_sys_startup {
cleanup_at_exit ()
disable_runstop_and_charsetswitch () -> clobbers (A)
enable_runstop_and_charsetswitch () -> clobbers (A)
disable_runstop_and_charsetswitch () clobbers (A)
enable_runstop_and_charsetswitch () clobbers (A)
init_system ()
init_system_phase2 ()
}
@@ -865,52 +894,54 @@ txt {
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (Y)
clear_screencolors (ubyte color @A) -> clobbers (Y)
clear_screenchars (ubyte character @A) clobbers (Y)
clear_screencolors (ubyte color @A) clobbers (Y)
cls ()
color (ubyte txtcol)
column (ubyte col @A) -> clobbers (A,X,Y)
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A)
column (ubyte col @A) clobbers (A,X,Y)
fill_screen (ubyte character @A, ubyte color @Y) clobbers (A)
get_column () -> ubyte @Y
get_cursor () -> ubyte @X, ubyte @Y
get_row () -> ubyte @X
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
getchr (ubyte col @A, ubyte row @Y) clobbers (Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) clobbers (Y) -> ubyte @A
height () clobbers (X,Y) -> ubyte @A
home ()
input_chars (^^ubyte buffer @AY) -> clobbers (A) -> ubyte @Y
input_chars (^^ubyte buffer @AY) clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print (str text @AY) clobbers (A,Y)
print_b (byte value @A) clobbers (A,X,Y)
print_bool (bool value)
print_f alias for: floats.print
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum @A) -> clobbers (A,X,Y)
print_l (long value)
print_ub (ubyte value @A) clobbers (A,X,Y)
print_ub0 (ubyte value @A) clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) clobbers (A,X,Y)
print_ulhex (long value, bool prefix)
print_uw (uword value @AY) clobbers (A,X,Y)
print_uw0 (uword value @AY) clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) clobbers (A,X,Y)
print_w (word value @AY) clobbers (A,X,Y)
row (ubyte rownum @A) clobbers (A,X,Y)
rvs_off ()
rvs_on ()
scroll_down (bool alsocolors @Pc) -> clobbers (A,X)
scroll_left (bool alsocolors @Pc) -> clobbers (A,X,Y)
scroll_right (bool alsocolors @Pc) -> clobbers (A,X)
scroll_up (bool alsocolors @Pc) -> clobbers (A,X)
scroll_down (bool alsocolors @Pc) clobbers (A,X)
scroll_left (bool alsocolors @Pc) clobbers (A,X,Y)
scroll_right (bool alsocolors @Pc) clobbers (A,X)
scroll_up (bool alsocolors @Pc) clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A,Y)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) clobbers (A,Y)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) clobbers (A,Y)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
width () clobbers (X,Y) -> ubyte @A
}
+364 -333
View File
@@ -1,12 +1,31 @@
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit c04908a9 in branch structs6502
Prog8 compiler v12.0 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-cx16.p8
Compiler target: cx16
LIBRARY MODULE NAME: bcd
------------------------
bcd {
addb (byte a, byte b) -> byte
addl (long a, long b) -> long
addtol (^^long a, long b)
addub (ubyte a, ubyte b) -> ubyte
adduw (uword a, uword b) -> uword
addw (word a, word b) -> word
clearbcd ()
setbcd ()
subb (byte a, byte b) -> byte
subfroml (^^long a, long b)
subl (long a, long b) -> long
subub (ubyte a, ubyte b) -> ubyte
subuw (uword a, uword b) -> uword
}
LIBRARY MODULE NAME: bmx
------------------------
@@ -100,12 +119,12 @@ LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) clobbers (X) -> uword @AY
decode_rle_vram (uword compressed @R0, ubyte vbank @X, uword vaddr @AY)
decode_tscrunch (uword compressed @R0, uword target @R1) -> clobbers (A,X,Y)
decode_tscrunch_inplace (uword compressed @R0) -> clobbers (A,X,Y)
decode_zx0 (uword compressed @R0, uword target @R1) -> clobbers (A,X,Y)
decode_tscrunch (uword compressed @R0, uword target @R1) clobbers (A,X,Y)
decode_tscrunch_inplace (uword compressed @R0) clobbers (A,X,Y)
decode_zx0 (uword compressed @R0, uword target @R1) clobbers (A,X,Y)
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)
}
@@ -116,28 +135,30 @@ LIBRARY MODULE NAME: conv
conv {
ubyte[] @shared string_out
any2uword (str string @AY) -> clobbers (Y) -> ubyte @A
any2uword (str string @AY) -> uword @AY, ubyte @X
bin2uword (str string @AY) -> uword @AY
hex2uword (str string @AY) -> uword @AY
internal_byte2decimal (byte value @A) -> ubyte @Y, ubyte @A, ubyte @X
internal_ubyte2decimal (ubyte value @A) -> ubyte @Y, ubyte @X, ubyte @A
internal_ubyte2hex (ubyte value @A) -> clobbers (X) -> ubyte @A, ubyte @Y
internal_ubyte2hex (ubyte value @A) clobbers (X) -> ubyte @A, ubyte @Y
internal_uword2decimal (uword value @AY) -> ubyte @Y, ubyte @A, ubyte @X
internal_uword2hex (uword value @AY) -> clobbers (A,Y)
str2byte (str string @AY) -> clobbers (Y) -> byte @A
str2ubyte (str string @AY) -> clobbers (Y) -> ubyte @A
internal_uword2hex (uword value @AY) clobbers (A,Y)
str2byte (str string @AY) clobbers (Y) -> byte @A
str2ubyte (str string @AY) clobbers (Y) -> ubyte @A
str2uword (str string @AY) -> uword @AY
str2word (str string @AY) -> word @AY
str_b (byte value @A) -> clobbers (X) -> str @AY
str_ub (ubyte value @A) -> clobbers (X) -> str @AY
str_ub0 (ubyte value @A) -> clobbers (X) -> str @AY
str_ubbin (ubyte value @A) -> clobbers (X) -> str @AY
str_ubhex (ubyte value @A) -> clobbers (X) -> str @AY
str_uw (uword value @AY) -> clobbers (X) -> str @AY
str_uw0 (uword value @AY) -> clobbers (X) -> str @AY
str_uwbin (uword value @AY) -> clobbers (X) -> str @AY
str_b (byte value @A) clobbers (X) -> str @AY
str_l (long value) -> str
str_ub (ubyte value @A) clobbers (X) -> str @AY
str_ub0 (ubyte value @A) clobbers (X) -> str @AY
str_ubbin (ubyte value @A) clobbers (X) -> str @AY
str_ubhex (ubyte value @A) clobbers (X) -> str @AY
str_ulhex (long value) -> str
str_uw (uword value @AY) clobbers (X) -> str @AY
str_uw0 (uword value @AY) clobbers (X) -> str @AY
str_uwbin (uword value @AY) clobbers (X) -> str @AY
str_uwhex (uword value @AY) -> str @AY
str_w (word value @AY) -> clobbers (X) -> str @AY
str_w (word value @AY) clobbers (X) -> str @AY
}
@@ -200,7 +221,7 @@ diskio {
f_open_w_seek (str filename) -> bool
f_read (uword bufferpointer, uword num_bytes) -> uword
f_read_all (uword bufferpointer) -> uword
f_readline (^^ubyte bufptr @AY) -> clobbers (X) -> ubyte @Y, ubyte @A
f_readline (^^ubyte bufptr @AY) clobbers (X) -> ubyte @Y, ubyte @A
f_seek (uword pos_hiword, uword pos_loword)
f_seek_w (uword pos_hiword, uword pos_loword)
f_tell () -> uword @R0, uword @R1, uword @R2, uword @R3
@@ -233,8 +254,8 @@ diskio {
send_command (str commandptr)
status () -> str
status_code () -> ubyte
vload (str name @R0, ubyte bank @A, uword startaddress @R1) -> clobbers (X,Y) -> bool @A
vload_raw (str name @R0, ubyte bank @A, uword startaddress @R1) -> clobbers (X,Y) -> bool @A
vload (str name @R0, ubyte bank @A, uword startaddress @R1) clobbers (X,Y) -> bool @A
vload_raw (str name @R0, ubyte bank @A, uword startaddress @R1) clobbers (X,Y) -> bool @A
}
@@ -282,63 +303,63 @@ floats {
const float PI
const float TWOPI
const float π
ABS () -> clobbers (A,X,Y) = $fe4e
ATN () -> clobbers (A,X,Y) = $fe48
AYINT () -> clobbers (A,X,Y) = $fe00
AYINT2 () -> clobbers (X) -> word @AY
CONUPK (uword mflpt @AY) -> clobbers (A,X,Y) = $fe5a
COS () -> clobbers (A,X,Y) = $fe3f
DIV10 () -> clobbers (A,X,Y) = $fe7e
EXP () -> clobbers (A,X,Y) = $fe3c
FADD (uword mflpt @AY) -> clobbers (A,X,Y) = $fe18
FADDH () -> clobbers (A,X,Y) = $fe6f
FADDT () -> clobbers (A,X,Y) = $fe1b
FCOMP (uword mflpt @AY) -> clobbers (X,Y) -> ubyte @A = $fe54
FDIV (uword mflpt @AY) -> clobbers (A,X,Y) = $fe24
FDIVT () -> clobbers (A,X,Y) = $fe27
FINLOG (byte value @A) -> clobbers (A,X,Y) = $fe90
FLOAT () -> clobbers (A,X,Y) = $fe87
FLOATC () -> clobbers (A,X,Y) = $fe0f
FLOATS () -> clobbers (A,X,Y) = $fe8a
FMULT (uword mflpt @AY) -> clobbers (A,X,Y) = $fe1e
FMULTT () -> clobbers (A,X,Y) = $fe21
FOUT () -> clobbers (X) -> str @AY = $fe06
FPWR (uword mflpt @AY) -> clobbers (A,X,Y) = $fe36
FPWRT () -> clobbers (A,X,Y) = $fe39
FREADSA (byte value @A) -> clobbers (A,X,Y)
FREADU24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) -> clobbers (A,X,Y) -> float @FAC1
ABS () clobbers (A,X,Y) = $fe4e
ATN () clobbers (A,X,Y) = $fe48
AYINT () clobbers (A,X,Y) = $fe00
AYINT2 () clobbers (X) -> word @AY
CONUPK (uword mflpt @AY) clobbers (A,X,Y) = $fe5a
COS () clobbers (A,X,Y) = $fe3f
DIV10 () clobbers (A,X,Y) = $fe7e
EXP () clobbers (A,X,Y) = $fe3c
FADD (uword mflpt @AY) clobbers (A,X,Y) = $fe18
FADDH () clobbers (A,X,Y) = $fe6f
FADDT () clobbers (A,X,Y) = $fe1b
FCOMP (uword mflpt @AY) clobbers (X,Y) -> ubyte @A = $fe54
FDIV (uword mflpt @AY) clobbers (A,X,Y) = $fe24
FDIVT () clobbers (A,X,Y) = $fe27
FINLOG (byte value @A) clobbers (A,X,Y) = $fe90
FLOAT () clobbers (A,X,Y) = $fe87
FLOATC () clobbers (A,X,Y) = $fe0f
FLOATS () clobbers (A,X,Y) = $fe8a
FMULT (uword mflpt @AY) clobbers (A,X,Y) = $fe1e
FMULTT () clobbers (A,X,Y) = $fe21
FOUT () clobbers (X) -> str @AY = $fe06
FPWR (uword mflpt @AY) clobbers (A,X,Y) = $fe36
FPWRT () clobbers (A,X,Y) = $fe39
FREADSA (byte value @A) clobbers (A,X,Y)
FREADU24AXY (ubyte lo @A, ubyte mid @X, ubyte hi @Y) clobbers (A,X,Y) -> float @FAC1
FREADUY (ubyte value @Y)
FSUB (uword mflpt @AY) -> clobbers (A,X,Y) = $fe12
FSUBT () -> clobbers (A,X,Y) = $fe15
GETADR () -> clobbers (X) -> ubyte @Y, ubyte @A = $fe0c
GETADRAY () -> clobbers (X) -> uword @AY
GIVAYF (ubyte lo @Y, ubyte hi @A) -> clobbers (A,X,Y) = $fe03
GIVAYFAY (uword value @AY) -> clobbers (A,X,Y)
GIVUAYFAY (uword value @AY) -> clobbers (A,X,Y)
INT () -> clobbers (A,X,Y) = $fe2d
LOG () -> clobbers (A,X,Y) = $fe2a
MOVAF () -> clobbers (A,X) = $fe6c
MOVEF () -> clobbers (A,X) = $fe81
MOVFA () -> clobbers (A,X) = $fe69
MOVFM (uword mflpt @AY) -> clobbers (A,X,Y) = $fe63
MOVFRM (uword mflpt @AY) -> clobbers (A,X,Y) = $fe60
MOVMF (uword mflpt @XY) -> clobbers (A,X,Y) = $fe66
MUL10 () -> clobbers (A,X,Y) = $fe7b
NEGFAC () -> clobbers (A) = $fe78
NEGOP () -> clobbers (A) = $fe33
NORMAL () -> clobbers (A,X,Y) = $fe75
QINT () -> clobbers (A,X,Y) = $fe8d
RND () -> clobbers (A,X,Y) = $fe57
RND_0 () -> clobbers (A,X,Y) = $fe57
ROMUPK (uword mflpt @AY) -> clobbers (A,X,Y) = $fe5d
ROUND () -> clobbers (A,X,Y) = $fe4b
SGN () -> clobbers (A,X,Y) = $fe84
SIGN () -> clobbers (X,Y) -> ubyte @A = $fe51
SIN () -> clobbers (A,X,Y) = $fe42
SQR () -> clobbers (A,X,Y) = $fe30
TAN () -> clobbers (A,X,Y) = $fe45
VAL_1 (str string @XY, ubyte length @A) -> clobbers (A,X,Y) -> float @FAC1 = $fe09
ZEROFC () -> clobbers (A,X,Y) = $fe72
FSUB (uword mflpt @AY) clobbers (A,X,Y) = $fe12
FSUBT () clobbers (A,X,Y) = $fe15
GETADR () clobbers (X) -> ubyte @Y, ubyte @A = $fe0c
GETADRAY () clobbers (X) -> uword @AY
GIVAYF (ubyte lo @Y, ubyte hi @A) clobbers (A,X,Y) = $fe03
GIVAYFAY (uword value @AY) clobbers (A,X,Y)
GIVUAYFAY (uword value @AY) clobbers (A,X,Y)
INT () clobbers (A,X,Y) = $fe2d
LOG () clobbers (A,X,Y) = $fe2a
MOVAF () clobbers (A,X) = $fe6c
MOVEF () clobbers (A,X) = $fe81
MOVFA () clobbers (A,X) = $fe69
MOVFM (uword mflpt @AY) clobbers (A,X,Y) = $fe63
MOVFRM (uword mflpt @AY) clobbers (A,X,Y) = $fe60
MOVMF (uword mflpt @XY) clobbers (A,X,Y) = $fe66
MUL10 () clobbers (A,X,Y) = $fe7b
NEGFAC () clobbers (A) = $fe78
NEGOP () clobbers (A) = $fe33
NORMAL () clobbers (A,X,Y) = $fe75
QINT () clobbers (A,X,Y) = $fe8d
RND () clobbers (A,X,Y) = $fe57
RND_0 () clobbers (A,X,Y) = $fe57
ROMUPK (uword mflpt @AY) clobbers (A,X,Y) = $fe5d
ROUND () clobbers (A,X,Y) = $fe4b
SGN () clobbers (A,X,Y) = $fe84
SIGN () clobbers (X,Y) -> ubyte @A = $fe51
SIN () clobbers (A,X,Y) = $fe42
SQR () clobbers (A,X,Y) = $fe30
TAN () clobbers (A,X,Y) = $fe45
VAL_1 (str string @XY, ubyte length @A) clobbers (A,X,Y) -> float @FAC1 = $fe09
ZEROFC () clobbers (A,X,Y) = $fe72
atan (float value) -> float
atan2 (float y, float x) -> float
ceil (float value) -> float
@@ -359,7 +380,7 @@ floats {
parse (str value @AY) -> float @FAC1
pop () -> float @FAC1
pow (float value, float power) -> float
print (float value @FAC1) -> clobbers (A,X,Y)
print (float value @FAC1) clobbers (A,X,Y)
push (float value @FAC1)
rad (float angle) -> float
rnd () -> float
@@ -369,7 +390,7 @@ floats {
sin (float angle) -> float
tan (float value) -> float
time () -> float @FAC1
tostr (float value @FAC1) -> clobbers (X) -> str @AY
tostr (float value @FAC1) clobbers (X) -> str @AY
}
@@ -381,10 +402,10 @@ gfx_hires {
const uword WIDTH
const uword charset_addr
const ubyte charset_bank
addr_mul_24_for_highres_4c (uword yy @R2, uword xx @R3) -> clobbers (A,Y) -> uword @R0, uword @R1
addr_mul_24_for_highres_4c (uword yy @R2, uword xx @R3) clobbers (A,Y) -> uword @R0, uword @R1
circle (uword xcenter, uword ycenter, ubyte radius, ubyte color)
clear_screen (ubyte color)
cs_innerloop640 (ubyte color @A) -> clobbers (Y)
cs_innerloop640 (ubyte color @A) clobbers (Y)
disc (uword xcenter, uword ycenter, ubyte radius, ubyte color)
fill (uword x, uword y, ubyte new_color, ubyte stack_rambank)
fillrect (uword xx, uword yy, uword rwidth, uword rheight, ubyte color)
@@ -392,7 +413,7 @@ gfx_hires {
horizontal_line (uword xx, uword yy, uword length, ubyte color)
line (uword x1, uword y1, uword x2, uword y2, ubyte color)
next_pixel (ubyte color @A)
next_pixels (uword pixels @AY, uword amount @R0) -> clobbers (A,X,Y)
next_pixels (uword pixels @AY, uword amount @R0) clobbers (A,X,Y)
pget (uword xx, uword yy) -> ubyte
plot (uword xx, uword yy, ubyte color)
position (uword xx, uword yy)
@@ -405,7 +426,7 @@ gfx_hires {
safe_plot (uword xx, uword yy, ubyte color)
safe_rect (uword xx, uword yy, uword rwidth, uword rheight, ubyte color)
safe_vertical_line (uword xx, uword yy, uword lheight, ubyte color)
set_8_pixels_from_bits (ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) -> clobbers (X)
set_8_pixels_from_bits (ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) clobbers (X)
text (uword xx, uword yy, ubyte color, str sctextptr)
text_charset (ubyte charset)
text_mode ()
@@ -432,7 +453,7 @@ gfx_lores {
horizontal_line (uword xx, ubyte yy, uword length, ubyte color)
line (uword x1, ubyte y1, uword x2, ubyte y2, ubyte color)
next_pixel (ubyte color @A)
next_pixels (uword pixels @AY, uword amount @R0) -> clobbers (A,X,Y)
next_pixels (uword pixels @AY, uword amount @R0) clobbers (A,X,Y)
pget (uword x @AX, ubyte y @Y) -> ubyte @A
plot (uword x @AX, ubyte y @Y, ubyte color @R0)
position (uword x @AX, ubyte y @Y)
@@ -444,7 +465,7 @@ gfx_lores {
safe_plot (uword xx, ubyte yy, ubyte color)
safe_rect (uword xx, ubyte yy, uword rwidth, ubyte rheight, ubyte color)
safe_vertical_line (uword xx, ubyte yy, ubyte lheight, ubyte color)
set_8_pixels_from_bits (ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) -> clobbers (X)
set_8_pixels_from_bits (ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) clobbers (X)
text (uword xx, uword yy, ubyte color, str textptr)
text_charset (ubyte charset)
text_mode ()
@@ -460,7 +481,7 @@ graphics {
const uword WIDTH
ubyte background_color
ubyte stroke_color
FB_cursor_position2 () -> clobbers (A,X,Y) = $feff
FB_cursor_position2 () clobbers (A,X,Y) = $feff
circle (uword xcenter, ubyte ycenter, ubyte radius)
clear_screen (ubyte pixelcolor, ubyte bgcolor)
colors (ubyte stroke, ubyte fill)
@@ -472,7 +493,7 @@ graphics {
horizontal_line (uword xx, uword yy, uword length)
line (uword x1, ubyte y1, uword x2, ubyte y2)
oval (uword xcenter, ubyte ycenter, uword h_radius, ubyte v_radius)
plot (uword plotx @R0, uword ploty @R1) -> clobbers (A,X,Y)
plot (uword plotx @R0, uword ploty @R1) clobbers (A,X,Y)
rect (uword xx, uword yy, uword width, uword height)
vertical_line (uword xx, uword yy, uword height)
}
@@ -483,17 +504,17 @@ LIBRARY MODULE NAME: math
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
cos8 (ubyte angle @A) clobbers (Y) -> byte @A
cos8u (ubyte angle @A) clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) clobbers (Y) -> ubyte @A
crc16 (^^ubyte data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (^^ubyte data, uword length)
crc32_end ()
crc32_end_result () -> uword @R15, uword @R14
crc32 (^^ubyte data, uword length) -> long
crc32_end () -> long
crc32_end_result () -> long @R14R15_32
crc32_start ()
crc32_update (ubyte value)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
@@ -510,20 +531,21 @@ math {
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
mul32 (uword a, uword b) -> long
randrange (ubyte n) -> ubyte
randrange_rom (ubyte n) -> ubyte
randrangew (uword n) -> uword
randrangew_rom (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rnd_rom () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndseed_rom (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rnd () clobbers (Y) -> ubyte @A
rnd_rom () clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) clobbers (A,Y)
rndseed_rom (uword seed1 @AY, uword seed2 @R0) clobbers (A,Y)
rndw () -> uword @AY
rndw_rom () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
sin8 (ubyte angle @A) clobbers (Y) -> byte @A
sin8u (ubyte angle @A) clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) clobbers (Y) -> ubyte @A
}
@@ -544,7 +566,7 @@ monogfx {
uword width
circle (uword xcenter, uword ycenter, ubyte radius, bool draw)
clear_screen (bool draw)
cs_innerloop640 (bool draw @A) -> clobbers (Y)
cs_innerloop640 (bool draw @A) clobbers (Y)
disc (uword xcenter, uword ycenter, ubyte radius, bool draw)
drawmode (ubyte dm)
enable_doublebuffer ()
@@ -635,11 +657,11 @@ sorting {
gnomesort_by_uw (uword uw_keys, uword wordvalues, ubyte num_elements)
gnomesort_ub (^^ubyte bytearray @AY, ubyte num_elements @X)
gnomesort_uw (uword wordvalues, ubyte num_elements)
shellsort_by_ub (^^ubyte ub_keys, uword wordvalues, ubyte num_elements)
shellsort_by_uw (uword uw_keys, uword wordvalues, ubyte num_elements)
shellsort_by_ub (^^ubyte ub_keys, ^^uword wordvalues, ubyte num_elements)
shellsort_by_uw (^^uword uw_keys, ^^uword wordvalues, ubyte num_elements)
shellsort_pointers (uword pointers, ubyte num_elements, uword comparefunc)
shellsort_ub (^^ubyte values, ubyte num_elements)
shellsort_uw (uword values, ubyte num_elements)
shellsort_uw (^^uword values, ubyte num_elements)
string_comparator (str string1 @R0, str string2 @R1) -> bool @Pc
}
@@ -687,10 +709,10 @@ LIBRARY MODULE NAME: strings
----------------------------
strings {
append (str target @R0, str suffix @R1) -> clobbers (Y) -> ubyte @A
compare (str string1 @R0, str string2 @AY) -> clobbers (Y) -> byte @A
append (str target @R0, str suffix @R1) clobbers (Y) -> ubyte @A
compare (str string1 @R0, str string2 @AY) clobbers (Y) -> byte @A
contains (str string @AY, ubyte character @X) -> bool @Pc
copy (str source @R0, str target @AY) -> clobbers (A) -> ubyte @Y
copy (str source @R0, str target @AY) clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (str string @AY, ubyte character @X) -> ubyte @A, bool @Pc
find_eol (str string @AY) -> ubyte @A, bool @Pc
@@ -702,21 +724,21 @@ strings {
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (str source @AX, ubyte length @Y, str target @R1) -> clobbers (A,Y)
length (str string @AY) -> clobbers (A) -> ubyte @Y
left (str source @AX, ubyte length @Y, str target @R1) clobbers (A,Y)
length (str string @AY) clobbers (A) -> ubyte @Y
lower (str st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
ncompare (str string1 @R0, str string2 @AY, ubyte length @X) -> clobbers (X,Y) -> byte @A
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
ncompare (str string1 @R0, str string2 @AY, ubyte length @X) clobbers (X,Y) -> byte @A
pattern_match (str string @AY, str pattern @R0) clobbers (Y) -> bool @A
rfind (str string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (str source @AY, ubyte length @X, str target @R1) -> clobbers (A,Y)
right (str source @AY, ubyte length @X, str target @R1) clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (str source @R0, ubyte start @A, ubyte length @Y, str target @R1) -> clobbers (A,Y)
slice (str source @R0, ubyte start @A, ubyte length @Y, str target @R1) clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
@@ -759,49 +781,51 @@ cbm {
&ubyte SYREG
&uword USRADD
ACPTR () -> ubyte @A = $ffa5
CHKIN (ubyte logical @X) -> clobbers (A,X) -> bool @Pc = $ffc6
CHKOUT (ubyte logical @X) -> clobbers (A,X) = $ffc9
CHRIN () -> clobbers (X,Y) -> ubyte @A = $ffcf
CHKIN (ubyte logical @X) clobbers (A,X) -> bool @Pc = $ffc6
CHKOUT (ubyte logical @X) clobbers (A,X) = $ffc9
CHRIN () clobbers (X,Y) -> ubyte @A = $ffcf
CHROUT (ubyte character @A) = $ffd2
CINT () -> clobbers (A,X,Y) = $ff81
CINT () clobbers (A,X,Y) = $ff81
CIOUT (ubyte databyte @A) = $ffa8
CLALL () -> clobbers (A,X) = $ffe7
CLALL () clobbers (A,X) = $ffe7
CLEARST ()
CLOSE (ubyte logical @A) -> clobbers (A,X,Y) = $ffc3
CLRCHN () -> clobbers (A,X) = $ffcc
GETIN () -> clobbers (X,Y) -> bool @Pc, ubyte @A = $ffe4
GETIN2 () -> clobbers (X,Y) -> ubyte @A
CLOSE (ubyte logical @A) clobbers (A,X,Y) = $ffc3
CLRCHN () clobbers (A,X) = $ffcc
GETIN () clobbers (X,Y) -> bool @Pc, ubyte @A = $ffe4
GETIN2 () clobbers (X,Y) -> ubyte @A
IOBASE () -> uword @XY = $fff3
IOINIT () -> clobbers (A,X) = $ff84
LISTEN (ubyte device @A) -> clobbers (A) = $ffb1
IOINIT () clobbers (A,X) = $ff84
LISTEN (ubyte device @A) clobbers (A) = $ffb1
LOAD (ubyte verify @A, uword address @XY) -> bool @Pc, ubyte @A, uword @XY = $ffd5
MEMBOT (uword address @XY, bool dir @Pc) -> uword @XY = $ff9c
MEMTOP (uword address @XY, bool dir @Pc) -> uword @XY, ubyte @A = $ff99
OPEN () -> clobbers (X,Y) -> bool @Pc, ubyte @A = $ffc0
PLOT (ubyte col @Y, ubyte row @X, bool dir @Pc) -> clobbers (A) -> ubyte @Y, ubyte @X = $fff0
RAMTAS () -> clobbers (A,X,Y) = $ff87
OPEN () clobbers (X,Y) -> bool @Pc, ubyte @A = $ffc0
PLOT (ubyte col @Y, ubyte row @X, bool dir @Pc) clobbers (A) -> ubyte @Y, ubyte @X = $fff0
RAMTAS () clobbers (A,X,Y) = $ff87
RDTIM () -> ubyte @A, ubyte @X, ubyte @Y = $ffde
RDTIM16 () -> clobbers (X) -> uword @AY
RDTIM16 () clobbers (X) -> uword @AY
RDTIML () clobbers (X) -> long @R0R1_32
RDTIM_safe () -> ubyte @A, ubyte @X, ubyte @Y
READST () -> ubyte @A = $ffb7
RESTOR () -> clobbers (A,X,Y) = $ff8a
SAVE (ubyte zp_startaddr @A, uword endaddr @XY) -> clobbers (X,Y) -> bool @Pc, ubyte @A = $ffd8
SCNKEY () -> clobbers (A,X,Y) = $ff9f
RESTOR () clobbers (A,X,Y) = $ff8a
SAVE (ubyte zp_startaddr @A, uword endaddr @XY) clobbers (X,Y) -> bool @Pc, ubyte @A = $ffd8
SCNKEY () clobbers (A,X,Y) = $ff9f
SCREEN () -> ubyte @X, ubyte @Y = $ffed
SECOND (ubyte address @A) -> clobbers (A) = $ff93
SECOND (ubyte address @A) clobbers (A) = $ff93
SETLFS (ubyte logical @A, ubyte device @X, ubyte secondary @Y) = $ffba
SETMSG (ubyte value @A) = $ff90
SETNAM (ubyte namelen @A, str filename @XY) = $ffbd
SETTIM (ubyte low @A, ubyte middle @X, ubyte high @Y) = $ffdb
SETTIML (long jiffies @R0R1_32)
SETTMO (ubyte timeout @A) = $ffa2
STOP () -> clobbers (X) -> bool @Pz, ubyte @A = $ffe1
STOP2 () -> clobbers (A,X) -> bool @Pz
TALK (ubyte device @A) -> clobbers (A) = $ffb4
TKSA (ubyte address @A) -> clobbers (A) = $ff96
UDTIM () -> clobbers (A,X) = $ffea
UNLSN () -> clobbers (A) = $ffae
UNTLK () -> clobbers (A) = $ffab
VECTOR (uword userptr @XY, bool dir @Pc) -> clobbers (A,Y) = $ff8d
STOP () clobbers (X) -> bool @Pz, ubyte @A = $ffe1
STOP2 () clobbers (A,X) -> bool @Pz
TALK (ubyte device @A) clobbers (A) = $ffb4
TKSA (ubyte address @A) clobbers (A) = $ff96
UDTIM () clobbers (A,X) = $ffea
UNLSN () clobbers (A) = $ffae
UNTLK () clobbers (A) = $ffab
VECTOR (uword userptr @XY, bool dir @Pc) clobbers (A,Y) = $ff8d
kbdbuf_clear ()
}
@@ -1070,68 +1094,67 @@ cx16 {
&ubyte via2t1ll
&ubyte via2t2h
&ubyte via2t2l
BSAVE (ubyte zp_startaddr @A, uword endaddr @XY) -> clobbers (X,Y) -> bool @Pc, ubyte @A = $feba
CLOSE_ALL (ubyte device @A) -> clobbers (A,X,Y) = $ff4a
FB_cursor_next_line (uword x @R0) -> clobbers (A,X,Y) = $ff02
FB_cursor_position (uword x @R0, uword y @R1) -> clobbers (A,X,Y) = $feff
FB_fill_pixels (uword count @R0, uword pstep @R1, ubyte color @A) -> clobbers (A,X,Y) = $ff17
FB_filter_pixels (uword pointer @R0, uword count @R1) -> clobbers (A,X,Y) = $ff1a
FB_get_info () -> clobbers (X,Y) -> byte @A, uword @R0, uword @R1 = $fef9
FB_get_pixel () -> clobbers (X,Y) -> ubyte @A = $ff05
FB_get_pixels (uword pointer @R0, uword count @R1) -> clobbers (A,X,Y) = $ff08
FB_init () -> clobbers (A,X,Y) = $fef6
FB_move_pixels (uword sx @R0, uword sy @R1, uword tx @R2, uword ty @R3, uword count @R4) -> clobbers (A,X,Y) = $ff1d
FB_set_8_pixels (ubyte pattern @A, ubyte color @X) -> clobbers (A,X,Y) = $ff11
FB_set_8_pixels_opaque (ubyte pattern @R0, ubyte mask @A, ubyte color1 @X, ubyte color2 @Y) -> clobbers (A,X,Y) = $ff14
FB_set_palette (uword pointer @R0, ubyte index @A, ubyte colorcount @X) -> clobbers (A,X,Y) = $fefc
FB_set_pixel (ubyte color @A) -> clobbers (A,X,Y) = $ff0b
FB_set_pixels (uword pointer @R0, uword count @R1) -> clobbers (A,X,Y) = $ff0e
GRAPH_clear () -> clobbers (A,X,Y) = $ff23
GRAPH_draw_image (uword x @R0, uword y @R1, uword ptr @R2, uword width @R3, uword height @R4) -> clobbers (A,X,Y) = $ff38
GRAPH_draw_line (uword x1 @R0, uword y1 @R1, uword x2 @R2, uword y2 @R3) -> clobbers (A,X,Y) = $ff2c
GRAPH_draw_oval (uword x @R0, uword y @R1, uword width @R2, uword height @R3, bool fill @Pc) -> clobbers (A,X,Y) = $ff35
GRAPH_draw_rect (uword x @R0, uword y @R1, uword width @R2, uword height @R3, uword cornerradius @R4, bool fill @Pc) -> clobbers (A,X,Y) = $ff2f
GRAPH_get_char_size (ubyte baseline @A, ubyte width @X, ubyte height_or_style @Y, bool is_control @Pc) -> clobbers (A,X,Y) = $ff3e
GRAPH_init (uword vectors @R0) -> clobbers (A,X,Y) = $ff20
GRAPH_move_rect (uword sx @R0, uword sy @R1, uword tx @R2, uword ty @R3, uword width @R4, uword height @R5) -> clobbers (A,X,Y) = $ff32
GRAPH_put_char (uword x @R0, uword y @R1, ubyte character @A) -> clobbers (A,X,Y) = $ff41
GRAPH_put_next_char (ubyte character @A) -> clobbers (A,X,Y) = $ff41
GRAPH_set_colors (ubyte stroke @A, ubyte fill @X, ubyte background @Y) -> clobbers (A,X,Y) = $ff29
GRAPH_set_font (uword fontptr @R0) -> clobbers (A,X,Y) = $ff3b
GRAPH_set_window (uword x @R0, uword y @R1, uword width @R2, uword height @R3) -> clobbers (A,X,Y) = $ff26
BSAVE (ubyte zp_startaddr @A, uword endaddr @XY) clobbers (X,Y) -> bool @Pc, ubyte @A = $feba
CLOSE_ALL (ubyte device @A) clobbers (A,X,Y) = $ff4a
FB_cursor_next_line (uword x @R0) clobbers (A,X,Y) = $ff02
FB_cursor_position (uword x @R0, uword y @R1) clobbers (A,X,Y) = $feff
FB_fill_pixels (uword count @R0, uword pstep @R1, ubyte color @A) clobbers (A,X,Y) = $ff17
FB_filter_pixels (uword pointer @R0, uword count @R1) clobbers (A,X,Y) = $ff1a
FB_get_info () clobbers (X,Y) -> byte @A, uword @R0, uword @R1 = $fef9
FB_get_pixel () clobbers (X,Y) -> ubyte @A = $ff05
FB_get_pixels (uword pointer @R0, uword count @R1) clobbers (A,X,Y) = $ff08
FB_init () clobbers (A,X,Y) = $fef6
FB_move_pixels (uword sx @R0, uword sy @R1, uword tx @R2, uword ty @R3, uword count @R4) clobbers (A,X,Y) = $ff1d
FB_set_8_pixels (ubyte pattern @A, ubyte color @X) clobbers (A,X,Y) = $ff11
FB_set_8_pixels_opaque (ubyte pattern @R0, ubyte mask @A, ubyte color1 @X, ubyte color2 @Y) clobbers (A,X,Y) = $ff14
FB_set_palette (uword pointer @R0, ubyte index @A, ubyte colorcount @X) clobbers (A,X,Y) = $fefc
FB_set_pixel (ubyte color @A) clobbers (A,X,Y) = $ff0b
FB_set_pixels (uword pointer @R0, uword count @R1) clobbers (A,X,Y) = $ff0e
GRAPH_clear () clobbers (A,X,Y) = $ff23
GRAPH_draw_image (uword x @R0, uword y @R1, uword ptr @R2, uword width @R3, uword height @R4) clobbers (A,X,Y) = $ff38
GRAPH_draw_line (uword x1 @R0, uword y1 @R1, uword x2 @R2, uword y2 @R3) clobbers (A,X,Y) = $ff2c
GRAPH_draw_oval (uword x @R0, uword y @R1, uword width @R2, uword height @R3, bool fill @Pc) clobbers (A,X,Y) = $ff35
GRAPH_draw_rect (uword x @R0, uword y @R1, uword width @R2, uword height @R3, uword cornerradius @R4, bool fill @Pc) clobbers (A,X,Y) = $ff2f
GRAPH_get_char_size (ubyte baseline @A, ubyte width @X, ubyte height_or_style @Y, bool is_control @Pc) clobbers (A,X,Y) = $ff3e
GRAPH_init (uword vectors @R0) clobbers (A,X,Y) = $ff20
GRAPH_move_rect (uword sx @R0, uword sy @R1, uword tx @R2, uword ty @R3, uword width @R4, uword height @R5) clobbers (A,X,Y) = $ff32
GRAPH_put_char (uword x @R0, uword y @R1, ubyte character @A) clobbers (A,X,Y) = $ff41
GRAPH_put_next_char (ubyte character @A) clobbers (A,X,Y) = $ff41
GRAPH_set_colors (ubyte stroke @A, ubyte fill @X, ubyte background @Y) clobbers (A,X,Y) = $ff29
GRAPH_set_font (uword fontptr @R0) clobbers (A,X,Y) = $ff3b
GRAPH_set_window (uword x @R0, uword y @R1, uword width @R2, uword height @R3) clobbers (A,X,Y) = $ff26
JSRFAR () = $ff6e
LKUPLA (ubyte la @A) -> clobbers (A,X,Y) = $ff59
LKUPSA (ubyte sa @Y) -> clobbers (A,X,Y) = $ff5c
MACPTR (ubyte length @A, uword buffer @XY, bool dontAdvance @Pc) -> clobbers (A) -> bool @Pc, uword @XY = $ff44
MCIOUT (ubyte length @A, uword buffer @XY, bool dontAdvance @Pc) -> clobbers (A) -> bool @Pc, uword @XY = $feb1
LKUPLA (ubyte la @A) clobbers (A,X,Y) = $ff59
LKUPSA (ubyte sa @Y) clobbers (A,X,Y) = $ff5c
MACPTR (ubyte length @A, uword buffer @XY, bool dontAdvance @Pc) clobbers (A) -> bool @Pc, uword @XY = $ff44
MCIOUT (ubyte length @A, uword buffer @XY, bool dontAdvance @Pc) clobbers (A) -> bool @Pc, uword @XY = $feb1
PRIMM () = $ff7d
audio_init () -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c09f
bas_fmchordstring (ubyte length @A, str string @XY) -> clobbers (A,X,Y) @bank 10 = $c08d
bas_fmfreq (ubyte channel @A, uword freq @XY, bool noretrigger @Pc) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c000
bas_fmnote (ubyte channel @A, ubyte note @X, ubyte fracsemitone @Y, bool noretrigger @Pc) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c003
bas_fmplaystring (ubyte length @A, str string @XY) -> clobbers (A,X,Y) @bank 10 = $c006
bas_fmvib (ubyte speed @A, ubyte depth @X) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c009
bas_playstringvoice (ubyte channel @A) -> clobbers (Y) @bank 10 = $c00c
bas_psgchordstring (ubyte length @A, str string @XY) -> clobbers (A,X,Y) @bank 10 = $c090
bas_psgfreq (ubyte voice @A, uword freq @XY) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c00f
bas_psgnote (ubyte voice @A, ubyte note @X, ubyte fracsemitone @Y) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c012
bas_psgplaystring (ubyte length @A, str string @XY) -> clobbers (A,X,Y) @bank 10 = $c018
bas_psgwav (ubyte voice @A, ubyte waveform @X) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c015
clock_get_date_time () -> clobbers (A,X,Y) -> uword @R0, uword @R1, uword @R2, uword @R3 = $ff50
clock_set_date_time (uword yearmonth @R0, uword dayhours @R1, uword minsecs @R2, uword jiffiesweekday @R3) -> clobbers (A,X,Y) = $ff4d
console_get_char () -> clobbers (X,Y) -> ubyte @A = $fee1
console_init (uword x @R0, uword y @R1, uword width @R2, uword height @R3) -> clobbers (A,X,Y) = $fedb
console_put_char (ubyte character @A, bool wrapping @Pc) -> clobbers (A,X,Y) = $fede
console_put_image (uword pointer @R0, uword width @R1, uword height @R2) -> clobbers (A,X,Y) = $fed8
console_set_paging_message (uword msgptr @R0) -> clobbers (A,X,Y) = $fed5
cpu_is_65816 () -> bool @A
audio_init () clobbers (A,X,Y) -> bool @Pc @bank 10 = $c09f
bas_fmchordstring (ubyte length @A, str string @XY) clobbers (A,X,Y) @bank 10 = $c08d
bas_fmfreq (ubyte channel @A, uword freq @XY, bool noretrigger @Pc) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c000
bas_fmnote (ubyte channel @A, ubyte note @X, ubyte fracsemitone @Y, bool noretrigger @Pc) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c003
bas_fmplaystring (ubyte length @A, str string @XY) clobbers (A,X,Y) @bank 10 = $c006
bas_fmvib (ubyte speed @A, ubyte depth @X) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c009
bas_playstringvoice (ubyte channel @A) clobbers (Y) @bank 10 = $c00c
bas_psgchordstring (ubyte length @A, str string @XY) clobbers (A,X,Y) @bank 10 = $c090
bas_psgfreq (ubyte voice @A, uword freq @XY) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c00f
bas_psgnote (ubyte voice @A, ubyte note @X, ubyte fracsemitone @Y) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c012
bas_psgplaystring (ubyte length @A, str string @XY) clobbers (A,X,Y) @bank 10 = $c018
bas_psgwav (ubyte voice @A, ubyte waveform @X) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c015
clock_get_date_time () clobbers (A,X,Y) -> uword @R0, uword @R1, uword @R2, uword @R3 = $ff50
clock_set_date_time (uword yearmonth @R0, uword dayhours @R1, uword minsecs @R2, uword jiffiesweekday @R3) clobbers (A,X,Y) = $ff4d
console_get_char () clobbers (X,Y) -> ubyte @A = $fee1
console_init (uword x @R0, uword y @R1, uword width @R2, uword height @R3) clobbers (A,X,Y) = $fedb
console_put_char (ubyte character @A, bool wrapping @Pc) clobbers (A,X,Y) = $fede
console_put_image (uword pointer @R0, uword width @R1, uword height @R2) clobbers (A,X,Y) = $fed8
console_set_paging_message (uword msgptr @R0) clobbers (A,X,Y) = $fed5
disable_irq_handlers ()
disable_irqs () -> clobbers (A)
enable_irq_handlers (bool disable_all_irq_sources @Pc) -> clobbers (A,Y)
enter_basic (bool cold_or_warm @Pc) -> clobbers (A,X,Y) = $ff47
disable_irqs () clobbers (A)
enable_irq_handlers (bool disable_all_irq_sources @Pc) clobbers (A,Y)
enter_basic (bool cold_or_warm @Pc) clobbers (A,X,Y) = $ff47
entropy_get () -> ubyte @A, ubyte @X, ubyte @Y = $fecf
extapi (ubyte callnumber @A) -> clobbers (A,X,Y) = $feab
fetch (ubyte zp_startaddr @A, ubyte bank @X, ubyte index @Y) -> clobbers (X) -> ubyte @A = $ff74
extapi (ubyte callnumber @A) clobbers (A,X,Y) = $feab
fetch (ubyte zp_startaddr @A, ubyte bank @X, ubyte index @Y) clobbers (X) -> ubyte @A = $ff74
get_charset () -> ubyte @A
get_chrin_keyhandler () -> ubyte @R0, uword @R1
get_default_palette () -> ubyte @A, uword @XY
@@ -1140,121 +1163,121 @@ cx16 {
getlfs () -> ubyte @X, ubyte @A, ubyte @Y
getrambank () -> ubyte @A
getrombank () -> ubyte @A
i2c_batch_read (ubyte device @X, uword buffer @R0, uword length @R1, bool advance @Pc) -> clobbers (A,Y) -> bool @Pc = $feb4
i2c_batch_write (ubyte device @X, uword buffer @R0, uword length @R1, bool advance @Pc) -> clobbers (A,Y) -> bool @Pc = $feb7
i2c_read_byte (ubyte device @X, ubyte offset @Y) -> clobbers (X,Y) -> ubyte @A, bool @Pc = $fec6
i2c_write_byte (ubyte device @X, ubyte offset @Y, ubyte data @A) -> clobbers (A,X,Y) -> bool @Pc = $fec9
iso_cursor_char (ubyte character @X) -> clobbers (A,X,Y)
i2c_batch_read (ubyte device @X, uword buffer @R0, uword length @R1, bool advance @Pc) clobbers (A,Y) -> bool @Pc = $feb4
i2c_batch_write (ubyte device @X, uword buffer @R0, uword length @R1, bool advance @Pc) clobbers (A,Y) -> bool @Pc = $feb7
i2c_read_byte (ubyte device @X, ubyte offset @Y) clobbers (X,Y) -> ubyte @A, bool @Pc = $fec6
i2c_write_byte (ubyte device @X, ubyte offset @Y, ubyte data @A) clobbers (A,X,Y) -> bool @Pc = $fec9
iso_cursor_char (ubyte character @X) clobbers (A,X,Y)
joystick_get (ubyte joynr @A) -> uword @AX, bool @Y = $ff56
joystick_scan () -> clobbers (A,X,Y) = $ff53
joystick_scan () clobbers (A,X,Y) = $ff53
joysticks_detect () -> ubyte
joysticks_getall (bool also_keyboard_js) -> uword
kbdbuf_get_modifiers () -> ubyte @A = $fec0
kbdbuf_peek () -> ubyte @A, ubyte @X = $febd
kbdbuf_put (ubyte key @A) -> clobbers (X) = $fec3
kbdbuf_put (ubyte key @A) clobbers (X) = $fec3
keymap (uword identifier @XY, bool read @Pc) -> bool @Pc = $fed2
memory_copy (uword source @R0, uword target @R1, uword num_bytes @R2) -> clobbers (A,X,Y) = $fee7
memory_crc (uword address @R0, uword num_bytes @R1) -> clobbers (A,X,Y) -> uword @R2 = $feea
memory_decompress (uword input @R0, uword output @R1) -> clobbers (A,X,Y) -> uword @R1 = $feed
memory_decompress_from_func (uword datafunction @R4, uword output @R1) -> clobbers (A,X,Y) -> uword @R1
memory_fill (uword address @R0, uword num_bytes @R1, ubyte value @A) -> clobbers (A,X,Y) = $fee4
monitor () -> clobbers (A,X,Y) = $fecc
mouse_config (byte shape @A, ubyte resX @X, ubyte resY @Y) -> clobbers (A,X,Y) = $ff68
mouse_config2 (byte shape @A) -> clobbers (A,X,Y)
memory_copy (uword source @R0, uword target @R1, uword num_bytes @R2) clobbers (A,X,Y) = $fee7
memory_crc (uword address @R0, uword num_bytes @R1) clobbers (A,X,Y) -> uword @R2 = $feea
memory_decompress (uword input @R0, uword output @R1) clobbers (A,X,Y) -> uword @R1 = $feed
memory_decompress_from_func (uword datafunction @R4, uword output @R1) clobbers (A,X,Y) -> uword @R1
memory_fill (uword address @R0, uword num_bytes @R1, ubyte value @A) clobbers (A,X,Y) = $fee4
monitor () clobbers (A,X,Y) = $fecc
mouse_config (byte shape @A, ubyte resX @X, ubyte resY @Y) clobbers (A,X,Y) = $ff68
mouse_config2 (byte shape @A) clobbers (A,X,Y)
mouse_get (ubyte zdataptr @X) -> ubyte @A, byte @X = $ff6b
mouse_get_sprite_offset () -> clobbers (A,X,Y) -> word @R0, word @R1
mouse_get_sprite_offset () clobbers (A,X,Y) -> word @R0, word @R1
mouse_pos () -> ubyte @A, uword @R0, uword @R1, byte @X
mouse_present () -> bool
mouse_scan () -> clobbers (A,X,Y) = $ff71
mouse_set_pos (uword xpos @R0, uword ypos @R1) -> clobbers (X)
mouse_set_sprite_offset (word xoffset @R0, word yoffset @R1) -> clobbers (A,X,Y)
notecon_bas2fm (ubyte note @X) -> clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c01b
notecon_bas2midi (ubyte note @X) -> clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c01e
notecon_bas2psg (ubyte note @X, ubyte fracsemitone @Y) -> clobbers (A) -> uword @XY, bool @Pc @bank 10 = $c021
notecon_fm2bas (ubyte note @X) -> clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c024
notecon_fm2midi (ubyte note @X) -> clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c027
notecon_fm2psg (ubyte note @X, ubyte fracsemitone @Y) -> clobbers (A) -> uword @XY, bool @Pc @bank 10 = $c02a
notecon_freq2bas (uword freqHz @XY) -> clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c02d
notecon_freq2fm (uword freqHz @XY) -> clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c030
notecon_freq2midi (uword freqHz @XY) -> clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c033
notecon_freq2psg (uword freqHz @XY) -> clobbers (A) -> uword @XY, bool @Pc @bank 10 = $c036
notecon_midi2bas (ubyte note @X) -> clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c039
notecon_midi2fm (ubyte note @X) -> clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c03c
notecon_midi2psg (ubyte note @X, ubyte fracsemitone @Y) -> clobbers (A) -> uword @XY, bool @Pc @bank 10 = $c03f
notecon_psg2bas (uword freq @XY) -> clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c042
notecon_psg2fm (uword freq @XY) -> clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c045
notecon_psg2midi (uword freq @XY) -> clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c048
numbanks () -> clobbers (X) -> uword @AY
mouse_scan () clobbers (A,X,Y) = $ff71
mouse_set_pos (uword xpos @R0, uword ypos @R1) clobbers (X)
mouse_set_sprite_offset (word xoffset @R0, word yoffset @R1) clobbers (A,X,Y)
notecon_bas2fm (ubyte note @X) clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c01b
notecon_bas2midi (ubyte note @X) clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c01e
notecon_bas2psg (ubyte note @X, ubyte fracsemitone @Y) clobbers (A) -> uword @XY, bool @Pc @bank 10 = $c021
notecon_fm2bas (ubyte note @X) clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c024
notecon_fm2midi (ubyte note @X) clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c027
notecon_fm2psg (ubyte note @X, ubyte fracsemitone @Y) clobbers (A) -> uword @XY, bool @Pc @bank 10 = $c02a
notecon_freq2bas (uword freqHz @XY) clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c02d
notecon_freq2fm (uword freqHz @XY) clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c030
notecon_freq2midi (uword freqHz @XY) clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c033
notecon_freq2psg (uword freqHz @XY) clobbers (A) -> uword @XY, bool @Pc @bank 10 = $c036
notecon_midi2bas (ubyte note @X) clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c039
notecon_midi2fm (ubyte note @X) clobbers (A) -> ubyte @X, bool @Pc @bank 10 = $c03c
notecon_midi2psg (ubyte note @X, ubyte fracsemitone @Y) clobbers (A) -> uword @XY, bool @Pc @bank 10 = $c03f
notecon_psg2bas (uword freq @XY) clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c042
notecon_psg2fm (uword freq @XY) clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c045
notecon_psg2midi (uword freq @XY) clobbers (A) -> ubyte @X, ubyte @Y, bool @Pc @bank 10 = $c048
numbanks () clobbers (X) -> uword @AY
pop_rambank ()
pop_rombank ()
poweroff_system ()
psg_getatten (ubyte voice @A) -> clobbers (Y) -> ubyte @X @bank 10 = $c093
psg_getpan (ubyte voice @A) -> clobbers (Y) -> ubyte @X @bank 10 = $c096
psg_init () -> clobbers (A,X,Y) @bank 10 = $c04b
psg_playfreq (ubyte voice @A, uword freq @XY) -> clobbers (A,X,Y) @bank 10 = $c04e
psg_read (ubyte offset @X, bool cookedVol @Pc) -> clobbers (Y) -> ubyte @A @bank 10 = $c051
psg_setatten (ubyte voice @A, ubyte attenuation @X) -> clobbers (A,X,Y) @bank 10 = $c054
psg_setfreq (ubyte voice @A, uword freq @XY) -> clobbers (A,X,Y) @bank 10 = $c057
psg_setpan (ubyte voice @A, ubyte panning @X) -> clobbers (A,X,Y) @bank 10 = $c05a
psg_setvol (ubyte voice @A, ubyte volume @X) -> clobbers (A,X,Y) @bank 10 = $c05d
psg_write (ubyte value @A, ubyte offset @X) -> clobbers (Y) @bank 10 = $c060
psg_write_fast (ubyte value @A, ubyte offset @X) -> clobbers (Y) @bank 10 = $c0a2
push_rambank (ubyte newbank @A) -> clobbers (Y)
push_rombank (ubyte newbank @A) -> clobbers (Y)
psg_getatten (ubyte voice @A) clobbers (Y) -> ubyte @X @bank 10 = $c093
psg_getpan (ubyte voice @A) clobbers (Y) -> ubyte @X @bank 10 = $c096
psg_init () clobbers (A,X,Y) @bank 10 = $c04b
psg_playfreq (ubyte voice @A, uword freq @XY) clobbers (A,X,Y) @bank 10 = $c04e
psg_read (ubyte offset @X, bool cookedVol @Pc) clobbers (Y) -> ubyte @A @bank 10 = $c051
psg_setatten (ubyte voice @A, ubyte attenuation @X) clobbers (A,X,Y) @bank 10 = $c054
psg_setfreq (ubyte voice @A, uword freq @XY) clobbers (A,X,Y) @bank 10 = $c057
psg_setpan (ubyte voice @A, ubyte panning @X) clobbers (A,X,Y) @bank 10 = $c05a
psg_setvol (ubyte voice @A, ubyte volume @X) clobbers (A,X,Y) @bank 10 = $c05d
psg_write (ubyte value @A, ubyte offset @X) clobbers (Y) @bank 10 = $c060
psg_write_fast (ubyte value @A, ubyte offset @X) clobbers (Y) @bank 10 = $c0a2
push_rambank (ubyte newbank @A) clobbers (Y)
push_rombank (ubyte newbank @A) clobbers (Y)
rambank (ubyte bank @A)
reset_system ()
restore_vera_context () -> clobbers (A)
restore_virtual_registers () -> clobbers (A,Y)
rom_version () -> clobbers (Y) -> ubyte @A, bool @Pc
restore_vera_context () clobbers (A)
restore_virtual_registers () clobbers (A,Y)
rom_version () clobbers (Y) -> ubyte @A, bool @Pc
rombank (ubyte bank @A)
save_vera_context () -> clobbers (A)
save_virtual_registers () -> clobbers (A,Y)
scnsiz (ubyte width @X, ubyte heigth @Y) -> clobbers (A,X,Y)
save_vera_context () clobbers (A)
save_virtual_registers () clobbers (A,Y)
scnsiz (ubyte width @X, ubyte heigth @Y) clobbers (A,X,Y)
screen_mode (ubyte mode @A, bool getCurrent @Pc) -> ubyte @A, ubyte @X, ubyte @Y, bool @Pc = $ff5f
screen_set_charset (ubyte charset @A, uword charsetptr @XY) -> clobbers (A,X,Y) = $ff62
screen_set_charset (ubyte charset @A, uword charsetptr @XY) clobbers (A,X,Y) = $ff62
search_x16edit () -> ubyte
set_aflow_irq_handler (uword address @AY) -> clobbers (A)
set_chrin_keyhandler (ubyte handlerbank @A, uword handler @XY) -> clobbers (A)
set_aflow_irq_handler (uword address @AY) clobbers (A)
set_chrin_keyhandler (ubyte handlerbank @A, uword handler @XY) clobbers (A)
set_default_palette ()
set_led_state (bool on)
set_line_irq_handler (uword rasterline @R0, uword address @AY) -> clobbers (A,Y)
set_line_irq_handler (uword rasterline @R0, uword address @AY) clobbers (A,Y)
set_program_args (str args_ptr, ubyte args_size)
set_screen_mode (ubyte mode @A) -> clobbers (A,X,Y)
set_sprcol_irq_handler (uword address @AY) -> clobbers (A)
set_vsync_irq_handler (uword address @AY) -> clobbers (A)
sprite_set_image (uword pixels @R0, uword mask @R1, ubyte bpp @R2, ubyte number @A, ubyte width @X, ubyte height @Y, bool apply_mask @Pc) -> clobbers (A,X,Y) -> bool @Pc = $fef0
sprite_set_position (uword x @R0, uword y @R1, ubyte number @A) -> clobbers (A,X,Y) = $fef3
stash (ubyte data @A, ubyte bank @X, ubyte index @Y) -> clobbers (X) = $ff77
vaddr (ubyte bank @A, uword address @R0, ubyte addrsel @R1, byte autoIncrOrDecrByOne @Y) -> clobbers (A)
vaddr_autodecr (ubyte bank @A, uword address @R0, ubyte addrsel @R1, uword autoDecrAmount @R2) -> clobbers (A,Y)
vaddr_autoincr (ubyte bank @A, uword address @R0, ubyte addrsel @R1, uword autoIncrAmount @R2) -> clobbers (A,Y)
vaddr_clone (ubyte port @A) -> clobbers (A,X,Y)
set_screen_mode (ubyte mode @A) clobbers (A,X,Y)
set_sprcol_irq_handler (uword address @AY) clobbers (A)
set_vsync_irq_handler (uword address @AY) clobbers (A)
sprite_set_image (uword pixels @R0, uword mask @R1, ubyte bpp @R2, ubyte number @A, ubyte width @X, ubyte height @Y, bool apply_mask @Pc) clobbers (A,X,Y) -> bool @Pc = $fef0
sprite_set_position (uword x @R0, uword y @R1, ubyte number @A) clobbers (A,X,Y) = $fef3
stash (ubyte data @A, ubyte bank @X, ubyte index @Y) clobbers (X) = $ff77
vaddr (ubyte bank @A, uword address @R0, ubyte addrsel @R1, byte autoIncrOrDecrByOne @Y) clobbers (A)
vaddr_autodecr (ubyte bank @A, uword address @R0, ubyte addrsel @R1, uword autoDecrAmount @R2) clobbers (A,Y)
vaddr_autoincr (ubyte bank @A, uword address @R0, ubyte addrsel @R1, uword autoIncrAmount @R2) clobbers (A,Y)
vaddr_clone (ubyte port @A) clobbers (A,X,Y)
vpeek (ubyte bank @A, uword address @XY) -> ubyte @A
vpoke (ubyte bank @A, uword address @R0, ubyte value @Y) -> clobbers (A)
vpoke_and (ubyte bank @A, uword address @R0, ubyte value @Y) -> clobbers (A)
vpoke_mask (ubyte bank @A, uword address @R0, ubyte mask @X, ubyte value @Y) -> clobbers (A)
vpoke_or (ubyte bank @A, uword address @R0, ubyte value @Y) -> clobbers (A)
vpoke_xor (ubyte bank @A, uword address @R0, ubyte value @Y) -> clobbers (A)
x16edit_default () -> clobbers (A,X,Y) = $c000
x16edit_loadfile (ubyte firstbank @X, ubyte lastbank @Y, str filename @R0, ubyte filenameLength @R1) -> clobbers (A,X,Y) = $c003
x16edit_loadfile_options (ubyte firstbank @X, ubyte lastbank @Y, str filename @R0, uword filenameLengthAndOptions @R1, uword tabstopAndWordwrap @R2, uword disknumberAndColors @R3, uword headerAndStatusColors @R4) -> clobbers (A,X,Y) = $c006
ym_get_chip_type () -> clobbers (X) -> ubyte @A @bank 10 = $c0a5
ym_getatten (ubyte channel @A) -> clobbers (Y) -> ubyte @X @bank 10 = $c099
ym_getpan (ubyte channel @A) -> clobbers (Y) -> ubyte @X @bank 10 = $c09c
ym_init () -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c063
ym_loaddefpatches () -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c066
ym_loadpatch (ubyte channel @A, uword patchOrAddress @XY, bool what @Pc) -> clobbers (A,X,Y) @bank 10 = $c069
ym_loadpatchlfn (ubyte channel @A, ubyte lfn @X) -> clobbers (X,Y) -> ubyte @A, bool @Pc @bank 10 = $c06c
ym_playdrum (ubyte channel @A, ubyte note @X) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c06f
ym_playnote (ubyte channel @A, ubyte kc @X, ubyte kf @Y, bool notrigger @Pc) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c072
ym_read (ubyte register @X, bool cooked @Pc) -> clobbers (Y) -> ubyte @A, bool @Pc @bank 10 = $c081
ym_release (ubyte channel @A) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c084
ym_setatten (ubyte channel @A, ubyte attenuation @X) -> clobbers (Y) -> bool @Pc @bank 10 = $c075
ym_setdrum (ubyte channel @A, ubyte note @X) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c078
ym_setnote (ubyte channel @A, ubyte kc @X, ubyte kf @Y) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c07b
ym_setpan (ubyte channel @A, ubyte panning @X) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c07e
ym_trigger (ubyte channel @A, bool noRelease @Pc) -> clobbers (A,X,Y) -> bool @Pc @bank 10 = $c087
ym_write (ubyte value @A, ubyte register @X) -> clobbers (Y) -> bool @Pc @bank 10 = $c08a
vpoke (ubyte bank @A, uword address @R0, ubyte value @Y) clobbers (A)
vpoke_and (ubyte bank @A, uword address @R0, ubyte value @Y) clobbers (A)
vpoke_mask (ubyte bank @A, uword address @R0, ubyte mask @X, ubyte value @Y) clobbers (A)
vpoke_or (ubyte bank @A, uword address @R0, ubyte value @Y) clobbers (A)
vpoke_xor (ubyte bank @A, uword address @R0, ubyte value @Y) clobbers (A)
x16edit_default () clobbers (A,X,Y) = $c000
x16edit_loadfile (ubyte firstbank @X, ubyte lastbank @Y, str filename @R0, ubyte filenameLength @R1) clobbers (A,X,Y) = $c003
x16edit_loadfile_options (ubyte firstbank @X, ubyte lastbank @Y, str filename @R0, uword filenameLengthAndOptions @R1, uword tabstopAndWordwrap @R2, uword disknumberAndColors @R3, uword headerAndStatusColors @R4) clobbers (A,X,Y) = $c006
ym_get_chip_type () clobbers (X) -> ubyte @A @bank 10 = $c0a5
ym_getatten (ubyte channel @A) clobbers (Y) -> ubyte @X @bank 10 = $c099
ym_getpan (ubyte channel @A) clobbers (Y) -> ubyte @X @bank 10 = $c09c
ym_init () clobbers (A,X,Y) -> bool @Pc @bank 10 = $c063
ym_loaddefpatches () clobbers (A,X,Y) -> bool @Pc @bank 10 = $c066
ym_loadpatch (ubyte channel @A, uword patchOrAddress @XY, bool what @Pc) clobbers (A,X,Y) @bank 10 = $c069
ym_loadpatchlfn (ubyte channel @A, ubyte lfn @X) clobbers (X,Y) -> ubyte @A, bool @Pc @bank 10 = $c06c
ym_playdrum (ubyte channel @A, ubyte note @X) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c06f
ym_playnote (ubyte channel @A, ubyte kc @X, ubyte kf @Y, bool notrigger @Pc) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c072
ym_read (ubyte register @X, bool cooked @Pc) clobbers (Y) -> ubyte @A, bool @Pc @bank 10 = $c081
ym_release (ubyte channel @A) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c084
ym_setatten (ubyte channel @A, ubyte attenuation @X) clobbers (Y) -> bool @Pc @bank 10 = $c075
ym_setdrum (ubyte channel @A, ubyte note @X) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c078
ym_setnote (ubyte channel @A, ubyte kc @X, ubyte kf @Y) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c07b
ym_setpan (ubyte channel @A, ubyte panning @X) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c07e
ym_trigger (ubyte channel @A, bool noRelease @Pc) clobbers (A,X,Y) -> bool @Pc @bank 10 = $c087
ym_write (ubyte value @A, ubyte register @X) clobbers (Y) -> bool @Pc @bank 10 = $c08a
}
sys {
@@ -1279,38 +1302,43 @@ sys {
const ubyte target
clear_carry ()
clear_irqd ()
cpu_is_65816 () -> bool @A
disable_caseswitch ()
enable_caseswitch ()
exit (ubyte returnvalue @A)
exit2 (ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y)
exit3 (ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc)
get_as_returnaddress (uword address @XY) -> uword @AX
internal_stringcopy (str source @R0, str target @AY) -> clobbers (A,Y)
internal_stringcopy (str source @R0, str target @AY) clobbers (A,Y)
irqsafe_clear_irqd ()
irqsafe_set_irqd ()
memcmp (uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A
memcopy (uword source @R0, uword target @R1, uword count @AY) -> clobbers (A,X,Y)
memset (uword mem @R0, uword numbytes @R1, ubyte value @A) -> clobbers (A,X,Y)
memsetw (uword mem @R0, uword numwords @R1, uword value @AY) -> clobbers (A,X,Y)
memcopy (uword source @R0, uword target @R1, uword count @AY) clobbers (A,X,Y)
memset (uword mem @R0, uword numbytes @R1, ubyte value @A) clobbers (A,X,Y)
memsetw (uword mem @R0, uword numwords @R1, uword value @AY) clobbers (A,X,Y)
pop () -> ubyte @A
popl () -> long @R0R1_32
popw () -> uword @AY
poweroff_system ()
progend () -> uword @AY
progstart () -> uword @AY
push (ubyte value @A)
push_returnaddress (uword address @XY)
pushl (long value @R0R1_32)
pushw (uword value @AY)
read_flags () -> ubyte @A
reset_system ()
restore_irq () -> clobbers (A)
restore_irq () clobbers (A)
restore_prog8_internals ()
save_prog8_internals ()
set_carry ()
set_irq (uword handler @AY) -> clobbers (A)
set_irq (uword handler @AY) clobbers (A)
set_irqd ()
set_rasterirq (uword handler @AY, uword rasterpos @R0) -> clobbers (A)
set_rasterirq (uword handler @AY, uword rasterpos @R0) clobbers (A)
set_rasterline (uword line @AY)
wait (uword jiffies @AY) -> clobbers (X)
update_rasterirq (uword handler @AY, uword rasterpos @R0) clobbers (A)
wait (uword jiffies @AY) clobbers (X)
waitrasterline (uword line @AY)
waitvsync ()
}
@@ -1341,22 +1369,22 @@ txt {
chrout (ubyte character @A) = $ffd2
chrout_lit (ubyte character @A)
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (X,Y)
clear_screencolors (ubyte color @A) -> clobbers (X,Y)
clear_screenchars (ubyte character @A) clobbers (X,Y)
clear_screencolors (ubyte color @A) clobbers (X,Y)
cls ()
color (ubyte txtcol)
color2 (ubyte txtcol, ubyte bgcol)
column (ubyte col @A) -> clobbers (A,X,Y)
column (ubyte col @A) clobbers (A,X,Y)
cp437 ()
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A,X)
fill_screen (ubyte character @A, ubyte color @Y) clobbers (A,X)
get_column () -> ubyte @Y
get_cursor () -> ubyte @X, ubyte @Y
get_row () -> ubyte @X
getchr (ubyte col @A, ubyte row @Y) -> ubyte @A
getclr (ubyte col @A, ubyte row @Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
height () clobbers (X,Y) -> ubyte @A
home ()
input_chars (^^ubyte buffer @AY) -> clobbers (A) -> ubyte @Y
input_chars (^^ubyte buffer @AY) clobbers (A) -> ubyte @Y
iso ()
iso16 ()
iso5 ()
@@ -1367,36 +1395,38 @@ txt {
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print (str text @AY) clobbers (A,Y)
print_b (byte value @A) clobbers (A,X,Y)
print_bool (bool value)
print_f alias for: floats.print
print_lit (str text @AY) -> clobbers (A,Y)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
row (ubyte rownum @A) -> clobbers (A,X,Y)
print_l (long value)
print_lit (str text @AY) clobbers (A,Y)
print_ub (ubyte value @A) clobbers (A,X,Y)
print_ub0 (ubyte value @A) clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) clobbers (A,X,Y)
print_ulhex (long value, bool prefix)
print_uw (uword value @AY) clobbers (A,X,Y)
print_uw0 (uword value @AY) clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) clobbers (A,X,Y)
print_w (word value @AY) clobbers (A,X,Y)
row (ubyte rownum @A) clobbers (A,X,Y)
rvs_off ()
rvs_on ()
scroll_down () -> clobbers (A,X,Y)
scroll_left () -> clobbers (A,X,Y)
scroll_right () -> clobbers (A,X,Y)
scroll_up () -> clobbers (A,X,Y)
scroll_down () clobbers (A,X,Y)
scroll_left () clobbers (A,X,Y)
scroll_right () clobbers (A,X,Y)
scroll_up () clobbers (A,X,Y)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor)
setcc2 (ubyte col, ubyte row, ubyte character, ubyte colors)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) -> clobbers (A)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) clobbers (A)
setclr (ubyte col @X, ubyte row @Y, ubyte color @A) clobbers (A)
spc ()
t256c (bool enable)
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
width () clobbers (X,Y) -> ubyte @A
}
@@ -1407,8 +1437,9 @@ verafx {
available () -> bool
clear (ubyte vbank, uword vaddr, ubyte data, uword num_longwords)
copy (ubyte srcbank, uword srcaddr, ubyte tgtbank, uword tgtaddr, uword num_longwords)
muls (word value1 @R0, word value2 @R1) -> clobbers (X) -> word @AY, word @R0
mult16 (uword value1 @R0, uword value2 @R1) -> clobbers (X) -> uword @AY
muls (word value1 @R0, word value2 @R1) clobbers (X) -> long @R0R1_32
muls16 (word value1 @R0, word value2 @R1) clobbers (X) -> word @AY
mult16 (uword value1 @R0, uword value2 @R1) clobbers (X) -> uword @AY
transparency (bool enable)
}
@@ -1,12 +1,31 @@
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit c04908a9 in branch structs6502
Prog8 compiler v12.0 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-pet32.p8
Compiler target: pet32
LIBRARY MODULE NAME: bcd
------------------------
bcd {
addb (byte a, byte b) -> byte
addl (long a, long b) -> long
addtol (^^long a, long b)
addub (ubyte a, ubyte b) -> ubyte
adduw (uword a, uword b) -> uword
addw (word a, word b) -> word
clearbcd ()
setbcd ()
subb (byte a, byte b) -> byte
subfroml (^^long a, long b)
subl (long a, long b) -> long
subub (ubyte a, ubyte b) -> ubyte
subuw (uword a, uword b) -> uword
}
LIBRARY MODULE NAME: buffers
----------------------------
@@ -63,11 +82,11 @@ LIBRARY MODULE NAME: compression
--------------------------------
compression {
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) -> clobbers (X) -> uword @AY
decode_tscrunch (uword compressed @R0, uword target @R1) -> clobbers (A,X,Y)
decode_tscrunch_inplace (uword compressed @R0) -> clobbers (A,X,Y)
decode_zx0 (uword compressed @R0, uword target @R1) -> clobbers (A,X,Y)
decode_rle (uword compressed @AY, uword target @R0, uword maxsize @R1) clobbers (X) -> uword @AY
decode_rle_srcfunc (uword source_function @AY, uword target @R0, uword maxsize @R1) clobbers (X) -> uword @AY
decode_tscrunch (uword compressed @R0, uword target @R1) clobbers (A,X,Y)
decode_tscrunch_inplace (uword compressed @R0) clobbers (A,X,Y)
decode_zx0 (uword compressed @R0, uword target @R1) clobbers (A,X,Y)
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
encode_rle_outfunc (uword data, uword size, uword output_function, bool is_last_block)
}
@@ -78,28 +97,30 @@ LIBRARY MODULE NAME: conv
conv {
ubyte[] @shared string_out
any2uword (str string @AY) -> clobbers (Y) -> ubyte @A
any2uword (str string @AY) -> uword @AY, ubyte @X
bin2uword (str string @AY) -> uword @AY
hex2uword (str string @AY) -> uword @AY
internal_byte2decimal (byte value @A) -> ubyte @Y, ubyte @A, ubyte @X
internal_ubyte2decimal (ubyte value @A) -> ubyte @Y, ubyte @X, ubyte @A
internal_ubyte2hex (ubyte value @A) -> clobbers (X) -> ubyte @A, ubyte @Y
internal_ubyte2hex (ubyte value @A) clobbers (X) -> ubyte @A, ubyte @Y
internal_uword2decimal (uword value @AY) -> ubyte @Y, ubyte @A, ubyte @X
internal_uword2hex (uword value @AY) -> clobbers (A,Y)
str2byte (str string @AY) -> clobbers (Y) -> byte @A
str2ubyte (str string @AY) -> clobbers (Y) -> ubyte @A
internal_uword2hex (uword value @AY) clobbers (A,Y)
str2byte (str string @AY) clobbers (Y) -> byte @A
str2ubyte (str string @AY) clobbers (Y) -> ubyte @A
str2uword (str string @AY) -> uword @AY
str2word (str string @AY) -> word @AY
str_b (byte value @A) -> clobbers (X) -> str @AY
str_ub (ubyte value @A) -> clobbers (X) -> str @AY
str_ub0 (ubyte value @A) -> clobbers (X) -> str @AY
str_ubbin (ubyte value @A) -> clobbers (X) -> str @AY
str_ubhex (ubyte value @A) -> clobbers (X) -> str @AY
str_uw (uword value @AY) -> clobbers (X) -> str @AY
str_uw0 (uword value @AY) -> clobbers (X) -> str @AY
str_uwbin (uword value @AY) -> clobbers (X) -> str @AY
str_b (byte value @A) clobbers (X) -> str @AY
str_l (long value) -> str
str_ub (ubyte value @A) clobbers (X) -> str @AY
str_ub0 (ubyte value @A) clobbers (X) -> str @AY
str_ubbin (ubyte value @A) clobbers (X) -> str @AY
str_ubhex (ubyte value @A) clobbers (X) -> str @AY
str_ulhex (long value) -> str
str_uw (uword value @AY) clobbers (X) -> str @AY
str_uw0 (uword value @AY) clobbers (X) -> str @AY
str_uwbin (uword value @AY) clobbers (X) -> str @AY
str_uwhex (uword value @AY) -> str @AY
str_w (word value @AY) -> clobbers (X) -> str @AY
str_w (word value @AY) clobbers (X) -> str @AY
}
@@ -137,17 +158,17 @@ LIBRARY MODULE NAME: math
math {
atan2 (ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A
cos8 (ubyte angle @A) -> clobbers (Y) -> byte @A
cos8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
cos8 (ubyte angle @A) clobbers (Y) -> byte @A
cos8u (ubyte angle @A) clobbers (Y) -> ubyte @A
cosr8 (ubyte radians @A) clobbers (Y) -> byte @A
cosr8u (ubyte radians @A) clobbers (Y) -> ubyte @A
crc16 (^^ubyte data, uword length) -> uword
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value @A)
crc32 (^^ubyte data, uword length)
crc32_end ()
crc32_end_result () -> uword @R15, uword @R14
crc32 (^^ubyte data, uword length) -> long
crc32_end () -> long
crc32_end_result () -> long @R14R15_32
crc32_start ()
crc32_update (ubyte value)
diff (ubyte v1 @A, ubyte v2 @Y) -> ubyte @A
@@ -161,20 +182,21 @@ math {
log2 (ubyte value @A) -> ubyte @Y
log2w (uword value @AY) -> ubyte @Y
mul16_last_upper () -> uword @AY
mul32 (uword a, uword b) -> long
randrange (ubyte n) -> ubyte
randrange_rom (ubyte n) -> ubyte
randrangew (uword n) -> uword
randrangew_rom (uword n) -> uword
rnd () -> clobbers (Y) -> ubyte @A
rnd_rom () -> clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rndseed_rom (uword seed1 @AY, uword seed2 @R0) -> clobbers (A,Y)
rnd () clobbers (Y) -> ubyte @A
rnd_rom () clobbers (Y) -> ubyte @A
rndseed (uword seed1 @AY, uword seed2 @R0) clobbers (A,Y)
rndseed_rom (uword seed1 @AY, uword seed2 @R0) clobbers (A,Y)
rndw () -> uword @AY
rndw_rom () -> uword @AY
sin8 (ubyte angle @A) -> clobbers (Y) -> byte @A
sin8u (ubyte angle @A) -> clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) -> clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) -> clobbers (Y) -> ubyte @A
sin8 (ubyte angle @A) clobbers (Y) -> byte @A
sin8u (ubyte angle @A) clobbers (Y) -> ubyte @A
sinr8 (ubyte radians @A) clobbers (Y) -> byte @A
sinr8u (ubyte radians @A) clobbers (Y) -> ubyte @A
}
@@ -186,11 +208,11 @@ sorting {
gnomesort_by_uw (uword uw_keys, uword wordvalues, ubyte num_elements)
gnomesort_ub (^^ubyte bytearray @AY, ubyte num_elements @X)
gnomesort_uw (uword wordvalues, ubyte num_elements)
shellsort_by_ub (^^ubyte ub_keys, uword wordvalues, ubyte num_elements)
shellsort_by_uw (uword uw_keys, uword wordvalues, ubyte num_elements)
shellsort_by_ub (^^ubyte ub_keys, ^^uword wordvalues, ubyte num_elements)
shellsort_by_uw (^^uword uw_keys, ^^uword wordvalues, ubyte num_elements)
shellsort_pointers (uword pointers, ubyte num_elements, uword comparefunc)
shellsort_ub (^^ubyte values, ubyte num_elements)
shellsort_uw (uword values, ubyte num_elements)
shellsort_uw (^^uword values, ubyte num_elements)
string_comparator (str string1 @R0, str string2 @R1) -> bool @Pc
}
@@ -199,10 +221,10 @@ LIBRARY MODULE NAME: strings
----------------------------
strings {
append (str target @R0, str suffix @R1) -> clobbers (Y) -> ubyte @A
compare (str string1 @R0, str string2 @AY) -> clobbers (Y) -> byte @A
append (str target @R0, str suffix @R1) clobbers (Y) -> ubyte @A
compare (str string1 @R0, str string2 @AY) clobbers (Y) -> byte @A
contains (str string @AY, ubyte character @X) -> bool @Pc
copy (str source @R0, str target @AY) -> clobbers (A) -> ubyte @Y
copy (str source @R0, str target @AY) clobbers (A) -> ubyte @Y
endswith (str st, str suffix) -> bool
find (str string @AY, ubyte character @X) -> ubyte @A, bool @Pc
find_eol (str string @AY) -> ubyte @A, bool @Pc
@@ -214,21 +236,21 @@ strings {
isprint (ubyte petsciichar @A) -> bool @Pc
isspace (ubyte petsciichar @A) -> bool @Pc
isupper (ubyte petsciichar @A) -> bool @Pc
left (str source @AX, ubyte length @Y, str target @R1) -> clobbers (A,Y)
length (str string @AY) -> clobbers (A) -> ubyte @Y
left (str source @AX, ubyte length @Y, str target @R1) clobbers (A,Y)
length (str string @AY) clobbers (A) -> ubyte @Y
lower (str st @AY) -> ubyte @Y
lowerchar (ubyte character @A) -> ubyte @A
lstrip (str s)
lstripped (str s) -> str
ltrim (str s)
ltrimmed (str s) -> str
ncompare (str string1 @R0, str string2 @AY, ubyte length @X) -> clobbers (X,Y) -> byte @A
pattern_match (str string @AY, str pattern @R0) -> clobbers (Y) -> bool @A
ncompare (str string1 @R0, str string2 @AY, ubyte length @X) clobbers (X,Y) -> byte @A
pattern_match (str string @AY, str pattern @R0) clobbers (Y) -> bool @A
rfind (str string @AY, ubyte character @X) -> ubyte @A, bool @Pc
right (str source @AY, ubyte length @X, str target @R1) -> clobbers (A,Y)
right (str source @AY, ubyte length @X, str target @R1) clobbers (A,Y)
rstrip (str s)
rtrim (str s)
slice (str source @R0, ubyte start @A, ubyte length @Y, str target @R1) -> clobbers (A,Y)
slice (str source @R0, ubyte start @A, ubyte length @Y, str target @R1) clobbers (A,Y)
startswith (str st, str prefix) -> bool
strip (str s)
trim (str s)
@@ -252,20 +274,22 @@ cbm {
&ubyte TIME_HI
&ubyte TIME_LO
&ubyte TIME_MID
CHKIN (ubyte logical @X) -> clobbers (A,X) -> bool @Pc = $ffc6
CHKOUT (ubyte logical @X) -> clobbers (A,X) = $ffc9
CHRIN () -> clobbers (X,Y) -> ubyte @A = $ffcf
CHKIN (ubyte logical @X) clobbers (A,X) -> bool @Pc = $ffc6
CHKOUT (ubyte logical @X) clobbers (A,X) = $ffc9
CHRIN () clobbers (X,Y) -> ubyte @A = $ffcf
CHROUT (ubyte character @A) = $ffd2
CLALL () -> clobbers (A,X) = $ffe7
CLRCHN () -> clobbers (A,X) = $ffcc
GETIN () -> clobbers (X,Y) -> bool @Pc, ubyte @A = $ffe4
GETIN2 () -> clobbers (X,Y) -> ubyte @A
CLALL () clobbers (A,X) = $ffe7
CLRCHN () clobbers (A,X) = $ffcc
GETIN () clobbers (X,Y) -> bool @Pc, ubyte @A = $ffe4
GETIN2 () clobbers (X,Y) -> ubyte @A
RDTIM () -> ubyte @A, ubyte @X, ubyte @Y
RDTIM16 () -> clobbers (X) -> uword @AY
RDTIM16 () clobbers (X) -> uword @AY
RDTIML () clobbers (X) -> long @R0R1_32
SETTIM (ubyte low @A, ubyte middle @X, ubyte high @Y)
STOP () -> clobbers (X) -> bool @Pz, ubyte @A = $ffe1
STOP2 () -> clobbers (A,X) -> bool @Pz
UDTIM () -> clobbers (A,X) = $ffea
SETTIML (long jiffies @R0R1_32)
STOP () clobbers (X) -> bool @Pz, ubyte @A = $ffe1
STOP2 () clobbers (A,X) -> bool @Pz
UDTIM () clobbers (A,X) = $ffea
kbdbuf_clear ()
}
@@ -289,25 +313,28 @@ sys {
const ubyte target
clear_carry ()
clear_irqd ()
cpu_is_65816 () -> bool
disable_caseswitch ()
enable_caseswitch ()
exit (ubyte returnvalue @A)
exit2 (ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y)
exit3 (ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc)
get_as_returnaddress (uword address @XY) -> uword @AX
internal_stringcopy (str source @R0, str target @AY) -> clobbers (A,Y)
internal_stringcopy (str source @R0, str target @AY) clobbers (A,Y)
irqsafe_clear_irqd ()
irqsafe_set_irqd ()
memcmp (uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A
memcopy (uword source @R0, uword target @R1, uword count @AY) -> clobbers (A,X,Y)
memset (uword mem @R0, uword numbytes @R1, ubyte value @A) -> clobbers (A,X,Y)
memsetw (uword mem @R0, uword numwords @R1, uword value @AY) -> clobbers (A,X,Y)
memcopy (uword source @R0, uword target @R1, uword count @AY) clobbers (A,X,Y)
memset (uword mem @R0, uword numbytes @R1, ubyte value @A) clobbers (A,X,Y)
memsetw (uword mem @R0, uword numwords @R1, uword value @AY) clobbers (A,X,Y)
pop () -> ubyte @A
popl () -> long @R0R1_32
popw () -> uword @AY
progend () -> uword @AY
progstart () -> uword @AY
push (ubyte value @A)
push_returnaddress (uword address @XY)
pushl (long value @R0R1_32)
pushw (uword value @AY)
read_flags () -> ubyte @A
reset_system ()
@@ -316,7 +343,7 @@ sys {
set_carry ()
set_irqd ()
wait (uword jiffies @AY)
waitvsync () -> clobbers (A)
waitvsync () clobbers (A)
}
cx16 {
@@ -448,9 +475,8 @@ cx16 {
&word r9s
&byte r9sH
&byte r9sL
cpu_is_65816 () -> bool
restore_virtual_registers () -> clobbers (A,Y)
save_virtual_registers () -> clobbers (A,Y)
restore_virtual_registers () clobbers (A,Y)
save_virtual_registers () clobbers (A,Y)
}
p8_sys_startup {
@@ -477,45 +503,47 @@ txt {
bell ()
chrout (ubyte character @A) = $ffd2
clear_screen ()
clear_screenchars (ubyte character @A) -> clobbers (Y)
clear_screenchars (ubyte character @A) clobbers (Y)
clear_screencolors (ubyte color)
cls ()
color (ubyte txtcol)
fill_screen (ubyte character @A, ubyte color @Y) -> clobbers (A)
getchr (ubyte col @A, ubyte row @Y) -> clobbers (Y) -> ubyte @A
height () -> clobbers (X,Y) -> ubyte @A
fill_screen (ubyte character @A, ubyte color @Y) clobbers (A)
getchr (ubyte col @A, ubyte row @Y) clobbers (Y) -> ubyte @A
height () clobbers (X,Y) -> ubyte @A
home ()
input_chars (^^ubyte buffer @AY) -> clobbers (A) -> ubyte @Y
input_chars (^^ubyte buffer @AY) clobbers (A) -> ubyte @Y
lowercase ()
nl ()
petscii2scr (ubyte petscii_char @A) -> ubyte @A
petscii2scr_str (str petscii_string @AY)
plot (ubyte col @Y, ubyte row @X)
print (str text @AY) -> clobbers (A,Y)
print_b (byte value @A) -> clobbers (A,X,Y)
print (str text @AY) clobbers (A,Y)
print_b (byte value @A) clobbers (A,X,Y)
print_bool (bool value)
print_ub (ubyte value @A) -> clobbers (A,X,Y)
print_ub0 (ubyte value @A) -> clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) -> clobbers (A,X,Y)
print_uw (uword value @AY) -> clobbers (A,X,Y)
print_uw0 (uword value @AY) -> clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) -> clobbers (A,X,Y)
print_w (word value @AY) -> clobbers (A,X,Y)
print_l (long value)
print_ub (ubyte value @A) clobbers (A,X,Y)
print_ub0 (ubyte value @A) clobbers (A,X,Y)
print_ubbin (ubyte value @A, bool prefix @Pc) clobbers (A,X,Y)
print_ubhex (ubyte value @A, bool prefix @Pc) clobbers (A,X,Y)
print_ulhex (long value, bool prefix)
print_uw (uword value @AY) clobbers (A,X,Y)
print_uw0 (uword value @AY) clobbers (A,X,Y)
print_uwbin (uword value @AY, bool prefix @Pc) clobbers (A,X,Y)
print_uwhex (uword value @AY, bool prefix @Pc) clobbers (A,X,Y)
print_w (word value @AY) clobbers (A,X,Y)
rvs_off ()
rvs_on ()
scroll_down () -> clobbers (A,X)
scroll_left () -> clobbers (A,X,Y)
scroll_right () -> clobbers (A,X)
scroll_up () -> clobbers (A,X)
scroll_down () clobbers (A,X)
scroll_left () clobbers (A,X,Y)
scroll_right () clobbers (A,X)
scroll_up () clobbers (A,X)
setcc (ubyte col, ubyte row, ubyte character, ubyte charcolor_ignored)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) -> clobbers (A,Y)
setchr (ubyte col @X, ubyte row @Y, ubyte character @A) clobbers (A,Y)
setclr (ubyte col, ubyte row, ubyte color)
spc ()
uppercase ()
waitkey () -> ubyte @A
width () -> clobbers (X,Y) -> ubyte @A
width () clobbers (X,Y) -> ubyte @A
}
@@ -1,6 +1,5 @@
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit c04908a9 in branch structs6502
Prog8 compiler v12.0 by Irmen de Jong (irmen@razorvine.net)
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-virtual.p8
@@ -74,7 +73,7 @@ LIBRARY MODULE NAME: conv
conv {
str hex_digits
str string_out
any2uword (str string) -> uword
any2uword (str string) -> uword, ubyte
bin2uword (str string) -> uword
hex2uword (str string) -> uword
internal_str_ub (ubyte value, str out_ptr)
@@ -84,10 +83,12 @@ conv {
str2uword (str string) -> uword
str2word (str string) -> word
str_b (byte value) -> str
str_l (long value) -> str
str_ub (ubyte value) -> str
str_ub0 (ubyte value) -> str
str_ubbin (ubyte value) -> str
str_ubhex (ubyte value) -> str
str_ulhex (long value) -> str
str_uw (uword value) -> str
str_uw0 (uword value) -> str
str_uwbin (uword value) -> str
@@ -203,8 +204,8 @@ math {
crc16_end () -> uword
crc16_start ()
crc16_update (ubyte value)
crc32 (^^ubyte data, uword length)
crc32_end ()
crc32 (^^ubyte data, uword length) -> long
crc32_end () -> long
crc32_start ()
crc32_update (ubyte value)
diff (ubyte b1, ubyte b2) -> ubyte
@@ -220,6 +221,7 @@ math {
log2 (ubyte value) -> ubyte
log2w (uword value) -> ubyte
mul16_last_upper () -> uword
mul32 (uword a, uword b) -> long
randrange (ubyte n) -> ubyte
randrange_rom alias for: math.randrange
randrangew (uword n) -> uword
@@ -348,6 +350,7 @@ sys {
const ubyte target
clear_carry ()
clear_irqd ()
cpu_is_65816 () -> bool
disable_caseswitch ()
enable_caseswitch ()
exit (ubyte returnvalue)
@@ -362,9 +365,11 @@ sys {
memset (uword mem, uword numbytes, ubyte value)
memsetw (uword mem, uword numwords, uword value)
pop () -> ubyte
popl () -> long
popw () -> uword
push (ubyte b)
push_returnaddress (uword w)
pushl (long l)
pushw (uword w)
read_flags () -> ubyte
reset_system ()
@@ -540,10 +545,12 @@ txt {
print_b (byte value)
print_bool (bool value)
print_f alias for: floats.print
print_l (long value)
print_ub (ubyte value)
print_ub0 (ubyte value)
print_ubbin (ubyte value, bool prefix)
print_ubhex (ubyte value, bool prefix)
print_ulhex (long value, bool prefix)
print_uw (uword value)
print_uw0 (uword value)
print_uwbin (uword value, bool prefix)
+9 -6
View File
@@ -55,7 +55,7 @@ The most interesting gradle commands to run are probably the ones listed below.
``./gradlew installShadowDist``
Creates a 'fat-jar' that contains the compiler and all dependencies, in a single
executable .jar file, and includes few start scripts to run it.
The output can be found in ``.compiler/build/install/compiler-shadow/``
The output can be found in ``.compiler/build/install/prog8c-shadow/``
``./gradlew shadowDistZip``
Creates a zipfile with the above in it, for easy distribution.
This file can be found in ``./compiler/build/distributions/``
@@ -102,7 +102,7 @@ If you are on Linux, there's probably a "64tass" package in the repositories, bu
A **Java runtime (jre or jdk), version 11 or newer** is required to run the prog8 compiler itself. Version 17 or higher if you want to
build the compiler from source.
If you're scared of Oracle's licensing terms, get one of the versions of another vendor. Even Microsoft provides their own version.
Other OpenJDK builds can be found at `Adoptium <https://adoptium.net/temurin/releases/?version=11>`_ .
Other OpenJDK builds can be found at `Adoptium <https://adoptium.net/temurin/releases>`_ .
For MacOS you can also use the Homebrew system to install a recent version of OpenJDK.
@@ -162,10 +162,6 @@ One or more .p8 module files
Add this user-defined symbol directly to the beginning of the generated assembly file.
Can be repeated to define multiple symbols.
``-dontsplitarrays``
Treat all word arrays as tagged with @nosplit so they are all stored linearly in memory,
instead of splitting them in separate lsb and msb arrays.
``-dumpsymbols``
print a dump of the variable declarations and subroutine signatures
@@ -191,6 +187,13 @@ One or more .p8 module files
for instance uncareful use of dirty variables, or reusing the R0-R15 registers for subroutine parameters.
With this option you're basically saying: "Yes, I know I am treading on mighty thin ice here, but I don't want to be reminded about that".
``-libsearch pattern``
Search in the embedded library files for occurences of the given regex pattern.
``-libdump path``
Extract all embedded library files into the given output directory.
Note: the library source code belongs to the Prog8 project and is licensed under the GPL 3.0 software license.
``-noasm``
Do not create assembly code and output program.
Useful for debugging or doing quick syntax checks.
+49 -29
View File
@@ -18,26 +18,37 @@
# -- Project information -----------------------------------------------------
project = 'Prog8'
copyright = 'Irmen de Jong'
author = 'Irmen de Jong'
import subprocess
project = "Prog8"
copyright = "Irmen de Jong"
author = "Irmen de Jong"
def read_properties(filename):
props = {}
for line in open("../../gradle.properties").readlines():
key, value = line.split('=')
key, value = line.split("=")
props[key] = value
return props
# The short X.Y version
version = read_properties("gradle.properties")["version"]
version = read_properties("gradle.properties")["version"].strip()
# The full version, including alpha/beta/rc tags
release = version
if release.endswith("SNAPSHOT"):
commit_id = subprocess.run(
["git", "rev-parse", "HEAD"], capture_output=True, text=True, check=True
).stdout.strip()
else:
commit_id = f"v{release}"
# -- extensions
def setup(app):
# add custom css
app.add_css_file("css/customize.css")
@@ -47,24 +58,29 @@ def setup(app):
# If your documentation needs a minimal Sphinx version, state it here.
#
needs_sphinx = '5.3'
needs_sphinx = "5.3"
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [ 'sphinxcontrib.jquery', 'sphinx_rtd_dark_mode', 'sphinx.ext.imgconverter']
extensions = [
"sphinxcontrib.jquery",
"sphinx_rtd_dark_mode",
"sphinx.ext.imgconverter",
"sphinx.ext.extlinks",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
source_suffix = ".rst"
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -79,8 +95,8 @@ master_doc = 'index'
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
#highlight_language = 'none'
pygments_style = "sphinx"
# highlight_language = 'none'
# -- Options for HTML output -------------------------------------------------
@@ -88,10 +104,10 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
html_theme = "sphinx_rtd_theme"
# logo in top of sidebar
html_logo = '_static/logo_small.jpg'
html_logo = "_static/logo_small.jpg"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -102,7 +118,7 @@ html_logo = '_static/logo_small.jpg'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
@@ -118,7 +134,7 @@ html_static_path = ['_static']
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'Prog8doc'
htmlhelp_basename = "Prog8doc"
# -- Options for LaTeX output ------------------------------------------------
@@ -127,15 +143,12 @@ latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
@@ -145,8 +158,7 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'Prog8.tex', 'Prog8 Documentation',
'Irmen de Jong', 'manual'),
(master_doc, "Prog8.tex", "Prog8 Documentation", "Irmen de Jong", "manual"),
]
@@ -154,10 +166,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'prog8', 'Prog8 Documentation',
[author], 1)
]
man_pages = [(master_doc, "prog8", "Prog8 Documentation", [author], 1)]
# -- Options for Texinfo output ----------------------------------------------
@@ -166,9 +175,15 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'Prog8', 'Prog8 Documentation',
author, 'Prog8', 'One line description of project.',
'Miscellaneous'),
(
master_doc,
"Prog8",
"Prog8 Documentation",
author,
"Prog8",
"One line description of project.",
"Miscellaneous",
),
]
@@ -181,4 +196,9 @@ default_dark_mode = False
# todo_include_todos = True
suppress_warnings = ['epub.unknown_project_files', 'html.unknown_project_files']
suppress_warnings = ["epub.unknown_project_files", "html.unknown_project_files"]
extlinks = {"source": (f"https://github.com/irmen/prog8/tree/{commit_id}/%s", None)}
rst_prolog = f"""
.. |commit_id| replace:: {commit_id}
"""
+2 -1
View File
@@ -101,6 +101,7 @@ Language Features
- Supports the sixteen 'virtual' 16-bit registers R0 to R15 as defined on the Commander X16. You can look at them as general purpose global variables. These are also available on the other compilation targets!
- On the Commander X16: Support for low level system features such as Vera Fx, which includes 16x16 bits multiplication in hardware and fast memory copy and fill.
- 50 Kb of available program RAM size on the C64 by default; because Basic ROM is banked out altogether
- 41 Kb of available program RAM size on the C128 by default; because Basic ROM is banked out altogether
- Many library routines are available across compiler targets. This means that as long as you only use standard Kernal
and core prog8 library routines, it is sometimes possible to compile the *exact same program* for different machines by just changing the compilation target flag.
@@ -197,5 +198,5 @@ There is also `Box16 <https://github.com/indigodarkwolf/box16>`_ which has power
If multiple options are listed above, you can select which one you want to launch using the ``-emu`` or ``-emu2`` command line options.
**Syntax highlighting:** for a few different editors, syntax highlighting definition files are provided.
Look in the `syntax-files <https://github.com/irmen/prog8/tree/master/syntax-files>`_ directory in the github repository to find them.
Look in the :source:`syntax-files <syntax-files>` directory in the github repository to find them.
+28 -28
View File
@@ -19,7 +19,7 @@ of these library modules automatically as required.
.. note::
For full details on what is available in the libraries, please study their source code here:
https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib
:source:`compiler/res/prog8lib`
.. caution::
The resulting compiled binary program *only works on the target machine it was compiled for*.
@@ -91,16 +91,13 @@ cmp (x,y)
Normally you should just use a comparison expression (``x < y``)
lsb (x)
Get the least significant (lower) byte of the value x. Equivalent to ``x & 255``.
Get the least significant (lower) byte of the value x. Equivalent to ``x & 255`` or even ``x as ubyte``.
lsw (x)
Get the least significant (lower) word of the value x. Equivalent to ``x & 65535``.
Get the least significant (lower) word of the value x. Equivalent to ``x & 65535`` or even ``x as uword``.
msb (x)
Get the most significant (higher) byte of the word value x.
If x is a value greater than a word, it will not actually return the *highest* byte of this value,
but it will only look a the lower word part of this value and return the higher byte from that.
So you're always getting bits 8-16 of the value x: ``msb($1234)`` is $12, whereas ``msb($123456)`` is $34.
Get the most significant (highest) byte of the word or long value x.
msw (x)
Get the most significant (higher) word of the value x. For all word and byte numbers this will always result in 0.
@@ -284,10 +281,10 @@ Grouped per compilation target.
bcd
---
Decimal addition and subtraction routines. Utilize the BCD mode of the CPU.
(note: not all 6502 variants support this mode).
Decimal addition and subtraction routines, so for example $0987 + $1111 = $2098 (rather than the usual hex outcome $1a98)
Utilizes the BCD mode of the CPU (note: not all 6502 variants support this mode).
This mode is useful for example for counting decimal score in a game, to avoid costly conversion to a decimal display string:
just print the hexadecimal score representation.
just print the hexadecimal score representation. (This gets especially noticable with long integers)
Available routines:
- ``sub addb(byte a, byte b) -> byte``
@@ -295,10 +292,12 @@ Available routines:
- ``sub addw(word a, word b) -> word``
- ``sub adduw(uword a, uword b) -> uword``
- ``sub addl(long a, long b) -> long``
- ``sub addtol(^^long a, long b)`` (adds b in-place to a, saves copying values)
- ``sub subb(byte a, byte b) -> byte``
- ``sub subub(ubyte a, ubyte b) -> ubyte``
- ``sub subuw(uword a, uword b) -> uword``
- ``sub subl(long a, long b) -> long``
- ``sub subfroml(^^long a, long b)`` (subtracts b in-place from a, saves copying values)
bmx (cx16 only)
@@ -311,7 +310,7 @@ The routines are designed to be fast and bulk load/save the data directly into o
without the need to buffer something in main memory.
For details about what routines are available, have a look at
the `bmx source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/bmx.p8>`_ .
the :source:`bmx source code <compiler/res/prog8lib/cx16/bmx.p8>` .
There's also the "showbmx" example to look at.
@@ -323,7 +322,7 @@ Stack is a LIFO container, ringbuffers are FIFO containers.
On the Commander X16 the stack and ringbuffer will use a HiRAM bank instead of system ram,
you have to initialize that via the init(bank) routine.
Read the `buffers source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/diskio.p8>`_
Read the :source:`buffers source code <compiler/res/prog8lib/diskio.p8>`
to see what's in there. Note that the init() routines have that extra bank parameter on the X16.
@@ -413,7 +412,8 @@ Routines to convert strings to numbers or vice versa.
- numbers to strings, in various formats (binary, hex, decimal)
- strings in decimal, hex and binary format into numbers (bytes, words)
Read the `conv source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/conv.p8>`_
Read the :source:`conv source code <compiler/res/prog8lib/conv.p8>`
to see what's in there.
@@ -424,7 +424,7 @@ A 'coroutine' is a subroutine whose execution you can pause and resume.
This library handles the voodoo for you to switch between such coroutines transparently,
so it can seem that your program is executing many subroutines at the same time.
Read the `coroutines source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/coroutines.p8>`_
Read the :source:`coroutines source code <compiler/res/prog8lib/coroutines.p8>`
to see what's in there. And look at the ``multitasking`` example to see how it can be used.
Here is a minimal example (if the library gets more stable, better docs will be written here)::
@@ -452,7 +452,7 @@ cx16
This is available on *all targets*, it is always imported as part of syslib.
On the Commander X16 this module contains a *whole bunch* of things specific to that machine.
It's way too much to include here, you have to study the
`syslib source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/syslib.p8>`_
:source:`syslib source code <compiler/res/prog8lib/cx16/syslib.p8>`
to see what is there.
On the other targets, it only contains the definition of the 16 memory-mapped virtual registers
@@ -513,7 +513,7 @@ to 16 bits, 64Kb)
Als contains routines for operating on subdirectories (chdir, mkdir, rmdir), to relabel the disk,
and to seek in open files.
Read the `diskio source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/diskio.p8>`_
Read the :source:`diskio source code <compiler/res/prog8lib/cx16/diskio.p8>`
to see what's in there. (Note: slight variations for different compiler targets)
.. note::
@@ -551,7 +551,7 @@ You have to explicitly output a character 10 on the console to see a newline the
emudbg.console_write(iso:"hello\x0a")
Read the `emudbg source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/emudbg.p8>`_
Read the :source:`emudbg source code <compiler/res/prog8lib/cx16/emudbg.p8>`
to see what's in there.
Information about the exposed debug registers is in the `emulator's documentation <https://github.com/X16Community/x16-emulator#debug-io-registers>`_.
@@ -670,8 +670,8 @@ Full-screen multicolor bitmap graphics routines, available on the X16 machine on
- flood fill
- drawing text inside the bitmap
Read the `gfx_lores source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_lores.p8>`_
or `gfx_hires source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_hires.p8>`_
Read the :source:`gfx_lores source code <compiler/res/prog8lib/cx16/gfx_lores.p8>`
or :source:`gfx_hires source code <compiler/res/prog8lib/cx16/gfx_hires.p8>`
to see what's in there.
They share the same routines.
@@ -689,7 +689,7 @@ This library is available both on the C64 and the cx16.
It uses the ROM based graphics routines on the latter, and it is a very small library because of that.
On the X16 there's also various other graphics modules if you want more features and different screen modes. See below for those.
Read the `graphics source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/c64/graphics.p8>`_
Read the :source:`graphics source code <compiler/res/prog8lib/c64/graphics.p8>`
to see what's in there. (Note: slight variations for different compiler targets)
@@ -884,7 +884,7 @@ Full-screen lores or hires monochrome bitmap graphics routines, available on the
- drawing text inside the bitmap
- can draw using a stipple pattern (alternate black/white pixels) and in invert mode (toggle pixels)
Read the `monogfx source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/monogfx.p8>`_
Read the :source:`monogfx source code <compiler/res/prog8lib/cx16/monogfx.p8>`
and the `testmonogfx` example program, to see what's in there.
@@ -898,7 +898,7 @@ and are quite different than how they looked on a VIC-II chip in a C64.
Some routines may require a colors array as @nosplit (such as fade_step_colors), otherwise wrong colors come out.
(this is the same for some kernal routines such as cx16.FB_set_palette)
Read the `palette source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/palette.p8>`_
Read the :source:`palette source code <compiler/res/prog8lib/cx16/palette.p8>`
to see what's in there.
@@ -915,7 +915,7 @@ Contains a simple abstraction for the Vera's PSG (programmable sound generator)
It includes an interrupt routine to handle simple Attack/Release envelopes as well.
See the examples/cx16/bdmusic.p8 program for ideas how to use it.
Read the `psg source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/psg.p8>`_
Read the :source:`psg source code <compiler/res/prog8lib/cx16/psg.p8>`
to see what's in there.
@@ -925,7 +925,7 @@ Various sorting routines (gnome sort and shell sort variants) for byte, word and
API is experimental and may change or disappear in a future version.
**NOTE:** all word and str arrays have to be @nosplit! Words and pointers need to be consecutive in memory for now.
**NOTE:** sorting is done in ascending order.
Read the `sorting source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/sorting.p8>`_
Read the :source:`sorting source code <compiler/res/prog8lib/sorting.p8>`
to see what's in there. Also check out the `sortingbech` example.
@@ -937,7 +937,7 @@ That's why they control one sprite at a time. The exception is the ``pos_batch``
which is quite efficient to update sprite positions of multiple sprites in one go.
See the examples/cx16/sprites/dragon.p8 and dragons.p8 programs for ideas how to use it.
Read the `sprites source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/sprites.p8>`_
Read the :source:`sprites source code <compiler/res/prog8lib/cx16/sprites.p8>`
to see what's in there.
@@ -1081,7 +1081,7 @@ Many of these definitions overlap for the C64 and Commander X16 targets so it is
to write programs that work on both targets without modifications.
This module is usually imported automatically and can provide definitions in the ``sys``, ``cbm``, ``c64``, ``cx16``, ``c128`` blocks
depending on the chosen compilation target. Read the `sys lib source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib>`_ for the correct compilation target to see exactly what is there.
depending on the chosen compilation target. Read the :source:`sys lib source code <compiler/res/prog8lib>` for the correct compilation target to see exactly what is there.
sys (part of syslib)
@@ -1249,7 +1249,7 @@ dealing with text-based input and output (to the screen). Such as
All routines work with Screencode character encoding, except `print`, `chrout` and `input_chars`,
these work with PETSCII encoding instead.
Read the `textio source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/textio.p8>`_
Read the :source:`textio source code <compiler/res/prog8lib/cx16/textio.p8>`
to see what's in there. (Note: slight variations for different compiler targets)
@@ -1293,6 +1293,6 @@ Available for the Cx16 target. Routines that use the Vera FX logic to accelerate
Set transparent write mode for VeraFX cached writes and also for normal writes to DATA0/DATA.
If enabled, pixels with value 0 do not modify VRAM when written (so they are "transparent")
Read the `verafx source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/verafx.p8>`_
Read the :source:`verafx source code <compiler/res/prog8lib/cx16/verafx.p8>`
to see what's in there.
+14 -4
View File
@@ -757,6 +757,14 @@ The expression form is also available for the conditionals ``if_cc``, ``if_cs``,
ubyte carryvalue = if_cs 1 else 0
**Optional ``then``:**
For readability reasons it is allowed to put a ``then`` keyword between the condition expression and the first value expression.
In the example above the separation between the two is still kinda obvious, but readability may be less clear with cases
like the following where the value and the last part of the condition are both numeric::
if value<999 888 else 777 ; slightly hard to read
if value<999 then 888 else 777 ; separation is clearer
on .. goto / on .. call statement (jump table)
@@ -927,14 +935,15 @@ within parentheses will be evaluated first. So ``(4 + 8) * 2`` is 24 and not 20,
and ``(true or false) and false`` is false instead of true.
.. attention::
**calculations keep their datatype even if the target variable is larger:**
**calculations keep their datatype even if the target variable is larger (unless it's a constant):**
When you do calculations on a BYTE type, the result will remain a BYTE.
When you do calculations on a WORD type, the result will remain a WORD.
For instance::
byte b = 44
; for the sake of this example: make sure this is not optimized away as a constant
byte @shared b = 44
word w = b*55 ; the result will be 116! (even though the target variable is a word)
w *= 999 ; the result will be -15188 (the multiplication stays within a word, but overflows)
w *= 999 ; the result will be -15188 (stays within a word, but overflows)
*The compiler does NOT warn about this!* It's doing this for
performance reasons - so you won't get sudden 16 bit (or even float)
@@ -942,7 +951,8 @@ and ``(true or false) and false`` is false instead of true.
If you do need the extended resulting value, cast at least one of the
operands explicitly to the larger datatype. For example::
byte b = 44
; for the sake of this example: make sure this is not optimized away as a constant
byte @shared b = 44
w = (b as word)*55
w = b*(55 as word)
+1 -1
View File
@@ -2,7 +2,7 @@
Software written in Prog8
*************************
Apart from the many `examples <https://github.com/irmen/prog8/tree/master/examples>`_ available in the source code repository,
Apart from the many :source:`examples <examples>` available in the source code repository,
there are also larger pieces of software written using Prog8. Here's a list.
+1 -1
View File
@@ -73,7 +73,7 @@ So the syntax for declaring typed pointers looks like this:
``^^type[size]``: array with size size containing pointers to a type.
So for example; ``^^word[100] values`` declares values to be an array of 100 pointers to words.
Note that an array of pointers (regardless of the type they point to) is always a @split word array at this time.
Note that an array of pointers (regardless of the type they point to) is always a split word array.
(this is the most efficient way to access the pointers, and they need to be copied to zeropage first to
be able to use them anyway. It also allows for arrays of up to 256 pointers instead of 128.)
+1 -1
View File
@@ -43,7 +43,7 @@ programs for new machines or existing ones it doesn't yet know about.
The configuration file should be a "properties" file (Java's ubiquitous configuration file format), which is basically a text file containing "key=value" lines.
The contents of the file is pretty extensive and it's easier to just look at some examples that are already included:
`target configuration examples <https://github.com/irmen/prog8/tree/master/examples/customtarget/>`_ .
:source:`target configuration examples <examples/customtarget/>` .
The filename base part (the part before any suffix) of the target configuration file will be taken as the name of the compilation target.
If it matches one of the existing built-in compilation targets, the internal library files for that target will also be searched,
if the user supplied library location doesn't contain a replacement library file for anything that might get imported.
+5 -5
View File
@@ -69,7 +69,7 @@ On the Commodore 64 some custom code is also emitted that toggle the banks, reta
Other compilation targets don't have banking or prog8 doesn't yet support automatic bank selection on them.
There's a "banking" example for the Commander X16 that shows a possible application
of the extsub with bank support, check out the `bank example code <https://github.com/irmen/prog8/tree/master/examples/cx16/banking>`_ .
of the extsub with bank support, check out the :source:`bank example code <examples/cx16/banking>` .
Notice that the symbol for this routine in the assembly source code will still be defined as usual.
@@ -129,8 +129,8 @@ All elements in scoped names such as ``main.routine.var1`` are prefixed so this
}}
Subroutine Calling Convention
-----------------------------
Subroutine Calling Conventions
------------------------------
Calling a subroutine requires three steps:
@@ -191,7 +191,7 @@ Other: ``sub foo(ubyte bar, ubyte baz, ubyte zoo) { ... }``
- A byte return value will be put in ``A`` .
- A boolean return value will be put in ``A`` too, as 0 or 1.
- A word return or pointer value will be put in ``A`` + ``Y`` register pair (lsb in A, msb in Y).
- A long return value will be put into ``cx16.r0 : cx16.r1`` (2 combined word registers to make up a single 32 bits long)
- A long return value will be put into ``cx16.r14`` and ``cx16.r15`` (2 word virtual registers, low word and high word, to make up a single 32 bits long)
- A float return value will be put in the ``FAC1`` float 'register'.
In case of *multiple* return values:
@@ -273,7 +273,7 @@ See it as a simple way of *profiling* your program to find the hotspots that may
The X16 emulator has a ``-memorystats`` option that enables it to keep track of memory access count statistics,
and write the accumulated counts to a file on exit.
Prog8 then provides a Python script ``profiler.py`` (find it in the "scripts" subdirectory of the source code distribution,
or `online here <https://github.com/irmen/prog8/blob/master/scripts/profiler.py>`_).
or :source:`online here <scripts/profiler.py>`).
This script cross-references the memory stats file with an assembly listing of the program, produced by the Prog8 compiler with the ``-asmlist`` option.
It then prints the top N lines in your (assembly) program source that perform the most reads and writes,
which you can use to identify possible hot spots/bottlenecks/variables that should be better placed in zeropage etc.
+41 -28
View File
@@ -1,10 +1,14 @@
TODO
====
LONG TYPE
---------
- implement the other comparison operators (<,>,<=,>=) on longs
- implement LONG testcases in testmemory
- implement the TODO in assignPointerDerefExpression()
- implement inplaceLongAdd/Sub in PointerAssignmentGen to make this compile::
struct Node {
long x
}
^^Node np = 20000
np.x += cx16.r0
STRUCTS and TYPED POINTERS
@@ -12,7 +16,7 @@ STRUCTS and TYPED POINTERS
- implement the remaining TODO's in PointerAssignmentsGen.
- optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0
- optimize the float copying in assignIndexedPointer() (also word?)
- optimize the float copying in assignIndexedPointer() (also word and long?)
- optimize augmented assignments to indexed pointer targets like sprptr[2]^^.y++ (these are now not performend in-place but as a regular assignment)
- implement even more struct instance assignments (via memcopy) in CodeDesugarer (see the TODO) (add to documentation as well, paragraph 'Structs')
- support @nosplit pointer arrays?
@@ -24,17 +28,22 @@ STRUCTS and TYPED POINTERS
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
- make $8000000 a valid long integer (-2147483648) this is more involved than you think. To make this work: long \|= $80000000
- make memory mapped variables support more constant expressions such as: &uword MyHigh = &mylong1+2
- fix the line, cols in Position, sometimes they count from 0 sometimes from 1, should both always be 1-based (is this the reason some source lines end up missing in the IR file?)
- handle Alias in a general way in LiteralsToAutoVarsAndRecombineIdentifiers instead of replacing it scattered over multiple functions
- After long variable type is completed: make all constants long by default (remove type name altogether), reduce to target type implictly if the actual value fits.
This will break some existing programs that depend on value wrap arounds, but gives more intuitive constant number handling.
Can give descriptive error message for old syntax that still includes the type name?
- improve ANTLR grammar with better error handling (as suggested by Qwen AI)
- allow memory() to occur in array initializer
- fix carry bit for cmp(long), check if it even worked for cmp(word)...
- add documentation for more library modules instead of just linking to the source code
- add an Index to the documentation
- allow memory() to occur in array initializer (maybe needed for 2 dimensional arrays?)
- Two- or even multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays?
- when a complete block is removed because unused, suppress all info messages about everything in the block being removed
- fix the line, cols in Position, sometimes they count from 0 sometimes from 1
- is "checkAssignmentCompatible" redundant (gets called just 1 time!) when we also have "checkValueTypeAndRange" ?
- enums?
- fix the c64 multiplexer example
- romable: should we have a way to explicitly set the memory address for the BSS area (add a -varsaddress and -slabsaddress options?)
- romable: fix remaining codegens (some for loops, see ForLoopsAsmGen)
- Kotlin: can we use inline value classes in certain spots? (domain types instead of primitives)
@@ -46,18 +55,20 @@ Future Things and Ideas
in certain situations (need examples!), the "wrong" order of evaluation of function call arguments is done which results
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEvaluating() and argumentsViaRegisters().
- Does it make codegen easier if everything is an expression? Start with the PtProgram ast classes, change statements to expressions that have (new) VOID data type
- Does it make codegen easier if everything is an expression? Start with the PtProgram ast classes, change statements to expressions that have (new) VOID data type. BUT probably not worth it if a new codegen is going to be based on the IR
- Can we support signed % (remainder) somehow?
- Multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays. Probaby only useful once we have typed pointers. (addressed in 'struct' branch)
- make a form of "manual generics" possible like: varsub routine(T arg)->T where T is expanded to a specific type
(this is already done hardcoded for several of the builtin functions)
- [much work:] more support for (64tass) SEGMENTS in the prog8 syntax itself?
- more support for (64tass) SEGMENTS in the prog8 syntax itself? maybe %segment blah in blocks?
- ability to use a sub instead of only a var for @bank ? what for though? dynamic bank/overlay loading?
- Zig-like try-based error handling where the V flag could indicate error condition? and/or BRK to jump into monitor on failure? (has to set BRK vector for that) But the V flag is also set on certain normal instructions
IR/VM
-----
- getting it in shape for code generation...: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)
- fix call() return value handling (... what's wrong with it again?)
- proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
- is it possible to use LOADFIELD/STOREFIELD instructions even more?
- make multiple classes of registers and maybe also categorize by life time , to prepare for better register allocation in the future
SYSCALL_ARGS, // Reserved for syscall arguments (r99000-99099, r99100-99199)
@@ -77,33 +88,31 @@ IR/VM
- Warm Registers: Moderately accessed
- Cold Registers: Rarely accessed (can be spilled to memory if needed)
We already have type-based pools
- byte, word, float registers
- byte, word, long, float registers
- pointer dt's are all reduced to just an uword (in the irTypeString method) - is this okay or could it be beneficial to reintroduce the actual pointer type information? See commit 88b074c208450c58aa32469745afa03e4c5f564a
- change the instruction format so an indirect register (a pointer) can be used more often, at least for the inplace assignment operators that operate on pointer
- getting it in shape for code generation...: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)
- fix call() return value handling (... what's wrong with it again?)
- proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
- register reuse to reduce the number of required variables in memory eventually. But can only re-use a register if a) it's the same type and b) if the second occurrence is not called from the first occurrence (otherwise the value gets overwritten!)
- reduce register usage via linear-scan algorithm (based on live intervals) https://anoopsarkar.github.io/compilers-class/assets/lectures/opt3-regalloc-linearscan.pdf
don't forget to take into account the data type of the register when it's going to be reused!
- encode asmsub/extsub clobber info in the call , or maybe include these definitions in the p8ir file itself too. (return registers are already encoded in the CALL instruction)
- implement fast code paths for TODO("inplace split....
- implement more TODOs in AssignmentGen
- do something with the 'split' tag on split word arrays
- add more optimizations in IRPeepholeOptimizer
- reduce register usage via linear-scan algorithm (based on live intervals) https://anoopsarkar.github.io/compilers-class/assets/lectures/opt3-regalloc-linearscan.pdf
don't forget to take into account the data type of the register when it's going to be reused!
- idea: (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
- idea: replace all scalar variables that are not @shared by an allocated register. Keep a table of the variable to register mapping (including the datatype)
global initialization values are simply a list of LOAD instructions.
Variables replaced include all subroutine parameters? Or not? So the only variables that remain as variables are arrays and strings.
- the @split arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line.
- the split word arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line.
maybe another representation is needed once actual codegeneration is done from the IR...? Should array operations be encoded in a more high level form in the IR?
- ExpressionCodeResult: get rid of the separation between single result register and multiple result registers? maybe not, this requires hundreds of lines to change.. :(
- sometimes source lines end up missing in the output p8ir, for example the first assignment is gone in:
- sometimes source lines end up missing in the output p8ir, for example the first assignment is gone in::
sub start() {
cx16.r0L = cx16.r1 as ubyte
cx16.r0sL = cx16.r1s as byte }
more detailed example:
not all source lines are correctly reported in the IR file,
More detailed example: not all source lines are correctly reported in the IR file,
for example the below subroutine only shows the sub() line::
sub two() {
@@ -112,13 +121,15 @@ for example the below subroutine only shows the sub() line::
and for example the below code omits line 5::
[examples/test.p8: line 4 col 6-8] sub start() {
[examples/test.p8: line 6 col 10-13] cx16.r2 = select2()
[examples/test.p8: line 7 col 10-13] cx16.r3 = select3()
[examples/test.p8: line 8 col 10-13] cx16.r4 = select4()
[examples/test.p8: line 9 col 10-13] cx16.r5 = select5()
[examples/test.p8: line 4 col 6-8] sub start() {
[examples/test.p8: line 6 col 10-13] cx16.r2 = select2()
[examples/test.p8: line 7 col 10-13] cx16.r3 = select3()
[examples/test.p8: line 8 col 10-13] cx16.r4 = select4()
[examples/test.p8: line 9 col 10-13] cx16.r5 = select5()
.. code-block::
%option enable_floats
main {
@@ -168,10 +179,12 @@ Libraries
Optimizations
-------------
- optimize inplaceLongShiftRight() for byte aligned cases
- more optimized operator handling of different types, for example uword a ^ byte b now does a type cast of b to word first
- optimize longEqualsValue() for const and variable operands to not assign needlessly to R0-R3.
- optimize optimizedBitwiseExpr() for const and variable operands to not assign needlessly to R0-R3.
- optimize inplacemodificationLongWithLiteralval() for more shift values such as 8, 16, 24 etc but take sign bit into account!
- optimize simple cases in funcPeekL and funcPokeL
- Port benchmarks from https://thred.github.io/c-bench-64/ to prog8 and see how it stacks up.
- Since fixing the missing zp-var initialization, programs grew in size again because STZ's reappeared. Can we add more intelligent (and correct!) optimizations to remove those STZs that might be redundant again?
- in Identifier: use typedarray of strings instead of listOf? Other places?
+15 -13
View File
@@ -243,13 +243,19 @@ to be done on word values, and don't want to explicitly have to cast everything
.. attention::
Not all operations on Long integers are supported at the moment, although most common
operations should work fine.
operations should work fine. Notably absent for now are multiplication and division of longs.
There is no unsigned long type at the moment, but you can sometimes simply treat the signed
long value as an unsigned 32 bits value just fine.
Operations on long integers take a lot of instructions on 8 bit cpu's so code that uses them
a lot will be much slower than when you restrict yourself to 8 or 16 bit values. Use long values sparingly.
**Several operations on long values require the use of the R0 and R1 virtual register as temporary storage**
so if you are working with long values, you should assume that the contents of R0 and R1 are destroyed.
.. danger::
**longs and cx16.R12,R13,R14,R15**:
**Some operations on long values require the use of the R12-R15 virtual register as temporary storage**
So if you are working with long values, you should assume that the contents of R12-R15 could be destroyed.
()Many operations preserve the values, but not all because of reasons)
**Using R12,R13,R14,R15 in expressions that work with longs, will sometimes give a corrupted result, without
a warning of the compiler!** It is strongly advised to *not* use R12-R15 at all when dealing with longs.
Booleans
@@ -358,7 +364,7 @@ See also :ref:`pointervars` and the chapter about it :ref:`pointers`.
**LSB/MSB split word and str arrays:**
As an optimization, (u)word arrays and str arrays are split by the compiler in memory as two separate arrays,
As an optimization, (u)word arrays, pointer arrays, and str arrays are split by the compiler in memory as two separate arrays,
one with the LSBs and one with the MSBs of the word values. This is more efficient to access by the 6502 cpu.
It also allows a maximum length of 256 for word arrays, where normally it would have been 128.
@@ -366,18 +372,14 @@ For normal prog8 array indexing, the compiler takes care of the distiction for y
*But for assembly code, or code that otherwise accesses the array elements directly, you have to be aware of the distinction from 'normal' arrays.*
In the assembly code, the array is generated as two byte arrays namely ``name_lsb`` and ``name_msb``, immediately following eachother in memory.
The ``@split`` tag can be added to the variable declaration to *always* split the array even when the command line option -dontsplitarrays is set
The ``@nosplit`` tag can be added to the variable declaration to *never* split the array. This is useful for compatibility with
The ``@nosplit`` tag can be added to the variable declaration to *not* split the array. This is useful for compatibility with
code that expects the words to be sequentially in memory (such as the cx16.FB_set_palette routine).
There is a command line option ``-dontsplitarrays`` that avoids splitting word arrays by default,
so every word array is layed out sequentially in memory (this is what older versions of Prog8 used to do).immediately
It reduces the maximum word array length to 128. You can still override this by adding ``@split`` explicitly.
.. note::
Most but not all array operations are supported yet on "split word arrays".
If you get a compiler error message, simply revert to a regular sequential word array using ``@nosplit``,
and please report the issue.
Some obscure array operations may not yet be supported on "split word arrays".
If you get a compiler error message hinting that this is the case,
simply revert to a regular sequential word array using ``@nosplit``, and please report the issue so that
the missing function can be added.
.. note::
Array literals are stored as split arrays if they're initializing a split word array, otherwise,
+1 -1
View File
@@ -81,7 +81,7 @@ main {
; TODO keep working with the previously sorted result instead of rewriting the list every time, makes sorting faster if not much changes in the Y positions
}
; TODO remove this simplistic anim but it's here to test the algorithms
; TODO remove this simplistic animation but it's here to test the algorithms
sprite = sprites[0]
sprite.y++
sort_ypositions[0] = sprites[0].y
+6 -3
View File
@@ -36,7 +36,7 @@ irq {
; Here is the actual multiplexing routine.
; it's a raster irq just after the start of the sprite,
; that updates the Y position of all the sprits,
; and registers a new rater irq for that next row of sprites.
; and registers a new raster irq for that next row of sprites.
; If the bottom of the screen is reached, it resets the X position of the sprites as well,
; and moves the sprites back to the top of the screen.
sub multiplexer() -> bool {
@@ -48,15 +48,18 @@ irq {
sprites_Y = sprites.sprites_Y_start
first_sprite_X++
if first_sprite_X >= 340
first_sprite_X =0
first_sprite_X = 0
sprites.set_sprites_Y(sprites_Y)
while c64.RASTER != cx16.r2 {
; wait until raster line after sprite has been fully drawn (at least 24 lines down)
; wait until raster line after sprites have been fully drawn (at least 24 lines down)
}
sprites.set_sprites_X(first_sprite_X) ; we can now update the X positions without risk of sprite tearing
system_irq = true
} else {
; only set the new Y positions. But it's possible to change other attributes as well ofcourse (colors, x-position, data)
; but raster timing is critical for that if you want to avoid tearing and glitches. Can probably not be done here at this raster position...
sprites.set_sprites_Y(sprites_Y)
c64.SPXY[0]++
}
sys.set_rasterline(sprites_Y+1)
+66 -64
View File
@@ -10,22 +10,20 @@
main {
^^uword palette = memory("palette", 256*2, 0)
^^ubyte closest = memory("closest", 4096, 0)
ubyte[256] fadeLUT ; for each of the 256 colors in the palette, give the color index of the closest 1 step darker color.
const ubyte WIDTH = 40
const ubyte HEIGHT = 30
sub start() {
fill_default_palette()
txt.print("\nprecalc color fade table, patience plz ")
precalc_fade_table()
cx16.set_screen_mode(128)
cx16.GRAPH_set_colors(0,0,0)
cx16.GRAPH_clear()
cx16.VERA_L1_CONFIG |= %1000 ; T256C on!
txt.t256c(true) ; to allow characters to use all 256 colors in the palette instead of just the first 16
ubyte x,y
for y in 0 to HEIGHT-1 {
for x in 0 to WIDTH-1 {
@@ -33,18 +31,15 @@ main {
}
}
sys.wait(60)
sys.wait(30)
repeat {
repeat 4 sys.waitvsync()
for y in 0 to HEIGHT-1 {
for x in 0 to WIDTH-1 {
ubyte @zp currentcolor = txt.getclr(x,y)
cx16.r0L = closest[darken(palette[currentcolor])]
if cx16.r0L>0 and cx16.r0L == currentcolor
cx16.r0L = 15 ; to avoid stuck colors, make it gray, this will be able to fade to black because the pallette contains all shades of gray.
txt.setclr(x,y, cx16.r0L)
; this can be done much faster using Vera's auto increment mode, but for the sake of clarity, we'll do it like this
txt.setclr(x,y, fadeLUT[txt.getclr(x,y)])
}
txt.setcc2(math.rnd() % WIDTH, math.rnd() % HEIGHT, math.rnd(), math.rnd()) ; add new chars
@@ -52,62 +47,69 @@ main {
}
}
sub precalc_fade_table() {
uword colorindex
ubyte r,g,b
alias color = cx16.r2
for r in 0 to 15 {
txt.print_ub(16-r)
txt.spc()
for g in 0 to 15 {
for b in 0 to 15 {
color = mkword(r, g<<4 | b)
closest[colorindex] = find_closest(color)
colorindex++
sub precalc_fade_table() {
txt.print("\nprecalc color fade table, patience plz")
fill_default_palette()
ubyte index
for index in 0 to 255 {
fadeLUT[index] = find_darker(index)
}
sub fill_default_palette() {
ubyte pal_bank
uword pal_addr
pal_bank, pal_addr = cx16.get_default_palette() ; needs ROM 49+
cx16.push_rombank(pal_bank)
sys.memcopy(pal_addr, palette, 256*2)
cx16.pop_rombank()
}
sub find_darker(ubyte color_index) -> ubyte {
uword darker_rgb = darken(palette[index])
if darker_rgb == 0
return 0
ubyte closest, second
closest, second = find_2_closest_colorindexes(darker_rgb)
if closest == color_index
return second ; to avoid stuck colors
return closest
}
sub darken(uword color @R0) -> uword {
if cx16.r0H!=0
cx16.r0H--
if cx16.r0L & $0f != 0
cx16.r0L--
if cx16.r0L & $f0 != 0
cx16.r0L -= $10
return cx16.r0
}
sub find_2_closest_colorindexes(uword rgb @R0) -> ubyte, ubyte {
ubyte distance = 255
ubyte current
ubyte second = 15
alias index = cx16.r1L
for index in 0 to 255 {
uword @zp pc = palette[index]
ubyte @zp d2 = abs(msb(pc) as byte - msb(rgb) as byte) ; RED distance
d2 += abs((lsb(pc) & $f0) as byte - (lsb(rgb) & $f0) as byte) >> 4 ; GREEN distance
d2 += abs((lsb(pc) & $0f) as byte - (lsb(rgb) & $0f) as byte) ; BLUE distance
if d2==0
return index, second
if d2 < distance {
distance = d2
second = current
current = index
}
}
return current, second
}
}
sub darken(uword color @R0) -> uword {
if cx16.r0H!=0
cx16.r0H--
if cx16.r0L & $0f != 0
cx16.r0L--
if cx16.r0L & $f0 != 0
cx16.r0L -= $10
return cx16.r0
}
sub find_closest(uword rgb @R0) -> ubyte {
ubyte distance = 255
ubyte current = 0
alias index = cx16.r1L
for index in 0 to 255 {
uword @zp pc = palette[index]
ubyte @zp d2 = abs(msb(pc) as byte - msb(rgb) as byte) ; RED distance
d2 += abs((lsb(pc) & $f0) as byte - (lsb(rgb) & $f0) as byte) >> 4 ; GREEN distance
d2 += abs((lsb(pc) & $0f) as byte - (lsb(rgb) & $0f) as byte) ; BLUE distance
if d2==0
return index
if d2 < distance {
distance = d2
current = index
}
}
return current
}
sub fill_default_palette() {
ubyte pal_bank
uword pal_addr
pal_bank, pal_addr = cx16.get_default_palette() ; needs ROM 49+
cx16.push_rombank(pal_bank)
sys.memcopy(pal_addr, palette, 256*2)
cx16.pop_rombank()
}
}
Loaded 100 of 116 files, more files were not shown because too many files have changed in this diff. Show more