mirror of
https://github.com/irmen/prog8.git
synced 2025-07-22 22:24:10 +00:00
Compare commits
1 Commits
structs
...
structs-wi
Author | SHA1 | Date | |
---|---|---|---|
|
df56be32b2 |
@@ -19,7 +19,7 @@ class StatementOptimizer(private val program: Program,
|
|||||||
val functionName = functionCallStatement.target.nameInSource[0]
|
val functionName = functionCallStatement.target.nameInSource[0]
|
||||||
if (functionName in functions.purefunctionNames) {
|
if (functionName in functions.purefunctionNames) {
|
||||||
if("ignore_unused" !in parent.definingBlock.options())
|
if("ignore_unused" !in parent.definingBlock.options())
|
||||||
errors.warn("statement has no effect (function return value is discarded)", functionCallStatement.position)
|
errors.info("statement has no effect (function return value is discarded)", functionCallStatement.position)
|
||||||
return listOf(IAstModification.Remove(functionCallStatement, parent as IStatementContainer))
|
return listOf(IAstModification.Remove(functionCallStatement, parent as IStatementContainer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -376,7 +376,7 @@ hline_filled_right .byte 0, %10000000, %11000000, %11100000, %11110000, %1111
|
|||||||
_ormask .byte 128, 64, 32, 16, 8, 4, 2, 1
|
_ormask .byte 128, 64, 32, 16, 8, 4, 2, 1
|
||||||
|
|
||||||
; note: this can be even faster if we also have a 320 word x-lookup table, but hey, that's a lot of memory.
|
; note: this can be even faster if we also have a 320 word x-lookup table, but hey, that's a lot of memory.
|
||||||
; see https://codebase64.net/doku.php?id=base:various_techniques_to_calculate_adresses_fast_common_screen_formats_for_pixel_graphics
|
; see http://codebase64.org/doku.php?id=base:various_techniques_to_calculate_adresses_fast_common_screen_formats_for_pixel_graphics
|
||||||
; the y lookup tables encodes this formula: BITMAP_ADDRESS + 320*(py>>3) + (py & 7) (y from 0..199)
|
; the y lookup tables encodes this formula: BITMAP_ADDRESS + 320*(py>>3) + (py & 7) (y from 0..199)
|
||||||
; We use the 64tass syntax for range expressions to calculate this table on assembly time.
|
; We use the 64tass syntax for range expressions to calculate this table on assembly time.
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
;
|
;
|
||||||
; some more interesting routines can be found here:
|
; some more interesting routines can be found here:
|
||||||
; http://6502org.wikidot.com/software-math
|
; http://6502org.wikidot.com/software-math
|
||||||
; https://codebase64.net/doku.php?id=base:6502_6510_maths
|
; http://codebase64.org/doku.php?id=base:6502_6510_maths
|
||||||
; https://github.com/TobyLobster/multiply_test
|
; https://github.com/TobyLobster/multiply_test
|
||||||
; https://github.com/TobyLobster/sqrt_test
|
; https://github.com/TobyLobster/sqrt_test
|
||||||
|
|
||||||
@@ -353,7 +353,7 @@ _divisor .word ?
|
|||||||
randword .proc
|
randword .proc
|
||||||
; -- 16 bit pseudo random number generator into AY
|
; -- 16 bit pseudo random number generator into AY
|
||||||
; default seed = $00c2 $1137. NOTE: uses self-modifying code so won't work in ROM (use randword_rom instead)
|
; default seed = $00c2 $1137. NOTE: uses self-modifying code so won't work in ROM (use randword_rom instead)
|
||||||
; routine from https://codebase64.net/doku.php?id=6502_6510_maths:x_abc_random_number_generator_8_16_bit
|
; routine from https://codebase64.org/doku.php?id=base:x_abc_random_number_generator_8_16_bit
|
||||||
inc x1
|
inc x1
|
||||||
clc
|
clc
|
||||||
x1=*+1
|
x1=*+1
|
||||||
@@ -377,7 +377,7 @@ b1=*+1
|
|||||||
randword_rom .proc
|
randword_rom .proc
|
||||||
; -- 16 bit pseudo random number generator into AY. Can run from ROM.
|
; -- 16 bit pseudo random number generator into AY. Can run from ROM.
|
||||||
; NOTE: you have to set the initial seed using randseed_rom! (a good default seed = $00c2 $1137)
|
; NOTE: you have to set the initial seed using randseed_rom! (a good default seed = $00c2 $1137)
|
||||||
; routine from https://codebase64.net/doku.php?id=6502_6510_maths:x_abc_random_number_generator_8_16_bit
|
; routine from https://codebase64.org/doku.php?id=base:x_abc_random_number_generator_8_16_bit
|
||||||
inc _x1
|
inc _x1
|
||||||
clc
|
clc
|
||||||
lda _x1
|
lda _x1
|
||||||
|
@@ -380,7 +380,7 @@ _quadrant_region_to_direction:
|
|||||||
asmsub atan2(ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A {
|
asmsub atan2(ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A {
|
||||||
;; Calculate the angle, in a 256-degree circle, between two points into A.
|
;; Calculate the angle, in a 256-degree circle, between two points into A.
|
||||||
;; The points (x1, y1) and (x2, y2) have to use *unsigned coordinates only* from the positive quadrant in the carthesian plane!
|
;; The points (x1, y1) and (x2, y2) have to use *unsigned coordinates only* from the positive quadrant in the carthesian plane!
|
||||||
;; http://codebase64.net/doku.php?id=base:8bit_atan2_8-bit_angle
|
;; https://www.codebase64.org/doku.php?id=base:8bit_atan2_8-bit_angle
|
||||||
;; This uses 2 large lookup tables so uses a lot of memory but is super fast.
|
;; This uses 2 large lookup tables so uses a lot of memory but is super fast.
|
||||||
|
|
||||||
%asm {{
|
%asm {{
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
compression {
|
compression {
|
||||||
|
|
||||||
sub decode_rle(^^ubyte @zp compressed, ^^ubyte @zp target, uword maxsize) -> uword {
|
sub decode_rle(uword @zp compressed, uword @zp target, uword maxsize) -> uword {
|
||||||
cx16.r0 = target ; original target
|
cx16.r0 = target ; original target
|
||||||
cx16.r1 = target+maxsize ; decompression limit
|
cx16.r1 = target+maxsize ; decompression limit
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ compression {
|
|||||||
return target-cx16.r0
|
return target-cx16.r0
|
||||||
}
|
}
|
||||||
|
|
||||||
sub encode_rle(^^ubyte data, uword size, ^^ubyte target, bool is_last_block) -> uword {
|
sub encode_rle(uword data, uword size, uword target, bool is_last_block) -> uword {
|
||||||
; -- Compress the given data block using ByteRun1 aka PackBits RLE encoding.
|
; -- Compress the given data block using ByteRun1 aka PackBits RLE encoding.
|
||||||
; Returns the size of the compressed RLE data. Worst case result storage size needed = (size + (size+126) / 127) + 1.
|
; Returns the size of the compressed RLE data. Worst case result storage size needed = (size + (size+126) / 127) + 1.
|
||||||
; is_last_block = usually true, but you can set it to false if you want to concatenate multiple
|
; is_last_block = usually true, but you can set it to false if you want to concatenate multiple
|
||||||
@@ -39,7 +39,7 @@ compression {
|
|||||||
uword idx = 0
|
uword idx = 0
|
||||||
uword literals_start_idx = 0
|
uword literals_start_idx = 0
|
||||||
ubyte literals_length = 0
|
ubyte literals_length = 0
|
||||||
^^ubyte orig_target = target
|
uword orig_target = target
|
||||||
|
|
||||||
sub next_same_span() {
|
sub next_same_span() {
|
||||||
; returns length in cx16.r1L, and the byte value in cx16.r1H
|
; returns length in cx16.r1L, and the byte value in cx16.r1H
|
||||||
@@ -54,7 +54,7 @@ compression {
|
|||||||
sub output_literals() {
|
sub output_literals() {
|
||||||
@(target) = literals_length-1
|
@(target) = literals_length-1
|
||||||
target++
|
target++
|
||||||
^^ubyte dataptr = data + literals_start_idx
|
uword dataptr = data + literals_start_idx
|
||||||
ubyte i
|
ubyte i
|
||||||
for i in 0 to literals_length-1 {
|
for i in 0 to literals_length-1 {
|
||||||
@(target) = @(dataptr)
|
@(target) = @(dataptr)
|
||||||
|
@@ -29,7 +29,7 @@ sub str_ub(ubyte value) -> str {
|
|||||||
|
|
||||||
sub str_b(byte value) -> str {
|
sub str_b(byte value) -> str {
|
||||||
; ---- convert the byte in A in decimal string form, without left padding 0s
|
; ---- convert the byte in A in decimal string form, without left padding 0s
|
||||||
^^ubyte out_ptr = &string_out
|
uword out_ptr = &string_out
|
||||||
if value<0 {
|
if value<0 {
|
||||||
@(out_ptr) = '-'
|
@(out_ptr) = '-'
|
||||||
out_ptr++
|
out_ptr++
|
||||||
@@ -39,7 +39,7 @@ sub str_b(byte value) -> str {
|
|||||||
return string_out
|
return string_out
|
||||||
}
|
}
|
||||||
|
|
||||||
sub internal_str_ub(ubyte value, str out_ptr) {
|
sub internal_str_ub(ubyte value, uword out_ptr) {
|
||||||
ubyte hundreds = value / 100
|
ubyte hundreds = value / 100
|
||||||
value -= hundreds*100
|
value -= hundreds*100
|
||||||
ubyte tens = value / 10
|
ubyte tens = value / 10
|
||||||
@@ -73,7 +73,7 @@ sub str_ubhex (ubyte value) -> str {
|
|||||||
|
|
||||||
sub str_ubbin (ubyte value) -> str {
|
sub str_ubbin (ubyte value) -> str {
|
||||||
; ---- convert the ubyte in A in binary string form
|
; ---- convert the ubyte in A in binary string form
|
||||||
^^ubyte out_ptr = &string_out
|
uword out_ptr = &string_out
|
||||||
repeat 8 {
|
repeat 8 {
|
||||||
rol(value)
|
rol(value)
|
||||||
if_cc
|
if_cc
|
||||||
@@ -88,7 +88,7 @@ sub str_ubbin (ubyte value) -> str {
|
|||||||
|
|
||||||
sub str_uwbin (uword value) -> str {
|
sub str_uwbin (uword value) -> str {
|
||||||
; ---- convert the uword in A/Y in binary string form
|
; ---- convert the uword in A/Y in binary string form
|
||||||
^^ubyte out_ptr = &string_out
|
uword out_ptr = &string_out
|
||||||
repeat 16 {
|
repeat 16 {
|
||||||
rol(value)
|
rol(value)
|
||||||
if_cc
|
if_cc
|
||||||
@@ -142,7 +142,7 @@ sub str_uw (uword value) -> str {
|
|||||||
|
|
||||||
sub str_w (word value) -> str {
|
sub str_w (word value) -> str {
|
||||||
; ---- convert the (signed) word in A/Y in decimal string form, without left padding 0's
|
; ---- convert the (signed) word in A/Y in decimal string form, without left padding 0's
|
||||||
^^ubyte out_ptr = &string_out
|
uword out_ptr = &string_out
|
||||||
if value<0 {
|
if value<0 {
|
||||||
@(out_ptr) = '-'
|
@(out_ptr) = '-'
|
||||||
out_ptr++
|
out_ptr++
|
||||||
@@ -152,7 +152,7 @@ sub str_w (word value) -> str {
|
|||||||
return string_out
|
return string_out
|
||||||
}
|
}
|
||||||
|
|
||||||
sub internal_str_uw(uword value, str out_ptr) {
|
sub internal_str_uw(uword value, uword out_ptr) {
|
||||||
uword value2 = value/10
|
uword value2 = value/10
|
||||||
ubyte digits = value-value2*10 as ubyte
|
ubyte digits = value-value2*10 as ubyte
|
||||||
uword value3 = value2/10
|
uword value3 = value2/10
|
||||||
|
@@ -24,7 +24,7 @@ diskio {
|
|||||||
|
|
||||||
; ----- iterative file loader functions (uses the input io channel) -----
|
; ----- iterative file loader functions (uses the input io channel) -----
|
||||||
|
|
||||||
sub f_open(str filenameptr) -> bool {
|
sub f_open(uword filenameptr) -> bool {
|
||||||
; -- open a file for iterative reading with f_read
|
; -- open a file for iterative reading with f_read
|
||||||
; note: only a single iteration loop can be active at a time!
|
; note: only a single iteration loop can be active at a time!
|
||||||
; Returns true if the file is successfully opened and readable.
|
; Returns true if the file is successfully opened and readable.
|
||||||
@@ -39,7 +39,7 @@ diskio {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub f_read(str bufferpointer, uword num_bytes) -> uword {
|
sub f_read(uword bufferpointer, uword num_bytes) -> uword {
|
||||||
; -- read from the currently open file, up to the given number of bytes.
|
; -- read from the currently open file, up to the given number of bytes.
|
||||||
; returns the actual number of bytes read. (checks for End-of-file and error conditions)
|
; returns the actual number of bytes read. (checks for End-of-file and error conditions)
|
||||||
uword actual
|
uword actual
|
||||||
@@ -57,7 +57,7 @@ diskio {
|
|||||||
return actual
|
return actual
|
||||||
}
|
}
|
||||||
|
|
||||||
sub f_read_all(str bufferpointer) -> uword {
|
sub f_read_all(uword bufferpointer) -> uword {
|
||||||
; -- read the full rest of the file, returns number of bytes read.
|
; -- read the full rest of the file, returns number of bytes read.
|
||||||
; It is assumed the file size is less than 64 K.
|
; It is assumed the file size is less than 64 K.
|
||||||
; Usually you will just be using load() / load_raw() to read entire files!
|
; Usually you will just be using load() / load_raw() to read entire files!
|
||||||
@@ -75,7 +75,7 @@ diskio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub f_readline(str bufptr) -> ubyte {
|
sub f_readline(uword bufptr) -> ubyte {
|
||||||
; Routine to read text lines from a text file. Lines must be less than 255 characters.
|
; Routine to read text lines from a text file. Lines must be less than 255 characters.
|
||||||
; Reads characters from the input file UNTIL a newline or return character, or 0 byte (likely EOF).
|
; Reads characters from the input file UNTIL a newline or return character, or 0 byte (likely EOF).
|
||||||
; The line read will be 0-terminated in the buffer (and not contain the end of line character).
|
; The line read will be 0-terminated in the buffer (and not contain the end of line character).
|
||||||
@@ -119,7 +119,7 @@ diskio {
|
|||||||
|
|
||||||
; ----- iterative file writing functions (uses write io channel) -----
|
; ----- iterative file writing functions (uses write io channel) -----
|
||||||
|
|
||||||
sub f_open_w(str filenameptr) -> bool {
|
sub f_open_w(uword filenameptr) -> bool {
|
||||||
; -- open a file for iterative writing with f_write
|
; -- open a file for iterative writing with f_write
|
||||||
; WARNING: returns true if the open command was received by the device,
|
; WARNING: returns true if the open command was received by the device,
|
||||||
; but this can still mean the file wasn't successfully opened for writing!
|
; but this can still mean the file wasn't successfully opened for writing!
|
||||||
@@ -133,13 +133,13 @@ diskio {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub f_write(str bufferpointer, uword num_bytes) -> bool {
|
sub f_write(uword bufferpointer, uword num_bytes) -> bool {
|
||||||
; -- write the given number of bytes to the currently open file
|
; -- write the given number of bytes to the currently open file
|
||||||
; you can call this multiple times to append more data
|
; you can call this multiple times to append more data
|
||||||
repeat num_bytes {
|
repeat num_bytes {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r99000,diskio.f_write.bufferpointer
|
loadm.w r0,diskio.f_write.bufferpointer
|
||||||
loadi.b r99100,r99000
|
loadi.b r99100,r0
|
||||||
syscall 55 (r99100.b): r99100.b
|
syscall 55 (r99100.b): r99100.b
|
||||||
storem.b r99100,$ff02
|
storem.b r99100,$ff02
|
||||||
}}
|
}}
|
||||||
@@ -185,7 +185,7 @@ diskio {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub curdir() -> str {
|
sub curdir() -> uword {
|
||||||
; return current directory name or 0 if error
|
; return current directory name or 0 if error
|
||||||
%ir {{
|
%ir {{
|
||||||
syscall 48 (): r99000.w
|
syscall 48 (): r99000.w
|
||||||
@@ -204,7 +204,7 @@ diskio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub save(str filenameptr, uword start_address, uword savesize) -> bool {
|
sub save(uword filenameptr, uword start_address, uword savesize) -> bool {
|
||||||
%ir {{
|
%ir {{
|
||||||
load.b r99100,0
|
load.b r99100,0
|
||||||
loadm.w r99000,diskio.save.filenameptr
|
loadm.w r99000,diskio.save.filenameptr
|
||||||
@@ -216,12 +216,12 @@ diskio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
; like save() but omits the 2 byte prg header.
|
; like save() but omits the 2 byte prg header.
|
||||||
sub save_raw(str filenameptr, uword start_address, uword savesize) -> bool {
|
sub save_raw(uword filenameptr, uword startaddress, uword savesize) -> bool {
|
||||||
%ir {{
|
%ir {{
|
||||||
load.b r99100,1
|
load.b r99100,1
|
||||||
loadm.w r99000,diskio.save_raw.filenameptr
|
loadm.w r99000,diskio.save.filenameptr
|
||||||
loadm.w r99001,diskio.save_raw.start_address
|
loadm.w r99001,diskio.save.start_address
|
||||||
loadm.w r99002,diskio.save_raw.savesize
|
loadm.w r99002,diskio.save.savesize
|
||||||
syscall 42 (r99100.b, r99000.w, r99001.w, r99002.w): r99100.b
|
syscall 42 (r99100.b, r99000.w, r99001.w, r99002.w): r99100.b
|
||||||
returnr.b r99100
|
returnr.b r99100
|
||||||
}}
|
}}
|
||||||
@@ -233,7 +233,7 @@ diskio {
|
|||||||
; If you specify a custom address_override, the first 2 bytes in the file are ignored
|
; If you specify a custom address_override, the first 2 bytes in the file are ignored
|
||||||
; and the rest is loaded at the given location in memory.
|
; and the rest is loaded at the given location in memory.
|
||||||
; Returns the end load address+1 if successful or 0 if a load error occurred.
|
; Returns the end load address+1 if successful or 0 if a load error occurred.
|
||||||
sub load(str filenameptr, uword address_override) -> uword {
|
sub load(uword filenameptr, uword address_override) -> uword {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r99000,diskio.load.filenameptr
|
loadm.w r99000,diskio.load.filenameptr
|
||||||
loadm.w r99001,diskio.load.address_override
|
loadm.w r99001,diskio.load.address_override
|
||||||
@@ -245,7 +245,7 @@ diskio {
|
|||||||
; Identical to load(), but DOES INCLUDE the first 2 bytes in the file.
|
; Identical to load(), but DOES INCLUDE the first 2 bytes in the file.
|
||||||
; No program header is assumed in the file. Everything is loaded.
|
; No program header is assumed in the file. Everything is loaded.
|
||||||
; See comments on load() for more details.
|
; See comments on load() for more details.
|
||||||
sub load_raw(str filenameptr, uword start_address) -> uword {
|
sub load_raw(uword filenameptr, uword start_address) -> uword {
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r99000,diskio.load_raw.filenameptr
|
loadm.w r99000,diskio.load_raw.filenameptr
|
||||||
loadm.w r99001,diskio.load_raw.start_address
|
loadm.w r99001,diskio.load_raw.start_address
|
||||||
@@ -254,7 +254,7 @@ diskio {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub delete(str filenameptr) {
|
sub delete(uword filenameptr) {
|
||||||
; -- delete a file on the drive
|
; -- delete a file on the drive
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r99000,diskio.delete.filenameptr
|
loadm.w r99000,diskio.delete.filenameptr
|
||||||
@@ -262,7 +262,7 @@ diskio {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub rename(str oldfileptr, str newfileptr) {
|
sub rename(uword oldfileptr, uword newfileptr) {
|
||||||
; -- rename a file on the drive
|
; -- rename a file on the drive
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r99000,diskio.rename.oldfileptr
|
loadm.w r99000,diskio.rename.oldfileptr
|
||||||
|
@@ -316,7 +316,7 @@ math {
|
|||||||
return w2-w1
|
return w2-w1
|
||||||
}
|
}
|
||||||
|
|
||||||
sub crc16(^^ubyte data, uword length) -> uword {
|
sub crc16(uword data, uword length) -> uword {
|
||||||
; calculates the CRC16 (XMODEM) checksum of the buffer.
|
; calculates the CRC16 (XMODEM) checksum of the buffer.
|
||||||
; There are also "streaming" crc16_start/update/end routines below, that allow you to calculate crc32 for data that doesn't fit in a single memory block.
|
; There are also "streaming" crc16_start/update/end routines below, that allow you to calculate crc32 for data that doesn't fit in a single memory block.
|
||||||
crc16_start()
|
crc16_start()
|
||||||
@@ -353,7 +353,7 @@ math {
|
|||||||
return cx16.r15
|
return cx16.r15
|
||||||
}
|
}
|
||||||
|
|
||||||
sub crc32(^^ubyte data, uword length) {
|
sub crc32(uword data, uword length) {
|
||||||
; Calculates the CRC-32 (ISO-HDLC/PKZIP) checksum of the buffer.
|
; Calculates the CRC-32 (ISO-HDLC/PKZIP) checksum of the buffer.
|
||||||
; because prog8 doesn't have 32 bits integers, we have to split up the calculation over 2 words.
|
; because prog8 doesn't have 32 bits integers, we have to split up the calculation over 2 words.
|
||||||
; result stored in cx16.r14 (low word) and cx16.r15 (high word)
|
; result stored in cx16.r14 (low word) and cx16.r15 (high word)
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
sorting {
|
sorting {
|
||||||
%option ignore_unused
|
%option ignore_unused
|
||||||
|
|
||||||
sub shellsort_ub(^^ubyte @requirezp values, ubyte num_elements) {
|
sub shellsort_ub(uword @requirezp values, ubyte num_elements) {
|
||||||
num_elements--
|
num_elements--
|
||||||
ubyte @zp gap
|
ubyte @zp gap
|
||||||
for gap in [132, 57, 23, 10, 4, 1] {
|
for gap in [132, 57, 23, 10, 4, 1] {
|
||||||
@@ -27,29 +27,29 @@ sorting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub shellsort_uw(^^uword @requirezp values, ubyte num_elements) {
|
sub shellsort_uw(uword @requirezp values, ubyte num_elements) {
|
||||||
num_elements--
|
num_elements--
|
||||||
ubyte gap
|
ubyte gap
|
||||||
for gap in [132, 57, 23, 10, 4, 1] {
|
for gap in [132, 57, 23, 10, 4, 1] {
|
||||||
ubyte i
|
ubyte i
|
||||||
for i in gap to num_elements {
|
for i in gap to num_elements {
|
||||||
uword @zp temp = values[i]
|
uword @zp temp = peekw(values+i*$0002)
|
||||||
ubyte @zp j = i
|
ubyte @zp j = i
|
||||||
ubyte @zp k = j-gap
|
ubyte @zp k = j-gap
|
||||||
while j>=gap {
|
while j>=gap {
|
||||||
uword @zp v = values[k]
|
uword @zp v = peekw(values+k*2)
|
||||||
if v <= temp break
|
if v <= temp break
|
||||||
values[j] = v
|
pokew(values+j*2, v)
|
||||||
j = k
|
j = k
|
||||||
k -= gap
|
k -= gap
|
||||||
}
|
}
|
||||||
values[j] = temp
|
pokew(values+j*2, temp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub shellsort_by_ub(^^ubyte @requirezp ub_keys, ^^uword @requirezp wordvalues, ubyte num_elements) {
|
sub shellsort_by_ub(uword @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).
|
; sorts the 'wordvalues' array (no-split array of words) according to the 'ub_keys' array (which also gets sorted ofcourse).
|
||||||
num_elements--
|
num_elements--
|
||||||
ubyte @zp gap
|
ubyte @zp gap
|
||||||
@@ -57,7 +57,7 @@ sorting {
|
|||||||
ubyte i
|
ubyte i
|
||||||
for i in gap to num_elements {
|
for i in gap to num_elements {
|
||||||
ubyte @zp temp = ub_keys[i]
|
ubyte @zp temp = ub_keys[i]
|
||||||
uword temp_wv = wordvalues[i]
|
uword temp_wv = peekw(wordvalues + i*$0002)
|
||||||
ubyte @zp j = i
|
ubyte @zp j = i
|
||||||
ubyte @zp k = j-gap
|
ubyte @zp k = j-gap
|
||||||
repeat {
|
repeat {
|
||||||
@@ -65,17 +65,17 @@ sorting {
|
|||||||
if v <= temp break
|
if v <= temp break
|
||||||
if j < gap break
|
if j < gap break
|
||||||
ub_keys[j] = v
|
ub_keys[j] = v
|
||||||
wordvalues[j] = wordvalues[k]
|
pokew(wordvalues + j*$0002, peekw(wordvalues + k*$0002))
|
||||||
j = k
|
j = k
|
||||||
k -= gap
|
k -= gap
|
||||||
}
|
}
|
||||||
ub_keys[j] = temp
|
ub_keys[j] = temp
|
||||||
wordvalues[j] = temp_wv
|
pokew(wordvalues + j*$0002, temp_wv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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).
|
; 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.
|
; both arrays should be no-split array of words. uw_keys are unsigned.
|
||||||
num_elements--
|
num_elements--
|
||||||
@@ -83,20 +83,20 @@ sorting {
|
|||||||
for gap in [132, 57, 23, 10, 4, 1] {
|
for gap in [132, 57, 23, 10, 4, 1] {
|
||||||
ubyte i
|
ubyte i
|
||||||
for i in gap to num_elements {
|
for i in gap to num_elements {
|
||||||
uword @zp temp = uw_keys[i]
|
uword @zp temp = peekw(uw_keys+i*$0002)
|
||||||
uword temp_wv = wordvalues[i]
|
uword temp_wv = peekw(wordvalues + i*$0002)
|
||||||
ubyte @zp j = i
|
ubyte @zp j = i
|
||||||
ubyte @zp k = j-gap
|
ubyte @zp k = j-gap
|
||||||
while j>=gap {
|
while j>=gap {
|
||||||
uword @zp v = uw_keys[k]
|
uword @zp v = peekw(uw_keys+k*2)
|
||||||
if v <= temp break
|
if v <= temp break
|
||||||
uw_keys[j] = v
|
pokew(uw_keys+j*2, v)
|
||||||
wordvalues[j] = wordvalues[k]
|
pokew(wordvalues + j*$0002, peekw(wordvalues + k*$0002))
|
||||||
j = k
|
j = k
|
||||||
k -= gap
|
k -= gap
|
||||||
}
|
}
|
||||||
uw_keys[j] = temp
|
pokew(uw_keys+j*2, temp)
|
||||||
wordvalues[j] = temp_wv
|
pokew(wordvalues + j*$0002, temp_wv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -82,7 +82,7 @@ strings {
|
|||||||
return 255, false
|
return 255, false
|
||||||
}
|
}
|
||||||
|
|
||||||
sub rfind(str stringptr, ubyte character) -> ubyte, bool {
|
sub rfind(uword stringptr, ubyte character) -> ubyte, bool {
|
||||||
; Locates the first position of the given character in the string, starting from the right.
|
; Locates the first position of the given character in the string, starting from the right.
|
||||||
; returns index in A, and boolean if found or not. (when false A will also be 255, an invalid index).
|
; returns index in A, and boolean if found or not. (when false A will also be 255, an invalid index).
|
||||||
ubyte ix
|
ubyte ix
|
||||||
|
@@ -48,7 +48,7 @@ sys {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub internal_stringcopy(str source, str tgt) {
|
sub internal_stringcopy(uword source, uword tgt) {
|
||||||
; Called when the compiler wants to assign a string value to another string.
|
; Called when the compiler wants to assign a string value to another string.
|
||||||
%ir {{
|
%ir {{
|
||||||
loadm.w r99000,sys.internal_stringcopy.source
|
loadm.w r99000,sys.internal_stringcopy.source
|
||||||
|
@@ -136,7 +136,7 @@ sub print_w (word value) {
|
|||||||
print(conv.str_w(value))
|
print(conv.str_w(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
sub input_chars (str buffer) -> ubyte {
|
sub input_chars (uword buffer) -> ubyte {
|
||||||
; ---- Input a string (max. 80 chars) from the keyboard. Returns length of input. (string is terminated with a 0 byte as well)
|
; ---- Input a string (max. 80 chars) from the keyboard. Returns length of input. (string is terminated with a 0 byte as well)
|
||||||
; It assumes the keyboard is selected as I/O channel!
|
; It assumes the keyboard is selected as I/O channel!
|
||||||
%ir {{
|
%ir {{
|
||||||
|
@@ -467,7 +467,7 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions
|
|||||||
errors.report()
|
errors.report()
|
||||||
program.constantFold(errors, compilerOptions)
|
program.constantFold(errors, compilerOptions)
|
||||||
errors.report()
|
errors.report()
|
||||||
program.reorderStatements(compilerOptions.compTarget, errors)
|
program.reorderStatements(errors)
|
||||||
errors.report()
|
errors.report()
|
||||||
program.desugaring(errors, compilerOptions)
|
program.desugaring(errors, compilerOptions)
|
||||||
errors.report()
|
errors.report()
|
||||||
|
@@ -82,7 +82,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkLongType(identifier)
|
|
||||||
val stmt = identifier.targetStatement(program.builtinFunctions)
|
val stmt = identifier.targetStatement(program.builtinFunctions)
|
||||||
if(stmt==null) {
|
if(stmt==null) {
|
||||||
if(identifier.parent is ArrayIndexedExpression) {
|
if(identifier.parent is ArrayIndexedExpression) {
|
||||||
@@ -172,7 +171,9 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(ifElse: IfElse) {
|
override fun visit(ifElse: IfElse) {
|
||||||
checkCondition(ifElse.condition)
|
if(!ifElse.condition.inferType(program).isBool) {
|
||||||
|
errors.err("condition should be a boolean", ifElse.condition.position)
|
||||||
|
}
|
||||||
|
|
||||||
val constvalue = ifElse.condition.constValue(program)
|
val constvalue = ifElse.condition.constValue(program)
|
||||||
if(constvalue!=null) {
|
if(constvalue!=null) {
|
||||||
@@ -360,10 +361,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
super.visit(label)
|
super.visit(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(numLiteral: NumericLiteral) {
|
|
||||||
checkLongType(numLiteral)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hasReturnOrExternalJumpOrRts(scope: IStatementContainer): Boolean {
|
private fun hasReturnOrExternalJumpOrRts(scope: IStatementContainer): Boolean {
|
||||||
class Searcher: IAstVisitor
|
class Searcher: IAstVisitor
|
||||||
{
|
{
|
||||||
@@ -494,9 +491,8 @@ internal class AstChecker(private val program: Program,
|
|||||||
errors.err("parameter '${param.first.name}' should be (u)byte or bool", param.first.position)
|
errors.err("parameter '${param.first.name}' should be (u)byte or bool", param.first.position)
|
||||||
}
|
}
|
||||||
else if(param.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
else if(param.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
||||||
if (!param.first.type.isWord && !param.first.type.isString && !param.first.type.isArray && param.first.type!=DataType.pointer(BaseDataType.UBYTE)) {
|
if (!param.first.type.isWord && !param.first.type.isString && !param.first.type.isArray)
|
||||||
err("parameter '${param.first.name}' should be (u)word, str or ^^ubyte")
|
err("parameter '${param.first.name}' should be (u)word (an address) or str")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(param.second.statusflag!=null) {
|
else if(param.second.statusflag!=null) {
|
||||||
if (!param.first.type.isBool)
|
if (!param.first.type.isBool)
|
||||||
@@ -509,8 +505,8 @@ internal class AstChecker(private val program: Program,
|
|||||||
err("return type #${index + 1} should be (u)byte")
|
err("return type #${index + 1} should be (u)byte")
|
||||||
}
|
}
|
||||||
else if(pair.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
else if(pair.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
|
||||||
if (!pair.first.isWord && !pair.first.isString && !pair.first.isArray && pair.first!=DataType.pointer(BaseDataType.UBYTE))
|
if (!pair.first.isWord && !pair.first.isString && !pair.first.isArray)
|
||||||
err("return type #${index + 1} should be (u)word/address or ^^ubyte")
|
err("return type #${index + 1} should be (u)word/address")
|
||||||
}
|
}
|
||||||
else if(pair.second.statusflag!=null) {
|
else if(pair.second.statusflag!=null) {
|
||||||
if (!pair.first.isBool)
|
if (!pair.first.isBool)
|
||||||
@@ -616,12 +612,18 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(untilLoop: UntilLoop) {
|
override fun visit(untilLoop: UntilLoop) {
|
||||||
checkCondition(untilLoop.condition)
|
if(!untilLoop.condition.inferType(program).isBool) {
|
||||||
|
errors.err("condition should be a boolean", untilLoop.condition.position)
|
||||||
|
}
|
||||||
|
|
||||||
super.visit(untilLoop)
|
super.visit(untilLoop)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(whileLoop: WhileLoop) {
|
override fun visit(whileLoop: WhileLoop) {
|
||||||
checkCondition(whileLoop.condition)
|
if(!whileLoop.condition.inferType(program).isBool) {
|
||||||
|
errors.err("condition should be a boolean", whileLoop.condition.position)
|
||||||
|
}
|
||||||
|
|
||||||
super.visit(whileLoop)
|
super.visit(whileLoop)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +802,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(addressOf: AddressOf) {
|
override fun visit(addressOf: AddressOf) {
|
||||||
checkLongType(addressOf)
|
|
||||||
val variable=addressOf.identifier?.targetVarDecl()
|
val variable=addressOf.identifier?.targetVarDecl()
|
||||||
if (variable!=null) {
|
if (variable!=null) {
|
||||||
if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null)
|
if (variable.type == VarDeclType.CONST && addressOf.arrayIndex == null)
|
||||||
@@ -816,7 +817,9 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(ifExpr: IfExpression) {
|
override fun visit(ifExpr: IfExpression) {
|
||||||
checkCondition(ifExpr.condition)
|
if(!ifExpr.condition.inferType(program).isBool)
|
||||||
|
errors.err("condition should be a boolean", ifExpr.condition.position)
|
||||||
|
|
||||||
val trueDt = ifExpr.truevalue.inferType(program)
|
val trueDt = ifExpr.truevalue.inferType(program)
|
||||||
val falseDt = ifExpr.falsevalue.inferType(program)
|
val falseDt = ifExpr.falsevalue.inferType(program)
|
||||||
if(trueDt.isUnknown || falseDt.isUnknown) {
|
if(trueDt.isUnknown || falseDt.isUnknown) {
|
||||||
@@ -827,23 +830,10 @@ internal class AstChecker(private val program: Program,
|
|||||||
super.visit(ifExpr)
|
super.visit(ifExpr)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkCondition(condition: Expression) {
|
|
||||||
if(!condition.inferType(program).isBool)
|
|
||||||
errors.err("condition should be a boolean", condition.position)
|
|
||||||
val cast = condition as? TypecastExpression
|
|
||||||
if(cast!=null && cast.type.isBool) {
|
|
||||||
if(cast.expression.inferType(program).isPointer) {
|
|
||||||
errors.err("condition should be a boolean", condition.position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visit(decl: VarDecl) {
|
override fun visit(decl: VarDecl) {
|
||||||
if(decl.names.size>1)
|
if(decl.names.size>1)
|
||||||
throw InternalCompilerException("vardecls with multiple names should have been converted into individual vardecls")
|
throw InternalCompilerException("vardecls with multiple names should have been converted into individual vardecls")
|
||||||
|
|
||||||
if(decl.datatype.isLong && decl.type!=VarDeclType.CONST)
|
|
||||||
errors.err("cannot use long type for variables; only for constants", decl.position)
|
|
||||||
if(decl.type==VarDeclType.MEMORY) {
|
if(decl.type==VarDeclType.MEMORY) {
|
||||||
if (decl.datatype.isString)
|
if (decl.datatype.isString)
|
||||||
errors.err("strings cannot be memory-mapped", decl.position)
|
errors.err("strings cannot be memory-mapped", decl.position)
|
||||||
@@ -1285,7 +1275,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkLongType(expr)
|
|
||||||
val dt = expr.expression.inferType(program).getOrUndef()
|
val dt = expr.expression.inferType(program).getOrUndef()
|
||||||
if(!dt.isUndefined) {
|
if(!dt.isUndefined) {
|
||||||
|
|
||||||
@@ -1420,8 +1409,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
checkLongType(expr)
|
|
||||||
|
|
||||||
val leftIDt = expr.left.inferType(program)
|
val leftIDt = expr.left.inferType(program)
|
||||||
val rightIDt = expr.right.inferType(program)
|
val rightIDt = expr.right.inferType(program)
|
||||||
if(!leftIDt.isKnown || !rightIDt.isKnown) {
|
if(!leftIDt.isKnown || !rightIDt.isKnown) {
|
||||||
@@ -1549,7 +1536,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(typecast: TypecastExpression) {
|
override fun visit(typecast: TypecastExpression) {
|
||||||
checkLongType(typecast)
|
|
||||||
if(typecast.type.isPassByRef)
|
if(typecast.type.isPassByRef)
|
||||||
errors.err("cannot type cast to string or array type", typecast.position)
|
errors.err("cannot type cast to string or array type", typecast.position)
|
||||||
|
|
||||||
@@ -1606,7 +1592,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(functionCallExpr: FunctionCallExpression) {
|
override fun visit(functionCallExpr: FunctionCallExpression) {
|
||||||
checkLongType(functionCallExpr)
|
|
||||||
// this function call is (part of) an expression, which should be in a statement somewhere.
|
// this function call is (part of) an expression, which should be in a statement somewhere.
|
||||||
val stmtOfExpression = findParentNode<Statement>(functionCallExpr)
|
val stmtOfExpression = findParentNode<Statement>(functionCallExpr)
|
||||||
?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCallExpr.position}")
|
?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCallExpr.position}")
|
||||||
@@ -1667,17 +1652,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(functionCallStatement: FunctionCallStatement) {
|
override fun visit(functionCallStatement: FunctionCallStatement) {
|
||||||
|
|
||||||
if(functionCallStatement.target.nameInSource.size==1) {
|
|
||||||
val functionName = functionCallStatement.target.nameInSource[0]
|
|
||||||
if (functionName in program.builtinFunctions.purefunctionNames) {
|
|
||||||
if("ignore_unused" !in functionCallStatement.parent.definingBlock.options()) {
|
|
||||||
errors.warn("statement has no effect (function return value is discarded)", functionCallStatement.position)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// most function calls, even to builtin functions, are still regular FunctionCall nodes here.
|
// most function calls, even to builtin functions, are still regular FunctionCall nodes here.
|
||||||
// they get converted to the more specialized node type in BeforeAsmTypecastCleaner
|
// they get converted to the more specialized node type in BeforeAsmTypecastCleaner
|
||||||
val targetStatement = functionCallStatement.target.checkFunctionOrLabelExists(program, functionCallStatement, errors)
|
val targetStatement = functionCallStatement.target.checkFunctionOrLabelExists(program, functionCallStatement, errors)
|
||||||
@@ -1870,7 +1844,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
args.forEach{
|
args.forEach{
|
||||||
checkLongType(it)
|
|
||||||
if(it.inferType(program).isStructInstance)
|
if(it.inferType(program).isStructInstance)
|
||||||
errors.err("structs can only be passed via a pointer", it.position)
|
errors.err("structs can only be passed via a pointer", it.position)
|
||||||
}
|
}
|
||||||
@@ -1883,7 +1856,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
|
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
|
||||||
checkLongType(arrayIndexedExpression)
|
|
||||||
val target = arrayIndexedExpression.plainarrayvar?.targetStatement(program.builtinFunctions)
|
val target = arrayIndexedExpression.plainarrayvar?.targetStatement(program.builtinFunctions)
|
||||||
if(target is VarDecl) {
|
if(target is VarDecl) {
|
||||||
if (!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer)
|
if (!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer)
|
||||||
@@ -2105,17 +2077,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
errors.err("unable to determine type of dereferenced pointer expression", deref.position)
|
errors.err("unable to determine type of dereferenced pointer expression", deref.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkLongType(expression: Expression) {
|
|
||||||
if(expression.inferType(program) issimpletype BaseDataType.LONG) {
|
|
||||||
if((expression.parent as? VarDecl)?.type!=VarDeclType.CONST) {
|
|
||||||
if (expression.parent !is RepeatLoop) {
|
|
||||||
if (errors.noErrorForLine(expression.position))
|
|
||||||
errors.err("integer overflow", expression.position)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteral) : Boolean {
|
private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteral) : Boolean {
|
||||||
return if (targetDt.isString) {
|
return if (targetDt.isString) {
|
||||||
when {
|
when {
|
||||||
|
@@ -20,8 +20,8 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
|
|||||||
checker.visit(this)
|
checker.visit(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Program.reorderStatements(target: ICompilationTarget, errors: IErrorReporter) {
|
internal fun Program.reorderStatements(errors: IErrorReporter) {
|
||||||
val reorder = StatementReorderer(this, target, errors)
|
val reorder = StatementReorderer(this, errors)
|
||||||
reorder.visit(this)
|
reorder.visit(this)
|
||||||
if(errors.noErrors()) {
|
if(errors.noErrors()) {
|
||||||
reorder.applyModifications()
|
reorder.applyModifications()
|
||||||
|
@@ -109,11 +109,6 @@ _loop:
|
|||||||
if not CONDITION
|
if not CONDITION
|
||||||
goto _loop
|
goto _loop
|
||||||
*/
|
*/
|
||||||
val error = checkCondition(untilLoop.condition)
|
|
||||||
if(error!=null) {
|
|
||||||
errors.err(error, untilLoop.condition.position)
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
val pos = untilLoop.position
|
val pos = untilLoop.position
|
||||||
val loopLabel = program.makeLabel("untilloop", pos)
|
val loopLabel = program.makeLabel("untilloop", pos)
|
||||||
val replacement = AnonymousScope(mutableListOf(
|
val replacement = AnonymousScope(mutableListOf(
|
||||||
@@ -127,27 +122,6 @@ if not CONDITION
|
|||||||
return listOf(IAstModification.ReplaceNode(untilLoop, replacement, parent))
|
return listOf(IAstModification.ReplaceNode(untilLoop, replacement, parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
|
|
||||||
val dt = expr.expression.inferType(program).getOrUndef()
|
|
||||||
if(dt.isPointerArray || dt.isPointer) {
|
|
||||||
errors.err("pointers don't support prefix operators", expr.position)
|
|
||||||
}
|
|
||||||
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkCondition(condition: Expression): String? {
|
|
||||||
if(!condition.inferType(program).isBool)
|
|
||||||
return "condition should be a boolean"
|
|
||||||
val cast = condition as? TypecastExpression
|
|
||||||
if(cast!=null && cast.type.isBool) {
|
|
||||||
if(cast.expression.inferType(program).isPointer) {
|
|
||||||
return "condition should be a boolean"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> {
|
override fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -155,12 +129,6 @@ if not CONDITION
|
|||||||
while false -> discard
|
while false -> discard
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val error = checkCondition(whileLoop.condition)
|
|
||||||
if(error!=null) {
|
|
||||||
errors.err(error, whileLoop.condition.position)
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
val constCondition = whileLoop.condition.constValue(program)?.asBooleanValue
|
val constCondition = whileLoop.condition.constValue(program)?.asBooleanValue
|
||||||
if(constCondition==true) {
|
if(constCondition==true) {
|
||||||
errors.warn("condition is always true", whileLoop.condition.position)
|
errors.warn("condition is always true", whileLoop.condition.position)
|
||||||
@@ -763,18 +731,4 @@ _after:
|
|||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
|
|
||||||
val error = checkCondition(ifElse.condition)
|
|
||||||
if(error!=null)
|
|
||||||
errors.err(error, ifElse.condition.position)
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun after(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> {
|
|
||||||
val error = checkCondition(ifExpr.condition)
|
|
||||||
if(error!=null)
|
|
||||||
errors.err(error, ifExpr.condition.position)
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -198,7 +198,7 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, program: PtPro
|
|||||||
is PtNumber,
|
is PtNumber,
|
||||||
is PtRange,
|
is PtRange,
|
||||||
is PtString -> true
|
is PtString -> true
|
||||||
is PtIdentifier -> true // actually PtIdentifier IS "complex" this time (it's a variable that might change) but it's kinda annoying to give a warning message for this very common case
|
// note that unlike most other times, PtIdentifier IS "complex" this time (it's a variable that might change)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,11 +5,13 @@ import prog8.ast.expressions.*
|
|||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.code.core.*
|
import prog8.code.core.AssociativeOperators
|
||||||
|
import prog8.code.core.BaseDataType
|
||||||
|
import prog8.code.core.DataType
|
||||||
|
import prog8.code.core.IErrorReporter
|
||||||
|
|
||||||
internal class StatementReorderer(
|
internal class StatementReorderer(
|
||||||
val program: Program,
|
val program: Program,
|
||||||
val target: ICompilationTarget,
|
|
||||||
val errors: IErrorReporter
|
val errors: IErrorReporter
|
||||||
) : AstWalker() {
|
) : AstWalker() {
|
||||||
// Reorders the statements in a way the compiler needs.
|
// Reorders the statements in a way the compiler needs.
|
||||||
@@ -213,16 +215,16 @@ internal class StatementReorderer(
|
|||||||
subs.map { IAstModification.InsertLast(it, subroutine) }
|
subs.map { IAstModification.InsertLast(it, subroutine) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// change 'str' and 'ubyte[]' parameters or return types into ^^ubyte (TODO also for 6502 target, that is still uword for now)
|
// change 'str' and 'ubyte[]' parameters into 'uword' (just treat it as an address)
|
||||||
val stringParams = subroutine.parameters.filter { it.type.isString || it.type.isUnsignedByteArray }
|
val stringParams = subroutine.parameters.filter { it.type.isString || it.type.isUnsignedByteArray }
|
||||||
val replacementForStrDt = if(target.cpu!=CpuType.VIRTUAL) DataType.UWORD else DataType.pointer(BaseDataType.UBYTE) // TODO fix this once 6502 has pointers too
|
|
||||||
val parameterChanges = stringParams.map {
|
val parameterChanges = stringParams.map {
|
||||||
val uwordParam = SubroutineParameter(it.name, replacementForStrDt, it.zp, it.registerOrPair, it.position)
|
val uwordParam = SubroutineParameter(it.name, DataType.UWORD, it.zp, it.registerOrPair, it.position)
|
||||||
IAstModification.ReplaceNode(it, uwordParam, subroutine)
|
IAstModification.ReplaceNode(it, uwordParam, subroutine)
|
||||||
}
|
}
|
||||||
|
// change 'str' and 'ubyte[]' return types into 'uword' (just treat it as an address)
|
||||||
subroutine.returntypes.withIndex().forEach { (index, type) ->
|
subroutine.returntypes.withIndex().forEach { (index, type) ->
|
||||||
if(type.isString || type.isUnsignedByteArray)
|
if(type.isString || type.isUnsignedByteArray)
|
||||||
subroutine.returntypes[index] = replacementForStrDt
|
subroutine.returntypes[index] = DataType.UWORD
|
||||||
}
|
}
|
||||||
|
|
||||||
val varsChanges = mutableListOf<IAstModification>()
|
val varsChanges = mutableListOf<IAstModification>()
|
||||||
|
@@ -501,19 +501,6 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
|||||||
val trueDt = ifExpr.truevalue.inferType(program)
|
val trueDt = ifExpr.truevalue.inferType(program)
|
||||||
val falseDt = ifExpr.falsevalue.inferType(program)
|
val falseDt = ifExpr.falsevalue.inferType(program)
|
||||||
if (trueDt != falseDt) {
|
if (trueDt != falseDt) {
|
||||||
|
|
||||||
val modifications = mutableListOf<IAstModification>()
|
|
||||||
|
|
||||||
// ubyte or uword combined with a pointer type -> cast BOTH to uword
|
|
||||||
if((trueDt.isPointer && falseDt.isInteger) || (falseDt.isPointer && trueDt.isInteger)) {
|
|
||||||
val leftCast = TypecastExpression(ifExpr.truevalue, DataType.UWORD, true, ifExpr.truevalue.position)
|
|
||||||
val rightCast = TypecastExpression(ifExpr.falsevalue, DataType.UWORD, true, ifExpr.falsevalue.position)
|
|
||||||
return listOf(
|
|
||||||
IAstModification.ReplaceNode(ifExpr.truevalue, leftCast, ifExpr),
|
|
||||||
IAstModification.ReplaceNode(ifExpr.falsevalue, rightCast, ifExpr)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val (commonDt, toFix) = BinaryExpression.commonDatatype(
|
val (commonDt, toFix) = BinaryExpression.commonDatatype(
|
||||||
trueDt.getOrUndef(),
|
trueDt.getOrUndef(),
|
||||||
falseDt.getOrUndef(),
|
falseDt.getOrUndef(),
|
||||||
@@ -521,11 +508,11 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
|
|||||||
ifExpr.falsevalue
|
ifExpr.falsevalue
|
||||||
)
|
)
|
||||||
if (toFix != null) {
|
if (toFix != null) {
|
||||||
|
val modifications = mutableListOf<IAstModification>()
|
||||||
addTypecastOrCastedValueModification(modifications, toFix, commonDt, ifExpr)
|
addTypecastOrCastedValueModification(modifications, toFix, commonDt, ifExpr)
|
||||||
return modifications
|
return modifications
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -178,6 +178,11 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
|||||||
return listOf(IAstModification.ReplaceNode(typecast, cmp, parent))
|
return listOf(IAstModification.ReplaceNode(typecast, cmp, parent))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (et.isPointer) {
|
||||||
|
val ptrAsUword = TypecastExpression(typecast.expression, DataType.UWORD, true, typecast.position)
|
||||||
|
val cmp = BinaryExpression(ptrAsUword, "!=", NumericLiteral.optimalNumeric(BaseDataType.UWORD, null, 0.0, typecast.position), typecast.position)
|
||||||
|
return listOf(IAstModification.ReplaceNode(typecast, cmp, parent))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
|
@@ -96,8 +96,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila
|
|||||||
|
|
||||||
// if uword is passed, check if the parameter type is pointer to array element type
|
// if uword is passed, check if the parameter type is pointer to array element type
|
||||||
if(argDt.isArray && paramDt.isPointer) {
|
if(argDt.isArray && paramDt.isPointer) {
|
||||||
if(argDt.sub==paramDt.sub)
|
TODO("array vs element pointer check")
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if expected is UWORD and actual is any pointer, we allow it (uword is untyped pointer, for backwards compatibility)
|
// if expected is UWORD and actual is any pointer, we allow it (uword is untyped pointer, for backwards compatibility)
|
||||||
|
@@ -5,7 +5,6 @@ import io.kotest.engine.spec.tempdir
|
|||||||
import io.kotest.inspectors.shouldForAll
|
import io.kotest.inspectors.shouldForAll
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.shouldNotBe
|
import io.kotest.matchers.shouldNotBe
|
||||||
import io.kotest.matchers.string.shouldContain
|
|
||||||
import prog8.ast.expressions.NumericLiteral
|
import prog8.ast.expressions.NumericLiteral
|
||||||
import prog8.ast.statements.Assignment
|
import prog8.ast.statements.Assignment
|
||||||
import prog8.ast.statements.FunctionCallStatement
|
import prog8.ast.statements.FunctionCallStatement
|
||||||
@@ -14,7 +13,6 @@ import prog8.code.core.BuiltinFunctions
|
|||||||
import prog8.code.core.RegisterOrPair
|
import prog8.code.core.RegisterOrPair
|
||||||
import prog8.code.core.isNumeric
|
import prog8.code.core.isNumeric
|
||||||
import prog8.code.target.Cx16Target
|
import prog8.code.target.Cx16Target
|
||||||
import prog8tests.helpers.ErrorReporterForTests
|
|
||||||
import prog8tests.helpers.compileText
|
import prog8tests.helpers.compileText
|
||||||
|
|
||||||
class TestBuiltinFunctions: FunSpec({
|
class TestBuiltinFunctions: FunSpec({
|
||||||
@@ -105,31 +103,5 @@ main {
|
|||||||
|
|
||||||
compileText(Cx16Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null
|
compileText(Cx16Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("warning for return value discarding of pure functions") {
|
|
||||||
val src="""
|
|
||||||
main {
|
|
||||||
sub start() {
|
|
||||||
word @shared ww = 2222
|
|
||||||
|
|
||||||
abs(ww)
|
|
||||||
sgn(ww)
|
|
||||||
sqrt(ww)
|
|
||||||
min(ww, 0)
|
|
||||||
max(ww, 0)
|
|
||||||
clamp(ww, 0, 319)
|
|
||||||
}
|
|
||||||
}"""
|
|
||||||
|
|
||||||
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
|
|
||||||
compileText(Cx16Target(), true, src, outputDir, errors=errors, writeAssembly = false) shouldNotBe null
|
|
||||||
errors.warnings.size shouldBe 6
|
|
||||||
errors.warnings[0] shouldContain "statement has no effect"
|
|
||||||
errors.warnings[1] shouldContain "statement has no effect"
|
|
||||||
errors.warnings[2] shouldContain "statement has no effect"
|
|
||||||
errors.warnings[3] shouldContain "statement has no effect"
|
|
||||||
errors.warnings[4] shouldContain "statement has no effect"
|
|
||||||
errors.warnings[5] shouldContain "statement has no effect"
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -240,13 +240,11 @@ class TestCompilerOnExamplesVirtual: FunSpec({
|
|||||||
listOf(
|
listOf(
|
||||||
"bouncegfx",
|
"bouncegfx",
|
||||||
"bsieve",
|
"bsieve",
|
||||||
"fountain",
|
|
||||||
"pixelshader",
|
"pixelshader",
|
||||||
"sincos",
|
"sincos",
|
||||||
"pointers/animalgame",
|
"pointers/animalgame",
|
||||||
"pointers/binarytree", // TODO add to "c64" later as well
|
"pointers/binarytree", // TODO add to "c64" later as well
|
||||||
"pointers/sortedlist", // TODO add to "c64" later as well
|
"pointers/sortedlist" // TODO add to "c64" later as well
|
||||||
"pointers/fountain" // TODO add to "c64" later as well
|
|
||||||
),
|
),
|
||||||
listOf(false, true)
|
listOf(false, true)
|
||||||
)
|
)
|
||||||
|
@@ -458,36 +458,6 @@ thing {
|
|||||||
// TODO compileText(C64Target(), false, src, outputDir) shouldNotBe null
|
// TODO compileText(C64Target(), false, src, outputDir) shouldNotBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("str or ubyte array params or return type replaced by pointer to ubyte") {
|
|
||||||
val src="""
|
|
||||||
main {
|
|
||||||
sub start() {
|
|
||||||
test1("zzz")
|
|
||||||
test2("zzz")
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test1(str arg) -> str {
|
|
||||||
cx16.r0++
|
|
||||||
return cx16.r0
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test2(ubyte[] arg) {
|
|
||||||
cx16.r0++
|
|
||||||
}
|
|
||||||
}"""
|
|
||||||
|
|
||||||
// TODO check this for C64 target too
|
|
||||||
val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!!
|
|
||||||
val main = result.compilerAst.allBlocks.first {it.name=="main"}
|
|
||||||
val test1 = main.statements[1] as Subroutine
|
|
||||||
val test2 = main.statements[2] as Subroutine
|
|
||||||
test1.name shouldBe "test1"
|
|
||||||
test1.parameters.single().type shouldBe DataType.pointer(DataType.UBYTE)
|
|
||||||
test1.returntypes.single() shouldBe DataType.pointer(DataType.UBYTE)
|
|
||||||
test2.name shouldBe "test2"
|
|
||||||
test2.parameters.single().type shouldBe DataType.pointer(DataType.UBYTE)
|
|
||||||
}
|
|
||||||
|
|
||||||
test("creating instances") {
|
test("creating instances") {
|
||||||
val src="""
|
val src="""
|
||||||
main {
|
main {
|
||||||
@@ -1442,57 +1412,4 @@ main {
|
|||||||
compileText(VMTarget(), false, src, outputDir) shouldNotBe null
|
compileText(VMTarget(), false, src, outputDir) shouldNotBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("pointer cannot be used in conditional expression in shorthand form") {
|
|
||||||
val src="""
|
|
||||||
main {
|
|
||||||
sub start() {
|
|
||||||
^^word ptr
|
|
||||||
|
|
||||||
if ptr cx16.r0++
|
|
||||||
if not ptr cx16.r1++
|
|
||||||
|
|
||||||
while ptr cx16.r0++
|
|
||||||
while not ptr cx16.r1++
|
|
||||||
|
|
||||||
do cx16.r0++ until ptr
|
|
||||||
do cx16.r1++ until not ptr
|
|
||||||
|
|
||||||
cx16.r0 = if ptr 1 else 0
|
|
||||||
cx16.r1 = if not ptr 1 else 0
|
|
||||||
}
|
|
||||||
}"""
|
|
||||||
|
|
||||||
val errors=ErrorReporterForTests()
|
|
||||||
compileText(VMTarget(), false, src, outputDir, errors=errors) shouldBe null
|
|
||||||
errors.errors.size shouldBe 8
|
|
||||||
errors.errors[0] shouldContain "condition should be a boolean"
|
|
||||||
errors.errors[1] shouldContain "pointers don't support prefix operators"
|
|
||||||
errors.errors[2] shouldContain "condition should be a boolean"
|
|
||||||
errors.errors[3] shouldContain "pointers don't support prefix operators"
|
|
||||||
errors.errors[4] shouldContain "condition should be a boolean"
|
|
||||||
errors.errors[5] shouldContain "pointers don't support prefix operators"
|
|
||||||
errors.errors[6] shouldContain "condition should be a boolean"
|
|
||||||
errors.errors[7] shouldContain "pointers don't support prefix operators"
|
|
||||||
}
|
|
||||||
|
|
||||||
test("pointers in if expressions") {
|
|
||||||
val src="""
|
|
||||||
main {
|
|
||||||
sub start() {
|
|
||||||
^^word ptr
|
|
||||||
|
|
||||||
if ptr!=0
|
|
||||||
cx16.r0++
|
|
||||||
if ptr==0
|
|
||||||
cx16.r0++
|
|
||||||
|
|
||||||
cx16.r0 = if ptr!=0 0 else ptr
|
|
||||||
cx16.r1 = if ptr==0 0 else ptr
|
|
||||||
cx16.r2 = if ptr!=0 ptr else 0
|
|
||||||
cx16.r3 = if ptr==0 ptr else 0
|
|
||||||
}
|
|
||||||
}"""
|
|
||||||
compileText(VMTarget(), false, src, outputDir) shouldNotBe null
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
@@ -752,7 +752,7 @@ main {
|
|||||||
errors.errors[3] shouldContain (":9:28: value type uword doesn't match target")
|
errors.errors[3] shouldContain (":9:28: value type uword doesn't match target")
|
||||||
}
|
}
|
||||||
|
|
||||||
test("str replaced with uword in subroutine params and return types (6502 only until that has pointers too)") { // TODO remove this test once 6502 has pointers too
|
test("str replaced with uword in subroutine params and return types") {
|
||||||
val src = """
|
val src = """
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
@@ -773,12 +773,13 @@ main {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
val result = compileText(C64Target(), true, src, outputDir, writeAssembly = true)!!
|
compileText(C64Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null
|
||||||
|
val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = true)!!
|
||||||
val main = result.codegenAst!!.allBlocks().first()
|
val main = result.codegenAst!!.allBlocks().first()
|
||||||
val derp = main.children.single { it is PtSub && it.name == "p8s_derp" } as PtSub
|
val derp = main.children.single { it is PtSub && it.name == "main.derp" } as PtSub
|
||||||
derp.signature.returns shouldBe listOf(DataType.UWORD)
|
derp.signature.returns shouldBe listOf(DataType.UWORD)
|
||||||
(derp.signature.children.single() as PtSubroutineParameter).type shouldBe DataType.UWORD
|
(derp.signature.children.single() as PtSubroutineParameter).type shouldBe DataType.UWORD
|
||||||
val mult3 = main.children.single { it is PtAsmSub && it.name == "p8s_mult3" } as PtAsmSub
|
val mult3 = main.children.single { it is PtAsmSub && it.name == "main.mult3" } as PtAsmSub
|
||||||
mult3.parameters.single().second.type shouldBe DataType.UWORD
|
mult3.parameters.single().second.type shouldBe DataType.UWORD
|
||||||
mult3.returns.single().second shouldBe DataType.UWORD
|
mult3.returns.single().second shouldBe DataType.UWORD
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
|
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
|
||||||
Prerelease version from git commit 893e16d8 in branch structs
|
|
||||||
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
||||||
|
|
||||||
Compiling program import-all-c128.p8
|
Compiling program import-all-c128.p8
|
||||||
@@ -533,7 +532,6 @@ sys {
|
|||||||
const ubyte SIZEOF_BYTE
|
const ubyte SIZEOF_BYTE
|
||||||
const ubyte SIZEOF_FLOAT
|
const ubyte SIZEOF_FLOAT
|
||||||
const ubyte SIZEOF_LONG
|
const ubyte SIZEOF_LONG
|
||||||
const ubyte SIZEOF_POINTER
|
|
||||||
const ubyte SIZEOF_UBYTE
|
const ubyte SIZEOF_UBYTE
|
||||||
const ubyte SIZEOF_UWORD
|
const ubyte SIZEOF_UWORD
|
||||||
const ubyte SIZEOF_WORD
|
const ubyte SIZEOF_WORD
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
|
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
|
||||||
Prerelease version from git commit 893e16d8 in branch structs
|
|
||||||
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
||||||
|
|
||||||
Compiling program import-all-c64.p8
|
Compiling program import-all-c64.p8
|
||||||
@@ -645,7 +644,6 @@ sys {
|
|||||||
const ubyte SIZEOF_BYTE
|
const ubyte SIZEOF_BYTE
|
||||||
const ubyte SIZEOF_FLOAT
|
const ubyte SIZEOF_FLOAT
|
||||||
const ubyte SIZEOF_LONG
|
const ubyte SIZEOF_LONG
|
||||||
const ubyte SIZEOF_POINTER
|
|
||||||
const ubyte SIZEOF_UBYTE
|
const ubyte SIZEOF_UBYTE
|
||||||
const ubyte SIZEOF_UWORD
|
const ubyte SIZEOF_UWORD
|
||||||
const ubyte SIZEOF_WORD
|
const ubyte SIZEOF_WORD
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
|
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
|
||||||
Prerelease version from git commit 893e16d8 in branch structs
|
|
||||||
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
||||||
|
|
||||||
Compiling program import-all-cx16.p8
|
Compiling program import-all-cx16.p8
|
||||||
@@ -1254,7 +1253,6 @@ sys {
|
|||||||
const ubyte SIZEOF_BYTE
|
const ubyte SIZEOF_BYTE
|
||||||
const ubyte SIZEOF_FLOAT
|
const ubyte SIZEOF_FLOAT
|
||||||
const ubyte SIZEOF_LONG
|
const ubyte SIZEOF_LONG
|
||||||
const ubyte SIZEOF_POINTER
|
|
||||||
const ubyte SIZEOF_UBYTE
|
const ubyte SIZEOF_UBYTE
|
||||||
const ubyte SIZEOF_UWORD
|
const ubyte SIZEOF_UWORD
|
||||||
const ubyte SIZEOF_WORD
|
const ubyte SIZEOF_WORD
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
|
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
|
||||||
Prerelease version from git commit 893e16d8 in branch structs
|
|
||||||
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
||||||
|
|
||||||
Compiling program import-all-pet32.p8
|
Compiling program import-all-pet32.p8
|
||||||
@@ -265,7 +264,6 @@ sys {
|
|||||||
const ubyte SIZEOF_BYTE
|
const ubyte SIZEOF_BYTE
|
||||||
const ubyte SIZEOF_FLOAT
|
const ubyte SIZEOF_FLOAT
|
||||||
const ubyte SIZEOF_LONG
|
const ubyte SIZEOF_LONG
|
||||||
const ubyte SIZEOF_POINTER
|
|
||||||
const ubyte SIZEOF_UBYTE
|
const ubyte SIZEOF_UBYTE
|
||||||
const ubyte SIZEOF_UWORD
|
const ubyte SIZEOF_UWORD
|
||||||
const ubyte SIZEOF_WORD
|
const ubyte SIZEOF_WORD
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
Prog8 compiler v12.0-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
|
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
|
||||||
Prerelease version from git commit 893e16d8 in branch structs
|
|
||||||
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
|
||||||
|
|
||||||
Compiling program import-all-virtual.p8
|
Compiling program import-all-virtual.p8
|
||||||
@@ -63,8 +62,8 @@ LIBRARY MODULE NAME: compression
|
|||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
compression {
|
compression {
|
||||||
decode_rle (^^ubyte compressed, ^^ubyte target, uword maxsize) -> uword
|
decode_rle (uword compressed, uword target, uword maxsize) -> uword
|
||||||
encode_rle (^^ubyte data, uword size, ^^ubyte target, bool is_last_block) -> uword
|
encode_rle (uword data, uword size, uword target, bool is_last_block) -> uword
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -77,8 +76,8 @@ conv {
|
|||||||
any2uword (str string) -> uword
|
any2uword (str string) -> uword
|
||||||
bin2uword (str string) -> uword
|
bin2uword (str string) -> uword
|
||||||
hex2uword (str string) -> uword
|
hex2uword (str string) -> uword
|
||||||
internal_str_ub (ubyte value, str out_ptr)
|
internal_str_ub (ubyte value, uword out_ptr)
|
||||||
internal_str_uw (uword value, str out_ptr)
|
internal_str_uw (uword value, uword out_ptr)
|
||||||
str2byte (str string) -> byte
|
str2byte (str string) -> byte
|
||||||
str2ubyte (str string) -> ubyte
|
str2ubyte (str string) -> ubyte
|
||||||
str2uword (str string) -> uword
|
str2uword (str string) -> uword
|
||||||
@@ -111,26 +110,26 @@ LIBRARY MODULE NAME: diskio
|
|||||||
|
|
||||||
diskio {
|
diskio {
|
||||||
chdir (str path)
|
chdir (str path)
|
||||||
curdir () -> str
|
curdir () -> uword
|
||||||
delete (str filenameptr)
|
delete (uword filenameptr)
|
||||||
directory () -> bool
|
directory () -> bool
|
||||||
exists (str filename) -> bool
|
exists (str filename) -> bool
|
||||||
f_close ()
|
f_close ()
|
||||||
f_close_w ()
|
f_close_w ()
|
||||||
f_open (str filenameptr) -> bool
|
f_open (uword filenameptr) -> bool
|
||||||
f_open_w (str filenameptr) -> bool
|
f_open_w (uword filenameptr) -> bool
|
||||||
f_read (str bufferpointer, uword num_bytes) -> uword
|
f_read (uword bufferpointer, uword num_bytes) -> uword
|
||||||
f_read_all (str bufferpointer) -> uword
|
f_read_all (uword bufferpointer) -> uword
|
||||||
f_readline (str bufptr) -> ubyte
|
f_readline (uword bufptr) -> ubyte
|
||||||
f_write (str bufferpointer, uword num_bytes) -> bool
|
f_write (uword bufferpointer, uword num_bytes) -> bool
|
||||||
get_loadaddress (str filename) -> uword
|
get_loadaddress (str filename) -> uword
|
||||||
load (str filenameptr, uword address_override) -> uword
|
load (uword filenameptr, uword address_override) -> uword
|
||||||
load_raw (str filenameptr, uword start_address) -> uword
|
load_raw (uword filenameptr, uword start_address) -> uword
|
||||||
mkdir (str name)
|
mkdir (str name)
|
||||||
rename (str oldfileptr, str newfileptr)
|
rename (uword oldfileptr, uword newfileptr)
|
||||||
rmdir (str name)
|
rmdir (str name)
|
||||||
save (str filenameptr, uword start_address, uword savesize) -> bool
|
save (uword filenameptr, uword start_address, uword savesize) -> bool
|
||||||
save_raw (str filenameptr, uword start_address, uword savesize) -> bool
|
save_raw (uword filenameptr, uword startaddress, uword savesize) -> bool
|
||||||
status () -> str
|
status () -> str
|
||||||
status_code () -> ubyte
|
status_code () -> ubyte
|
||||||
}
|
}
|
||||||
@@ -199,11 +198,11 @@ math {
|
|||||||
cos8u (ubyte angle) -> ubyte
|
cos8u (ubyte angle) -> ubyte
|
||||||
cosr8 (ubyte radians) -> byte
|
cosr8 (ubyte radians) -> byte
|
||||||
cosr8u (ubyte radians) -> ubyte
|
cosr8u (ubyte radians) -> ubyte
|
||||||
crc16 (^^ubyte data, uword length) -> uword
|
crc16 (uword data, uword length) -> uword
|
||||||
crc16_end () -> uword
|
crc16_end () -> uword
|
||||||
crc16_start ()
|
crc16_start ()
|
||||||
crc16_update (ubyte value)
|
crc16_update (ubyte value)
|
||||||
crc32 (^^ubyte data, uword length)
|
crc32 (uword data, uword length)
|
||||||
crc32_end ()
|
crc32_end ()
|
||||||
crc32_start ()
|
crc32_start ()
|
||||||
crc32_update (ubyte value)
|
crc32_update (ubyte value)
|
||||||
@@ -299,7 +298,7 @@ strings {
|
|||||||
ltrim (str s)
|
ltrim (str s)
|
||||||
ltrimmed (str s) -> str
|
ltrimmed (str s) -> str
|
||||||
ncompare (str st1, str st2, ubyte length) -> byte
|
ncompare (str st1, str st2, ubyte length) -> byte
|
||||||
rfind (str stringptr, ubyte character) -> ubyte, bool
|
rfind (uword stringptr, ubyte character) -> ubyte, bool
|
||||||
right (str source, ubyte slen, str target)
|
right (str source, ubyte slen, str target)
|
||||||
rstrip (str s)
|
rstrip (str s)
|
||||||
rtrim (str s)
|
rtrim (str s)
|
||||||
@@ -330,7 +329,6 @@ sys {
|
|||||||
const ubyte SIZEOF_BYTE
|
const ubyte SIZEOF_BYTE
|
||||||
const ubyte SIZEOF_FLOAT
|
const ubyte SIZEOF_FLOAT
|
||||||
const ubyte SIZEOF_LONG
|
const ubyte SIZEOF_LONG
|
||||||
const ubyte SIZEOF_POINTER
|
|
||||||
const ubyte SIZEOF_UBYTE
|
const ubyte SIZEOF_UBYTE
|
||||||
const ubyte SIZEOF_UWORD
|
const ubyte SIZEOF_UWORD
|
||||||
const ubyte SIZEOF_WORD
|
const ubyte SIZEOF_WORD
|
||||||
@@ -345,7 +343,7 @@ sys {
|
|||||||
gfx_enable (ubyte mode)
|
gfx_enable (ubyte mode)
|
||||||
gfx_getpixel (uword xx, uword yy) -> ubyte
|
gfx_getpixel (uword xx, uword yy) -> ubyte
|
||||||
gfx_plot (uword xx, uword yy, ubyte color)
|
gfx_plot (uword xx, uword yy, ubyte color)
|
||||||
internal_stringcopy (str source, str tgt)
|
internal_stringcopy (uword source, uword tgt)
|
||||||
memcmp (uword address1, uword address2, uword size) -> byte
|
memcmp (uword address1, uword address2, uword size) -> byte
|
||||||
memcopy (uword source, uword tgt, uword count)
|
memcopy (uword source, uword tgt, uword count)
|
||||||
memset (uword mem, uword numbytes, ubyte value)
|
memset (uword mem, uword numbytes, ubyte value)
|
||||||
@@ -518,7 +516,7 @@ txt {
|
|||||||
column (ubyte col)
|
column (ubyte col)
|
||||||
height () -> ubyte
|
height () -> ubyte
|
||||||
home ()
|
home ()
|
||||||
input_chars (str buffer) -> ubyte
|
input_chars (uword buffer) -> ubyte
|
||||||
lowercase ()
|
lowercase ()
|
||||||
nl ()
|
nl ()
|
||||||
petscii2scr (ubyte petscii_char) -> ubyte
|
petscii2scr (ubyte petscii_char) -> ubyte
|
||||||
|
@@ -27,7 +27,7 @@ of these library modules automatically as required.
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Several algorithms and math routines in Prog8's assembly library files are adapted from
|
Several algorithms and math routines in Prog8's assembly library files are adapted from
|
||||||
code publicly available on https://www.codebase64.net/
|
code publicly available on https://www.codebase64.org/
|
||||||
|
|
||||||
|
|
||||||
.. _builtinfunctions:
|
.. _builtinfunctions:
|
||||||
|
@@ -65,11 +65,6 @@ Various things:
|
|||||||
and it does it at run time. In this demo a jump table is not only created in the library,
|
and it does it at run time. In this demo a jump table is not only created in the library,
|
||||||
but also in the main program and copied into the library for its use.
|
but also in the main program and copied into the library for its use.
|
||||||
|
|
||||||
`Additional custom compilation targets (such as VIC-20) <https://github.com/gillham/prog8targets>`_
|
|
||||||
Various custom targets for Prog8 that are not (yet?) part of the Prog8 examples themselves.
|
|
||||||
These additional compilation targets may be in varying state of completeness.
|
|
||||||
Perhaps most recognisable at the time of adding this link, are the various VIC-20 targets.
|
|
||||||
|
|
||||||
|
|
||||||
.. image:: _static/curious.png
|
.. image:: _static/curious.png
|
||||||
:align: center
|
:align: center
|
||||||
|
@@ -46,6 +46,9 @@ Pointers of different types cannot be assigned to one another, unless you use an
|
|||||||
|
|
||||||
Typed pointers and an 'untyped' uword pointer/value can be assigned to each other without an explicit cast.
|
Typed pointers and an 'untyped' uword pointer/value can be assigned to each other without an explicit cast.
|
||||||
|
|
||||||
|
Because it is pretty common to check if a pointer value is zero or not (because zero usually means that the pointer doesn't exist/has no value),
|
||||||
|
pointers can be implicitly cast to a boolean. This allows you to easily write conditionals such as ``while ptr { ... }``
|
||||||
|
|
||||||
|
|
||||||
Dereferencing a pointer, pointer arithmetic
|
Dereferencing a pointer, pointer arithmetic
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|
||||||
STRUCTS and TYPED POINTERS
|
STRUCTS and TYPED POINTERS
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ STRUCTS and TYPED POINTERS
|
|||||||
- DONE: you should be able to get the address of an individual field: ``&structpointer.field``
|
- DONE: you should be able to get the address of an individual field: ``&structpointer.field``
|
||||||
- DONE: teach sizeof() how to calculate struct sizes (need unit test + doc)
|
- DONE: teach sizeof() how to calculate struct sizes (need unit test + doc)
|
||||||
- DONE: sizeof(ptr^^) works
|
- DONE: sizeof(ptr^^) works
|
||||||
|
- DONE: implicit cast of pointer to bool, also in loop conditions (while ptr {...})
|
||||||
- DONE: implicit cast of pointer to uword in conditional expressions
|
- DONE: implicit cast of pointer to uword in conditional expressions
|
||||||
- DONE: subroutine parameters and return values should be able to accept pointers as well now
|
- DONE: subroutine parameters and return values should be able to accept pointers as well now
|
||||||
- DONE (for basic types only): allow array syntax on pointers too: ptr[2] means ptr+sizeof()*2, ptr[0] just means ptr^^ .
|
- DONE (for basic types only): allow array syntax on pointers too: ptr[2] means ptr+sizeof()*2, ptr[0] just means ptr^^ .
|
||||||
@@ -60,9 +62,8 @@ STRUCTS and TYPED POINTERS
|
|||||||
- DONE: added peekbool() and pokebool() and pokebowl() boolean peek and poke, the latter is equivalent to pokebool()
|
- DONE: added peekbool() and pokebool() and pokebowl() boolean peek and poke, the latter is equivalent to pokebool()
|
||||||
- DONE: fixed support for (expression) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with peek()
|
- DONE: fixed support for (expression) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with peek()
|
||||||
- DONE: fixed support for (assigntarget) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with poke()
|
- DONE: fixed support for (assigntarget) array index dereferencing "array[2]^^" where array contains pointers to primitives: replace with poke()
|
||||||
- DONE: replace str or ubyte[] param and returnvalue type into ^^ubyte rather than uword
|
|
||||||
- write docs in structpointers.rst
|
- write docs in structpointers.rst
|
||||||
- virtual/sorting.p8 module generates slightly less efficient code than the old version with untyped uword pointers
|
- scan through virtual library modules to change untyped uword pointers to typed pointers
|
||||||
- add support for array index dereferencing as assign target "array[2]^^.value = 99" where array is struct pointers (currently a 'no support' error)
|
- add support for array index dereferencing as assign target "array[2]^^.value = 99" where array is struct pointers (currently a 'no support' error)
|
||||||
- add support for array index dereferencing as assign target "array[2].value = 99" where array is struct pointers (currently a parser error)
|
- add support for array index dereferencing as assign target "array[2].value = 99" where array is struct pointers (currently a parser error)
|
||||||
- try to fix parse error l1^^.s[0] = 4242 (equivalent to l1.s[0]=4242 , which does parse correctly)
|
- try to fix parse error l1^^.s[0] = 4242 (equivalent to l1.s[0]=4242 , which does parse correctly)
|
||||||
@@ -71,7 +72,6 @@ STRUCTS and TYPED POINTERS
|
|||||||
- 6502 codegen: remove checks in checkForPointerTypesOn6502()
|
- 6502 codegen: remove checks in checkForPointerTypesOn6502()
|
||||||
- 6502 codegen should warn about writing to initialized struct instances when using romable code, like with arrays "can only be used as read-only in ROMable code"
|
- 6502 codegen should warn about writing to initialized struct instances when using romable code, like with arrays "can only be used as read-only in ROMable code"
|
||||||
- 6502 asm symbol name prefixing should work for dereferences too.
|
- 6502 asm symbol name prefixing should work for dereferences too.
|
||||||
- 6502 statementreorderer: fix todo for str -> ^^ubyte instead of uword
|
|
||||||
- update structpointers.rst docs with 6502 things?
|
- update structpointers.rst docs with 6502 things?
|
||||||
- scan through 6502 library modules to change untyped uword pointers to typed pointers
|
- scan through 6502 library modules to change untyped uword pointers to typed pointers
|
||||||
- scan through 6502 examples to change untyped uword pointers to typed pointers
|
- scan through 6502 examples to change untyped uword pointers to typed pointers
|
||||||
@@ -146,14 +146,6 @@ Libraries
|
|||||||
Optimizations
|
Optimizations
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
- if expression generates more instructions than old style if else (IR):
|
|
||||||
pp.next = if particles!=0 particles else 0
|
|
||||||
versus:
|
|
||||||
if particles!=0
|
|
||||||
pp.next = particles
|
|
||||||
else
|
|
||||||
pp.next = 0
|
|
||||||
|
|
||||||
- in Identifier: use typedarray of strings instead of listOf? Other places?
|
- in Identifier: use typedarray of strings instead of listOf? Other places?
|
||||||
- Compilation speed: try to join multiple modifications in 1 result in the AST processors instead of returning it straight away every time
|
- Compilation speed: try to join multiple modifications in 1 result in the AST processors instead of returning it straight away every time
|
||||||
- Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples)
|
- Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples)
|
||||||
|
@@ -69,6 +69,7 @@ main {
|
|||||||
|
|
||||||
sub learn_new_animal() {
|
sub learn_new_animal() {
|
||||||
str new_animal = "?" * 30
|
str new_animal = "?" * 30
|
||||||
|
str answer = "?" * 10
|
||||||
|
|
||||||
; note that we make copies of the animal name and question strings to store them later
|
; note that we make copies of the animal name and question strings to store them later
|
||||||
txt.print("\nI give up. What is the animal? ")
|
txt.print("\nI give up. What is the animal? ")
|
||||||
|
@@ -68,14 +68,14 @@ btree {
|
|||||||
^^Node parent = root
|
^^Node parent = root
|
||||||
repeat {
|
repeat {
|
||||||
if parent.value >= value {
|
if parent.value >= value {
|
||||||
if parent.left!=0
|
if parent.left
|
||||||
parent = parent.left
|
parent = parent.left
|
||||||
else {
|
else {
|
||||||
parent.left = node
|
parent.left = node
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if parent.right!=0
|
if parent.right
|
||||||
parent = parent.right
|
parent = parent.right
|
||||||
else {
|
else {
|
||||||
parent.right = node
|
parent.right = node
|
||||||
@@ -88,7 +88,7 @@ btree {
|
|||||||
|
|
||||||
sub contains(uword value) -> bool {
|
sub contains(uword value) -> bool {
|
||||||
^^Node r = root
|
^^Node r = root
|
||||||
while r!=0 {
|
while r {
|
||||||
if r.value==value
|
if r.value==value
|
||||||
return true
|
return true
|
||||||
if r.value>value
|
if r.value>value
|
||||||
@@ -102,19 +102,19 @@ btree {
|
|||||||
sub size() -> ubyte {
|
sub size() -> ubyte {
|
||||||
ubyte count
|
ubyte count
|
||||||
|
|
||||||
if root!=0
|
if root
|
||||||
count_node(root)
|
count_node(root)
|
||||||
|
|
||||||
return count
|
return count
|
||||||
|
|
||||||
sub count_node(^^Node r) {
|
sub count_node(^^Node r) {
|
||||||
count++
|
count++
|
||||||
if r.left!=0 {
|
if r.left {
|
||||||
sys.pushw(r)
|
sys.pushw(r)
|
||||||
count_node(r.left)
|
count_node(r.left)
|
||||||
r = sys.popw()
|
r = sys.popw()
|
||||||
}
|
}
|
||||||
if r.right!=0 {
|
if r.right {
|
||||||
sys.pushw(r)
|
sys.pushw(r)
|
||||||
count_node(r.right)
|
count_node(r.right)
|
||||||
r = sys.popw()
|
r = sys.popw()
|
||||||
@@ -126,7 +126,7 @@ btree {
|
|||||||
; note: we don't deallocate the memory from the node, for simplicity sake
|
; note: we don't deallocate the memory from the node, for simplicity sake
|
||||||
^^Node n = root
|
^^Node n = root
|
||||||
^^Node parent = 0
|
^^Node parent = 0
|
||||||
while n!=0 {
|
while n {
|
||||||
if n.value==value {
|
if n.value==value {
|
||||||
if n.left==0
|
if n.left==0
|
||||||
replacechild(parent, n, n.right)
|
replacechild(parent, n, n.right)
|
||||||
@@ -154,7 +154,7 @@ btree {
|
|||||||
sub find_successor(^^Node p) -> ^^Node {
|
sub find_successor(^^Node p) -> ^^Node {
|
||||||
^^Node succ = p
|
^^Node succ = p
|
||||||
p = p.right
|
p = p.right
|
||||||
while p!=0 {
|
while p {
|
||||||
succ = p
|
succ = p
|
||||||
p = p.left
|
p = p.left
|
||||||
}
|
}
|
||||||
@@ -171,19 +171,19 @@ btree {
|
|||||||
|
|
||||||
|
|
||||||
sub print_tree_inorder() {
|
sub print_tree_inorder() {
|
||||||
if root!=0
|
if root
|
||||||
print_tree(root)
|
print_tree(root)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
sub print_tree(^^Node r) {
|
sub print_tree(^^Node r) {
|
||||||
if r.left!=0 {
|
if r.left {
|
||||||
sys.pushw(r)
|
sys.pushw(r)
|
||||||
print_tree(r.left)
|
print_tree(r.left)
|
||||||
r = sys.popw()
|
r = sys.popw()
|
||||||
}
|
}
|
||||||
txt.print_uw(r.value)
|
txt.print_uw(r.value)
|
||||||
txt.print(", ")
|
txt.print(", ")
|
||||||
if r.right!=0 {
|
if r.right {
|
||||||
sys.pushw(r)
|
sys.pushw(r)
|
||||||
print_tree(r.right)
|
print_tree(r.right)
|
||||||
r = sys.popw()
|
r = sys.popw()
|
||||||
@@ -193,7 +193,7 @@ btree {
|
|||||||
|
|
||||||
|
|
||||||
sub print_tree_preorder() {
|
sub print_tree_preorder() {
|
||||||
if root!=0
|
if root
|
||||||
print_tree(root,0)
|
print_tree(root,0)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
@@ -201,14 +201,14 @@ btree {
|
|||||||
repeat depth txt.print(" ")
|
repeat depth txt.print(" ")
|
||||||
txt.print_uw(r.value)
|
txt.print_uw(r.value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
if r.left!=0 {
|
if r.left {
|
||||||
sys.pushw(r)
|
sys.pushw(r)
|
||||||
sys.push(depth)
|
sys.push(depth)
|
||||||
print_tree(r.left, depth+1)
|
print_tree(r.left, depth+1)
|
||||||
depth = sys.pop()
|
depth = sys.pop()
|
||||||
r = sys.popw()
|
r = sys.popw()
|
||||||
}
|
}
|
||||||
if r.right!=0 {
|
if r.right {
|
||||||
sys.pushw(r)
|
sys.pushw(r)
|
||||||
sys.push(depth)
|
sys.push(depth)
|
||||||
print_tree(r.right, depth+1)
|
print_tree(r.right, depth+1)
|
||||||
|
@@ -1,94 +0,0 @@
|
|||||||
; Particle fountain.
|
|
||||||
; This is NOT necessarily the most efficient or idiomatic Prog8 way to do this!
|
|
||||||
; But it is just an example for how you could allocate and use structs dynamically.
|
|
||||||
; It uses a linked list to store all active particles.
|
|
||||||
|
|
||||||
|
|
||||||
%import math
|
|
||||||
|
|
||||||
main {
|
|
||||||
|
|
||||||
struct Particle {
|
|
||||||
word x,y
|
|
||||||
byte speedx, speedy
|
|
||||||
ubyte brightness
|
|
||||||
^^Particle next
|
|
||||||
}
|
|
||||||
|
|
||||||
const uword MAX_PARTICLES = 450
|
|
||||||
const ubyte GRAVITY = 1
|
|
||||||
|
|
||||||
^^Particle particles ; linked list of all active particles
|
|
||||||
uword active_particles = 0
|
|
||||||
|
|
||||||
sub start() {
|
|
||||||
|
|
||||||
repeat 4
|
|
||||||
spawnrandom()
|
|
||||||
|
|
||||||
sys.gfx_enable(0) ; enable lo res screen
|
|
||||||
|
|
||||||
repeat {
|
|
||||||
sys.gfx_clear(0)
|
|
||||||
update_particles()
|
|
||||||
sys.wait(2)
|
|
||||||
sys.waitvsync()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub spawnrandom() {
|
|
||||||
if active_particles < MAX_PARTICLES {
|
|
||||||
^^Particle pp = arena.alloc(sizeof(Particle))
|
|
||||||
pp.next = if particles!=0 particles else 0
|
|
||||||
particles = pp
|
|
||||||
initparticle(pp)
|
|
||||||
active_particles++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub initparticle(^^Particle pp) {
|
|
||||||
pp.x = 160
|
|
||||||
pp.y = 238
|
|
||||||
pp.speedx = math.rnd() % 10 as byte -5
|
|
||||||
if pp.speedx==0
|
|
||||||
pp.speedx=1
|
|
||||||
pp.speedy = -10 - math.rnd() % 12
|
|
||||||
pp.brightness = 255
|
|
||||||
}
|
|
||||||
|
|
||||||
sub update_particles() {
|
|
||||||
^^Particle pp = particles
|
|
||||||
while pp!=0 {
|
|
||||||
pp.speedy += GRAVITY
|
|
||||||
pp.x += pp.speedx
|
|
||||||
pp.y += pp.speedy
|
|
||||||
|
|
||||||
if pp.y >= 239 {
|
|
||||||
; reuse the particle that went off the screen and spawn another one (if allowed)
|
|
||||||
initparticle(pp)
|
|
||||||
spawnrandom()
|
|
||||||
} else {
|
|
||||||
pp.x = clamp(pp.x, 0, 319)
|
|
||||||
}
|
|
||||||
|
|
||||||
sys.gfx_plot(pp.x as uword, pp.y as uword, pp.brightness)
|
|
||||||
if pp.brightness>=7
|
|
||||||
pp.brightness -= 7
|
|
||||||
|
|
||||||
pp = pp.next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
arena {
|
|
||||||
; extremely trivial arena allocator (that never frees)
|
|
||||||
uword buffer = memory("arena", 4000, 0)
|
|
||||||
uword next = buffer
|
|
||||||
|
|
||||||
sub alloc(ubyte size) -> uword {
|
|
||||||
defer next += size
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
}
|
|
@@ -28,7 +28,7 @@ main {
|
|||||||
sub printlist() {
|
sub printlist() {
|
||||||
ubyte count = 0
|
ubyte count = 0
|
||||||
^^slist.Node n = slist.head
|
^^slist.Node n = slist.head
|
||||||
while n!=0 {
|
while n {
|
||||||
txt.print_uw(n.size)
|
txt.print_uw(n.size)
|
||||||
txt.chrout(':')
|
txt.chrout(':')
|
||||||
txt.chrout(n.letter)
|
txt.chrout(n.letter)
|
||||||
@@ -60,10 +60,10 @@ slist {
|
|||||||
uword size = node.size
|
uword size = node.size
|
||||||
^^Node predecessor = 0
|
^^Node predecessor = 0
|
||||||
^^Node current = head
|
^^Node current = head
|
||||||
while current!=0 {
|
while current {
|
||||||
if current.size >= size {
|
if current.size >= size {
|
||||||
node.next = current
|
node.next = current
|
||||||
if predecessor!=0
|
if predecessor
|
||||||
break
|
break
|
||||||
else {
|
else {
|
||||||
head = node
|
head = node
|
||||||
|
209
examples/test.p8
209
examples/test.p8
@@ -1,215 +1,8 @@
|
|||||||
%option no_sysinit
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%import textio
|
|
||||||
%import compression
|
|
||||||
%import math
|
|
||||||
%import sorting
|
|
||||||
%import strings
|
|
||||||
%import diskio
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
test_compression()
|
long @shared num = 123456789
|
||||||
test_math()
|
|
||||||
test_sorting()
|
|
||||||
test_syslib()
|
|
||||||
test_strings()
|
|
||||||
test_conv()
|
|
||||||
test_diskio()
|
|
||||||
;test_textio()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test_diskio() {
|
|
||||||
txt.print("--diskio--\n")
|
|
||||||
sys.memset(target, len(target), 0)
|
|
||||||
diskio.delete("derp.bin")
|
|
||||||
diskio.delete("derp2.bin")
|
|
||||||
void diskio.f_open_w("derp.bin")
|
|
||||||
repeat 12
|
|
||||||
void diskio.f_write("derpderp123", 11)
|
|
||||||
diskio.f_close_w()
|
|
||||||
|
|
||||||
void diskio.f_open("derp.bin")
|
|
||||||
diskio.f_read(target, 60)
|
|
||||||
diskio.f_close()
|
|
||||||
txt.print(target)
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
sys.memset(target, len(target), 0)
|
|
||||||
void diskio.f_open("derp.bin")
|
|
||||||
diskio.f_read_all(target)
|
|
||||||
diskio.f_close()
|
|
||||||
txt.print(target)
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
diskio.rename("derp.bin", "derp2.bin")
|
|
||||||
sys.memset(target, len(target), 0)
|
|
||||||
void diskio.f_open("derp2.bin")
|
|
||||||
diskio.f_readline(target)
|
|
||||||
diskio.f_close()
|
|
||||||
txt.print(target)
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
txt.print(diskio.curdir())
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
txt.print_bool(diskio.exists("derp3.bin"))
|
|
||||||
txt.print_bool(diskio.exists("derp2.bin"))
|
|
||||||
txt.print_bool(diskio.exists("derp1.bin"))
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
diskio.delete("save.bin")
|
|
||||||
diskio.delete("saver.bin")
|
|
||||||
txt.print_bool(diskio.save("save.bin", 2000, 100))
|
|
||||||
txt.spc()
|
|
||||||
txt.print_bool(diskio.save_raw("saver.bin", 2000, 100))
|
|
||||||
txt.nl()
|
|
||||||
txt.print_uw(diskio.load("save.bin", 0))
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(diskio.load_raw("saver.bin", 2000))
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
ubyte[255] target
|
|
||||||
|
|
||||||
sub test_conv() {
|
|
||||||
txt.print("--conv--\n")
|
|
||||||
txt.print_b(-111)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_ub(222)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw(22222)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_w(-22222)
|
|
||||||
txt.nl()
|
|
||||||
txt.print_ubbin(222, true)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_ubhex(222, true)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uwbin(2222, true)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uwhex(2222, true)
|
|
||||||
txt.nl()
|
|
||||||
txt.print_ub0(1)
|
|
||||||
txt.spc()
|
|
||||||
txt.print_uw0(123)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test_strings() {
|
|
||||||
txt.print("--strings--\n")
|
|
||||||
ubyte idx
|
|
||||||
bool found
|
|
||||||
idx, found = strings.rfind(source, '1')
|
|
||||||
txt.print_ub(idx)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test_textio() {
|
|
||||||
txt.print("--textio--\n")
|
|
||||||
txt.print("enter some input: ")
|
|
||||||
void txt.input_chars(&target)
|
|
||||||
txt.print(target)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test_syslib() {
|
|
||||||
txt.print("--syslib--\n")
|
|
||||||
sys.internal_stringcopy(source, target)
|
|
||||||
txt.print(target)
|
|
||||||
txt.nl()
|
|
||||||
sys.memset(target, sizeof(target), 0)
|
|
||||||
txt.print(target)
|
|
||||||
txt.nl()
|
|
||||||
sys.memcopy(source, target, len(source))
|
|
||||||
txt.print(target)
|
|
||||||
txt.nl()
|
|
||||||
sys.memsetw(&target as ^^uword, 20, $5051)
|
|
||||||
txt.print(target)
|
|
||||||
txt.nl()
|
|
||||||
txt.print_b(sys.memcmp(source, target, len(source)))
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test_sorting() {
|
|
||||||
txt.print("--sorting--\n")
|
|
||||||
ubyte[] bytes1 = [77,33,44,99,11,55]
|
|
||||||
ubyte[] bytes2 = [77,33,44,99,11,55]
|
|
||||||
uword[] @nosplit values1 = [1,2,3,4,5,6]
|
|
||||||
uword[] @nosplit words1 = [777,333,444,999,111,555]
|
|
||||||
uword[] @nosplit words2 = [777,333,444,999,111,555]
|
|
||||||
uword[] @nosplit values2 = [1,2,3,4,5,6]
|
|
||||||
sorting.shellsort_ub(&bytes1, len(bytes1))
|
|
||||||
sorting.shellsort_by_ub(&bytes2, &values1, len(bytes2))
|
|
||||||
sorting.shellsort_uw(&words1, len(words1))
|
|
||||||
sorting.shellsort_by_uw(&words2, &values2, len(words2))
|
|
||||||
|
|
||||||
for cx16.r0L in bytes1 {
|
|
||||||
txt.print_ub(cx16.r0L)
|
|
||||||
txt.spc()
|
|
||||||
}
|
|
||||||
txt.nl()
|
|
||||||
for cx16.r0L in bytes2 {
|
|
||||||
txt.print_ub(cx16.r0L)
|
|
||||||
txt.spc()
|
|
||||||
}
|
|
||||||
txt.nl()
|
|
||||||
for cx16.r0 in values1 {
|
|
||||||
txt.print_uw(cx16.r0)
|
|
||||||
txt.spc()
|
|
||||||
}
|
|
||||||
txt.nl()
|
|
||||||
for cx16.r0 in words1 {
|
|
||||||
txt.print_uw(cx16.r0)
|
|
||||||
txt.spc()
|
|
||||||
}
|
|
||||||
txt.nl()
|
|
||||||
for cx16.r0 in words2 {
|
|
||||||
txt.print_uw(cx16.r0)
|
|
||||||
txt.spc()
|
|
||||||
}
|
|
||||||
txt.nl()
|
|
||||||
for cx16.r0 in values2 {
|
|
||||||
txt.print_uw(cx16.r0)
|
|
||||||
txt.spc()
|
|
||||||
}
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub test_math() {
|
|
||||||
txt.print("--math--\n")
|
|
||||||
txt.print("expected 15567: ")
|
|
||||||
txt.print_uw(math.crc16(source, len(source)))
|
|
||||||
txt.print("\nexpected 8747,54089: ")
|
|
||||||
math.crc32(source, len(source))
|
|
||||||
txt.print_uw(cx16.r14)
|
|
||||||
txt.chrout(',')
|
|
||||||
txt.print_uw(cx16.r15)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
str source = petscii:"Lorem ipsuuuuuuuuuuuum dollllllllllllllloooooooor sit ametttttttttttttttt, cccccccccccccccconsecteeeeetuuuuuur aaaaaaaaa111111222222333333444444"
|
|
||||||
|
|
||||||
sub test_compression() {
|
|
||||||
txt.print("--compression--\n")
|
|
||||||
|
|
||||||
ubyte[256] compressed
|
|
||||||
ubyte[256] decompressed
|
|
||||||
|
|
||||||
txt.print_uw(len(source))
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
uword size = compression.encode_rle(source, len(source), compressed, true)
|
|
||||||
txt.print_uw(size)
|
|
||||||
txt.nl()
|
|
||||||
|
|
||||||
size = compression.decode_rle(compressed, decompressed, sizeof(decompressed))
|
|
||||||
txt.print_uw(size)
|
|
||||||
txt.nl()
|
|
||||||
txt.print(source)
|
|
||||||
txt.nl()
|
|
||||||
txt.print(decompressed)
|
|
||||||
txt.nl()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -4,16 +4,14 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
const ubyte MAX_PARTICLES = 128
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
word[MAX_PARTICLES] particleX
|
word[128] particleX
|
||||||
word[MAX_PARTICLES] particleY
|
word[128] particleY
|
||||||
byte[MAX_PARTICLES] particleDX
|
byte[128] particleDX
|
||||||
byte[MAX_PARTICLES] particleDY
|
byte[128] particleDY
|
||||||
|
|
||||||
ubyte pi
|
ubyte pi
|
||||||
for pi in 0 to MAX_PARTICLES-1 {
|
for pi in 0 to 127 {
|
||||||
particleX[pi] = math.rndw() % 319 as word
|
particleX[pi] = math.rndw() % 319 as word
|
||||||
particleY[pi] = math.rndw() % 240 as word
|
particleY[pi] = math.rndw() % 240 as word
|
||||||
particleDX[pi] = (math.rnd() & 1)*2 as byte - 1
|
particleDX[pi] = (math.rnd() & 1)*2 as byte - 1
|
||||||
@@ -44,7 +42,7 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub plot_particles() {
|
sub plot_particles() {
|
||||||
for pi in 0 to MAX_PARTICLES-1 {
|
for pi in 0 to 127 {
|
||||||
particleX[pi] += particleDX[pi]
|
particleX[pi] += particleDX[pi]
|
||||||
particleY[pi] += particleDY[pi]
|
particleY[pi] += particleDY[pi]
|
||||||
if particleX[pi]<0 or particleX[pi]>319 {
|
if particleX[pi]<0 or particleX[pi]>319 {
|
||||||
|
@@ -1,72 +0,0 @@
|
|||||||
; Particle fountain.
|
|
||||||
; based on fixed array allocation of arrays of all the particle's properties.
|
|
||||||
|
|
||||||
%import math
|
|
||||||
|
|
||||||
main {
|
|
||||||
|
|
||||||
const ubyte MAX_PARTICLES = 255
|
|
||||||
const ubyte GRAVITY = 1
|
|
||||||
|
|
||||||
word[MAX_PARTICLES] particleX
|
|
||||||
word[MAX_PARTICLES] particleY
|
|
||||||
byte[MAX_PARTICLES] particleSpeedX
|
|
||||||
byte[MAX_PARTICLES] particleSpeedY
|
|
||||||
ubyte[MAX_PARTICLES] particleBrightness
|
|
||||||
|
|
||||||
ubyte active_particles = 0
|
|
||||||
|
|
||||||
sub start() {
|
|
||||||
|
|
||||||
repeat 4
|
|
||||||
spawnrandom()
|
|
||||||
|
|
||||||
sys.gfx_enable(0) ; enable lo res screen
|
|
||||||
|
|
||||||
repeat {
|
|
||||||
sys.gfx_clear(0)
|
|
||||||
update_particles()
|
|
||||||
sys.wait(2)
|
|
||||||
sys.waitvsync()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub spawnrandom() {
|
|
||||||
if active_particles < MAX_PARTICLES {
|
|
||||||
initparticle(active_particles)
|
|
||||||
active_particles++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub initparticle(ubyte pi) {
|
|
||||||
particleX[pi] = 160
|
|
||||||
particleY[pi] = 238
|
|
||||||
particleSpeedX[pi] = math.rnd() % 10 as byte -5
|
|
||||||
if particleSpeedX[pi]==0
|
|
||||||
particleSpeedX[pi]=1
|
|
||||||
particleSpeedY[pi] = -10 - math.rnd() % 12
|
|
||||||
particleBrightness[pi] = 255
|
|
||||||
}
|
|
||||||
|
|
||||||
sub update_particles() {
|
|
||||||
ubyte pi
|
|
||||||
for pi in 0 to active_particles-1 {
|
|
||||||
|
|
||||||
particleSpeedY[pi] += GRAVITY
|
|
||||||
particleX[pi] += particleSpeedX[pi]
|
|
||||||
particleY[pi] += particleSpeedY[pi]
|
|
||||||
|
|
||||||
if particleY[pi] >= 239 {
|
|
||||||
; reuse the particle that went off the screen and spawn another one (if allowed)
|
|
||||||
initparticle(pi)
|
|
||||||
spawnrandom()
|
|
||||||
} else {
|
|
||||||
particleX[pi] = clamp(particleX[pi], 0, 319)
|
|
||||||
}
|
|
||||||
|
|
||||||
sys.gfx_plot(particleX[pi] as uword, particleY[pi] as uword, particleBrightness[pi])
|
|
||||||
if particleBrightness[pi]>=7
|
|
||||||
particleBrightness[pi] -= 7
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -11,10 +11,8 @@ Intermediate Representation instructions for the IR Virtual machine.
|
|||||||
|
|
||||||
Specs of the virtual machine this will run on:
|
Specs of the virtual machine this will run on:
|
||||||
Program to execute is not stored in the system memory, it's just a separate list of instructions.
|
Program to execute is not stored in the system memory, it's just a separate list of instructions.
|
||||||
100K virtual registers, 16 bits wide, can also be used as 8 bits. r0-r99999
|
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
|
||||||
reserved 99000 - 99099 : WORD registers for syscall arguments and response value(s)
|
65536 virtual floating point registers (64 bits double precision) fr0-fr65535
|
||||||
reserved 99100 - 99199 : BYTE registers for syscall arguments and response value(s)
|
|
||||||
100K virtual floating point registers (64 bits double precision) fr0-fr99999
|
|
||||||
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
|
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
|
||||||
Value stack, max 128 entries of 1 byte each.
|
Value stack, max 128 entries of 1 byte each.
|
||||||
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC,
|
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC,
|
||||||
@@ -25,8 +23,7 @@ Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by t
|
|||||||
|
|
||||||
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.
|
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.
|
||||||
|
|
||||||
Value types: integers (.b=byte=8 bits, .w=word=16 bits) and float (.f=64 bits). Omitting it defaults to b if the instruction requires a type.
|
Value types: integers (.b=byte=8 bits, .w=word=16 bits, .l=long=32 bits) and float (.f=64 bits). Omitting it defaults to b if the instruction requires a type.
|
||||||
Currently ther is NO support for 24 or 32 bits integers.
|
|
||||||
There is no distinction between signed and unsigned integers.
|
There is no distinction between signed and unsigned integers.
|
||||||
Instead, a different instruction is used if a distinction should be made (for example div and divs).
|
Instead, a different instruction is used if a distinction should be made (for example div and divs).
|
||||||
Floating point operations are just 'f' typed regular instructions, however there are a few unique fp conversion instructions.
|
Floating point operations are just 'f' typed regular instructions, however there are a few unique fp conversion instructions.
|
||||||
@@ -36,7 +33,7 @@ NOTE: Labels in source text should always start with an underscore.
|
|||||||
|
|
||||||
LOAD/STORE
|
LOAD/STORE
|
||||||
----------
|
----------
|
||||||
All have type b or w or f.
|
All have type b or w or l or f.
|
||||||
|
|
||||||
load reg1, value - load immediate value into register. If you supply a symbol, loads the *address* of the symbol! (variable values are loaded from memory via the loadm instruction)
|
load reg1, value - load immediate value into register. If you supply a symbol, loads the *address* of the symbol! (variable values are loaded from memory via the loadm instruction)
|
||||||
loadm reg1, address - load reg1 with value at memory address
|
loadm reg1, address - load reg1 with value at memory address
|
||||||
@@ -520,8 +517,8 @@ val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThat
|
|||||||
enum class IRDataType {
|
enum class IRDataType {
|
||||||
BYTE,
|
BYTE,
|
||||||
WORD,
|
WORD,
|
||||||
|
LONG,
|
||||||
FLOAT
|
FLOAT
|
||||||
// TODO add INT (32-bit)? INT24 (24-bit)?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class OperandDirection {
|
enum class OperandDirection {
|
||||||
@@ -864,6 +861,7 @@ data class IRInstruction(
|
|||||||
when (type) {
|
when (type) {
|
||||||
IRDataType.BYTE -> require(immediate in -128..255) { "immediate value out of range for byte: $immediate" }
|
IRDataType.BYTE -> require(immediate in -128..255) { "immediate value out of range for byte: $immediate" }
|
||||||
IRDataType.WORD -> require(immediate in -32768..65535) { "immediate value out of range for word: $immediate" }
|
IRDataType.WORD -> require(immediate in -32768..65535) { "immediate value out of range for word: $immediate" }
|
||||||
|
IRDataType.LONG -> require(immediate in -2147483647..2147483647) { "immediate value out of range for long: $immediate" }
|
||||||
IRDataType.FLOAT, null -> {}
|
IRDataType.FLOAT, null -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1117,6 +1115,7 @@ data class IRInstruction(
|
|||||||
when(it.reg.dt) {
|
when(it.reg.dt) {
|
||||||
IRDataType.BYTE -> result.add("${location}r${it.reg.registerNum}.b$cpuReg,")
|
IRDataType.BYTE -> result.add("${location}r${it.reg.registerNum}.b$cpuReg,")
|
||||||
IRDataType.WORD -> result.add("${location}r${it.reg.registerNum}.w$cpuReg,")
|
IRDataType.WORD -> result.add("${location}r${it.reg.registerNum}.w$cpuReg,")
|
||||||
|
IRDataType.LONG -> result.add("${location}r${it.reg.registerNum}.l$cpuReg,")
|
||||||
IRDataType.FLOAT -> result.add("${location}fr${it.reg.registerNum}.f$cpuReg,")
|
IRDataType.FLOAT -> result.add("${location}fr${it.reg.registerNum}.f$cpuReg,")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1138,12 +1137,14 @@ data class IRInstruction(
|
|||||||
when (returnspec.dt) {
|
when (returnspec.dt) {
|
||||||
IRDataType.BYTE -> "r${returnspec.registerNum}.b"
|
IRDataType.BYTE -> "r${returnspec.registerNum}.b"
|
||||||
IRDataType.WORD -> "r${returnspec.registerNum}.w"
|
IRDataType.WORD -> "r${returnspec.registerNum}.w"
|
||||||
|
IRDataType.LONG -> "r${returnspec.registerNum}.l"
|
||||||
IRDataType.FLOAT -> "fr${returnspec.registerNum}.f"
|
IRDataType.FLOAT -> "fr${returnspec.registerNum}.f"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
when (returnspec.dt) {
|
when (returnspec.dt) {
|
||||||
IRDataType.BYTE -> "r${returnspec.registerNum}.b@" + cpuReg
|
IRDataType.BYTE -> "r${returnspec.registerNum}.b@" + cpuReg
|
||||||
IRDataType.WORD -> "r${returnspec.registerNum}.w@" + cpuReg
|
IRDataType.WORD -> "r${returnspec.registerNum}.w@" + cpuReg
|
||||||
|
IRDataType.LONG -> "r${returnspec.registerNum}.l@" + cpuReg
|
||||||
IRDataType.FLOAT -> "r${returnspec.registerNum}.f@" + cpuReg
|
IRDataType.FLOAT -> "r${returnspec.registerNum}.f@" + cpuReg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -216,6 +216,7 @@ fun parseIRCodeLine(line: String): Either<IRInstruction, String> {
|
|||||||
if (immediateInt!=null && (immediateInt < -32768 || immediateInt > 65535))
|
if (immediateInt!=null && (immediateInt < -32768 || immediateInt > 65535))
|
||||||
throw IRParseException("immediate value out of range for word: $immediateInt")
|
throw IRParseException("immediate value out of range for word: $immediateInt")
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {}
|
||||||
IRDataType.FLOAT -> {}
|
IRDataType.FLOAT -> {}
|
||||||
null -> {}
|
null -> {}
|
||||||
}
|
}
|
||||||
@@ -368,6 +369,7 @@ fun irType(type: DataType): IRDataType {
|
|||||||
BaseDataType.UBYTE,
|
BaseDataType.UBYTE,
|
||||||
BaseDataType.BYTE -> IRDataType.BYTE
|
BaseDataType.BYTE -> IRDataType.BYTE
|
||||||
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.POINTER -> IRDataType.WORD
|
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.POINTER -> IRDataType.WORD
|
||||||
|
BaseDataType.LONG -> IRDataType.LONG
|
||||||
BaseDataType.FLOAT -> IRDataType.FLOAT
|
BaseDataType.FLOAT -> IRDataType.FLOAT
|
||||||
BaseDataType.STRUCT_INSTANCE -> TODO("IR datatype for struct instances")
|
BaseDataType.STRUCT_INSTANCE -> TODO("IR datatype for struct instances")
|
||||||
else -> throw AssemblyError("no IR datatype for $type")
|
else -> throw AssemblyError("no IR datatype for $type")
|
||||||
|
@@ -32,19 +32,30 @@ class Memory {
|
|||||||
return (mem[address] + 256u*mem[address+1]).toUShort()
|
return (mem[address] + 256u*mem[address+1]).toUShort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getSL(address: Int): Int {
|
||||||
|
return (mem[address] + 256u*mem[address+1] + 65536u*mem[address+2] + 16777216u*mem[address+3]).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
fun getSW(address: Int): Short {
|
fun getSW(address: Int): Short {
|
||||||
return (mem[address].toInt() + mem[address+1].toInt()*256).toShort()
|
return (mem[address].toInt() + mem[address+1].toInt()*256).toShort()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setUW(address: Int, value: UShort) {
|
fun setUW(address: Int, value: UShort) {
|
||||||
mem[address+1] = (value.toInt() ushr 8).toUByte()
|
|
||||||
mem[address] = value.toUByte()
|
mem[address] = value.toUByte()
|
||||||
|
mem[address+1] = (value.toInt() ushr 8).toUByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSL(address: Int, value: Int) {
|
||||||
|
mem[address] = value.toUByte()
|
||||||
|
mem[address+1] = (value ushr 8).toUByte()
|
||||||
|
mem[address+2] = (value ushr 16).toUByte()
|
||||||
|
mem[address+3] = (value ushr 24).toUByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSW(address: Int, value: Short) {
|
fun setSW(address: Int, value: Short) {
|
||||||
val uv = value.toUShort()
|
val uv = value.toUShort()
|
||||||
mem[address+1] = (uv.toInt() ushr 8).toUByte()
|
|
||||||
mem[address] = uv.toUByte()
|
mem[address] = uv.toUByte()
|
||||||
|
mem[address+1] = (uv.toInt() ushr 8).toUByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setFloat(address: Int, value: Double) {
|
fun setFloat(address: Int, value: Double) {
|
||||||
|
@@ -6,14 +6,14 @@ package prog8.vm
|
|||||||
* A,X and Y "physical" 6502 registers.
|
* A,X and Y "physical" 6502 registers.
|
||||||
*/
|
*/
|
||||||
class Registers {
|
class Registers {
|
||||||
private val registers = Array<UShort>(99999) { 0u }
|
private val registers = Array<Int>(99999) { 0 }
|
||||||
private val floatRegisters = Array(99999) { 0.0 }
|
private val floatRegisters = Array(99999) { 0.0 }
|
||||||
var cpuA: UByte = 0u
|
var cpuA: UByte = 0u
|
||||||
var cpuX: UByte = 0u
|
var cpuX: UByte = 0u
|
||||||
var cpuY: UByte = 0u
|
var cpuY: UByte = 0u
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
registers.fill(0u)
|
registers.fill(0)
|
||||||
floatRegisters.fill(0.0)
|
floatRegisters.fill(0.0)
|
||||||
cpuA = 0u
|
cpuA = 0u
|
||||||
cpuX = 0u
|
cpuX = 0u
|
||||||
@@ -21,26 +21,32 @@ class Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setUB(reg: Int, value: UByte) {
|
fun setUB(reg: Int, value: UByte) {
|
||||||
registers[reg] = registers[reg] and 0xff00u or value.toUShort()
|
registers[reg] = value.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSB(reg: Int, value: Byte) {
|
fun setSB(reg: Int, value: Byte) {
|
||||||
registers[reg] = registers[reg] and 0xff00u or (value.toUShort() and 0x00ffu)
|
registers[reg] = value.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setUW(reg: Int, value: UShort) {
|
fun setUW(reg: Int, value: UShort) {
|
||||||
registers[reg] = value
|
registers[reg] = value.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSW(reg: Int, value: Short) {
|
fun setSW(reg: Int, value: Short) {
|
||||||
registers[reg] = value.toUShort()
|
registers[reg] = value.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSL(reg: Int, value: Int) {
|
||||||
|
registers[reg] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUB(reg: Int) = registers[reg].toUByte()
|
fun getUB(reg: Int) = registers[reg].toUByte()
|
||||||
|
|
||||||
fun getSB(reg: Int) = registers[reg].toByte()
|
fun getSB(reg: Int) = registers[reg].toByte()
|
||||||
|
|
||||||
fun getUW(reg: Int) = registers[reg]
|
fun getUW(reg: Int) = registers[reg].toUShort()
|
||||||
|
|
||||||
|
fun getSL(reg: Int) = registers[reg]
|
||||||
|
|
||||||
fun getSW(reg: Int) = registers[reg].toShort()
|
fun getSW(reg: Int) = registers[reg].toShort()
|
||||||
|
|
||||||
|
@@ -143,6 +143,7 @@ object SysCalls {
|
|||||||
when(it.reg.dt) {
|
when(it.reg.dt) {
|
||||||
IRDataType.BYTE -> vm.registers.getUB(it.reg.registerNum)
|
IRDataType.BYTE -> vm.registers.getUB(it.reg.registerNum)
|
||||||
IRDataType.WORD -> vm.registers.getUW(it.reg.registerNum)
|
IRDataType.WORD -> vm.registers.getUW(it.reg.registerNum)
|
||||||
|
IRDataType.LONG -> vm.registers.getSL(it.reg.registerNum)
|
||||||
IRDataType.FLOAT -> vm.registers.getFloat(it.reg.registerNum)
|
IRDataType.FLOAT -> vm.registers.getFloat(it.reg.registerNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,6 +165,7 @@ object SysCalls {
|
|||||||
when(returns.dt) {
|
when(returns.dt) {
|
||||||
IRDataType.BYTE -> vm.registers.setUB(returns.registerNum, vv.toInt().toUByte())
|
IRDataType.BYTE -> vm.registers.setUB(returns.registerNum, vv.toInt().toUByte())
|
||||||
IRDataType.WORD -> vm.registers.setUW(returns.registerNum, vv.toInt().toUShort())
|
IRDataType.WORD -> vm.registers.setUW(returns.registerNum, vv.toInt().toUShort())
|
||||||
|
IRDataType.LONG -> vm.registers.setSL(returns.registerNum, vv.toInt())
|
||||||
IRDataType.FLOAT -> vm.registers.setFloat(returns.registerNum, vv)
|
IRDataType.FLOAT -> vm.registers.setFloat(returns.registerNum, vv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -360,6 +360,11 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
statusZero = value==0
|
statusZero = value==0
|
||||||
statusNegative = value>=0x8000
|
statusNegative = value>=0x8000
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {
|
||||||
|
registers.setSL(reg, value)
|
||||||
|
statusZero = value==0
|
||||||
|
statusNegative = value<0
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> throw IllegalArgumentException("attempt to set integer result register but float type")
|
IRDataType.FLOAT -> throw IllegalArgumentException("attempt to set integer result register but float type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,6 +382,10 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
val value = registers.getUW(i.reg1!!)
|
val value = registers.getUW(i.reg1!!)
|
||||||
valueStack.pushw(value)
|
valueStack.pushw(value)
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {
|
||||||
|
val value = registers.getSL(i.reg1!!)
|
||||||
|
valueStack.pushl(value)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.FLOAT -> {
|
||||||
val value = registers.getFloat(i.fpReg1!!)
|
val value = registers.getFloat(i.fpReg1!!)
|
||||||
valueStack.pushf(value)
|
valueStack.pushf(value)
|
||||||
@@ -389,6 +398,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> setResultReg(i.reg1!!, valueStack.removeLast().toInt(), i.type!!)
|
IRDataType.BYTE -> setResultReg(i.reg1!!, valueStack.removeLast().toInt(), i.type!!)
|
||||||
IRDataType.WORD -> setResultReg(i.reg1!!, valueStack.popw().toInt(), i.type!!)
|
IRDataType.WORD -> setResultReg(i.reg1!!, valueStack.popw().toInt(), i.type!!)
|
||||||
|
IRDataType.LONG -> setResultReg(i.reg1!!, valueStack.popl(), i.type!!)
|
||||||
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, valueStack.popf())
|
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, valueStack.popf())
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -425,6 +435,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(value.dt!!) {
|
when(value.dt!!) {
|
||||||
IRDataType.BYTE -> valueStack.add(value.value as UByte)
|
IRDataType.BYTE -> valueStack.add(value.value as UByte)
|
||||||
IRDataType.WORD -> valueStack.pushw(value.value as UShort)
|
IRDataType.WORD -> valueStack.pushw(value.value as UShort)
|
||||||
|
IRDataType.LONG -> valueStack.pushl(value.value as Int)
|
||||||
IRDataType.FLOAT -> valueStack.pushf(value.value as Double)
|
IRDataType.FLOAT -> valueStack.pushf(value.value as Double)
|
||||||
}
|
}
|
||||||
value.dt=null
|
value.dt=null
|
||||||
@@ -472,6 +483,11 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
registers.setUW(i.reg1!!, value)
|
registers.setUW(i.reg1!!, value)
|
||||||
statusbitsNZ(value.toInt(), i.type!!)
|
statusbitsNZ(value.toInt(), i.type!!)
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {
|
||||||
|
val value = memory.getSL(i.address!!)
|
||||||
|
registers.setSL(i.reg1!!, value)
|
||||||
|
statusbitsNZ(value, i.type!!)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!!))
|
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!!))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -489,6 +505,11 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
registers.setUW(i.reg1!!, value)
|
registers.setUW(i.reg1!!, value)
|
||||||
statusbitsNZ(value.toInt(), i.type!!)
|
statusbitsNZ(value.toInt(), i.type!!)
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {
|
||||||
|
val value = memory.getSL(registers.getUW(i.reg2!!).toInt())
|
||||||
|
registers.setSL(i.reg1!!, value)
|
||||||
|
statusbitsNZ(value, i.type!!)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt()))
|
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt()))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -508,6 +529,11 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
registers.setUW(i.reg1!!, value)
|
registers.setUW(i.reg1!!, value)
|
||||||
statusbitsNZ(value.toInt(), i.type!!)
|
statusbitsNZ(value.toInt(), i.type!!)
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {
|
||||||
|
val value = memory.getSL(registers.getUW(i.reg2!!).toInt() + offset)
|
||||||
|
registers.setSL(i.reg1!!, value)
|
||||||
|
statusbitsNZ(value.toInt(), i.type!!)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.FLOAT -> {
|
||||||
registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt() + offset))
|
registers.setFloat(i.fpReg1!!, memory.getFloat(registers.getUW(i.reg1!!).toInt() + offset))
|
||||||
}
|
}
|
||||||
@@ -527,6 +553,11 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
registers.setUW(i.reg1!!, value)
|
registers.setUW(i.reg1!!, value)
|
||||||
statusbitsNZ(value.toInt(), i.type!!)
|
statusbitsNZ(value.toInt(), i.type!!)
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {
|
||||||
|
val value = memory.getSL(i.address!! + registers.getUB(i.reg2!!).toInt())
|
||||||
|
registers.setSL(i.reg1!!, value)
|
||||||
|
statusbitsNZ(value, i.type!!)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!! + registers.getUB(i.reg1!!).toInt()))
|
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, memory.getFloat(i.address!! + registers.getUB(i.reg1!!).toInt()))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -546,6 +577,12 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
registers.setUW(i.reg1!!, value)
|
registers.setUW(i.reg1!!, value)
|
||||||
statusbitsNZ(value.toInt(), i.type!!)
|
statusbitsNZ(value.toInt(), i.type!!)
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {
|
||||||
|
val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg2!!)
|
||||||
|
val value = memory.getSL(pointer.toInt())
|
||||||
|
registers.setSL(i.reg1!!, value)
|
||||||
|
statusbitsNZ(value, i.type!!)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.FLOAT -> {
|
||||||
val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg1!!)
|
val pointer = memory.getUW(i.address!!) + registers.getUB(i.reg1!!)
|
||||||
registers.setFloat(i.fpReg1!!, memory.getFloat(pointer.toInt()))
|
registers.setFloat(i.fpReg1!!, memory.getFloat(pointer.toInt()))
|
||||||
@@ -566,6 +603,11 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
registers.setUW(i.reg1!!, value)
|
registers.setUW(i.reg1!!, value)
|
||||||
statusbitsNZ(value.toInt(), i.type!!)
|
statusbitsNZ(value.toInt(), i.type!!)
|
||||||
}
|
}
|
||||||
|
IRDataType.LONG -> {
|
||||||
|
val value = registers.getSL(i.reg2!!)
|
||||||
|
registers.setSL(i.reg1!!, value)
|
||||||
|
statusbitsNZ(value, i.type!!)
|
||||||
|
}
|
||||||
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg2!!))
|
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, registers.getFloat(i.fpReg2!!))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -575,6 +617,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(i.address!!, registers.getUB(i.reg1!!))
|
IRDataType.BYTE -> memory.setUB(i.address!!, registers.getUB(i.reg1!!))
|
||||||
IRDataType.WORD -> memory.setUW(i.address!!, registers.getUW(i.reg1!!))
|
IRDataType.WORD -> memory.setUW(i.address!!, registers.getUW(i.reg1!!))
|
||||||
|
IRDataType.LONG -> memory.setSL(i.address!!, registers.getSL(i.reg1!!))
|
||||||
IRDataType.FLOAT -> memory.setFloat(i.address!!, registers.getFloat(i.fpReg1!!))
|
IRDataType.FLOAT -> memory.setFloat(i.address!!, registers.getFloat(i.fpReg1!!))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -584,6 +627,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when (i.type!!) {
|
when (i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt(), registers.getUB(i.reg1!!))
|
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt(), registers.getUB(i.reg1!!))
|
||||||
IRDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt(), registers.getUW(i.reg1!!))
|
IRDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt(), registers.getUW(i.reg1!!))
|
||||||
|
IRDataType.LONG -> memory.setSL(registers.getUW(i.reg2!!).toInt(), registers.getSL(i.reg1!!))
|
||||||
IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), registers.getFloat(i.fpReg1!!))
|
IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), registers.getFloat(i.fpReg1!!))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -595,6 +639,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when (i.type!!) {
|
when (i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt() + offset, registers.getUB(i.reg1!!))
|
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg2!!).toInt() + offset, registers.getUB(i.reg1!!))
|
||||||
IRDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt() + offset, registers.getUW(i.reg1!!))
|
IRDataType.WORD -> memory.setUW(registers.getUW(i.reg2!!).toInt() + offset, registers.getUW(i.reg1!!))
|
||||||
|
IRDataType.LONG -> memory.setSL(registers.getUW(i.reg2!!).toInt() + offset, registers.getSL(i.reg1!!))
|
||||||
IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt() + offset, registers.getFloat(i.fpReg1!!))
|
IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt() + offset, registers.getFloat(i.fpReg1!!))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -604,6 +649,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when (i.type!!) {
|
when (i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getUB(i.reg1!!))
|
IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getUB(i.reg1!!))
|
||||||
IRDataType.WORD -> memory.setUW(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getUW(i.reg1!!))
|
IRDataType.WORD -> memory.setUW(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getUW(i.reg1!!))
|
||||||
|
IRDataType.LONG -> memory.setSL(i.address!! + registers.getUB(i.reg2!!).toInt(), registers.getSL(i.reg1!!))
|
||||||
IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), registers.getFloat(i.fpReg1!!))
|
IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), registers.getFloat(i.fpReg1!!))
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -631,6 +677,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(i.address!!, 0u)
|
IRDataType.BYTE -> memory.setUB(i.address!!, 0u)
|
||||||
IRDataType.WORD -> memory.setUW(i.address!!, 0u)
|
IRDataType.WORD -> memory.setUW(i.address!!, 0u)
|
||||||
|
IRDataType.LONG -> memory.setSL(i.address!!, 0)
|
||||||
IRDataType.FLOAT -> memory.setFloat(i.address!!, 0.0)
|
IRDataType.FLOAT -> memory.setFloat(i.address!!, 0.0)
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -640,6 +687,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when (i.type!!) {
|
when (i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg1!!).toInt(), 0u)
|
IRDataType.BYTE -> memory.setUB(registers.getUW(i.reg1!!).toInt(), 0u)
|
||||||
IRDataType.WORD -> memory.setUW(registers.getUW(i.reg1!!).toInt(), 0u)
|
IRDataType.WORD -> memory.setUW(registers.getUW(i.reg1!!).toInt(), 0u)
|
||||||
|
IRDataType.LONG -> memory.setSL(registers.getUW(i.reg1!!).toInt(), 0)
|
||||||
IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), 0.0)
|
IRDataType.FLOAT -> memory.setFloat(registers.getUW(i.reg1!!).toInt(), 0.0)
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -649,6 +697,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when (i.type!!) {
|
when (i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u)
|
IRDataType.BYTE -> memory.setUB(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u)
|
||||||
IRDataType.WORD -> memory.setUW(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u)
|
IRDataType.WORD -> memory.setUW(i.address!! + registers.getUB(i.reg1!!).toInt(), 0u)
|
||||||
|
IRDataType.LONG -> memory.setSL(i.address!! + registers.getUB(i.reg1!!).toInt(), 0)
|
||||||
IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), 0.0)
|
IRDataType.FLOAT -> memory.setFloat(i.address!! + registers.getUB(i.reg1!!).toInt(), 0.0)
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -1922,6 +1971,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte())
|
IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte())
|
||||||
IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort())
|
IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort())
|
||||||
|
IRDataType.LONG -> registers.setSL(i.reg1!!, value)
|
||||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||||
}
|
}
|
||||||
statusbitsNZ(value, i.type!!)
|
statusbitsNZ(value, i.type!!)
|
||||||
@@ -1973,6 +2023,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte())
|
IRDataType.BYTE -> registers.setUB(i.reg1!!, value.toUByte())
|
||||||
IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort())
|
IRDataType.WORD -> registers.setUW(i.reg1!!, value.toUShort())
|
||||||
|
IRDataType.LONG -> registers.setSL(i.reg1!!, value)
|
||||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||||
}
|
}
|
||||||
statusbitsNZ(value, i.type!!)
|
statusbitsNZ(value, i.type!!)
|
||||||
@@ -2022,6 +2073,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg1!!).inv())
|
IRDataType.BYTE -> registers.setUB(i.reg1!!, registers.getUB(i.reg1!!).inv())
|
||||||
IRDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(i.reg1!!).inv())
|
IRDataType.WORD -> registers.setUW(i.reg1!!, registers.getUW(i.reg1!!).inv())
|
||||||
|
IRDataType.LONG -> registers.setSL(i.reg1!!, registers.getSL(i.reg1!!).inv())
|
||||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -2032,6 +2084,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> memory.setUB(address, memory.getUB(address).inv())
|
IRDataType.BYTE -> memory.setUB(address, memory.getUB(address).inv())
|
||||||
IRDataType.WORD -> memory.setUW(address, memory.getUW(address).inv())
|
IRDataType.WORD -> memory.setUW(address, memory.getUW(address).inv())
|
||||||
|
IRDataType.LONG -> memory.setSL(address, memory.getSL(address).inv())
|
||||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -2042,6 +2095,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte())
|
IRDataType.BYTE -> registers.setSB(i.reg1!!, (left shr right).toByte())
|
||||||
IRDataType.WORD -> registers.setSW(i.reg1!!, (left shr right).toShort())
|
IRDataType.WORD -> registers.setSW(i.reg1!!, (left shr right).toShort())
|
||||||
|
IRDataType.LONG -> registers.setSL(i.reg1!!, (left shr right))
|
||||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -2104,6 +2158,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
when(i.type!!) {
|
when(i.type!!) {
|
||||||
IRDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte())
|
IRDataType.BYTE -> registers.setUB(i.reg1!!, (left shr right.toInt()).toUByte())
|
||||||
IRDataType.WORD -> registers.setUW(i.reg1!!, (left shr right.toInt()).toUShort())
|
IRDataType.WORD -> registers.setUW(i.reg1!!, (left shr right.toInt()).toUShort())
|
||||||
|
IRDataType.LONG -> registers.setSL(i.reg1!!, (left shr right.toInt()).toInt())
|
||||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||||
}
|
}
|
||||||
nextPc()
|
nextPc()
|
||||||
@@ -2582,6 +2637,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
return when(i.type) {
|
return when(i.type) {
|
||||||
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt())
|
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt())
|
||||||
IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), registers.getSW(i.reg2!!).toInt())
|
IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), registers.getSW(i.reg2!!).toInt())
|
||||||
|
IRDataType.LONG -> Pair(registers.getSL(i.reg1!!), registers.getSL(i.reg2!!))
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.FLOAT -> {
|
||||||
throw IllegalArgumentException("can't use float here")
|
throw IllegalArgumentException("can't use float here")
|
||||||
}
|
}
|
||||||
@@ -2593,6 +2649,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
return when(i.type) {
|
return when(i.type) {
|
||||||
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), i.immediate!!)
|
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), i.immediate!!)
|
||||||
IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), i.immediate!!)
|
IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), i.immediate!!)
|
||||||
|
IRDataType.LONG -> Pair(registers.getSL(i.reg1!!), i.immediate!!)
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.FLOAT -> {
|
||||||
throw IllegalArgumentException("can't use float here")
|
throw IllegalArgumentException("can't use float here")
|
||||||
}
|
}
|
||||||
@@ -2604,8 +2661,8 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
return when(i.type) {
|
return when(i.type) {
|
||||||
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt())
|
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt())
|
||||||
IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt())
|
IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt())
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.LONG, IRDataType.FLOAT -> {
|
||||||
throw IllegalArgumentException("can't use float here")
|
throw IllegalArgumentException("can't use long or float here")
|
||||||
}
|
}
|
||||||
null -> throw IllegalArgumentException("need type for branch instruction")
|
null -> throw IllegalArgumentException("need type for branch instruction")
|
||||||
}
|
}
|
||||||
@@ -2615,8 +2672,8 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
return when(i.type) {
|
return when(i.type) {
|
||||||
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), i.immediate!!.toUInt())
|
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), i.immediate!!.toUInt())
|
||||||
IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), i.immediate!!.toUInt())
|
IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), i.immediate!!.toUInt())
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.LONG, IRDataType.FLOAT -> {
|
||||||
throw IllegalArgumentException("can't use float here")
|
throw IllegalArgumentException("can't use long or float here")
|
||||||
}
|
}
|
||||||
null -> throw IllegalArgumentException("need type for branch instruction")
|
null -> throw IllegalArgumentException("need type for branch instruction")
|
||||||
}
|
}
|
||||||
@@ -2626,8 +2683,8 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
return when(i.type) {
|
return when(i.type) {
|
||||||
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt())
|
IRDataType.BYTE -> Pair(registers.getUB(i.reg1!!).toUInt(), registers.getUB(i.reg2!!).toUInt())
|
||||||
IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt())
|
IRDataType.WORD -> Pair(registers.getUW(i.reg1!!).toUInt(), registers.getUW(i.reg2!!).toUInt())
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.LONG, IRDataType.FLOAT -> {
|
||||||
throw IllegalArgumentException("can't use float here")
|
throw IllegalArgumentException("can't use long or float here")
|
||||||
}
|
}
|
||||||
null -> throw IllegalArgumentException("need type for logical instruction")
|
null -> throw IllegalArgumentException("need type for logical instruction")
|
||||||
}
|
}
|
||||||
@@ -2637,6 +2694,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
return when(i.type) {
|
return when(i.type) {
|
||||||
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt())
|
IRDataType.BYTE -> Pair(registers.getSB(i.reg1!!).toInt(), registers.getSB(i.reg2!!).toInt())
|
||||||
IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), registers.getSW(i.reg2!!).toInt())
|
IRDataType.WORD -> Pair(registers.getSW(i.reg1!!).toInt(), registers.getSW(i.reg2!!).toInt())
|
||||||
|
IRDataType.LONG -> Pair(registers.getSL(i.reg1!!), registers.getSL(i.reg2!!))
|
||||||
IRDataType.FLOAT -> {
|
IRDataType.FLOAT -> {
|
||||||
throw IllegalArgumentException("can't use float here")
|
throw IllegalArgumentException("can't use float here")
|
||||||
}
|
}
|
||||||
@@ -2750,6 +2808,13 @@ internal fun ArrayDeque<UByte>.pushw(value: UShort) {
|
|||||||
add((value.toInt() ushr 8).toUByte())
|
add((value.toInt() ushr 8).toUByte())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun ArrayDeque<UByte>.pushl(value: Int) {
|
||||||
|
add((value and 255).toUByte())
|
||||||
|
add((value ushr 8).toUByte())
|
||||||
|
add((value ushr 16).toUByte())
|
||||||
|
add((value ushr 24).toUByte())
|
||||||
|
}
|
||||||
|
|
||||||
internal fun ArrayDeque<UByte>.pushf(value: Double) {
|
internal fun ArrayDeque<UByte>.pushf(value: Double) {
|
||||||
// push float; lsb first, msb last
|
// push float; lsb first, msb last
|
||||||
var bits = value.toBits()
|
var bits = value.toBits()
|
||||||
@@ -2776,6 +2841,14 @@ internal fun ArrayDeque<UByte>.popw(): UShort {
|
|||||||
return ((msb.toInt() shl 8) + lsb.toInt()).toUShort()
|
return ((msb.toInt() shl 8) + lsb.toInt()).toUShort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun ArrayDeque<UByte>.popl(): Int {
|
||||||
|
val msb24 = removeLast()
|
||||||
|
val msb16 = removeLast()
|
||||||
|
val msb = removeLast()
|
||||||
|
val lsb = removeLast()
|
||||||
|
return (msb24.toInt() shl 24) + (msb16.toInt() shl 16) + (msb.toInt() shl 8) + lsb.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
internal fun ArrayDeque<UByte>.popf(): Double {
|
internal fun ArrayDeque<UByte>.popf(): Double {
|
||||||
// pop float; lsb is on bottom, msb on top
|
// pop float; lsb is on bottom, msb on top
|
||||||
val b0 = removeLast().toLong()
|
val b0 = removeLast().toLong()
|
||||||
|
Reference in New Issue
Block a user