Compare commits

..

1 Commits

Author SHA1 Message Date
Irmen de Jong
df56be32b2 working on long variable type 2025-07-15 20:28:03 +02:00
47 changed files with 277 additions and 780 deletions

View File

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

View File

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

View File

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

View File

@@ -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 {{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 {{

View File

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

View File

@@ -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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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:

View File

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

View File

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

View File

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

View File

@@ -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? ")

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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