mirror of
https://github.com/irmen/prog8.git
synced 2026-10-22 20:02:27 +00:00
Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
513ee25432 | ||
|
|
be74290ddc | ||
|
|
a36501a9ed | ||
|
|
ee5d33a230 | ||
|
|
a8fd66cfdb | ||
|
|
f5ce744748 | ||
|
|
68066acdec | ||
|
|
6286035d89 | ||
|
|
9a37eb9146 | ||
|
|
307796f115 | ||
|
|
e962431139 | ||
|
|
b7620abc9a | ||
|
|
d2719d23f5 | ||
|
|
d69eead6d8 | ||
|
|
6db3611d93 | ||
|
|
a84320c7e2 | ||
|
|
dfc720557c | ||
|
|
32149d073a | ||
|
|
fc38be6376 | ||
|
|
13f6efc1d1 | ||
|
|
8296002887 | ||
|
|
424b89f357 | ||
|
|
4f5590fbff | ||
|
|
598e70c49a | ||
|
|
a6d051b496 | ||
|
|
796d3242e1 | ||
|
|
1e8ff6f82a | ||
|
|
07bb5c36bd | ||
|
|
7e26ecb0b6 | ||
|
|
0c59ad70d4 | ||
|
|
53ce688cc5 | ||
|
|
bb8b44d9d0 | ||
|
|
51ae32d23e | ||
|
|
c873fac0dc | ||
|
|
f0a67fff8a | ||
|
|
f85ccd837d | ||
|
|
396fcbc927 | ||
|
|
0f564b301d | ||
|
|
f4f34fc2ed | ||
|
|
f7639cb78f | ||
|
|
f5f5aef722 | ||
|
|
d6e30d8468 | ||
|
|
37afdf5a18 | ||
|
|
5eb7074172 | ||
|
|
9aff280d10 | ||
|
|
44741a8e32 | ||
|
|
37535f2913 | ||
|
|
ec9475c308 | ||
|
|
b961ce97d6 | ||
|
|
4ed92d71a7 | ||
|
|
3e1386a987 | ||
|
|
4195e3968a | ||
|
|
961095bfec |
No files matched your search
@@ -193,3 +193,12 @@ For instance here's a well known space ship animated in 3D with hidden line remo
|
||||
in the CommanderX16 emulator:
|
||||
|
||||

|
||||
|
||||
|
||||
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)
|
||||
@@ -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 .
|
||||
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 |
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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(""),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
bcd {
|
||||
; virtual machine does not support BCD
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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() }
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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""")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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}
|
||||
"""
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
@@ -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.)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
Reference in new issue
Block a user