diff --git a/LICENSE b/LICENSE
index f823fec..4c593e1 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
BSD 2-Clause License
-Copyright (c) 2022, Tom Herman
+Copyright (c) 2023, Tom Herman
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index efc2933..840615c 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,11 @@
# FlipJump
+[![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/tomhea/flip-jump)](https://github.com/tomhea/flip-jump#project-structure)
+[![GitHub release (latest by date)](https://img.shields.io/github/v/release/tomhea/flip-jump)](https://github.com/tomhea/flip-jump/releases/latest)
+[![GitHub Discussions](https://img.shields.io/github/discussions/tomhea/flip-jump)](https://github.com/tomhea/flip-jump/discussions)
+[![GitHub](https://img.shields.io/github/license/tomhea/flip-jump)](LICENSE)
+[![Website](https://img.shields.io/website?down_color=red&down_message=down&up_message=up&url=https%3A%2F%2Fesolangs.org%2Fwiki%2FFlipJump)](https://esolangs.org/wiki/FlipJump)
+
FlipJump is the simplest programing language.
Yet, it can do **any modern computation**.
@@ -64,11 +70,11 @@ def end_loop @ loop_label {
The FlipJump assembly supports a ```"Hello, World!"``` syntax for initializing a variable with a string value.
Look at the [hello_world.fj](programs/print_tests/hello_world.fj) program for more info.
-Note that all of these macros are already implemented in the standard library:
-- startup in [runlib.fj](stl/runlib.fj)
-- end_loop in [bitlib.fj](stl/bitlib.fj) (loop)
-- output_char in [iolib.fj](stl/iolib.fj)
-- output in [iolib.fj](stl/iolib.fj) (for printing string consts, e.g. output "Hello, World!")
+Note that all of these macros are already implemented in the standard library (all in [runlib.fj](stl/runlib.fj)):
+- startup
+- end_loop (loop)
+- output_char
+- output (for printing string consts, e.g. output "Hello, World!")
# How to download?
@@ -79,7 +85,9 @@ Cloning into 'flip-jump'...
>>> pip install -r requirements.txt
```
-You can add syntax highlighting support for *.fj files on Pycharm - just import the [PycharmHighlighting.zip](PycharmHighlighting.zip) settings.
+Pycharm Extensions:
+- Add syntax highlighting support for *.fj files - just import the [PycharmHighlighting.zip](ide-extensions/pycharm/PycharmHighlighting.zip) settings.
+- Add a ctrl+shift+click (find fj-macro definition) functionality by using the [AutoHotKey script](ide-extensions/pycharm/fj-pycharm-def-finder.ahk).
# How to run?
@@ -114,6 +122,15 @@ You can also use the faster [cpp-based interpreter](https://github.com/tomhea/fj
Hello, World!
```
+### How to Debug?
+Programs won't work on their first run. They just can't. That's why we support the next debugging flags.
+
+- No debugging flags at all: Shows the last 10 executed addresses of tests that failed their run (i.e. finished not by looping).
+- `-d [PATH]`: Save debug information: Adds [very extensive label names](tests/README.md#example-label-name-youll-get-with-using---debuginfo-len), Which are like a "**macro-stack**" for each of the last executed address. (can be used with `--debug-ops-list LEN`)
+- `--debug-ops-list LEN`: Shows the last _LEN_ executed addresses (instead of 10). (can be used with `-d`)
+- `-b NAME [NAME ...]`: Places breakpoints at every specified label NAMEs (note that label names are long: [more information about labels](src/README.md#generated-label-names)). (requires `-b`)
+- `-B NAME [NAME ...]`: Places breakpoints at every label that contains one of the given NAMEs. (requires `-b`)
+
# Project Structure
**[src](src/README.md)** (assembler + interpreter source files):
@@ -126,11 +143,11 @@ Hello, World!
- [more...](src/README.md)
**[stl](stl/README.md)** (standard library files - macros. [list of all macros](https://esolangs.org/wiki/FlipJump#The_Standard_Library)):
- - runlib.fj - constants and initialization macros.
- - bitlib.fj - macros for manipulating binary variables and vectors (i.e. numbers).
+ - runlib.fj - constants and initialization macros. output constant strings.
+ - [bit/](stl/README.md#bit) - macros for io/manipulating binary variables and vectors (i.e. numbers).
- mathlib.fj - advanced math macros (mul/div).
- - hexlib.fj - macros for manipulating hexadecimal variables and vectors.
- - iolib.fj - input/output macros, bit/hex/dec casting.
+ - [hex/](stl/README.md#hex) - macros for io/manipulating hexadecimal variables and vectors.
+ - casting.fj - casting between bit/hex.
- ptrlib.fj - pointers, stack and functions.
- conf.json - standard library list file.
@@ -164,7 +181,7 @@ Read more about the [flip-jump source files](src/README.md) and [how to run the
If you want to contribute to this project, read the [CONTRIBUTING.md](CONTRIBUTING.md) file, and take a look at the [Discussions](https://github.com/tomhea/flip-jump/discussions/148).
-If you are new to FlipJump and you want to learn how modern computation can be executed using FlipJump, Start by reading the [bitlib.fj](stl/bitlib.fj) standard library file (start with `xor`, `if`). That's where the FlipJump magic begins.
+If you are new to FlipJump and you want to learn how modern computation can be executed using FlipJump, Start by reading the [bit/math.fj](stl/bit/math.fj) standard library file (start with `xor`, `if`). That's where the FlipJump magic begins.
You can also write and run programs for yourself! It is just [that](README.md#how-to-run) easy :)
diff --git a/PycharmHighlighting.zip b/ide-extensions/pycharm/PycharmHighlighting.zip
similarity index 100%
rename from PycharmHighlighting.zip
rename to ide-extensions/pycharm/PycharmHighlighting.zip
diff --git a/ide-extensions/pycharm/fj-pycharm-def-finder.ahk b/ide-extensions/pycharm/fj-pycharm-def-finder.ahk
new file mode 100644
index 0000000..3a368aa
--- /dev/null
+++ b/ide-extensions/pycharm/fj-pycharm-def-finder.ahk
@@ -0,0 +1,38 @@
+; Double-click the script (with AutoHotKey v1 installed) to run now. Copy e script to "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup" to still take effect after reboot.
+
+; The script makes a Ctrl+Shift+Click Pycharm shortcut for flip-jump files (Find macro declaration), that resembles the Ctrl+Click shortcut for python (Find function declaration).
+
+; Script summery: Replace Ctrl+Shift+Click with [ Click -> Copy the pointed word -> Ctrl+Shift+F (search in project) -> (search) "def " + copied word ].
+
+
+^+Lbutton::
+{
+ old_clipboard := clipboard
+
+ ; Click
+ Send {Lbutton}
+
+ ; Mark the pointed word
+ Send ^{Left}
+ Send ^+{Right}
+
+ ; Copy the pointed word
+ Send ^c
+
+ ; Unmark word
+ Send {Right}
+
+ ; Open the "Find in files" window (shortcut in Pycharm)
+ Send ^+f
+ Sleep 100
+
+ ; Search for "def COPIED_WORD"
+ Send {Home}
+ Send +{End}
+ Send def{Space}
+ Send ^v
+ Send {Space}
+
+ clipboard := old_clipboard
+ return
+}
\ No newline at end of file
diff --git a/programs/calc.fj b/programs/calc.fj
index ebb7839..351e74b 100644
--- a/programs/calc.fj
+++ b/programs/calc.fj
@@ -1,4 +1,4 @@
-startup
+stl.startup
loop:
@@ -39,7 +39,7 @@ loop:
do_print:
print_int a
- output '\n'
+ stl.output '\n'
bit.if should_finish, loop, finish
@@ -52,7 +52,7 @@ loop:
line_ended loop, finish, finish
finish:
- loop
+ stl.loop
@@ -70,7 +70,9 @@ def remove_spaces @ main_loop, try2, next_ascii, end < space1, space2, ascii {
-def insert_number x @ check1, set_minus, check2, before_hex, hex_loop, before_dec, dec_loop, minus_flag, end, after_minus < dec, hex_prefix1, hex_prefix2, t, hex, minus, ascii, error, hex_used {
+def insert_number x @ \
+ check1, set_minus, check2, before_hex, hex_loop, before_dec, dec_loop, minus_flag, end, after_minus \
+ < dec, hex_prefix1, hex_prefix2, t, hex, minus, ascii, error, hex_used {
bit.zero w, x
bit.zero minus_flag
bit.cmp 8, ascii, minus, check1, set_minus, check1
@@ -105,7 +107,7 @@ def insert_number x @ check1, set_minus, check2, before_hex, hex_loop, before_de
;dec_loop
minus_flag:
- bit
+ bit.bit
end:
bit.if0 minus_flag, after_minus
bit.neg w, x
@@ -115,7 +117,9 @@ def insert_number x @ check1, set_minus, check2, before_hex, hex_loop, before_de
-def calc a, op, b @ try_add, try_sub, try_mul, try_mul_loop, try_div, try_mod, add, sub, mul, mul_loop, div_mod, div, mod, bad, div_mod_flag, r, q, end < minus, asterisk, error, percentage, roof, slash, plus {
+def calc a, op, b @ try_add, try_sub, try_mul, try_mul_loop, try_div, try_mod, \
+ add, sub, mul, mul_loop, div_mod, div, mod, bad, div_mod_flag, r, q, end \
+ < minus, asterisk, error, percentage, roof, slash, plus {
bit.zero error
try_add:
@@ -159,7 +163,7 @@ def calc a, op, b @ try_add, try_sub, try_mul, try_mul_loop, try_div, try_mod, a
;end
div_mod_flag:
- bit
+ bit.bit
r:
bit.vec w
q:
@@ -206,11 +210,11 @@ def print_int x @ print_hex, end < hex_used {
op: bit.vec 8, 0
ascii: bit.vec 8, 0
-error: bit 0
+error: bit.bit 0
hex: bit.vec 4, 0
dec: bit.vec 4, 0
-should_finish: bit 0
-hex_used: bit 0
+should_finish: bit.bit 0
+hex_used: bit.bit 0
a: bit.vec w, 0
b: bit.vec w, 0
diff --git a/programs/concept_checks/ptr.fj b/programs/concept_checks/bit_ptr.fj
similarity index 64%
rename from programs/concept_checks/ptr.fj
rename to programs/concept_checks/bit_ptr.fj
index d396201..0b01101 100644
--- a/programs/concept_checks/ptr.fj
+++ b/programs/concept_checks/bit_ptr.fj
@@ -1,22 +1,22 @@
-startup
+stl.startup
test0:
bit.ptr_flip p0
bit.if d0, d00, d01
d00:
- output '0'
+ stl.output '0'
;test1
d01:
- output '1'
+ stl.output '1'
;test1
test1:
bit.ptr_jump p1
jump_to6:
- output '6'
+ stl.output '6'
;test2
jump_to7:
- output '7'
+ stl.output '7'
;test2
test2:
@@ -27,10 +27,10 @@ test2:
;p20
;p21
p20:
- output 'N'
+ stl.output 'N'
;test3
p21:
- output 'Y'
+ stl.output 'Y'
;test3
test3:
@@ -38,20 +38,18 @@ test3:
bit.xor_from_ptr d3_var, p3
bit.if d3_var, d30, d31
d30:
- output 'F'
- loop
+ stl.output 'F'
+ stl.loop
d31:
- output 'T'
- loop
+ stl.output 'T'
+ stl.loop
- bit.ptr_init
-
p0:
bit.vec w, d0+dbit
d0:
- bit 0 // 0 => 1, 1 => 0
+ bit.bit 0 // 0 => 1, 1 => 0
p1:
bit.vec w, d1
@@ -63,11 +61,14 @@ test3:
p2_jump:
bit.vec w, d2
d2:
- bit 0 // 0 => N, 1 => Y
+ bit.bit 0 // 0 => N, 1 => Y
p3:
bit.vec w, d3
d3:
- bit 1 // 0 => F, 1 => T
+ bit.bit 1 // 0 => F, 1 => T
d3_var:
- bit 0
+ bit.bit 0
+
+
+bit.pointers.ptr_init
diff --git a/programs/concept_checks/casting.fj b/programs/concept_checks/casting.fj
index a262f6d..a32346c 100644
--- a/programs/concept_checks/casting.fj
+++ b/programs/concept_checks/casting.fj
@@ -1,31 +1,31 @@
-startup
+stl.startup
-bit2hex h, b0
+stl.bit2hex h, b0
hex.print_as_digit h, 0
-bit2hex h, b1
+stl.bit2hex h, b1
hex.print_as_digit h, 0
-output '\n'
+stl.output '\n'
-bit2hex 12, hex, bits
+stl.bit2hex 12, hex, bits
hex.print_as_digit 3, hex, 0
-output '\n'
-output '\n'
+stl.output '\n'
+stl.output '\n'
-hex2bit 10, bits2, hex2
+stl.hex2bit 10, bits2, hex2
hex.print_as_digit 10, hex2, 0
-output '\n'
-bit2hex 40, hex2, bits2
+stl.output '\n'
+stl.bit2hex 40, hex2, bits2
bit.print_hex_uint 40, bits2, 0
-output '\n'
+stl.output '\n'
bit.print_as_digit 40, bits2
-output '\n'
+stl.output '\n'
-loop
+stl.loop
-b0: bit 0
-b1: bit 1
-h: hex
+b0: bit.bit 0
+b1: bit.bit 1
+h: hex.hex
bits: bit.vec 12, 0x123
hex: hex.vec 3
diff --git a/programs/concept_checks/hex_ptr.fj b/programs/concept_checks/hex_ptr.fj
new file mode 100644
index 0000000..f76bc4c
--- /dev/null
+++ b/programs/concept_checks/hex_ptr.fj
@@ -0,0 +1,71 @@
+stl.startup
+
+test0:
+ hex.ptr_flip p0
+ bit.if d0, d00, d01
+ d00:
+ stl.output '0'
+ ;test1
+ d01:
+ stl.output '1'
+ ;test1
+
+test1:
+ hex.ptr_jump p1
+ jump_to6:
+ stl.output '6'
+ ;test2
+ jump_to7:
+ stl.output '7'
+ ;test2
+
+test2:
+ hex.ptr_wflip p2, base_jump_label2
+ hex.ptr_jump p2_jump
+ pad 2
+ base_jump_label2:
+ ;p20
+ ;p21
+ p20:
+ stl.output 'N'
+ ;test3
+ p21:
+ stl.output 'Y'
+ ;test3
+
+test3:
+ hex.set d3, 6
+ hex.set d3_var, 0xD
+ hex.xor_from_ptr d3_var, p3
+ hex.print_as_digit d3_var, 1
+
+ stl.loop
+
+
+
+ p0:
+ hex.vec w/4, d0+dbit
+ d0:
+ bit.bit 0 // 0 => 1, 1 => 0
+
+ p1:
+ hex.vec w/4, d1
+ d1:
+ ;jump_to7 // jump_to6 => 6, jump_to7 => 7
+
+ p2:
+ hex.vec w/4, d2+w
+ p2_jump:
+ hex.vec w/4, d2
+ d2:
+ bit.bit 0 // 0 => N, 1 => Y
+
+ p3:
+ hex.vec w/4, d3
+ d3:
+ hex.hex
+ d3_var:
+ hex.hex
+
+
+stl.ptr_init
diff --git a/programs/concept_checks/pair_ns.fj b/programs/concept_checks/pair_ns.fj
index 5e1bc94..9fd27bf 100644
--- a/programs/concept_checks/pair_ns.fj
+++ b/programs/concept_checks/pair_ns.fj
@@ -23,12 +23,12 @@ ns Pair {
}
def print this {
- output '('
+ stl.output '('
._.print_hex_int this+.first
- output ','
- output ' '
+ stl.output ','
+ stl.output ' '
._.print_hex_int this+.second
- output ')'
+ stl.output ')'
}
def init {
@@ -39,7 +39,7 @@ ns Pair {
def add dst, src < .add, .ret_reg, .temp1, .temp2 {
bit.xor ..len, .temp2, src
bit.xor_zero ..len, .temp1, dst
- fcall .add, .ret_reg
+ stl.fcall .add, .ret_reg
bit.xor_zero ..len, dst, .temp1
bit.zero ..len, .temp2
}
@@ -47,7 +47,7 @@ ns Pair {
def print_hex_int val < .print_hex_int, .ret_reg, .temp1 {
bit.xor ..len, .temp1, val
- fcall .print_hex_int, .ret_reg
+ stl.fcall .print_hex_int, .ret_reg
bit.xor ..len, .temp1, val
}
@@ -56,13 +56,13 @@ ns Pair {
add:
bit.add ..len, .temp1, .temp2
- fret .ret_reg
+ stl.fret .ret_reg
print_hex_int:
bit.print_hex_int ..len, .temp1, 1
- fret .ret_reg
+ stl.fret .ret_reg
- ret_reg: bit 0
+ ret_reg: bit.bit 0
temp1: bit.vec ..len, 0
temp2: bit.vec ..len, 0
@@ -78,11 +78,11 @@ ns Pair {
ns prints {
def print_two p1, p2 {
..print p1
- output ','
- output ' '
- output ' '
+ stl.output ','
+ stl.output ' '
+ stl.output ' '
..print p2
- output '\n'
+ stl.output '\n'
}
}
}
diff --git a/programs/concept_checks/segments.fj b/programs/concept_checks/segments.fj
index 19a7b2a..92dc081 100644
--- a/programs/concept_checks/segments.fj
+++ b/programs/concept_checks/segments.fj
@@ -1,4 +1,4 @@
-startup
+stl.startup
X1 = 0x10000000
X2 = 0x20000000
@@ -22,7 +22,7 @@ back:
error:
- bit
+ bit.bit
str_hi:
bit.str "Hi!\n"
@@ -46,7 +46,7 @@ segment X4
bit.print_hex_int 20, num, 1
;back
end:
- loop
+ stl.loop
num:
reserve dw*10
diff --git a/programs/func_tests/func1.fj b/programs/func_tests/func1.fj
index be5b488..0126cd7 100644
--- a/programs/func_tests/func1.fj
+++ b/programs/func_tests/func1.fj
@@ -1,19 +1,18 @@
-startup
+// Tests a parameterless function call
+
+
+stl.startup_and_init_all 10
// Prints "ABC"
test1:
- output 'A'
- bit.call func1
- output 'C'
+ stl.output 'A'
+ stl.call func1
+ stl.output 'C'
- output '\n'
- loop
+ stl.output '\n'
+ stl.loop
func1:
- output 'B'
- bit.return
-
-
-bit.ptr_init
-bit.stack 10
+ stl.output 'B'
+ stl.return
diff --git a/programs/func_tests/func2.fj b/programs/func_tests/func2.fj
index 8041108..f68f886 100644
--- a/programs/func_tests/func2.fj
+++ b/programs/func_tests/func2.fj
@@ -1,30 +1,29 @@
-startup
+// Tests a diamond call-stack. (main->a->c ==> main->b->c)
+
+
+stl.startup_and_init_all 10
// Prints "AB~CD~EF"
test2:
- output 'A'
- bit.call func2a
- bit.call func2b
- output 'F'
+ stl.output 'A'
+ stl.call func2a
+ stl.call func2b
+ stl.output 'F'
- output '\n'
- loop
+ stl.output '\n'
+ stl.loop
func2a:
- output 'B'
- bit.call func2c
- output 'C'
- bit.return
+ stl.output 'B'
+ stl.call func2c
+ stl.output 'C'
+ stl.return
func2b:
- output 'D'
- bit.call func2c
- output 'E'
- bit.return
+ stl.output 'D'
+ stl.call func2c
+ stl.output 'E'
+ stl.return
func2c:
- output '~'
- bit.return
-
-
-bit.ptr_init
-bit.stack 10
+ stl.output '~'
+ stl.return
diff --git a/programs/func_tests/func3.fj b/programs/func_tests/func3.fj
index 09541c6..7877e54 100644
--- a/programs/func_tests/func3.fj
+++ b/programs/func_tests/func3.fj
@@ -1,26 +1,26 @@
-startup
+// Tests push/pop_unchanged_parameter with an empty function call
+
+
+stl.startup_and_init_all 10
// Prints "ABCDE"
test3:
- output 'A'
- bit.push x3
- output 'B'
- bit.call func3
- output 'D'
- bit.pop x3
- output 'E'
+ stl.output 'A'
+ hex.push x3
+ stl.output 'B'
+ stl.call func3
+ stl.output 'D'
+ hex.pop_unchanged_parameter x3
+ stl.output 'E'
- output '\n'
- loop
+ stl.output '\n'
+ stl.loop
func3:
- output 'C'
- bit.return
+ stl.output 'C'
+ stl.return
x3:
- bit 0
-
-bit.ptr_init
-bit.stack 10
+ bit.bit 0
diff --git a/programs/func_tests/func4.fj b/programs/func_tests/func4.fj
index 42f0c35..e362b6c 100644
--- a/programs/func_tests/func4.fj
+++ b/programs/func_tests/func4.fj
@@ -1,43 +1,43 @@
-startup
+// Tests the ptr_flip_dbit and function calls
+
+
+stl.startup_and_init_all 10
// Prints "ABCDEFGH-" and then 0/1, the invert of x4
test4:
- output 'A'
- bit.push x4
- output 'B'
+ stl.output 'A'
+ hex.push x4
+ stl.output 'B'
- bit.call func4
+ stl.call func4
- output 'G'
- bit.pop_res x4
- output 'H'
+ stl.output 'G'
+ hex.pop x4
+ stl.output 'H'
bit.bin2ascii ascii, x4
- output '-'
+ stl.output '-'
bit.print ascii
- output '\n'
- loop
+ stl.output '\n'
+ stl.loop
func4:
- output 'C'
- bit.get_sp __func4_arg_ptr
- output 'D'
- bit.dec_ptr __func4_arg_ptr
- output 'E'
- bit.ptr_flip_dbit __func4_arg_ptr
- output 'F'
- bit.return
+ stl.output 'C'
+ stl.get_sp __func4_arg_ptr
+ stl.output 'D'
+ hex.ptr_dec __func4_arg_ptr
+ stl.output 'E'
+ hex.ptr_flip_dbit __func4_arg_ptr
+ stl.output 'F'
+ stl.return
__func4_arg_ptr:
- bit.vec w, 0
+ hex.vec w/4, 0
x4:
- bit 0
+ bit.bit 0
ascii:
bit.vec 8
-
-bit.ptr_init
-bit.stack 10
diff --git a/programs/func_tests/func5.fj b/programs/func_tests/func5.fj
index 253ed85..50bb053 100644
--- a/programs/func_tests/func5.fj
+++ b/programs/func_tests/func5.fj
@@ -1,70 +1,70 @@
-startup
+// Tests the xor_from_ptr, xor_to_ptr and function calls
+
+
+stl.startup_and_init_all 10
// Prints "ABC abcdefg ABCD-", and then 0/1, the xor of x5,y5
test5:
- output 'A'
- bit.push res5
- output 'B'
- bit.push x5
- output 'C'
- bit.push y5
+ stl.output 'A'
+ hex.push res5
+ stl.output 'B'
+ hex.push x5
+ stl.output 'C'
+ hex.push y5
- output ' '
- bit.call func5
- output ' '
+ stl.output ' '
+ stl.call func5
+ stl.output ' '
- output 'A'
- bit.pop y5
- output 'B'
- bit.pop x5
- output 'C'
- bit.pop_res res5
- output 'D'
+ stl.output 'A'
+ hex.pop_unchanged_parameter y5
+ stl.output 'B'
+ hex.pop_unchanged_parameter x5
+ stl.output 'C'
+ hex.pop res5
+ stl.output 'D'
bit.bin2ascii ascii, res5
- output '-'
+ stl.output '-'
bit.print ascii
- output '\n'
- loop
+ stl.output '\n'
+ stl.loop
// res = arg0 xor arg1
func5:
bit.zero __func5_res
- bit.get_sp __func5_arg_ptr
- output 'a'
+ stl.get_sp __func5_arg_ptr
+ stl.output 'a'
- bit.dec_ptr __func5_arg_ptr
- output 'b'
- bit.xor_from_ptr __func5_res, __func5_arg_ptr
- output 'c'
- bit.dec_ptr __func5_arg_ptr
- output 'd'
- bit.xor_from_ptr __func5_res, __func5_arg_ptr
- output 'e'
+ hex.ptr_dec __func5_arg_ptr
+ stl.output 'b'
+ hex.xor_from_ptr __func5_res, __func5_arg_ptr
+ stl.output 'c'
+ hex.ptr_dec __func5_arg_ptr
+ stl.output 'd'
+ hex.xor_from_ptr __func5_res, __func5_arg_ptr
+ stl.output 'e'
- bit.dec_ptr __func5_arg_ptr
- output 'f'
- bit.xor_to_ptr __func5_arg_ptr, __func5_res
- output 'g'
+ hex.ptr_dec __func5_arg_ptr
+ stl.output 'f'
+ hex.xor_to_ptr __func5_arg_ptr, __func5_res
+ stl.output 'g'
- bit.return
+ stl.return
__func5_res:
- bit
+ bit.bit
__func5_arg_ptr:
- bit.vec w
+ hex.vec w/4
x5:
- bit 1
+ bit.bit 1
y5:
- bit 1
+ bit.bit 1
res5:
- bit 0
+ bit.bit 0
ascii:
bit.vec 8
-
-bit.ptr_init
-bit.stack 10
diff --git a/programs/func_tests/func6.fj b/programs/func_tests/func6.fj
new file mode 100644
index 0000000..81e7152
--- /dev/null
+++ b/programs/func_tests/func6.fj
@@ -0,0 +1,43 @@
+// calculate the unsigned multiplication between two numbers.
+
+
+N = 4
+stl.startup_and_init_all 100
+
+hex.set N, x, 7438
+hex.set N, y, 2524
+
+
+hex.push N, x
+hex.push N, y
+stl.call math.add, N
+hex.pop N, res
+hex.print_as_digit N, res, 1
+stl.output '\n'
+
+stl.loop
+
+
+
+ns math {
+add:
+ hex.sp_dec
+ hex.pop N, .res
+ hex.pop N, .temp
+
+ hex.add N, .res, .temp
+
+ hex.push N, .res
+ hex.sp_add N+1
+
+ stl.return
+
+
+temp: hex.vec 2*N
+res: hex.vec 2*N
+}
+
+
+x: hex.vec N
+y: hex.vec N
+res: hex.vec N
diff --git a/programs/func_tests/func7.fj b/programs/func_tests/func7.fj
new file mode 100644
index 0000000..faf1ca4
--- /dev/null
+++ b/programs/func_tests/func7.fj
@@ -0,0 +1,207 @@
+// Calculate the squared distance between each pair of points (between the 3 points)
+// Tests a complicated call stack, with many push/pop n, that's repeated 3 times.
+
+
+stl.startup_and_init_all 100
+N = 2
+
+hex.set N, p1_x, 9
+hex.set N, p1_y, 0-54
+
+hex.set N, p2_x, 0-22
+hex.set N, p2_y, 69
+
+hex.set N, p3_x, 87
+hex.set N, p3_y, 0-127
+
+calc_dist_squared p1_x, p1_y, p2_x, p2_y, "dist[p1, p2] ** 2 = 0x"
+calc_dist_squared p1_x, p1_y, p3_x, p3_y, "dist[p1, p3] ** 2 = 0x"
+calc_dist_squared p2_x, p2_y, p3_x, p3_y, "dist[p2, p3] ** 2 = 0x"
+
+
+stl.loop
+
+p1_x: hex.vec N
+p1_y: hex.vec N
+p2_x: hex.vec N
+p2_y: hex.vec N
+p3_x: hex.vec N
+p3_y: hex.vec N
+
+
+
+def calc_dist_squared x1, y1, x2, y2, prefix_distance_string @ end, res < math.square_distance {
+ stl.output 'A'
+ hex.push N, x1
+ hex.push N, y1
+ hex.push N, x2
+ hex.push N, y2
+ stl.output 'B'
+
+ stl.call math.square_distance, 2*N
+ stl.output 'I'
+
+ hex.pop 2*N, res
+ stl.output "J\n"
+
+ stl.output prefix_distance_string
+ hex.print_as_digit 2*N, res, 1
+ stl.output "\n\n"
+
+ ;end
+ res: hex.vec 2*N
+ end:
+}
+
+
+
+ns math {
+sub:
+ns sub {
+ hex.sp_dec
+ hex.pop N, .res
+ hex.pop N, .temp
+ stl.output "-1"
+
+ hex.sub N, .res, .temp
+ stl.output '2'
+
+ hex.push N, .res
+ hex.sp_add N+1
+ stl.output "3-"
+
+ stl.return
+res: hex.vec N
+temp: hex.vec N
+}
+
+
+add_2N:
+ns add_2N {
+ hex.sp_dec
+ hex.pop 2*N, .res
+ hex.pop 2*N, .temp
+ stl.output "-1"
+
+ hex.add 2*N, .res, .temp
+ stl.output '2'
+
+ hex.push 2*N, .res
+ hex.sp_add 2*N+1
+ stl.output "3-"
+
+ stl.return
+
+res: hex.vec 2*N
+temp: hex.vec 2*N
+}
+
+
+mul:
+ns mul {
+ stl.output "-1"
+ hex.sp_dec
+
+ stl.output '2'
+ hex.pop N, .temp1
+ hex.sign_extend 2*N, N, .temp1
+ stl.output '3'
+ hex.pop N, .temp2
+ hex.sign_extend 2*N, N, .temp2
+
+ stl.output '4'
+ hex.mul 2*N, .res, .temp1, .temp2
+
+ stl.output '5'
+ hex.push 2*N, .res
+ hex.sp_inc
+
+ stl.output "6-"
+ stl.return
+
+temp1: hex.vec 2*N
+temp2: hex.vec 2*N
+res: hex.vec 2*N
+}
+
+
+square_sub:
+ns square_sub {
+ hex.sp_dec
+ hex.pop N, .b
+ hex.pop N, .a
+ hex.sp_add 2*N+1
+ stl.output 'a'
+
+ hex.push N, .a
+ hex.push N, .b
+ stl.call ..sub, N
+ hex.pop N, .res
+ stl.output 'b'
+
+ hex.push N, .res
+ hex.push N, .res
+ stl.call ..mul
+ hex.pop 2*N, .res
+ stl.output 'c'
+
+ hex.sp_sub 2*N+1
+ hex.push 2*N, .res
+ hex.sp_inc
+ stl.output "d\n"
+
+ stl.return
+
+a: hex.vec 2*N
+b: hex.vec 2*N
+res: hex.vec 2*N
+}
+
+
+square_distance:
+ns square_distance {
+ stl.output 'C'
+ hex.sp_dec
+ hex.pop N, .y2
+ hex.pop N, .x2
+ hex.pop N, .y1
+ hex.pop N, .x1
+ hex.sp_add 4*N+1
+ stl.output 'D'
+
+ // (x1-x2)**2
+ hex.push N, .x1
+ hex.push N, .x2
+ stl.call ..square_sub
+ hex.pop 2*N, .res1
+ stl.output 'E'
+
+ // (y1-y2)**2
+ hex.push N, .y1
+ hex.push N, .y2
+ stl.call ..square_sub
+ hex.pop 2*N, .res2
+ stl.output 'F'
+
+ // (x1-x2)**2 + (y1-y2)**2
+ hex.push 2*N, .res1
+ hex.push 2*N, .res2
+ stl.call ..add_2N, 2*N
+ hex.pop 2*N, .res1
+ stl.output 'G'
+
+ hex.sp_sub 4*N+1
+ hex.push 2*N, .res1
+ hex.sp_add 2*N+1
+ stl.output 'H'
+
+ stl.return
+
+x1: hex.vec N
+y1: hex.vec N
+x2: hex.vec N
+y2: hex.vec N
+res1: hex.vec 2*N
+res2: hex.vec 2*N
+}
+}
diff --git a/programs/hexlib_tests/2params/add.fj b/programs/hexlib_tests/2params/add.fj
index 4109f7c..8cca77d 100644
--- a/programs/hexlib_tests/2params/add.fj
+++ b/programs/hexlib_tests/2params/add.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_add i&0xf, i>>4
-loop
+stl.loop
hex.init
@@ -13,29 +13,29 @@ def test_add a, b @ c0_1st, c1_1st, print_1st, c0_2nd, c1_2nd, print_2nd, ah_1st
hex.add ah_1st, bh
hex.add.clear_carry c0_1st, c1_1st
c0_1st:
- output '0'
+ stl.output '0'
;print_1st
c1_1st:
- output '1'
+ stl.output '1'
print_1st:
hex.print_as_digit ah_1st, 0
- output '-'
+ stl.output '-'
hex.add.not_carry
hex.add ah_2nd, bh
hex.add.clear_carry c0_2nd, c1_2nd
c0_2nd:
- output '0'
+ stl.output '0'
;print_2nd
c1_2nd:
- output '1'
+ stl.output '1'
print_2nd:
hex.print_as_digit ah_2nd, 0
- output '\n'
+ stl.output '\n'
;end
- ah_1st: hex a
- ah_2nd: hex a
- bh: hex b
+ ah_1st: hex.hex a
+ ah_2nd: hex.hex a
+ bh: hex.hex b
end:
}
diff --git a/programs/hexlib_tests/2params/add_n.fj b/programs/hexlib_tests/2params/add_n.fj
index 0207ded..2544c8d 100644
--- a/programs/hexlib_tests/2params/add_n.fj
+++ b/programs/hexlib_tests/2params/add_n.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
ADD_N = 0x0000ffff800040a73dd06622dc0594c9e1b9b001
rep(100, i) test_add_n 4, (ADD_N>>((i%10)*4)&0xf), (ADD_N>>((i/10))*4&0xf)
-loop
+stl.loop
hex.init
@@ -14,18 +14,18 @@ def test_add_n n, a, b @ lt, eq, gt, ah, bh, ch, end {
hex.cmp n, ah, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
ah: hex.vec n, a
bh: hex.vec n, b
ch: hex.vec n, a+b
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/2params/add_shifted.fj b/programs/hexlib_tests/2params/add_shifted.fj
new file mode 100644
index 0000000..f7a4c2d
--- /dev/null
+++ b/programs/hexlib_tests/2params/add_shifted.fj
@@ -0,0 +1,53 @@
+stl.startup
+
+EACH_INDEX_REPEATS = 3
+DST_N = 8
+// ADD_N hex-size is: EACH_INDEX_REPEATS * 2 * DST_N * (DST_N * DST_N)
+ADD_N = 0x747651c5ba3acd47e92894d005eef113e5a0bc88d937e656b8f071e013ae206a10501cdb5a480e243b89bd817bd60288ae8570eb8c34d62914cd47950752869915ca7b5374c2df7b548628846d568decdfd290cbc4ec942acf89808f888d2415aa91b6081a0ac791a166139c3c9ad29ab5c6ae09f16a7aae29ae31d4e0ca3963f22109f1b47865e8b3bce7f4a218255750141fa3f08f8659086cce047014a10db555b996cedd6d609c47a9377d659e9fa546c17361e3f8eac58bf45f02833a987b6b1c0e03f2f7a1e9836862118fd34cb78c6f87c672b5cc6764b2b3b842c1c783cc98a1367ff1f8193a123d24ee1adb4cad7a5927ad24cf43cc6f56647a2fb619a52b48e5003202e353a7a4b1da775282db3f2478396fa872c5ccb159bc31b619e774ff6a3aaa28646e7e58365a7904b19a107d52017a3e5fefbb3b45023b22eb9a473b6aed9ac5ea1094506fba4de9e2808e1870123d5cf20f8a1edea39c9a2863e037e965ae6f581e57dc493126979ac85697e452f731b56df08d8e8bf59e40e2563fd2f5ffcbe0c3878dfa2a8e40e2865dd568b1476fcc57caa4397fe19bc288eeaea731d1291cbdaf94699082e5f362f57aeb67b56b247bc7c0dc87fe8497ccdad95dcb32685a2ac102cef5278c39955a0c96b79abb488047a921509240a5626310e6b6f97a35101009edb2616bc154d6a70b5eb1129aa1a80fbd145f2eae4d10933026285303487ac6984eb445bcfafde8e002844d0242148af9bbc9a37008aea3cf2ca5fe0431ff0e46b23a4e24e37521411dea35889764bd1d13ff3e25489b9aff064a8ecd7052524aae7084826e269e6d30596da015c9eeae37b78182af51b90105a5e04e43433347fd500d1d932092ef50426d5219bf1fd069af129e267aa6afe2e4bc852a17da6a17e82beb51e79e67f701def5511522e78f9d8bafd74b9481c4fc36be3398ebddd52187c37e9fb0c34b3c4560c3d4d8f9e288ea1944e3c87aabe5b7491817ad31ab43901f8805e657b98fdfae8d11cfd9bf93a305abbba9e0297da912c2a94a2ddc0737df438889ff40e86b541cfa4694cde62253b8782403eb86b9f8990974759b9cee0f60f393f54a4027a2d1eac176ae13f4f9fa82d71c9c22be8ec12555183f07ac552ec2bf6e8a13f66d70759f5ad48a08bbfdf1bd408b151e85b079f35499f8734df9f0bb94902d4fc0469f441f99179b7ec4b8818ecdb114ab6b231db46b9f4f8e02c3d00d082db7b8251f8063ce08bba53fb8e2ac160c1a76bbb0dd04c37dae05ff1d4fd23ec5360ca070bd030cf3bbafe8023489a5735b4b7ee9a3584540137caad6c8063e8605b5029ecf5f164f942821114ed83320064b4072da5fbe9eda192bf57796cb344bc24c35aaccd16bfdeda060a1fae48a6b69dff50be79d724c0ddd217562f88cef51b59688db514a7c0fcc567a61c7bc64cdc26d95fe1a913e990c08c64a00ea1cd2e1e1c8c967b96d939a25142f91d52bba681ed4e2d100b75a063b98d79fa6a16de95567b9b35b10fd450d2aec5083ba1bf5b975fb8a298a8cff12d3a6bbb80bd4224e9bbb932d19a5a7d86f56977dfce7fb5993476ef08a4ebbde5d3b6e71356e080b39ac0f76d5c266a4bcbc72e27b12115b4ed742fe4ff52221bda32d00d7559cb552da44e1f13e2cd10f836d054f1c704f78d9c15a86528bd7cf074d2a22554eb315ace78bbf54f5f2baadacf5ec79e78300baa1523200cfe59ebfbdbd3e27b0152b98ef040807ee8bd8fb3c5ac83f29ff68e33f4119eaaafde1147fd8ac692944ff7e8331ef1cfac2d4ab76d0b3e4eb9470aa023a2d4ea03e3839092b2052a9b7a50ce292c3f19b9ae5b5154b83fff85d686dec2414c865af96bd9b5cf1cbfda48cf7c6b9ae71e1fee6ea15010d33efdbde7ebeb03937e442fe8e8d2b37e6e9e40a1cbecebdde0437d91f6337c3d1f94f9541d8d6fac79da7e9d3051a6fc60bd198026c20311568b3d332edade28754910b0504886b12547c9da672343a85057bfe541ac0710312f70d95f685880a0e3c13f82063c81ae7ee6416e98de35e3ca4c66ca40d0e8bc159358624e1f441026ab078dd0e7475723d3cbcd1cce033f5cae51fe8a3f74b44f67c71657916b65cd207c5c1b808c1ab5dd4039e4562cf29c370d1f6ab84
+rep(DST_N, src_n_minus_1) test_entire_src_length_from_data \
+ (ADD_N >> (4*2*DST_N*EACH_INDEX_REPEATS*DST_N * src_n_minus_1)) & ((1<<(4*2*DST_N*EACH_INDEX_REPEATS*DST_N))-1), \
+ DST_N, src_n_minus_1 + 1
+
+stl.loop
+
+
+hex.init
+
+
+def test_entire_src_length_from_data test_data, dst_n, src_n {
+ rep(dst_n - src_n + 1, hex_shift) test_entire_index_from_data \
+ (test_data >> (4*2*DST_N*EACH_INDEX_REPEATS * hex_shift)) & ((1<<(4*2*DST_N*EACH_INDEX_REPEATS))-1), \
+ dst_n, src_n, hex_shift
+}
+
+def test_entire_index_from_data test_data, dst_n, src_n, hex_shift {
+ rep(EACH_INDEX_REPEATS, i) test_1_time_from_data \
+ (test_data >> (4*2*DST_N * i)) & ((1<<(4*2*DST_N))-1), dst_n, src_n, hex_shift
+}
+
+def test_1_time_from_data test_data, dst_n, src_n, hex_shift {
+ test_add_shifted dst_n, src_n, test_data & (0xffffffff), (test_data >> 32) & ((1 << (4*src_n)) - 1), hex_shift
+}
+
+
+// Number of actual tests that run: EACH_INDEX_REPEATS * len([x for x in range(1, DST_N+1) for y in range(0, DST_N) if x + y <= DST_N])
+def test_add_shifted dst_n, src_n, dst_constant, src_constant, hex_shift @ lt, eq, gt, dst, src, expected_result, end {
+ hex.add_shifted dst_n, src_n, dst, src, hex_shift
+ hex.cmp dst_n, dst, expected_result, lt, eq, gt
+
+ lt:
+ stl.output '<'
+ ;end
+ eq:
+ stl.output '='
+ ;end
+ gt:
+ stl.output '>'
+ ;end
+
+ dst: hex.vec dst_n, dst_constant
+ src: hex.vec src_n, src_constant
+ expected_result: hex.vec dst_n, dst_constant + (src_constant << (4*hex_shift))
+ end:
+ stl.output '\n'
+}
diff --git a/programs/hexlib_tests/2params/and.fj b/programs/hexlib_tests/2params/and.fj
index 51d9717..35589ed 100644
--- a/programs/hexlib_tests/2params/and.fj
+++ b/programs/hexlib_tests/2params/and.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_and i&0xf, i>>4
-loop
+stl.loop
hex.init
@@ -13,11 +13,11 @@ def test_and a, b @ ah, ah_copy, bh, end {
hex.and bh, ah_copy
hex.print_as_digit ah, 0
hex.print_as_digit bh, 0
- output '\n'
+ stl.output '\n'
;end
- ah: hex a
- ah_copy: hex a
- bh: hex b
+ ah: hex.hex a
+ ah_copy: hex.hex a
+ bh: hex.hex b
end:
}
diff --git a/programs/hexlib_tests/2params/and_n.fj b/programs/hexlib_tests/2params/and_n.fj
index 7aa6603..cbb8a03 100644
--- a/programs/hexlib_tests/2params/and_n.fj
+++ b/programs/hexlib_tests/2params/and_n.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
AND_N = 0x0000ffff8000b32cccc69dea2047c8e0ae1e5299
rep(100, i) test_and_n 4, (AND_N>>((i%10)*4)&0xf), (AND_N>>((i/10))*4&0xf)
-loop
+stl.loop
hex.init
@@ -14,18 +14,18 @@ def test_and_n n, a, b @ lt, eq, gt, ah, bh, ch, end {
hex.cmp n, ah, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
ah: hex.vec n, a
bh: hex.vec n, b
ch: hex.vec n, a&b
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/2params/cmp.fj b/programs/hexlib_tests/2params/cmp.fj
index cead52e..1504d4f 100644
--- a/programs/hexlib_tests/2params/cmp.fj
+++ b/programs/hexlib_tests/2params/cmp.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_cmp i&0xf, i>>4
-loop
+stl.loop
hex.init
@@ -12,16 +12,16 @@ def test_cmp a, b @ lt, eq, gt, ah, bh, end {
hex.cmp ah, bh, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
- ah: hex a
- bh: hex b
+ ah: hex.hex a
+ bh: hex.hex b
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/2params/cmp_n.fj b/programs/hexlib_tests/2params/cmp_n.fj
index 8852194..87587ea 100644
--- a/programs/hexlib_tests/2params/cmp_n.fj
+++ b/programs/hexlib_tests/2params/cmp_n.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
CMP_N = 0x012345 | (0x123456 << 32) | (0x333333 << 64) | (0x654321 << 96)
rep(16, i) test_cmp_n 8, (CMP_N >> ((i&3)*32)) & ((1<<32)-1), (CMP_N >> ((i>>2)*32)) & ((1<<32)-1)
-loop
+stl.loop
hex.init
@@ -13,16 +13,16 @@ def test_cmp_n n, a, b @ lt, eq, gt, ah, bh, end {
hex.cmp n, ah, bh, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
ah: hex.vec n, a
bh: hex.vec n, b
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/2params/or.fj b/programs/hexlib_tests/2params/or.fj
index c8148c5..e0d74bd 100644
--- a/programs/hexlib_tests/2params/or.fj
+++ b/programs/hexlib_tests/2params/or.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_or i&0xf, i>>4
-loop
+stl.loop
hex.init
@@ -13,11 +13,11 @@ def test_or a, b @ ah, ah_copy, bh, end {
hex.or bh, ah_copy
hex.print_as_digit ah, 0
hex.print_as_digit bh, 0
- output '\n'
+ stl.output '\n'
;end
- ah: hex a
- ah_copy: hex a
- bh: hex b
+ ah: hex.hex a
+ ah_copy: hex.hex a
+ bh: hex.hex b
end:
}
diff --git a/programs/hexlib_tests/2params/or_n.fj b/programs/hexlib_tests/2params/or_n.fj
index 91cced1..e6b04c3 100644
--- a/programs/hexlib_tests/2params/or_n.fj
+++ b/programs/hexlib_tests/2params/or_n.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
OR_N = 0x0000ffff8000c47b5d8bbebfbe0bf47bc2600b85
rep(100, i) test_or_n 4, (OR_N>>((i%10)*4)&0xf), (OR_N>>((i/10))*4&0xf)
-loop
+stl.loop
hex.init
@@ -14,18 +14,18 @@ def test_or_n n, a, b @ lt, eq, gt, ah, bh, ch, end {
hex.cmp n, ah, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
ah: hex.vec n, a
bh: hex.vec n, b
ch: hex.vec n, a|b
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/2params/sub.fj b/programs/hexlib_tests/2params/sub.fj
index 0fbe73a..fc52964 100644
--- a/programs/hexlib_tests/2params/sub.fj
+++ b/programs/hexlib_tests/2params/sub.fj
@@ -1,41 +1,41 @@
-startup
+stl.startup
rep(256, i) test_sub i&0xf, i>>4
-loop
+stl.loop
hex.init
-def test_sub a, b @ c0_1st, c1_1st, print_1st, c0_2nd, c1_2nd, print_2nd, ah_1st, bh, ah_2nd, end < hex.sub.dst {
+def test_sub a, b @ c0_1st, c1_1st, print_1st, c0_2nd, c1_2nd, print_2nd, ah_1st, bh, ah_2nd, end {
hex.sub.clear_carry
hex.sub ah_1st, bh
hex.sub.clear_carry c0_1st, c1_1st
c0_1st:
- output '0'
+ stl.output '0'
;print_1st
c1_1st:
- output 'f'
+ stl.output 'f'
print_1st:
hex.print_as_digit ah_1st, 0
- output '-'
+ stl.output '-'
hex.sub.not_carry
hex.sub ah_2nd, bh
hex.sub.clear_carry c0_2nd, c1_2nd
c0_2nd:
- output '0'
+ stl.output '0'
;print_2nd
c1_2nd:
- output 'f'
+ stl.output 'f'
print_2nd:
hex.print_as_digit ah_2nd, 0
- output '\n'
+ stl.output '\n'
;end
- ah_1st: hex a
- ah_2nd: hex a
- bh: hex b
+ ah_1st: hex.hex a
+ ah_2nd: hex.hex a
+ bh: hex.hex b
end:
}
diff --git a/programs/hexlib_tests/2params/sub_n.fj b/programs/hexlib_tests/2params/sub_n.fj
index 3ef9df5..20e6d55 100644
--- a/programs/hexlib_tests/2params/sub_n.fj
+++ b/programs/hexlib_tests/2params/sub_n.fj
@@ -1,10 +1,10 @@
-startup
+stl.startup
SUB_N = 0x0000ffff8000ada41d9d587f40027d6d07f2c898
rep(100, i) test_sub_n 4, (SUB_N>>((i%10)*4)&0xf), (SUB_N>>((i/10))*4&0xf)
-loop
+stl.loop
hex.init
@@ -15,18 +15,18 @@ def test_sub_n n, a, b @ lt, eq, gt, ah, bh, ch, end {
hex.cmp n, ah, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
ah: hex.vec n, a
bh: hex.vec n, b
ch: hex.vec n, a-b
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/2params/sub_shifted.fj b/programs/hexlib_tests/2params/sub_shifted.fj
new file mode 100644
index 0000000..f3c7a1f
--- /dev/null
+++ b/programs/hexlib_tests/2params/sub_shifted.fj
@@ -0,0 +1,53 @@
+stl.startup
+
+EACH_INDEX_REPEATS = 3
+DST_N = 8
+// DEC_N hex-size is: EACH_INDEX_REPEATS * 2 * DST_N * (DST_N * DST_N)
+DEC_N = 0x7a1c6a46571fb2045bfdbbf27f4348f9e0592328eb5aaca54c746c9435fd161a85aa0b9d1dc7df8a6e8fb15616479b8170fbb86e689dff4481c9117fdf21fed4a836405f4695fc715445ee9f3dfeb7f72563a5a8af275d4a88b9f9162b67f268a521895c30366daa7f4b9739342faa9448788af00e4b12797da90d6abbec35368420f600564001e5d8818c7095d4fe8d7af77b73a6d9e98839532bc344403b8de9dbedec7c107a9700cedae8314afbb9004aa23bb21b90a37fd57c0b26f9942fbfee8aed0b50e713a54eaf512421199d4bc7928c830fddeb33a8be38307ebc392b0a93743671da1af466a071b28a05a37013aa30ff02ba4c420e69d7c91f5621daaf54468f0425cff47cccc4af8cad1df7b1d0ff4539720c72c1fbf0fdd67594923bffad959582f04025db1187408ae1b2238f34d7c1a1ad0e2a813b89320ec44e524100980da6d56e652a2a0b535a5e9256d1721474205db4e9f7bc8aed6bf7f3c9801d893040ef12c4ce50e93b784c7740dc84ffa599cc0bc99d1a47e65ccdb8234f3669ac95e0ae9c18d5f284dbf6aa944bc9ccbbb5830350f8b6f0ec4348f1f2151a5c2c620d25a57db8414a887133cf4a25b46fdaac080ac9dc86fd78032a773fff344afd0477e1d4e06e6cd97c5430dbb3f2bab83c6a799543344fed42e062d571a4bf774f287ab7ce39a0d0b91dde9cf06af91cdddb221284ba9b48539889a5440d01efa0ec600d670203c26e66f19cc0db635fd48fa1114aebe4c429abeab1e537ecf9519af8b529dfed5269eaca9ae7a1db8804a8589e3a7ccd9f7269364d18a106d03a26629c3de86276488c0055bae2e98d75c1e9b9e27be70778e58d5bc50f040c6a7f13a4cd20b82600e78376bef28166cbbba8f2a204e8401bcc383181a4573c1400534af1b2482c96feff23dc12c31c05c6a5586b7b6198e9529d928ce3493c95281fa25f3d69d529d27276262518aef04033d116b2cfaa3ccfdadde460266cc5b2f5360dc1e2ce0503a18b172105855113986e696ec015ecc96fbe6a38d8d54b0f8485a0abffe003dc3214f881c68705b97e5ab474999ccf6716b3babe3373095f799386ed972e44893a75eb018ab58684616920448c85d42cd1c84f3fa6b450b1b92f4d7261e8e15e0def0737ab66239356aae5952383e29bedf3cb77d3987b42109e111aa694ae972907707ce49e2b36d91d7c6a20183d696d018033466669e8707d250fc5a9fd30e6e2ece43caa42f0dbc679f6f46c88cfdb95350e546dabbaeddcff5fc610124d99f67d48b4cc7cf9a67ba17a50226290850ada4a99c82a018abb733a6a569524cf96cdfa22bcab5eb742f32cb5b94271081107ef0f7a0b8eb79a2e824ebe216b38c92d69e5eb366cb271a2ce4546a1ef8de323ddf3abf7c5d7f225bbab4a0d340c6b9ed7ef5bb0e40e263a3fbc4a0157f3c9869a23228ad218422911d227a82402fdf6e4b6f2a9b91f5c9757dcc5dddaed72e310edc54c903da87c46d04793c1ee619b64e20b43da4cde511af80aa675dea6ffbb14fc535549ba8bda27c2f1af81df855d4c789a8103cfefdfa75835263f2232920cdbaa651d1bd1f95092a48a95ec610d14ddc9b22c42e24f6e01e63cbcb2f2f1cc787a28ca02a95db31f233268dd6d5b1b0597df0349c72e8170896699f152a927f01fe1ffc6950bc82c8d0b0e588b2260faff570cea6367396ed59c67b9bf873d07769a27954b9169c2d9bf22506ba9e7aa7d988f3f93fda5fea93a32cf7da7db84748a5c568a2a378eb557e718470c7efef94621da856b90bd432418b71f592c8841dd922868a019f0cf45f8d88aae1b9f841526d34b46a09134fcb2298c83e82f1a53e162c6b19508da098b03b33af91c289d052c7fa1c5b3f17b53649976fdcf74d2918612e3f71467b8ded467eab6ef4b978322ca41de37e62bd5d2c66e84b0d465133c4aadf0fc19b12ac916a11666a49f57139a558f28f78768197183f7ca7bd290126ec4df15e712d06e03c6cf9b57e0fdfa6fe44d00ab30781b5f1356b837c745f76b7625f74c7393a5bbd6452a2b76eb69e01ff0930b3530f0c93ba30de9a8444fc341d2d28075b7ace29ea3b02190f69de4ff44e249efbbdc5b02c7fe859566067b9ab4353b9309a0a3ecaed38624647d880f05ad59
+rep(DST_N, src_n_minus_1) test_entire_src_length_from_data \
+ (DEC_N >> (4*2*DST_N*EACH_INDEX_REPEATS*DST_N * src_n_minus_1)) & ((1<<(4*2*DST_N*EACH_INDEX_REPEATS*DST_N))-1), \
+ DST_N, src_n_minus_1 + 1
+
+stl.loop
+
+
+hex.init
+
+
+def test_entire_src_length_from_data test_data, dst_n, src_n {
+ rep(dst_n - src_n + 1, hex_shift) test_entire_index_from_data \
+ (test_data >> (4*2*DST_N*EACH_INDEX_REPEATS * hex_shift)) & ((1<<(4*2*DST_N*EACH_INDEX_REPEATS))-1), \
+ dst_n, src_n, hex_shift
+}
+
+def test_entire_index_from_data test_data, dst_n, src_n, hex_shift {
+ rep(EACH_INDEX_REPEATS, i) test_1_time_from_data \
+ (test_data >> (4*2*DST_N * i)) & ((1<<(4*2*DST_N))-1), dst_n, src_n, hex_shift
+}
+
+def test_1_time_from_data test_data, dst_n, src_n, hex_shift {
+ test_sub_shifted dst_n, src_n, test_data & (0xffffffff), (test_data >> 32) & ((1 << (4*src_n)) - 1), hex_shift
+}
+
+
+// Number of actual tests that run: EACH_INDEX_REPEATS * len([x for x in range(1, DST_N+1) for y in range(0, DST_N) if x + y <= DST_N])
+def test_sub_shifted dst_n, src_n, dst_constant, src_constant, hex_shift @ lt, eq, gt, dst, src, expected_result, end {
+ hex.sub_shifted dst_n, src_n, dst, src, hex_shift
+ hex.cmp dst_n, dst, expected_result, lt, eq, gt
+
+ lt:
+ stl.output '<'
+ ;end
+ eq:
+ stl.output '='
+ ;end
+ gt:
+ stl.output '>'
+ ;end
+
+ dst: hex.vec dst_n, dst_constant
+ src: hex.vec src_n, src_constant
+ expected_result: hex.vec dst_n, dst_constant - (src_constant << (4*hex_shift))
+ end:
+ stl.output '\n'
+}
diff --git a/programs/hexlib_tests/basics1/basic_math.fj b/programs/hexlib_tests/basics1/basic_math.fj
index 5114582..882149c 100644
--- a/programs/hexlib_tests/basics1/basic_math.fj
+++ b/programs/hexlib_tests/basics1/basic_math.fj
@@ -1,89 +1,89 @@
-startup
+stl.startup
// inc1
-output "inc1:\n"
+stl.output "inc1:\n"
rep(16, i) inc1_print_carry vars+i*dw, vars2+i*dw
hex.print_as_digit 16, vars2, 0
-output '\n'
+stl.output '\n'
hex.print_as_digit 16, vars, 0
-output "\n\n"
+stl.output "\n\n"
// inc, not
-output "inc, not:\n"
+stl.output "inc, not:\n"
hex.zero 16, vars
hex.inc 16, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.set vars, 0xf
hex.inc 16, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.zero 16, vars
hex.not 16, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.inc 16, vars
hex.print_as_digit 16, vars, 0
-output "\n\n"
+stl.output "\n\n"
// dec1
-output "dec1:\n"
+stl.output "dec1:\n"
hex.mov 16, vars, consts
rep(16, i) dec1_print_borrow vars+i*dw, vars2+i*dw
hex.print_as_digit 16, vars2, 0
-output '\n'
+stl.output '\n'
hex.print_as_digit 16, vars, 0
-output "\n\n"
+stl.output "\n\n"
// dec
-output "dec:\n"
+stl.output "dec:\n"
hex.zero 16, vars
hex.set vars, 2
hex.dec 16, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.dec 16, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.dec 16, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.dec 16, vars
hex.print_as_digit 16, vars, 0
-output "\n\n"
+stl.output "\n\n"
// neg
-output "neg:\n"
+stl.output "neg:\n"
hex.zero 16, vars
hex.neg 16, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.set vars+dw, 3
hex.neg 16, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.neg 16, vars
hex.print_as_digit 16, vars, 0
-output "\n\n"
+stl.output "\n\n"
// sign
-output "sign:\n"
+stl.output "sign:\n"
rep( 16, i) test_sign 1, i
-output '\n'
+stl.output '\n'
rep(256, i) test_sign 2, i
-output "\n\n"
+stl.output "\n\n"
-loop
+stl.loop
-vars: rep(16, j) hex j
-vars2: rep(16, j) hex 15-j
-consts: rep(16, j) hex j
+vars: rep(16, j) hex.hex j
+vars2: rep(16, j) hex.hex 15-j
+consts: rep(16, j) hex.hex j
def inc1_print_carry hex, carry @ output1, end {
@@ -108,10 +108,10 @@ def test_sign n, x @ neg, zpos, xh, end {
hex.sign n, xh, neg, zpos
neg:
- output '-'
+ stl.output '-'
;end
zpos:
- output '+'
+ stl.output '+'
;end
xh: hex.vec n, x
diff --git a/programs/hexlib_tests/basics1/basic_memory.fj b/programs/hexlib_tests/basics1/basic_memory.fj
index ce2cbea..91489f4 100644
--- a/programs/hexlib_tests/basics1/basic_memory.fj
+++ b/programs/hexlib_tests/basics1/basic_memory.fj
@@ -1,64 +1,64 @@
-startup
+stl.startup
// xor
-output "xor:\n"
+stl.output "xor:\n"
rep (16, val) xor_all val
-output '\n'
+stl.output '\n'
// zero
-output "zero:\n"
+stl.output "zero:\n"
hex.zero 16, vars
hex.print_as_digit 16, vars, 0
-output "\n\n"
+stl.output "\n\n"
// xor (as vec) once again
-output "xor n:\n"
+stl.output "xor n:\n"
hex.xor 16, vars, consts
hex.print_as_digit 16, vars, 0
-output "\n\n"
+stl.output "\n\n"
// xor_zero
-output "xor_zero:\n"
+stl.output "xor_zero:\n"
hex.xor_zero 16, vars2, vars
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.print_as_digit 16, vars2, 0
-output "\n\n"
+stl.output "\n\n"
// mov
-output "mov:\n"
+stl.output "mov:\n"
hex.mov 16, vars, vars2
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.print_as_digit 16, vars2, 0
-output "\n\n"
+stl.output "\n\n"
// set
-output "set:\n"
+stl.output "set:\n"
rep(16, i) hex.set vars+i*dw, 15-i
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.print_as_digit 16, vars2, 0
-output "\n\n"
+stl.output "\n\n"
// swap
-output "swap:\n"
+stl.output "swap:\n"
hex.swap 16, vars, vars2
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.print_as_digit 16, vars2, 0
-output "\n\n"
+stl.output "\n\n"
-loop
+stl.loop
-vars: rep(16, j) hex j
+vars: rep(16, j) hex.hex j
vars2: hex.vec 16, 0
-consts: rep(16, j) hex j
+consts: rep(16, j) hex.hex j
def xor_all val < vars, consts {
rep (16, i) hex.xor vars+i*dw, consts+val*dw
hex.print_as_digit 16, vars, 0
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/basics1/if.fj b/programs/hexlib_tests/basics1/if.fj
index 0c09a12..199b52c 100644
--- a/programs/hexlib_tests/basics1/if.fj
+++ b/programs/hexlib_tests/basics1/if.fj
@@ -1,42 +1,42 @@
-startup
+stl.startup
// if_flags
-output "if_flags:\n"
+stl.output "if_flags:\n"
// ops = [(randint(0, 15), randint(0,(2**16)-1)) for _ in range(100)]
// hexlib.out line: for h, f in ops: print((f>>h)&1, end='')
// IF_100_NUMS = hex(sum(h+f*16 << (i*20) for i, (h,f) in enumerate(ops)))
IF_FLAGS_NUMS = 0x2098593d070776a83803ed025fcf2630b539677e0a51278ec3b572bfa969f37eb32fa5a27d38f4f1ba10d5900345ee5d4b50f0d9b73a3ef84d8cbd2258f5a9cdedd958464321a1be0a3d2ba53a12ff684678ccaeea178472da56b4559e3b6e1fb5afd9afc3d69a167c53a95b2516817ba4f9890ded69f06b8e4eae281a4968d57d836496ceea29b290de0a64f6352588dc27b156aa22acc8147ff6400f5d71cd956b7021d2175e2f44c5f78c7d2afc97dacc10e9f17d11206ab17f05ffaf20a7af40b9c09c305a72f0dd8782762922df18191171efd38c65b187350bbecbd27c62c480459289ce5599ceda69a776420065898f22b7cf640a898
rep(100, i) print_if_flags (IF_FLAGS_NUMS>>(i*20))&((i<<20)-1)
-output "\n\n"
+stl.output "\n\n"
// if
-output "if:\n"
+stl.output "if:\n"
hex.zero vars
print_if vars
print_if0 vars
print_if1 vars
-output '\n'
+stl.output '\n'
hex.set vars, 1
print_if vars
print_if0 vars
print_if1 vars
-output '\n'
+stl.output '\n'
hex.set vars, 8
print_if vars
print_if0 vars
print_if1 vars
-output '\n'
+stl.output '\n'
hex.set vars, 15
print_if vars
print_if0 vars
print_if1 vars
-output "\n\n"
+stl.output "\n\n"
// if n
@@ -45,72 +45,72 @@ hex.zero 16, vars
print_if_16 vars
print_if0_16 vars
print_if1_16 vars
-output '\n'
+stl.output '\n'
hex.set vars, 1
print_if_16 vars
print_if0_16 vars
print_if1_16 vars
-output '\n'
+stl.output '\n'
hex.set vars, 0
hex.set vars+7*dw, 4
print_if_16 vars
print_if0_16 vars
print_if1_16 vars
-output '\n'
+stl.output '\n'
hex.zero 16, vars
hex.not 16, vars
print_if_16 vars
print_if0_16 vars
print_if1_16 vars
-output "\n\n"
+stl.output "\n\n"
-loop
+stl.loop
vars: hex.vec 16
-def print_if_flags hex_flags_val @ l0, l1, hex < IO {
+def print_if_flags hex_flags_val @ l0, l1, hex < stl.IO {
hex.if_flags hex, hex_flags_val>>4, l0, l1
- hex: hex hex_flags_val & 0xf
+ hex: hex.hex hex_flags_val & 0xf
l0:
- IO+0;l1+dw
+ stl.IO+0;l1+dw
l1:
- output '1'
+ stl.output '1'
}
-def print_if hex @ l0, l1 < IO {
+def print_if hex @ l0, l1 < stl.IO {
hex.if hex, l0, l1
- l0: IO+0;l1+dw
- l1: output '1'
+ l0: stl.IO+0;l1+dw
+ l1: stl.output '1'
}
-def print_if0 hex @ l0 < IO {
+def print_if0 hex @ l0 < stl.IO {
hex.if0 hex, l0
- IO+1;l0+dw
- l0: output '0'
+ stl.IO+1;l0+dw
+ l0: stl.output '0'
}
-def print_if1 hex @ l1 < IO {
+def print_if1 hex @ l1 < stl.IO {
hex.if1 hex, l1
- IO+0;l1+dw
- l1: output '1'
+ stl.IO+0;l1+dw
+ l1: stl.output '1'
}
-def print_if_16 hex @ l0, l1 < IO {
+def print_if_16 hex @ l0, l1 < stl.IO {
hex.if 16, hex, l0, l1
- l0: IO+0;l1+dw
- l1: output '1'
+ l0: stl.IO+0;l1+dw
+ l1: stl.output '1'
}
-def print_if0_16 hex @ l0 < IO {
+def print_if0_16 hex @ l0 < stl.IO {
hex.if0 16, hex, l0
- IO+1;l0+dw
- l0: output '0'
+ stl.IO+1;l0+dw
+ l0: stl.output '0'
}
-def print_if1_16 hex @ l1 < IO {
+def print_if1_16 hex @ l1 < stl.IO {
hex.if1 16, hex, l1
- IO+0;l1+dw
- l1: output '1'
+ stl.IO+0;l1+dw
+ l1: stl.output '1'
}
diff --git a/programs/hexlib_tests/basics1/input.fj b/programs/hexlib_tests/basics1/input.fj
index 7d34a07..f6cebae 100644
--- a/programs/hexlib_tests/basics1/input.fj
+++ b/programs/hexlib_tests/basics1/input.fj
@@ -1,31 +1,31 @@
-startup
+stl.startup
// input_hex
-output "input_hex:\n"
+stl.output "input_hex:\n"
rep(16, i) input2hex input+i*dw
hex.print_as_digit 16, input, 0
input2hex garbage
-output '\n'
+stl.output '\n'
// input_hex
rep(64, i) input_hex_print_error
input2hex garbage
-output "\n\n"
+stl.output "\n\n"
// input-print
-output "input-print:\n"
+stl.output "input-print:\n"
hex.input 16, input
hex.print 16, input
input2hex garbage
-output '\n'
+stl.output '\n'
rep(11, i) cat_char
input2hex garbage
-output "\n\n"
+stl.output "\n\n"
-loop
+stl.loop
input: hex.vec 16*2
@@ -42,9 +42,9 @@ def input_hex_print_error @ hex, error, end {
hex.print_as_digit hex, 0
;end
- hex: hex
+ hex: hex.hex
error:
- output 'X'
+ stl.output 'X'
end:
}
diff --git a/programs/hexlib_tests/basics1/print_as_digit.fj b/programs/hexlib_tests/basics1/print_as_digit.fj
index 5f721c3..9be000a 100644
--- a/programs/hexlib_tests/basics1/print_as_digit.fj
+++ b/programs/hexlib_tests/basics1/print_as_digit.fj
@@ -1,11 +1,11 @@
-startup
+stl.startup
hex.print_as_digit 16, vars, 0
-output '\n'
+stl.output '\n'
hex.print_as_digit 16, vars, 1
-output '\n'
+stl.output '\n'
-loop
+stl.loop
-vars: rep(16, j) hex j
+vars: rep(16, j) hex.hex j
diff --git a/programs/hexlib_tests/basics1/print_int.fj b/programs/hexlib_tests/basics1/print_int.fj
index 23a87c0..daf53c9 100644
--- a/programs/hexlib_tests/basics1/print_int.fj
+++ b/programs/hexlib_tests/basics1/print_int.fj
@@ -1,18 +1,18 @@
-startup
+stl.startup
// print_uint
-output "print_uint:\n"
+stl.output "print_uint:\n"
rep(5, i) print_uint 16, positive+16*i*dw
-output '\n'
+stl.output '\n'
// print_int
-output "print_int:\n"
+stl.output "print_int:\n"
rep(9, i) print_int 16, positive+16*i*dw
-output '\n'
+stl.output '\n'
-loop
+stl.loop
positive:
@@ -30,22 +30,22 @@ negative:
def print_uint n, x {
hex.print_uint n, x, 1, 0
- output ", "
+ stl.output ", "
hex.print_uint n, x, 1, 1
- output ", "
+ stl.output ", "
hex.print_uint n, x, 0, 0
- output ", "
+ stl.output ", "
hex.print_uint n, x, 0, 1
- output "\n"
+ stl.output "\n"
}
def print_int n, x {
hex.print_int n, x, 1, 0
- output ", "
+ stl.output ", "
hex.print_int n, x, 1, 1
- output ", "
+ stl.output ", "
hex.print_int n, x, 0, 0
- output ", "
+ stl.output ", "
hex.print_int n, x, 0, 1
- output "\n"
+ stl.output "\n"
}
diff --git a/programs/hexlib_tests/basics2/add_count_bits.fj b/programs/hexlib_tests/basics2/add_count_bits.fj
index 2bacde1..cc5419c 100644
--- a/programs/hexlib_tests/basics2/add_count_bits.fj
+++ b/programs/hexlib_tests/basics2/add_count_bits.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_add_count_bits i&0xf, i>>4
-loop
+stl.loop
hex.init
@@ -17,26 +17,26 @@ ret: ;0
add_count_bits_2:
hex.add_count_bits 2, bh, ah
- fret ret
+ stl.fret ret
def test_add_count_bits dst, x @ lt, eq, gt, end < ah, bh, ch, add_count_bits_2, ret {
hex.set ah, x
hex.set 2, bh, dst
hex.set 2, ch, dst + ((x>>0)&1) + ((x>>1)&1) + ((x>>2)&1) + ((x>>3)&1)
- fcall add_count_bits_2, ret
+ stl.fcall add_count_bits_2, ret
hex.cmp 2, bh, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/basics2/count_bits.fj b/programs/hexlib_tests/basics2/count_bits.fj
index 316fdfd..10ceb2d 100644
--- a/programs/hexlib_tests/basics2/count_bits.fj
+++ b/programs/hexlib_tests/basics2/count_bits.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
CB_NUM = 0x1f4a245bbcb588e8a76ec9f10c25fd21aac218d91e9d6a6bd7965a99ec604d6f9a662865e3c1fd319a75eea0390d3a50f52a60bfdd890f79db7ab0bedc2bab04268d47d95069f296a32a4ef00aed76feecf3260bf6dcf0004fd0cb68df5cc6ebbe0f5636b58665b148d0d8fb4ebd7e2a68efffaf782ebabc1a66d0991dc02ac46b5e25d40cec197b90a4eafc67976da0091f7cac5a58d10a36817702a59e1371f3f64f2298135574768c139833bce2e7b250e9984b65164efe9c77fa1c7b55069c96be65e256bdb6c6087d915c839157df4f67f5feef7483bad6697d7afdda6317290f68febf4701e926b81ea180e5db274d202379cb68b436872060e966afc4e886e8fa7f39f5d31656937c3a6c03ab39b6f99b47a9520c63a69b42f5f38ef0e669d2fe749aa478bd80f5a055f08bd4e930bb5b03f00a48bda48498f83e567cc0dbd585bd3ca29b81cb29ab37d2e9997c07da8353675afe26936c39ba45be43db24a8042b4655c9d4e68a4ae4dd331dd7d10aba78697ff647e7c7f04e5ef7bd8001c0f2eac3ea1f8913940b822026d0f3d44269d61f2a9814d5af4d72550a0c8449d257c6fbf418aaba244af95b4266cba3a57b142977f341f68db4534cc6d47d4ed534c1a07c4b069cd3c913f88471a670a53ef3ac9af50cb0d28739ce7b53abc1e9b5f57d079b58e3403293df0c343386a1358de67b8ebe1c3fc761d6fdd7144676ee4aace3f96c3157a5823609328f34a5b93ca3a7bdf978c725ff8552252b6507b77dd4e356137e8664d1a4eda46cb8abf02c5978e763ea8bc430368c81666a5f468f413d920da5b718ca73161a3d4a85f78668bdac3546b22626267a98d0b653ce275a066b2faa25697eb229ab39c6c1f6581aa8cb68c7d4d57256c54b154f8314d533e349710da4c8054cc5fa3218d0d58cf8624275b92b9f3102e199c376e5258b1332b957c2192cc5c325410b5894510bd5d4470233a97479a0398039c971f468b7cbe0e364f1bf2ebb4c0ddb540bfc80dc1dfc3983e6fb979cbf9bd5631f0e051ece545a3fceb4c8876a5b72b77606d44f73c80111701c790be1c240e843cccda50ed9313c0be528848fd065d80e77428a90c002986c558629426c
rep(100, i) test_count_bits_64 (CB_NUM>>(64*i))&((1<<64)-1)
-loop
+stl.loop
hex.init
@@ -18,25 +18,33 @@ ret: ;0
count_bits_64:
hex.count_bits 16, count, xh
- fret ret
+ stl.fret ret
def test_count_bits_64 x @ lt, eq, gt, end < xh, count, ch, count_bits_64, ret {
hex.set 16, xh, x
- hex.set 2, ch, ((x>>0)&1)+((x>>1)&1)+((x>>2)&1)+((x>>3)&1)+((x>>4)&1)+((x>>5)&1)+((x>>6)&1)+((x>>7)&1)+((x>>8)&1)+((x>>9)&1)+((x>>10)&1)+((x>>11)&1)+((x>>12)&1)+((x>>13)&1)+((x>>14)&1)+((x>>15)&1)+((x>>16)&1)+((x>>17)&1)+((x>>18)&1)+((x>>19)&1)+((x>>20)&1)+((x>>21)&1)+((x>>22)&1)+((x>>23)&1)+((x>>24)&1)+((x>>25)&1)+((x>>26)&1)+((x>>27)&1)+((x>>28)&1)+((x>>29)&1)+((x>>30)&1)+((x>>31)&1)+((x>>32)&1)+((x>>33)&1)+((x>>34)&1)+((x>>35)&1)+((x>>36)&1)+((x>>37)&1)+((x>>38)&1)+((x>>39)&1)+((x>>40)&1)+((x>>41)&1)+((x>>42)&1)+((x>>43)&1)+((x>>44)&1)+((x>>45)&1)+((x>>46)&1)+((x>>47)&1)+((x>>48)&1)+((x>>49)&1)+((x>>50)&1)+((x>>51)&1)+((x>>52)&1)+((x>>53)&1)+((x>>54)&1)+((x>>55)&1)+((x>>56)&1)+((x>>57)&1)+((x>>58)&1)+((x>>59)&1)+((x>>60)&1)+((x>>61)&1)+((x>>62)&1)+((x>>63)&1)
- fcall count_bits_64, ret
+ hex.set 2, ch, \
+ ((x>>0)&1)+((x>>1)&1)+((x>>2)&1)+((x>>3)&1)+((x>>4)&1)+((x>>5)&1)+((x>>6)&1)+((x>>7)&1)+\
+ ((x>>8)&1)+((x>>9)&1)+((x>>10)&1)+((x>>11)&1)+((x>>12)&1)+((x>>13)&1)+((x>>14)&1)+((x>>15)&1)+\
+ ((x>>16)&1)+((x>>17)&1)+((x>>18)&1)+((x>>19)&1)+((x>>20)&1)+((x>>21)&1)+((x>>22)&1)+((x>>23)&1)+\
+ ((x>>24)&1)+((x>>25)&1)+((x>>26)&1)+((x>>27)&1)+((x>>28)&1)+((x>>29)&1)+((x>>30)&1)+((x>>31)&1)+\
+ ((x>>32)&1)+((x>>33)&1)+((x>>34)&1)+((x>>35)&1)+((x>>36)&1)+((x>>37)&1)+((x>>38)&1)+((x>>39)&1)+\
+ ((x>>40)&1)+((x>>41)&1)+((x>>42)&1)+((x>>43)&1)+((x>>44)&1)+((x>>45)&1)+((x>>46)&1)+((x>>47)&1)+\
+ ((x>>48)&1)+((x>>49)&1)+((x>>50)&1)+((x>>51)&1)+((x>>52)&1)+((x>>53)&1)+((x>>54)&1)+((x>>55)&1)+\
+ ((x>>56)&1)+((x>>57)&1)+((x>>58)&1)+((x>>59)&1)+((x>>60)&1)+((x>>61)&1)+((x>>62)&1)+((x>>63)&1)
+ stl.fcall count_bits_64, ret
hex.cmp 2, count, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/basics2/shift_utils.fj b/programs/hexlib_tests/basics2/shift_utils.fj
index 7f58a93..2db557e 100644
--- a/programs/hexlib_tests/basics2/shift_utils.fj
+++ b/programs/hexlib_tests/basics2/shift_utils.fj
@@ -3,19 +3,19 @@ def test_shl_bit n, x @ lt, eq, gt, xh, ch, end {
hex.cmp n, xh, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
xh: hex.vec n, x
ch: hex.vec n, (x<<1)&((1<<(4*n))-1)
end:
- output '\n'
+ stl.output '\n'
}
def test_shr_bit n, x @ lt, eq, gt, xh, ch, end {
@@ -23,19 +23,19 @@ def test_shr_bit n, x @ lt, eq, gt, xh, ch, end {
hex.cmp n, xh, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
xh: hex.vec n, x
ch: hex.vec n, (x>>1)&((1<<(4*n))-1)
end:
- output '\n'
+ stl.output '\n'
}
@@ -44,19 +44,19 @@ def test_shl_hex n, x @ lt, eq, gt, xh, ch, end {
hex.cmp n, xh, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
xh: hex.vec n, x
ch: hex.vec n, (x<<4)&((1<<(4*n))-1)
end:
- output '\n'
+ stl.output '\n'
}
def test_shr_hex n, x @ lt, eq, gt, xh, ch, end {
@@ -64,17 +64,17 @@ def test_shr_hex n, x @ lt, eq, gt, xh, ch, end {
hex.cmp n, xh, ch, lt, eq, gt
lt:
- output '<'
+ stl.output '<'
;end
eq:
- output '='
+ stl.output '='
;end
gt:
- output '>'
+ stl.output '>'
;end
xh: hex.vec n, x
ch: hex.vec n, (x>>4)&((1<<(4*n))-1)
end:
- output '\n'
+ stl.output '\n'
}
diff --git a/programs/hexlib_tests/basics2/shl_bit.fj b/programs/hexlib_tests/basics2/shl_bit.fj
index d8f2875..f2baa52 100644
--- a/programs/hexlib_tests/basics2/shl_bit.fj
+++ b/programs/hexlib_tests/basics2/shl_bit.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_shl_bit 2, i
-loop
+stl.loop
hex.init
diff --git a/programs/hexlib_tests/basics2/shl_bit_n.fj b/programs/hexlib_tests/basics2/shl_bit_n.fj
index 6a3ff5f..059f374 100644
--- a/programs/hexlib_tests/basics2/shl_bit_n.fj
+++ b/programs/hexlib_tests/basics2/shl_bit_n.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
SHL_BIT_NUM = 0xc8fcbed153fd0e8d144845766379fd5efd18ff7292af2fa040411b27bebf949cd8228ad4200b17b3e6e590c162947c5e17efc1d43f0873c0cc7ed9b1d784a515a1c18e511d26f79c4c4c9d7def6d05a1c3d672d8e3ba80089e0d970f95371981ace3365c03b2962ed08468a0f1b48f611e6cfb197146709487d6e3a8f74ba06e1ad0ac4be09ab36ba6561e79dc8fa3cb33e30d11032eb2a4e7d158b65cc3b6b753b4b85dab3efc9cb10f1ee8a4a4504f52f08be95c3f565edac2b9c139424c3e77d2d94904f691e5
rep(25, i) test_shl_bit 16, (SHL_BIT_NUM>>(64*i))&((1<<64)-1)
-loop
+stl.loop
hex.init
diff --git a/programs/hexlib_tests/basics2/shl_hex.fj b/programs/hexlib_tests/basics2/shl_hex.fj
index a97a79f..90ea4ae 100644
--- a/programs/hexlib_tests/basics2/shl_hex.fj
+++ b/programs/hexlib_tests/basics2/shl_hex.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_shl_hex 2, i
-loop
+stl.loop
hex.init
diff --git a/programs/hexlib_tests/basics2/shl_hex_n.fj b/programs/hexlib_tests/basics2/shl_hex_n.fj
index a20c050..f854f25 100644
--- a/programs/hexlib_tests/basics2/shl_hex_n.fj
+++ b/programs/hexlib_tests/basics2/shl_hex_n.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
SHL_HEX_NUM = 0x96bfc00f7403bc38e061eb9731b57671c8b91d42cc6d54c38d79bdfa65ab3fd958bfabb437a62f5b8be4298fa31a6a50c978c81cc41db2aa886ce6ac0692d7e6b983225eafc74831c4604b587ef2358baed4abcb99583f45d0041d3e8ada9ded0326b3d70df57810958477b3f1627a1b1f79aea80e3b3a1b6d20b43fae73800a547d7016a7d1681cdb2a9134ba57bdf3ebc19c65574d12c8ac814e237cca4fed4bdde8a916be96d6706a200ad39def191c944a75d402a25d3dad2b2bbd61e943804a2d26caf292e8
rep(25, i) test_shl_hex 16, (SHL_HEX_NUM>>(64*i))&((1<<64)-1)
-loop
+stl.loop
hex.init
diff --git a/programs/hexlib_tests/basics2/shr_bit.fj b/programs/hexlib_tests/basics2/shr_bit.fj
index 2cf4676..c6ee928 100644
--- a/programs/hexlib_tests/basics2/shr_bit.fj
+++ b/programs/hexlib_tests/basics2/shr_bit.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_shr_bit 2, i
-loop
+stl.loop
hex.init
diff --git a/programs/hexlib_tests/basics2/shr_bit_n.fj b/programs/hexlib_tests/basics2/shr_bit_n.fj
index c033186..f099400 100644
--- a/programs/hexlib_tests/basics2/shr_bit_n.fj
+++ b/programs/hexlib_tests/basics2/shr_bit_n.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
SHR_BIT_NUM = 0xe71e3e4a716549fb31fc565d0dbb2f96c846c32ee4018325d1cd59436959489e67e9c48d3c4861da188988ead4f9fefab18e0c51c22c7241405f456ff95023b9cec204245f9bc9285cdead281e5aef9458296a4036cdb03ffcece333cb5c2d05fd66ddf091b82de8e16bc08b648ab018a3f05a1d812f94223419680ea44e0b11121da44b5bdf7f55a1346ea0d69a244177005a266bfb233372c7e12a8b6f76a39c1364624820a19d395f224d19d91fb6f535c8d485420d4c6520065687092d730d5257944ce12a5e
rep(25, i) test_shr_bit 16, (SHR_BIT_NUM>>(64*i))&((1<<64)-1)
-loop
+stl.loop
hex.init
diff --git a/programs/hexlib_tests/basics2/shr_hex.fj b/programs/hexlib_tests/basics2/shr_hex.fj
index 3c9c970..123e51d 100644
--- a/programs/hexlib_tests/basics2/shr_hex.fj
+++ b/programs/hexlib_tests/basics2/shr_hex.fj
@@ -1,8 +1,8 @@
-startup
+stl.startup
rep(256, i) test_shr_hex 2, i
-loop
+stl.loop
hex.init
diff --git a/programs/hexlib_tests/basics2/shr_hex_n.fj b/programs/hexlib_tests/basics2/shr_hex_n.fj
index 4bc0ae1..1d7a596 100644
--- a/programs/hexlib_tests/basics2/shr_hex_n.fj
+++ b/programs/hexlib_tests/basics2/shr_hex_n.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
SHR_HEX_NUM = 0xe7d664775cec9f714aa04965fae77bdcb9d3a528efac59559589e77b7c358996028b86dcc178781acc44a171f47b25dda80f96c221b1c20a5364d240bd4cf46f782dd4d0cb6acfc393c30d03235e34197afef6c03c6f0828101f0b567d39319d68055fe664537da50df3c2434a4ab5fcf933fd3e70da4a79d040c38bca236b892710168279486eda4e0bf9c2914987648afef39bccd9c06e53010a637a9defc0e200b486b48d6c58772d8f7f45ba8931a325fd17af6c1739a70ee9bc472351ef224c6ce145c554ae
rep(25, i) test_shr_hex 16, (SHR_HEX_NUM>>(64*i))&((1<<64)-1)
-loop
+stl.loop
hex.init
diff --git a/programs/hexlib_tests/div/hexlib_div.fj b/programs/hexlib_tests/div/hexlib_div.fj
index 6365f4e..20c5a04 100644
--- a/programs/hexlib_tests/div/hexlib_div.fj
+++ b/programs/hexlib_tests/div/hexlib_div.fj
@@ -1,4 +1,4 @@
-startup
+stl.startup
;end_of_div
@@ -24,64 +24,65 @@ ret: ;0
div0:
- output "0"
- fret ret
+ stl.output "0"
+ stl.fret ret
neq_div_print:
- output '\n'
+ stl.output '\n'
hex.print_uint 16, ah, 1, 0
- output " / "
+ stl.output " / "
hex.print_uint 16, bh, 1, 0
- output " = "
+ stl.output " = "
hex.print_uint 16, res, 1, 0
- output " != "
+ stl.output " != "
hex.print_uint 16, ch, 1, 0
- output '\n'
- fret ret
+ stl.output '\n'
+ stl.fret ret
neq_mod_print:
- output '\n'
+ stl.output '\n'
hex.print_uint 16, ah, 1, 0
- output " % "
+ stl.output " % "
hex.print_uint 16, bh, 1, 0
- output " = "
+ stl.output " = "
hex.print_uint 16, mod, 1, 0
- output " != "
+ stl.output " != "
hex.print_uint 16, mh, 1, 0
- output '\n'
- fret ret
+ stl.output '\n'
+ stl.fret ret
-def test_div n, nb, div_label, a, b @ neq_div, eq_div, cmp_mod, neq_mod, eq_mod, end < ah, bh, res, ch, mod, mh, ret, neq_div_print, neq_mod_print {
+def test_div n, nb, div_label, a, b @ neq_div, eq_div, cmp_mod, neq_mod, eq_mod, end \
+ < ah, bh, res, ch, mod, mh, ret, neq_div_print, neq_mod_print {
hex.set n, ah, a
hex.zero nb, bh
- fcall div_label, ret
+ stl.fcall div_label, ret
hex.set nb, bh, b
hex.set n, ch, (a/b)&((1<<(4*n ))-1)
hex.set nb, mh, (a%b)&((1<<(4*nb))-1)
- fcall div_label, ret
+ stl.fcall div_label, ret
hex.cmp n, res, ch, neq_div, eq_div, neq_div
neq_div:
- fcall neq_div_print, ret
+ stl.fcall neq_div_print, ret
;cmp_mod
eq_div:
- output "="
+ stl.output "="
;cmp_mod
cmp_mod:
hex.cmp nb, mod, mh, neq_mod, eq_mod, neq_mod
neq_mod:
- fcall neq_mod_print, ret
+ stl.fcall neq_mod_print, ret
;end
eq_mod:
- output "="
+ stl.output "="
;end
end:
- output "\n"
+ stl.output "\n"
}
diff --git a/programs/hexlib_tests/div/test4_1.fj b/programs/hexlib_tests/div/test4_1.fj
index 9f92202..46876eb 100644
--- a/programs/hexlib_tests/div/test4_1.fj
+++ b/programs/hexlib_tests/div/test4_1.fj
@@ -1,8 +1,8 @@
rep(50, i) test_div 4, 1, div4_1, (DIV_NUM>>(16*i+0))&((1<<16)-1), (DIV_B1_NUM>>( 4*i))&((1<< 4)-1)
-loop
+stl.loop
div4_1:
hex.div 4, 1, res, mod, ah, bh, div0
- fret ret
+ stl.fret ret
diff --git a/programs/hexlib_tests/div/test4_2.fj b/programs/hexlib_tests/div/test4_2.fj
index 1774076..63bceb6 100644
--- a/programs/hexlib_tests/div/test4_2.fj
+++ b/programs/hexlib_tests/div/test4_2.fj
@@ -1,8 +1,8 @@
rep(30, i) test_div 4, 2, div4_2, (DIV_NUM>>(16*i+1))&((1<<16)-1), (DIV_B2_NUM>>( 8*i))&((1<< 8)-1)
-loop
+stl.loop
div4_2:
hex.div 4, 2, res, mod, ah, bh, div0
- fret ret
+ stl.fret ret
diff --git a/programs/hexlib_tests/div/test4_4.fj b/programs/hexlib_tests/div/test4_4.fj
index bc89d14..abc0f77 100644
--- a/programs/hexlib_tests/div/test4_4.fj
+++ b/programs/hexlib_tests/div/test4_4.fj
@@ -1,8 +1,8 @@
rep(20, i) test_div 4, 4, div4_4, (DIV_NUM>>(16*i+2))&((1<<16)-1), (DIV_B4_NUM>>(16*i))&((1<<16)-1)
-loop
+stl.loop
div4_4:
hex.div 4, 4, res, mod, ah, bh, div0
- fret ret
+ stl.fret ret
diff --git a/programs/hexlib_tests/div/test8_1.fj b/programs/hexlib_tests/div/test8_1.fj
index 1af4161..48c253c 100644
--- a/programs/hexlib_tests/div/test8_1.fj
+++ b/programs/hexlib_tests/div/test8_1.fj
@@ -1,8 +1,8 @@
rep(40, i) test_div 8, 1, div8_1, (DIV_NUM>>(64*i+3))&((1<<32)-1), (DIV_B1_NUM>>( 4*i + 50* 4))&((1<< 4)-1)
-loop
+stl.loop
div8_1:
hex.div 8, 1, res, mod, ah, bh, div0
- fret ret
+ stl.fret ret
diff --git a/programs/hexlib_tests/div/test8_2.fj b/programs/hexlib_tests/div/test8_2.fj
index 8740106..4a8869e 100644
--- a/programs/hexlib_tests/div/test8_2.fj
+++ b/programs/hexlib_tests/div/test8_2.fj
@@ -1,8 +1,8 @@
rep(30, i) test_div 8, 2, div8_2, (DIV_NUM>>(64*i+4))&((1<<32)-1), (DIV_B2_NUM>>( 8*i + 50* 8))&((1<< 8)-1)
-loop
+stl.loop
div8_2:
hex.div 8, 2, res, mod, ah, bh, div0
- fret ret
+ stl.fret ret
diff --git a/programs/hexlib_tests/div/test8_4.fj b/programs/hexlib_tests/div/test8_4.fj
index a5b3133..0a4038a 100644
--- a/programs/hexlib_tests/div/test8_4.fj
+++ b/programs/hexlib_tests/div/test8_4.fj
@@ -1,8 +1,8 @@
rep(20, i) test_div 8, 4, div8_4, (DIV_NUM>>(64*i+5))&((1<<32)-1), (DIV_B4_NUM>>(16*i + 50*16))&((1<<16)-1)
-loop
+stl.loop
div8_4:
hex.div 8, 4, res, mod, ah, bh, div0
- fret ret
+ stl.fret ret
diff --git a/programs/hexlib_tests/div/test8_8.fj b/programs/hexlib_tests/div/test8_8.fj
index bd79b34..7758cd7 100644
--- a/programs/hexlib_tests/div/test8_8.fj
+++ b/programs/hexlib_tests/div/test8_8.fj
@@ -1,8 +1,8 @@
rep(10, i) test_div 8, 8, div8_8, (DIV_NUM>>(64*i+6))&((1<<32)-1), (DIV_B8_NUM>>(32*i + 50*32))&((1<<32)-1)
-loop
+stl.loop
div8_8:
hex.div 8, 8, res, mod, ah, bh, div0
- fret ret
+ stl.fret ret
diff --git a/programs/hexlib_tests/mul/add_mul_test.fj b/programs/hexlib_tests/mul/add_mul_test.fj
index 0310c7f..d5e06ce 100644
--- a/programs/hexlib_tests/mul/add_mul_test.fj
+++ b/programs/hexlib_tests/mul/add_mul_test.fj
@@ -1,11 +1,14 @@
-startup
+stl.startup
HexSize = NumSize / 4
Flag = ((1<>(BlockSize*i))&Flag, (Data>>(BlockSize*i + NumSize))&Flag, (Data>>(BlockSize*i + 2*NumSize))&0xf
+rep(Repetitions, i) test_add_mul \
+ (Data>>(BlockSize*i))&Flag, \
+ (Data>>(BlockSize*i + NumSize))&Flag, \
+ (Data>>(BlockSize*i + 2*NumSize))&0xf
-loop
+stl.loop
hex.init
@@ -26,59 +29,60 @@ zero_all_5:
hex.zero 16, ch
hex.zero 16, res
hex.zero 16, old_res
- fret ret
+ stl.fret ret
add_mul_lt_print:
- output '\n'
+ stl.output '\n'
hex.print_uint 16, old_res, 1, 0
- output " + "
+ stl.output " + "
hex.print_uint 16, ah, 1, 0
- output " * "
+ stl.output " * "
hex.print_uint 16, bh, 1, 0
- output " = "
+ stl.output " = "
hex.print_uint 16, res, 1, 0
- output " < "
+ stl.output " < "
hex.print_uint 16, ch, 1, 0
- output '\n'
- fret ret
+ stl.output '\n'
+ stl.fret ret
add_mul_gt_print:
- output '\n'
+ stl.output '\n'
hex.print_uint 16, old_res, 1, 0
- output " + "
+ stl.output " + "
hex.print_uint 16, ah, 1, 0
- output " * "
+ stl.output " * "
hex.print_uint 16, bh, 1, 0
- output " = "
+ stl.output " = "
hex.print_uint 16, res, 1, 0
- output " > "
+ stl.output " > "
hex.print_uint 16, ch, 1, 0
- output '\n'
- fret ret
+ stl.output '\n'
+ stl.fret ret
add_mul:
hex.add_mul HexSize, res, ah, bh
- fret ret
+ stl.fret ret
-def test_add_mul r, a, b @ lt, eq, gt, end < ah, bh, res, old_res, ch, ret, add_mul_lt_print, add_mul_gt_print, add_mul, zero_all_5 {
- fcall zero_all_5, ret
+def test_add_mul r, a, b @ lt, eq, gt, end \
+ < ah, bh, res, old_res, ch, ret, add_mul_lt_print, add_mul_gt_print, add_mul, zero_all_5 {
+ stl.fcall zero_all_5, ret
hex.xor_by HexSize, ah, a
hex.xor_by HexSize, bh, b
hex.xor_by HexSize, res, r
hex.xor_by HexSize, old_res, r
hex.xor_by HexSize, ch, (r+a*b)&Flag
- fcall add_mul, ret
+ stl.fcall add_mul, ret
hex.cmp HexSize, res, ch, lt, eq, gt
lt:
- fcall add_mul_lt_print, ret
+ stl.fcall add_mul_lt_print, ret
;end
eq:
- output "=\n"
+ stl.output "=\n"
;end
gt:
- fcall add_mul_gt_print, ret
+ stl.fcall add_mul_gt_print, ret
;end
end:
}
diff --git a/programs/hexlib_tests/mul/mul_test.fj b/programs/hexlib_tests/mul/mul_test.fj
index 05bf14b..39d4112 100644
--- a/programs/hexlib_tests/mul/mul_test.fj
+++ b/programs/hexlib_tests/mul/mul_test.fj
@@ -1,11 +1,13 @@
-startup
+stl.startup
HexSize = NumSize / 4
Flag = (1<>(BlockSize*i))&Flag, (Data>>(BlockSize*i+NumSize))&Flag
+rep(Repetitions, i) test_mul HexSize, \
+ (Data>>(BlockSize*i))&Flag, \
+ (Data>>(BlockSize*i+NumSize))&Flag
-loop
+stl.loop
hex.init
@@ -21,50 +23,50 @@ ret: ;0
lt_print:
- output '\n'
+ stl.output '\n'
hex.print_uint 16, ah, 1, 0
- output " * "
+ stl.output " * "
hex.print_uint 16, bh, 1, 0
- output " = "
+ stl.output " = "
hex.print_uint 16, res, 1, 0
- output " < "
+ stl.output " < "
hex.print_uint 16, ch, 1, 0
- output '\n'
- fret ret
+ stl.output '\n'
+ stl.fret ret
gt_print:
- output '\n'
+ stl.output '\n'
hex.print_uint 16, ah, 1, 0
- output " * "
+ stl.output " * "
hex.print_uint 16, bh, 1, 0
- output " = "
+ stl.output " = "
hex.print_uint 16, res, 1, 0
- output " > "
+ stl.output " > "
hex.print_uint 16, ch, 1, 0
- output '\n'
- fret ret
+ stl.output '\n'
+ stl.fret ret
mul:
hex.mul HexSize, res, ah, bh
- fret ret
+ stl.fret ret
def test_mul n, a, b @ lt, eq, gt, end < ah, bh, res, ch, ret, lt_print, gt_print, mul {
hex.set n, ah, a
hex.set n, bh, b
hex.set n, ch, (a*b)&((1<<(4*n))-1)
- fcall mul, ret
+ stl.fcall mul, ret
hex.cmp n, res, ch, lt, eq, gt
lt:
- fcall lt_print, ret
+ stl.fcall lt_print, ret
;end
eq:
- output "=\n"
+ stl.output "=\n"
;end
gt:
- fcall gt_print, ret
+ stl.fcall gt_print, ret
;end
end:
}
diff --git a/programs/multi_comp/a.fj b/programs/multi_comp/a.fj
index 8fb011a..e387b65 100644
--- a/programs/multi_comp/a.fj
+++ b/programs/multi_comp/a.fj
@@ -1,4 +1,4 @@
-startup
+stl.startup
get_aaaaN
@@ -8,4 +8,4 @@ print_chars N, 'T'
println
-loop
+stl.loop
diff --git a/programs/multi_comp/a_no_stl.fj b/programs/multi_comp/a_no_stl.fj
index bba5418..345cdb2 100644
--- a/programs/multi_comp/a_no_stl.fj
+++ b/programs/multi_comp/a_no_stl.fj
@@ -13,10 +13,12 @@ println
loop:;loop
-def output_bit bit < IO {
- IO + (bit ? 1 : 0);
-}
-
-def output_char ascii {
- rep(8, i) output_bit (ascii>>i)&1
+ns stl {
+ def output_bit bit < IO {
+ IO + (bit ? 1 : 0);
+ }
+
+ def output_char ascii {
+ rep(8, i) .output_bit (ascii>>i)&1
+ }
}
diff --git a/programs/multi_comp/c.fj b/programs/multi_comp/c.fj
index dedf556..b99f3d7 100644
--- a/programs/multi_comp/c.fj
+++ b/programs/multi_comp/c.fj
@@ -2,9 +2,9 @@ NL = '\n'
def print_chars n, c {
- rep(n, i) output_char c
+ rep(n, i) stl.output_char c
}
def println {
- output_char NL
+ stl.output_char NL
}
diff --git a/programs/multi_comp/defs.fj b/programs/multi_comp/defs.fj
index 7cb9f8f..80a18e6 100644
--- a/programs/multi_comp/defs.fj
+++ b/programs/multi_comp/defs.fj
@@ -1,6 +1,6 @@
N = 3
-def get_aaaaN > aaaaN {
+def get_aaaaN {
aaaaN = 5
}
diff --git a/programs/pair_ns_tests/test1.fj b/programs/pair_ns_tests/test1.fj
index cf18cc1..9225b1c 100644
--- a/programs/pair_ns_tests/test1.fj
+++ b/programs/pair_ns_tests/test1.fj
@@ -1,4 +1,4 @@
-startup
+stl.startup
Pair.init
@@ -7,7 +7,7 @@ Pair.init p2
Pair.prints.print_two p1, p2
-loop
+stl.loop
p1: bit.vec Pair.size
diff --git a/programs/pair_ns_tests/test2.fj b/programs/pair_ns_tests/test2.fj
index 1847a75..392f163 100644
--- a/programs/pair_ns_tests/test2.fj
+++ b/programs/pair_ns_tests/test2.fj
@@ -1,4 +1,4 @@
-startup
+stl.startup
Pair.init
@@ -20,7 +20,7 @@ Pair.prints.print_two p1, p2
Pair.add p2, p1
Pair.prints.print_two p1, p2
-loop
+stl.loop
p1: bit.vec Pair.size
diff --git a/programs/pair_ns_tests/test3.fj b/programs/pair_ns_tests/test3.fj
index 56d4ad8..6db122c 100644
--- a/programs/pair_ns_tests/test3.fj
+++ b/programs/pair_ns_tests/test3.fj
@@ -1,4 +1,4 @@
-startup
+stl.startup
Pair.init
@@ -12,8 +12,8 @@ Pair.add_second p1, v02
Pair.swap p1
Pair.print p1
-output '\n'
-loop
+stl.output '\n'
+stl.loop
p1: bit.vec Pair.size
diff --git a/programs/print_tests/cat.fj b/programs/print_tests/cat.fj
index 183ce17..c6c1131 100644
--- a/programs/print_tests/cat.fj
+++ b/programs/print_tests/cat.fj
@@ -1,4 +1,4 @@
- startup
+ stl.startup
start:
bit.input ascii
bit.if0 8, ascii, end
@@ -9,7 +9,7 @@ print:
bit.print ascii
;start
end:
- loop
+ stl.loop
ascii:
diff --git a/programs/print_tests/hello_world.fj b/programs/print_tests/hello_world.fj
index 330dc6a..d81a3d7 100644
--- a/programs/print_tests/hello_world.fj
+++ b/programs/print_tests/hello_world.fj
@@ -1,3 +1,3 @@
-startup
-output "Hello, World!\n(:"
-loop
+stl.startup
+stl.output "Hello, World!\n(:"
+stl.loop
diff --git a/programs/print_tests/hello_world_with_str.fj b/programs/print_tests/hello_world_with_str.fj
index 2ef1366..9cddb4f 100644
--- a/programs/print_tests/hello_world_with_str.fj
+++ b/programs/print_tests/hello_world_with_str.fj
@@ -1,7 +1,7 @@
- startup
+ stl.startup
bit.print_str 20, str
- loop
+ stl.loop
str:
bit.str "Hello, World!\n(:"
diff --git a/programs/print_tests/hexprint.fj b/programs/print_tests/hexprint.fj
index 911532f..f08bd44 100644
--- a/programs/print_tests/hexprint.fj
+++ b/programs/print_tests/hexprint.fj
@@ -1,8 +1,8 @@
- startup
+ stl.startup
bit.add 4, a, b
bit.hex2ascii c, a
bit.print c
- loop
+ stl.loop
a:
bit.vec 4, 0x5
diff --git a/programs/print_tests/ncat.fj b/programs/print_tests/ncat.fj
index 1ce46ad..6d6d9ab 100644
--- a/programs/print_tests/ncat.fj
+++ b/programs/print_tests/ncat.fj
@@ -1,4 +1,4 @@
-startup
+stl.startup
start:
bit.input ascii
bit.if0 8, ascii, end
@@ -10,7 +10,7 @@ print:
bit.print ascii
;start
end:
- loop
+ stl.loop
ascii:
bit.vec 8
diff --git a/programs/print_tests/print_as_digit.fj b/programs/print_tests/print_as_digit.fj
index 25ec9ac..c6fb52c 100644
--- a/programs/print_tests/print_as_digit.fj
+++ b/programs/print_tests/print_as_digit.fj
@@ -1,16 +1,16 @@
-startup
+stl.startup
bit.print_as_digit b0
bit.print_as_digit b1
-output '\n'
+stl.output '\n'
rep(16, i) hex.print_as_digit h+i*dw, 0
-output '\n'
+stl.output '\n'
rep(16, i) hex.print_as_digit h+i*dw, 1
-output '\n'
+stl.output '\n'
-loop
+stl.loop
-b0: bit 0
-b1: bit 1
-h: rep(16, i) hex i
+b0: bit.bit 0
+b1: bit.bit 1
+h: rep(16, i) hex.hex i
diff --git a/programs/print_tests/print_dec.fj b/programs/print_tests/print_dec.fj
index 5549389..c10f884 100644
--- a/programs/print_tests/print_dec.fj
+++ b/programs/print_tests/print_dec.fj
@@ -1,9 +1,9 @@
-startup
+stl.startup
print_int v1
print_int v2
print_int v3
-loop
+stl.loop
v1: bit.vec w, 123456
@@ -13,11 +13,11 @@ ret_reg: 0;0
def print_int v < ret_reg, val, print_int {
bit.mov w, val, v
- fcall print_int, ret_reg
+ stl.fcall print_int, ret_reg
}
print_int:
bit.print_dec_int w, val
- output '\n'
- fret ret_reg
+ stl.output '\n'
+ stl.fret ret_reg
val: bit.vec w
diff --git a/programs/print_tests/print_hex_int.fj b/programs/print_tests/print_hex_int.fj
index 8e1bfd7..3b7540b 100644
--- a/programs/print_tests/print_hex_int.fj
+++ b/programs/print_tests/print_hex_int.fj
@@ -1,7 +1,7 @@
- startup
+ stl.startup
bit.print_hex_int w, a, 1
- loop
+ stl.loop
a:
bit.vec w, 0-0xabcdef
diff --git a/programs/sanity_checks/mathbit.fj b/programs/sanity_checks/mathbit.fj
index 8b0ee1c..4afbffb 100644
--- a/programs/sanity_checks/mathbit.fj
+++ b/programs/sanity_checks/mathbit.fj
@@ -1,8 +1,8 @@
- startup
+ stl.startup
bit.inc1 x, carry
- loop
+ stl.loop
x:
- bit 0
+ bit.bit 0
carry:
- bit 1
+ bit.bit 1
diff --git a/programs/sanity_checks/mathvec.fj b/programs/sanity_checks/mathvec.fj
index 3f56b76..25e04f4 100644
--- a/programs/sanity_checks/mathvec.fj
+++ b/programs/sanity_checks/mathvec.fj
@@ -1,6 +1,6 @@
- startup
+ stl.startup
bit.inc 2, x
- loop
+ stl.loop
x:
bit.vec 2, 0
diff --git a/programs/sanity_checks/not.fj b/programs/sanity_checks/not.fj
index c855c8c..3589e35 100644
--- a/programs/sanity_checks/not.fj
+++ b/programs/sanity_checks/not.fj
@@ -1,6 +1,6 @@
- startup
+ stl.startup
bit.not x
- loop
+ stl.loop
x:
- bit 0
+ bit.bit 0
diff --git a/programs/sanity_checks/rep.fj b/programs/sanity_checks/rep.fj
index 3abd406..b76029c 100644
--- a/programs/sanity_checks/rep.fj
+++ b/programs/sanity_checks/rep.fj
@@ -1,6 +1,6 @@
- startup
+ stl.startup
rep(7, i) bit.exact_not x+i+i
- loop
+ stl.loop
x:
- bit 0
+ bit.bit 0
diff --git a/programs/sanity_checks/simple.fj b/programs/sanity_checks/simple.fj
index e7c2771..7c127bb 100644
--- a/programs/sanity_checks/simple.fj
+++ b/programs/sanity_checks/simple.fj
@@ -1,9 +1,11 @@
- skip
- IO:
+ stl.skip
+ ns stl {
+ IO:
+ }
;
bit.not x
- output '0'+#0b111
- loop
+ stl.output '0'+#0b111
+ stl.loop
x:
- bit 0
+ bit.bit 0
diff --git a/programs/sanity_checks/startup_init_all.fj b/programs/sanity_checks/startup_init_all.fj
new file mode 100644
index 0000000..4019391
--- /dev/null
+++ b/programs/sanity_checks/startup_init_all.fj
@@ -0,0 +1,35 @@
+stl.startup_and_init_all
+N = 4
+
+hex.sub N, a, b
+
+hex.print_uint N, a, 1, 1
+stl.output "\n"
+
+flip_and_print
+flip_and_print
+flip_and_print
+flip_and_print
+stl.output "\n"
+
+stl.loop
+
+a: hex.vec N, 0xE973
+b: hex.vec N, 0xDEAD
+
+p: bit.vec w, d+dbit
+d: bit.bit 0 // 0 => 1
+
+def flip_and_print @ d0, d1, end < p, d {
+ bit.ptr_flip p
+ bit.if d, d0, d1
+ d0:
+ stl.output "0"
+ ;end
+ d1:
+ stl.output "1"
+ ;end
+ end:
+}
+
+
diff --git a/programs/sanity_checks/testbit.fj b/programs/sanity_checks/testbit.fj
index 32ec5dd..591fc89 100644
--- a/programs/sanity_checks/testbit.fj
+++ b/programs/sanity_checks/testbit.fj
@@ -1,12 +1,12 @@
-startup
+stl.startup
bit.if x, l0, l1
l0:
- output 6 ? 'Z' : '0'
- loop
+ stl.output 6 ? 'Z' : '0'
+ stl.loop
l1:
- output '1'
- loop
+ stl.output '1'
+ stl.loop
x:
- bit 0 // bit0 => 'Z', bit1 => '1'
+ bit.bit 0 // bit0 => 'Z', bit1 => '1'
diff --git a/programs/sanity_checks/testbit_with_nops.fj b/programs/sanity_checks/testbit_with_nops.fj
index ad8bf82..630df17 100644
--- a/programs/sanity_checks/testbit_with_nops.fj
+++ b/programs/sanity_checks/testbit_with_nops.fj
@@ -1,20 +1,20 @@
-startup
+stl.startup
rep(10, i) bit.mov y, z
bit.mov x, x
bit.if x, l0, l1
l0:
- output 0x5A // 'Z'
+ stl.output 0x5A // 'Z'
;loop
l1:
- output 0x10*3+1*3-4/2 // '1'
+ stl.output 0x10*3+1*3-4/2 // '1'
;
;loop
loop:
;
- loop
+ stl.loop
pad 2
wflip l1, loop
@@ -22,7 +22,7 @@ loop:
;dloop
bit.vec 8, 3
bananas:
- output 0x5c
+ stl.output 0x5c
dy=3
n=15
@@ -37,9 +37,9 @@ def temp_macro g, y {
}
x:
- bit 1 // bit0 => 'Z', bit1 => '1'
+ bit.bit 1 // bit0 => 'Z', bit1 => '1'
y:
- bit 1
+ bit.bit 1
z:
- bit 1
+ bit.bit 1
diff --git a/programs/simple_math_checks/div10.fj b/programs/simple_math_checks/div10.fj
index c0d8cf1..376d5b0 100644
--- a/programs/simple_math_checks/div10.fj
+++ b/programs/simple_math_checks/div10.fj
@@ -1,16 +1,16 @@
-startup
+stl.startup
loop:
bit.print_hex_uint w, var, 1
-output ','
+stl.output ','
bit.div10 w, dst, var
bit.dec2ascii ascii, var
bit.print ascii
-output '\n'
+stl.output '\n'
bit.mov w, var, dst
bit.if1 w, var, loop
-loop
+stl.loop
var: bit.vec w, 1281 // (128, 12, 1)
diff --git a/programs/simple_math_checks/nadd.fj b/programs/simple_math_checks/nadd.fj
index 6719463..99c40db 100644
--- a/programs/simple_math_checks/nadd.fj
+++ b/programs/simple_math_checks/nadd.fj
@@ -1,7 +1,7 @@
- startup
+ stl.startup
bit.add 8, a, b
bit.print a
- loop
+ stl.loop
a:
bit.vec 8, '5'
diff --git a/programs/simple_math_checks/ncmp.fj b/programs/simple_math_checks/ncmp.fj
index ca73c2c..e5da42d 100644
--- a/programs/simple_math_checks/ncmp.fj
+++ b/programs/simple_math_checks/ncmp.fj
@@ -1,16 +1,19 @@
-startup 0, 0
+stl.startup
+stl.default_input 0, 0
+
+
n=4
bit.cmp n, a, b, lt, eq, gt
lt:
- output '<'
- loop
+ stl.output '<'
+ stl.loop
eq:
- output '='
- loop
+ stl.output '='
+ stl.loop
gt:
- output '>'
- loop
+ stl.output '>'
+ stl.loop
a:
bit.vec n, 3
diff --git a/programs/simple_math_checks/series_sum.fj b/programs/simple_math_checks/series_sum.fj
index 7dbd785..d9c9b2d 100644
--- a/programs/simple_math_checks/series_sum.fj
+++ b/programs/simple_math_checks/series_sum.fj
@@ -1,15 +1,15 @@
N = 8 // 32bits
-startup
+stl.startup
// starting printings:
-output "params: a1 = "
+stl.output "params: a1 = "
print_hex_as_decimal a1
-output ", d = "
+stl.output ", d = "
print_hex_as_decimal d
-output ", n = "
+stl.output ", n = "
print_hex_as_decimal n
-output ".\n\n"
+stl.output ".\n\n"
hex.mov N, n_1, n
@@ -18,33 +18,33 @@ hex.mul N, an, n_1, d // an = d(n-1)
hex.add N, an, a1 // an = a1 + d(n-1)
// print an
-output "an = "
+stl.output "an = "
print_hex_as_decimal an
-output ".\n"
+stl.output ".\n"
hex.add N, an, a1 // a1 + an
hex.mul N, s, an, n // s = (a1+an) * n
hex.shr_bit N, s // s = (a1+an) * n/2
// print sum
-output "Sum(a1, a2, ..., an) = "
+stl.output "Sum(a1, a2, ..., an) = "
print_hex_as_decimal s
-output ".\n"
+stl.output ".\n"
-loop
+stl.loop
hex.init // inits the hex.mul
def print_hex_as_decimal hexxx < num, ret, print_num {
- hex2bit N, num, hexxx
- fcall print_num, ret
+ stl.hex2bit N, num, hexxx
+ stl.fcall print_num, ret
}
print_num:
bit.print_dec_int N*4, num
;ret
num: bit.vec N*4
-ret: bit
+ret: bit.bit
// inputs and variables:
diff --git a/src/assembler.py b/src/assembler.py
index 5c43279..96a03c2 100644
--- a/src/assembler.py
+++ b/src/assembler.py
@@ -7,7 +7,7 @@
from fj_parser import parse_macro_tree
from preprocessor import resolve_macros
-from defs import PrintTimer, save_debugging_labels
+from defs import PrintTimer, save_debugging_labels, WFLIP_LABEL_PREFIX
from ops import FlipJump, WordFlip, LastPhaseOp, NewSegment, ReserveBits, Padding
from exceptions import FJAssemblerException, FJException, FJWriteFjmException
@@ -58,12 +58,15 @@ class WFlipSpot:
class BinaryData:
- def __init__(self, w: int, first_segment: NewSegment):
+ def __init__(self, w: int, first_segment: NewSegment, labels: Dict[str, int]):
self.w = w
self.first_address = first_segment.start_address
self.wflip_address = first_segment.wflip_start_address
+ self.labels = labels
+ self.wflips_so_far = 0
+
self.current_address = self.first_address
self.fj_words: List[int] = []
@@ -87,6 +90,10 @@ def get_wflip_spot(self) -> WFlipSpot:
def close_and_add_segment(self, fjm_writer: fjm.Writer) -> None:
add_segment_to_fjm(self.w, fjm_writer, self.first_address, self.wflip_address, self.fj_words, self.wflip_words)
+ def _insert_wflip_label(self, address: int):
+ self.labels[f'{WFLIP_LABEL_PREFIX}{self.wflips_so_far}'] = address
+ self.wflips_so_far += 1
+
def insert_fj_op(self, flip: int, jump: int) -> None:
self.fj_words += (flip, jump)
self.current_address += 2*self.w
@@ -116,6 +123,7 @@ def insert_wflip_ops(self, word_address: int, flip_value: int, return_address: i
else:
# insert a new wflip op, and connect the last one to it
wflip_spot = self.get_wflip_spot()
+ self._insert_wflip_label(wflip_spot.address)
ops_list[last_address_index] = wflip_spot.address
return_dict[flips_key] = wflip_spot.address
@@ -163,21 +171,21 @@ def labels_resolve(ops: Deque[LastPhaseOp], labels: Dict[str, int],
if not isinstance(first_segment, NewSegment):
raise FJAssemblerException(f"The first op must be of type NewSegment (and not {first_segment}).")
- binary_data = BinaryData(w, first_segment)
+ binary_data = BinaryData(w, first_segment, labels)
for op in ops:
if isinstance(op, FlipJump):
try:
binary_data.insert_fj_op(op.get_flip(labels), op.get_jump(labels))
except FJException as e:
- raise FJAssemblerException(f"Can't resolve labels in op {op}.") from e
+ raise FJAssemblerException(f"{e} in op {op}.")
elif isinstance(op, WordFlip):
try:
binary_data.insert_wflip_ops(op.get_word_address(labels), op.get_flip_value(labels),
op.get_return_address(labels))
except FJException as e:
- raise FJAssemblerException(f"Can't resolve labels in op {op}.") from e
+ raise FJAssemblerException(f"{e} in op {op}.")
elif isinstance(op, Padding):
binary_data.insert_padding(op.ops_count)
diff --git a/src/breakpoints.py b/src/breakpoints.py
index 4b38a6f..f088fff 100644
--- a/src/breakpoints.py
+++ b/src/breakpoints.py
@@ -7,7 +7,7 @@
import fjm
-from defs import macro_separator_string, RunStatistics, load_debugging_labels
+from defs import MACRO_SEPARATOR_STRING, RunStatistics, load_debugging_labels
class BreakpointHandlerUnnecessary(Exception):
@@ -20,7 +20,7 @@ def display_message_box_and_get_answer(msg: str, title: str, choices: List[str])
def get_nice_label_repr(label: str, pad: int = 0) -> str:
- parts = label.split(macro_separator_string)
+ parts = label.split(MACRO_SEPARATOR_STRING)
return ' ->\n'.join(f"{' '*(pad+i)}{part}" for i, part in enumerate(parts))
@@ -32,8 +32,8 @@ def __init__(self, breakpoints: Dict[int, str], address_to_label: Dict[int, str]
self.breakpoints = breakpoints
self.address_to_label = address_to_label
- if 0 not in self.address_to_label:
- self.address_to_label[0] = 'memory_start_0x0000'
+ if self.address_to_label and 0 not in self.address_to_label:
+ self.address_to_label[0] = ':memory-start:'
self.next_break = None
@@ -43,14 +43,17 @@ def should_break(self, ip: int, op_counter: int) -> bool:
def get_address_str(self, address: int) -> str:
if address in self.breakpoints and self.breakpoints[address] is not None:
label_repr = get_nice_label_repr(self.breakpoints[address], pad=4)
- return f'{hex(address)[2:]}:\n{label_repr}'
+ return f'{hex(address)}:\n{label_repr}'
elif address in self.address_to_label:
label_repr = get_nice_label_repr(self.address_to_label[address], pad=4)
- return f'{hex(address)[2:]}:\n{label_repr}'
+ return f'{hex(address)}:\n{label_repr}'
else:
- address_before = max([a for a in self.address_to_label if a <= address])
- label_repr = get_nice_label_repr(self.address_to_label[address_before], pad=4)
- return f'{hex(address)[2:]} ({hex(address - address_before)} after:)\n{label_repr}'
+ try:
+ address_before = max(a for a in self.address_to_label if a <= address)
+ label_repr = get_nice_label_repr(self.address_to_label[address_before], pad=4)
+ return f'{hex(address)} ({hex(address - address_before)} bits after:)\n{label_repr}'
+ except ValueError:
+ return f'{hex(address)}'
def get_message_box_body(self, ip: int, mem: fjm.Reader, op_counter: int) -> str:
address = self.get_address_str(ip)
@@ -152,8 +155,8 @@ def update_breakpoints_from_breakpoint_contains_set(breakpoint_contains_labels:
"""
# TODO improve the speed of this part with suffix trees
if breakpoint_contains_labels:
- for bcl in breakpoint_contains_labels:
- for label in label_to_address:
+ for label in tuple(label_to_address)[::-1]:
+ for bcl in breakpoint_contains_labels:
if bcl in label:
address = label_to_address[label]
breakpoints[address] = label
@@ -187,7 +190,7 @@ def load_labels_dictionary(debugging_file: Optional[Path], labels_file_needed: b
def get_breakpoint_handler(debugging_file: Path, breakpoint_addresses: Set[int], breakpoint_labels: Set[str],
- breakpoint_contains_labels: Set[str]) -> Optional[BreakpointHandler]:
+ breakpoint_contains_labels: Set[str]) -> BreakpointHandler:
"""
generate the breakpoint handler from the debugging file and the breakpoint sets.
@param debugging_file: the debug file path (created at assemble time)
@@ -199,7 +202,7 @@ def get_breakpoint_handler(debugging_file: Path, breakpoint_addresses: Set[int],
labels_file_needed = any((breakpoint_addresses, breakpoint_contains_labels))
label_to_address = load_labels_dictionary(debugging_file, labels_file_needed)
- address_to_label = {label_to_address[label]: label for label in label_to_address}
+ address_to_label = {label_to_address[label]: label for label in tuple(label_to_address)[::-1]}
breakpoints = get_breakpoints(breakpoint_addresses, breakpoint_labels, breakpoint_contains_labels, label_to_address)
- return BreakpointHandler(breakpoints, address_to_label) if breakpoints else None
+ return BreakpointHandler(breakpoints, address_to_label)
diff --git a/src/defs.py b/src/defs.py
index b02fd69..1583c12 100644
--- a/src/defs.py
+++ b/src/defs.py
@@ -1,14 +1,13 @@
from __future__ import annotations
-import dataclasses
+import argparse
import json
import lzma
+from collections import deque
from enum import IntEnum # IntEnum equality works between files.
from pathlib import Path
from time import time
-from typing import List, Dict
-
-from ops import CodePosition, Op
+from typing import List, Dict, Deque, Optional
def get_stl_paths() -> List[Path]:
@@ -22,17 +21,23 @@ def get_stl_paths() -> List[Path]:
class TerminationCause(IntEnum):
- Looping = 0 # Finished by jumping to the last op, without flipping it (the "regular" finish/exit)
- EOF = 1 # Finished by reading input when there is no more input
- NullIP = 2 # Finished by jumping back to the initial op 0 (bad finish)
- UnalignedWord = 3 # FOR FUTURE SUPPORT - tried to access an unaligned word (bad finish)
- UnalignedOp = 4 # FOR FUTURE SUPPORT - tried to access a dword-unaligned op (bad finish)
+ Looping = 0 # Finished by jumping to the last op, without flipping it (the "regular" finish/exit)
+ EOF = 1 # Finished by reading input when there is no more input
+ NullIP = 2 # Finished by jumping back to the initial op 0 (bad finish)
+ UnalignedWord = 3 # FOR FUTURE SUPPORT - tried to access an unaligned word (bad finish)
+ UnalignedOp = 4 # FOR FUTURE SUPPORT - tried to access a dword-unaligned op (bad finish)
+ RuntimeMemoryError = 5 # Finished by trying to read/write something out of the defined memory
+ # (probably a bug in the fj-program)
def __str__(self) -> str:
- return ['looping', 'EOF', 'ip<2w', 'unaligned-word', 'unaligned-op'][self.value]
+ return ['looping', 'EOF', 'ip<2w', 'unaligned-word', 'unaligned-op', 'runtime-memory-error'][self.value]
+
+MACRO_SEPARATOR_STRING = "---"
+STARTING_LABEL_IN_MACROS_STRING = ':start:'
+WFLIP_LABEL_PREFIX = ':wflips:'
-macro_separator_string = "---"
+LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH = 10
io_bytes_encoding = 'raw_unicode_escape'
@@ -42,6 +47,13 @@ def __str__(self) -> str:
_debug_json_lzma_filters: List[Dict[str, int]] = [{"id": lzma.FILTER_LZMA2}]
+def check_int_positive(value):
+ ivalue = int(value)
+ if ivalue <= 0:
+ raise argparse.ArgumentTypeError(f"{value} is an invalid positive int value")
+ return ivalue
+
+
def save_debugging_labels(debugging_file_path: Path, labels: Dict[str, int]) -> None:
"""
save the labels' dictionary to the debugging-file as lzma2-compressed json
@@ -89,18 +101,6 @@ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
print(f'{time() - self.start_time:.3f}s')
-@dataclasses.dataclass
-class Macro:
- """
- The python representation of a .fj macro (macro declaration).
- """
- params: List[str]
- local_params: List[str]
- ops: List[Op]
- namespace: str
- code_position: CodePosition
-
-
class RunStatistics:
"""
maintains times and counters of the current run.
@@ -115,7 +115,12 @@ def __enter__(self):
def __exit__(self, exc_type, exc_val, exc_tb):
self.paused_time += time() - self.pause_start_time
- def __init__(self, w: int):
+ def __init__(self, w: int, last_ops_debugging_list_length: Optional[int]):
+ """
+ Saves statistics about the current run (and a queue of the last executed ops).
+ @param w: the memory bit-length
+ @param last_ops_debugging_list_length: The length of the last-ops list
+ """
self._op_size = 2 * w
self._after_null_flip = 2 * w
@@ -123,12 +128,20 @@ def __init__(self, w: int):
self.flip_counter = 0
self.jump_counter = 0
+ self.last_ops_addresses: Optional[Deque[int]] = None
+ if last_ops_debugging_list_length is not None:
+ self.last_ops_addresses = deque(maxlen=last_ops_debugging_list_length)
+
self._start_time = time()
self.pause_timer = self.PauseTimer()
def get_run_time(self) -> float:
return time() - self._start_time - self.pause_timer.paused_time
+ def register_op_address(self, ip: int):
+ if self.last_ops_addresses is not None:
+ self.last_ops_addresses.append(ip)
+
def register_op(self, ip: int, flip_address: int, jump_address: int) -> None:
self.op_counter += 1
if flip_address >= self._after_null_flip:
diff --git a/src/exceptions.py b/src/exceptions.py
index 8a098d5..78840b4 100644
--- a/src/exceptions.py
+++ b/src/exceptions.py
@@ -24,3 +24,7 @@ class FJReadFjmException(FJException):
class FJWriteFjmException(FJException):
pass
+
+
+class FJRuntimeMemoryException(FJException):
+ pass
diff --git a/src/expr.py b/src/expr.py
index 56cff74..e595ef9 100644
--- a/src/expr.py
+++ b/src/expr.py
@@ -3,6 +3,7 @@
from typing import Union, Tuple, Set, Dict
from operator import mul, add, sub, floordiv, lshift, rshift, mod, xor, or_, and_
+from defs import MACRO_SEPARATOR_STRING
from exceptions import FJExprException
@@ -109,9 +110,12 @@ def __str__(self) -> str:
if isinstance(self.value, str):
return self.value
if isinstance(self.value, int):
- return hex(self.value)[2:]
+ return str(self.value)
raise FJExprException(f'bad expression: {self.value} (of type {type(self.value)})')
+ def __repr__(self) -> str:
+ return str(self)
+
def get_minimized_expr(op: str, params: Tuple[Expr, ...]) -> Expr:
"""
diff --git a/src/fj.py b/src/fj.py
index 8d68228..0d8fa3d 100644
--- a/src/fj.py
+++ b/src/fj.py
@@ -10,7 +10,7 @@
import fjm
from io_devices.StandardIO import StandardIO
-from defs import get_stl_paths
+from defs import get_stl_paths, LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH, check_int_positive
from exceptions import FJReadFjmException
from breakpoints import get_breakpoint_handler
@@ -116,10 +116,12 @@ def run(in_fjm_path: Path, debug_file: Path, args: argparse.Namespace, error_fun
io_device=io_device,
show_trace=args.trace,
time_verbose=not args.silent,
- breakpoint_handler=breakpoint_handler
+ breakpoint_handler=breakpoint_handler if breakpoint_handler.breakpoints else None,
+ last_ops_debugging_list_length=args.debug_ops_list,
)
if not args.silent:
- print(termination_statistics)
+ termination_statistics.print(labels_handler=breakpoint_handler,
+ output_to_print=io_device.get_output(allow_incomplete_output=True))
except FJReadFjmException as e:
print()
print(e)
@@ -215,6 +217,12 @@ def add_run_only_arguments(parser: argparse.ArgumentParser) -> None:
"""
run_arguments = parser.add_argument_group('run arguments', 'Ignored when using the --assemble option')
+ run_arguments.add_argument('--debug-ops-list', metavar='LENGTH', type=check_int_positive,
+ default=LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH,
+ help=f"show the last LENGTH executed opcodes on tests that failed during their run "
+ f"({LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH} by default)."
+ )
+
run_arguments.add_argument('-t', '--trace', help="output every running opcode", action='store_true')
run_arguments.add_argument('--no_output', help="don't print the program's output", action='store_true')
diff --git a/src/fj_parser.py b/src/fj_parser.py
index d2e90f8..b1be4f0 100644
--- a/src/fj_parser.py
+++ b/src/fj_parser.py
@@ -6,14 +6,13 @@
from sly.yacc import YaccProduction as ParsedRule
from sly.lex import Token
-from defs import Macro
from exceptions import FJExprException, FJParsingException
from expr import Expr, get_minimized_expr
from ops import get_used_labels, get_declared_labels, \
- CodePosition, MacroName, Op, initial_macro_name, \
+ CodePosition, MacroName, Op, Macro, initial_macro_name, \
MacroCall, RepCall, FlipJump, WordFlip, Label, Segment, Reserve, Pad
-global curr_file, curr_file_short_name, curr_text, error_occurred, curr_namespace
+global curr_file, curr_file_short_name, curr_text, error_occurred, all_errors, curr_namespace
def get_position(lineno: int) -> CodePosition:
@@ -21,30 +20,32 @@ def get_position(lineno: int) -> CodePosition:
def syntax_error(lineno: int, msg='') -> None:
- global error_occurred
+ global error_occurred, all_errors
error_occurred = True
curr_position = get_position(lineno)
- print()
+
if msg:
- print(f"Syntax Error in {curr_position}:")
- print(f" {msg}")
+ error_string = f"Syntax Error in {curr_position}:\n {msg}"
else:
- print(f"Syntax Error in {curr_position}")
+ error_string = f"Syntax Error in {curr_position}"
+ all_errors += f"{error_string}\n"
+
+ print(error_string)
def syntax_warning(line: int, is_error: bool, msg: str = '') -> None:
- if is_error:
- global error_occurred
- error_occurred = True
- print()
- print(f"Syntax Warning in file {curr_file}", end="")
+ error_string = f"Syntax Warning in file {curr_file}"
if line is not None:
- print(f" line {line}", end="")
+ error_string += f" line {line}"
if msg:
- print(f":")
- print(f" {msg}")
- else:
- print()
+ error_string += f":\n {msg}"
+
+ if is_error:
+ global error_occurred, all_errors
+ error_occurred = True
+ all_errors += f"{error_string}\n"
+
+ print(error_string)
# Regex for the parser
@@ -93,6 +94,7 @@ class FJLexer(sly.Lexer):
"@", ","}
ignore_ending_comment = r'//.*'
+ ignore_line_continuation = r'\\[ \t]*\n'
# Tokens
DOT_ID = dot_id_re
@@ -156,10 +158,13 @@ def NL(self, t: Token) -> Token:
return t
def error(self, t: Token) -> None:
- global error_occurred
+ global error_occurred, all_errors
error_occurred = True
- print()
- print(f"Lexing Error in {get_position(self.lineno)}: {t.value[0]}")
+
+ error_string = f"Lexing Error in {get_position(self.lineno)}: {t.value[0]}"
+ all_errors += f"{error_string}\n"
+ print(error_string)
+
self.index += 1
@@ -211,10 +216,11 @@ def validate_label_usage(self, labels_used: Set[str], labels_declared: Set[str],
lineno: int, macro_name: MacroName) -> None:
self.validate_labels_groups(extern_labels, global_labels, regular_labels, lineno, macro_name)
- self.validate_no_unused_labels(regular_labels, labels_declared, labels_used, lineno, macro_name)
- self.validate_no_bad_label_declarations(regular_labels, extern_labels, labels_declared, lineno, macro_name)
+ self.validate_no_unused_labels(regular_labels, global_labels, labels_declared, labels_used, lineno, macro_name)
self.validate_no_unknown_label_uses(regular_labels, global_labels, labels_declared, labels_used,
lineno, macro_name)
+ self.validate_no_bad_label_declarations(regular_labels, extern_labels, labels_declared, lineno, macro_name)
+ self.validate_all_extern_labels_are_declared(extern_labels, labels_declared, lineno, macro_name)
@staticmethod
def validate_labels_groups(extern_labels: Set[str], global_labels: Set[str], regular_labels: Set[str],
@@ -229,15 +235,23 @@ def validate_labels_groups(extern_labels: Set[str], global_labels: Set[str], reg
syntax_error(lineno, f"In macro {macro_name}: "
f"global labels can't be regular labels: " + ', '.join(extern_labels & regular_labels))
- def validate_no_unused_labels(self, regular_labels: Set[str],
+ def validate_no_unused_labels(self, regular_labels: Set[str], global_labels: Set[str],
labels_declared: Set[str], labels_used: Set[str],
lineno: int, macro_name: MacroName) -> None:
- unused_labels = regular_labels - labels_used.union(self.to_base_name(label) for label in labels_declared)
+ unused_labels = regular_labels.union(global_labels) - labels_used.union(self.to_base_name(label) for label in labels_declared)
if unused_labels:
syntax_warning(lineno, self.warning_as_errors,
f"In macro {macro_name}: "
f"unused labels: {', '.join(unused_labels)}.")
+ def validate_all_extern_labels_are_declared(self, extern_labels: Set[str], labels_declared: Set[str],
+ lineno: int, macro_name: MacroName) -> None:
+ unused_labels = extern_labels - {self.to_base_name(label) for label in labels_declared}
+ if unused_labels:
+ syntax_warning(lineno, self.warning_as_errors,
+ f"In macro {macro_name}: "
+ f"undeclared extern label: {', '.join(unused_labels)}.")
+
def validate_no_bad_label_declarations(self, regular_labels: Set[str], extern_labels: Set[str],
labels_declared: Set[str],
lineno: int, macro_name: MacroName) -> None:
@@ -304,13 +318,17 @@ def to_base_name(name: str) -> str:
return name.split('.')[-1]
def error(self, token: Token) -> None:
- global error_occurred
+ global error_occurred, all_errors
error_occurred = True
- print()
+
if token is None:
- print(f'Syntax Error in {get_position(self.line_position(None))}. Maybe missing }} or {{ before this line?')
+ error_string = f'Syntax Error in {get_position(self.line_position(None))}. Maybe missing }} or {{ before this line?'
else:
- print(f'Syntax Error in {get_position(token.lineno)}, token=("{token.type}", {token.value})')
+ error_string = f'Syntax Error in {get_position(token.lineno)}, token=("{token.type}", {token.value})'
+
+ all_errors += f"{error_string}\n"
+ print(error_string)
+
@_('definable_line_statements')
def program(self, p: ParsedRule) -> None:
@@ -638,7 +656,7 @@ def expr_(self, p: ParsedRule) -> Tuple[Expr, int]:
def exit_if_errors() -> None:
if error_occurred:
- raise FJParsingException(f'Errors found in file {curr_file}. Assembly stopped.')
+ raise FJParsingException(f'Errors found in file {curr_file}. Assembly stopped.\n\nThe Errors:\n{all_errors}')
def validate_current_file(files_seen: Set[Union[str, Path]]) -> None:
@@ -678,8 +696,9 @@ def parse_macro_tree(input_files: List[Tuple[str, Path]], w: int, warning_as_err
@param warning_as_errors:[in]: treat warnings as errors (stop execution on warnings)
@return: the macro-dictionary.
"""
- global curr_file, curr_file_short_name, error_occurred
+ global curr_file, curr_file_short_name, error_occurred, all_errors
error_occurred = False
+ all_errors = ''
files_seen: Set[Union[str, Path]] = set()
diff --git a/src/fjm.py b/src/fjm.py
index ca34627..f25b3e3 100644
--- a/src/fjm.py
+++ b/src/fjm.py
@@ -7,8 +7,7 @@
import lzma
-from exceptions import FJReadFjmException, FJWriteFjmException
-
+from exceptions import FJReadFjmException, FJWriteFjmException, FJRuntimeMemoryException
"""
struct {
@@ -174,7 +173,7 @@ def _get_memory_word(self, word_address: int) -> int:
garbage_message = f'Reading garbage word at mem[{hex(word_address << self.w)[2:]}] = {hex(garbage_val)[2:]}'
if GarbageHandling.Stop == self.garbage_handling:
- raise FJReadFjmException(garbage_message)
+ raise FJRuntimeMemoryException(garbage_message)
elif GarbageHandling.OnlyWarning == self.garbage_handling:
print(f'\nWarning: {garbage_message}')
elif GarbageHandling.SlowRead == self.garbage_handling:
@@ -232,7 +231,7 @@ def get_word(self, bit_address: int) -> int:
if bit_offset == 0:
return self._get_memory_word(word_address)
if word_address == ((1 << self.w) - 1):
- raise FJReadFjmException(f'Accessed outside of memory (beyond the last bit).')
+ raise FJRuntimeMemoryException(f'Accessed outside of memory (beyond the last bit).')
lsw = self._get_memory_word(word_address)
msw = self._get_memory_word(word_address + 1)
diff --git a/src/fjm_run.py b/src/fjm_run.py
index f81d725..fba2fde 100644
--- a/src/fjm_run.py
+++ b/src/fjm_run.py
@@ -1,10 +1,11 @@
from pathlib import Path
-from typing import Optional
+from typing import Optional, Deque
import fjm
from defs import TerminationCause, PrintTimer, RunStatistics
from breakpoints import BreakpointHandler, handle_breakpoint
+from exceptions import FJRuntimeMemoryException
from io_devices.IODevice import IODevice
from io_devices.BrokenIO import BrokenIO
@@ -22,23 +23,57 @@ def __init__(self, run_statistics: RunStatistics, termination_cause: Termination
self.op_counter = run_statistics.op_counter
self.flip_counter = run_statistics.flip_counter
self.jump_counter = run_statistics.jump_counter
+ self.last_ops_addresses: Deque[int] = run_statistics.last_ops_addresses
self.termination_cause = termination_cause
- def __str__(self):
+ @staticmethod
+ def beautify_address(address: int, breakpoint_handler: Optional[BreakpointHandler]):
+ if not breakpoint_handler:
+ return hex(address)
+
+ return breakpoint_handler.get_address_str(address)
+
+ def print(self, *, labels_handler: Optional[BreakpointHandler] = None, output_to_print: Optional[bytes] = None):
+ """
+ Prints the termination cause, run times, ops-statistics.
+ If ended not by looping - Then print the last-opcodes` addresses as well (and their label names if possible).
+ @param labels_handler: Used to find the label name for each address (from the last-opcodes` addresses).
+ @param output_to_print: if specified and terminated not by looping - print the given output.
+ """
+
flips_percentage = self.flip_counter / self.op_counter * 100
jumps_percentage = self.jump_counter / self.op_counter * 100
- return f'Finished by {str(self.termination_cause)} after {self.run_time:.3f}s ' \
- f'(' \
- f'{self.op_counter:,} ops executed; ' \
- f'{flips_percentage:.2f}% flips, ' \
- f'{jumps_percentage:.2f}% jumps' \
- f').'
+
+ last_ops_str = ''
+ output_str = ''
+ if TerminationCause.Looping != self.termination_cause:
+ if self.last_ops_addresses is not None:
+ labels_handler_missing_string = '' if labels_handler is not None and labels_handler.address_to_label \
+ else f'**** You may want to use debugging flags for more debugging info ****\n\n'
+ last_ops_str = f'\n\n{labels_handler_missing_string}' \
+ f'Last {len(self.last_ops_addresses)} ops were at these addresses ' \
+ f'(The most-recent op, the one that failed, is first):\n ' \
+ + '\n '.join([self.beautify_address(address, labels_handler)
+ for address in self.last_ops_addresses][::-1])
+ if output_to_print is not None:
+ output_str = f"Program's output before it was terminated: {output_to_print}\n\n"
+
+ print(f'\n'
+ f'{output_str}'
+ f'Finished by {str(self.termination_cause)} after {self.run_time:.3f}s '
+ f'('
+ f'{self.op_counter:,} ops executed; '
+ f'{flips_percentage:.2f}% flips, '
+ f'{jumps_percentage:.2f}% jumps'
+ f').'
+ f'{last_ops_str}'
+ )
def handle_input(io_device: IODevice, ip: int, mem: fjm.Reader, statistics: RunStatistics) -> None:
w = mem.w
- in_addr = 3 * w + w.bit_length() # 3w + dww
+ in_addr = 3 * w + w.bit_length() # 3w + #w
if ip <= in_addr < ip + 2 * w:
with statistics.pause_timer:
@@ -67,7 +102,8 @@ def run(fjm_path: Path, *,
breakpoint_handler: Optional[BreakpointHandler] = None,
io_device: Optional[IODevice] = None,
show_trace: bool = False,
- time_verbose: bool = False) \
+ time_verbose: bool = False,
+ last_ops_debugging_list_length: Optional[int] = None) \
-> TerminationStatistics:
"""
run / debug a .fjm file (a FlipJump interpreter)
@@ -76,6 +112,7 @@ def run(fjm_path: Path, *,
@param io_device:[in,out]: the device handling input/output
@param show_trace: if true print every opcode executed
@param time_verbose: if true print running times
+ @param last_ops_debugging_list_length: The length of the last-ops list
@return: the run's termination-statistics
"""
with PrintTimer(' loading memory: ', print_time=time_verbose):
@@ -87,37 +124,43 @@ def run(fjm_path: Path, *,
ip = 0
w = mem.w
- statistics = RunStatistics(w)
+ statistics = RunStatistics(w, last_ops_debugging_list_length)
+
+ try:
+ while True:
+ statistics.register_op_address(ip)
+
+ # handle breakpoints
+ if breakpoint_handler and breakpoint_handler.should_break(ip, statistics.op_counter):
+ breakpoint_handler = handle_breakpoint(breakpoint_handler, ip, mem, statistics)
- while True:
- # handle breakpoints
- if breakpoint_handler and breakpoint_handler.should_break(ip, statistics.op_counter):
- breakpoint_handler = handle_breakpoint(breakpoint_handler, ip, mem, statistics)
+ # read flip word
+ flip_address = mem.get_word(ip)
+ trace_flip(ip, flip_address, show_trace)
- # read flip word
- flip_address = mem.get_word(ip)
- trace_flip(ip, flip_address, show_trace)
+ # handle IO
+ handle_output(flip_address, io_device, w)
+ try:
+ handle_input(io_device, ip, mem, statistics)
+ except IOReadOnEOF:
+ return TerminationStatistics(statistics, TerminationCause.EOF)
- # handle IO
- handle_output(flip_address, io_device, w)
- try:
- handle_input(io_device, ip, mem, statistics)
- except IOReadOnEOF:
- return TerminationStatistics(statistics, TerminationCause.EOF)
+ # FLIP!
+ mem.write_bit(flip_address, not mem.read_bit(flip_address))
- # FLIP!
- mem.write_bit(flip_address, not mem.read_bit(flip_address))
+ # read jump word
+ jump_address = mem.get_word(ip+w)
+ trace_jump(jump_address, show_trace)
+ statistics.register_op(ip, flip_address, jump_address)
- # read jump word
- jump_address = mem.get_word(ip+w)
- trace_jump(jump_address, show_trace)
- statistics.register_op(ip, flip_address, jump_address)
+ # check finish?
+ if jump_address == ip and not ip <= flip_address < ip+2*w:
+ return TerminationStatistics(statistics, TerminationCause.Looping)
+ if jump_address < 2*w:
+ return TerminationStatistics(statistics, TerminationCause.NullIP)
- # check finish?
- if jump_address == ip and not ip <= flip_address < ip+2*w:
- return TerminationStatistics(statistics, TerminationCause.Looping)
- if jump_address < 2*w:
- return TerminationStatistics(statistics, TerminationCause.NullIP)
+ # JUMP!
+ ip = jump_address
- # JUMP!
- ip = jump_address
+ except FJRuntimeMemoryException:
+ return TerminationStatistics(statistics, TerminationCause.RuntimeMemoryError)
diff --git a/src/io_devices/FixedIO.py b/src/io_devices/FixedIO.py
index e53e072..2f27296 100644
--- a/src/io_devices/FixedIO.py
+++ b/src/io_devices/FixedIO.py
@@ -39,12 +39,12 @@ def write_bit(self, bit: bool) -> None:
self.current_output_byte = 0
self.bits_to_write_in_output_byte = 0
- def get_output(self) -> bytes:
+ def get_output(self, *, allow_incomplete_output=False) -> bytes:
"""
@raise IncompleteOutput when the number of outputted bits can't be divided by 8
@return: full output until now
"""
- if 0 != self.bits_to_write_in_output_byte:
+ if not allow_incomplete_output and 0 != self.bits_to_write_in_output_byte:
raise IncompleteOutput("tries to get output when an unaligned number of bits was outputted "
"(doesn't divide 8)")
diff --git a/src/io_devices/StandardIO.py b/src/io_devices/StandardIO.py
index 278086d..a355e77 100644
--- a/src/io_devices/StandardIO.py
+++ b/src/io_devices/StandardIO.py
@@ -51,8 +51,8 @@ def write_bit(self, bit: bool) -> None:
self.current_output_byte = 0
self.bits_to_write_in_output_byte = 0
- def get_output(self) -> bytes:
- if 0 != self.bits_to_write_in_output_byte:
+ def get_output(self, *, allow_incomplete_output=False) -> bytes:
+ if not allow_incomplete_output and 0 != self.bits_to_write_in_output_byte:
raise IncompleteOutput("tries to get output when an unaligned number of bits was outputted "
"(doesn't divide 8)")
diff --git a/src/macro_usage_graph.py b/src/macro_usage_graph.py
index 8a6d579..6de331f 100644
--- a/src/macro_usage_graph.py
+++ b/src/macro_usage_graph.py
@@ -3,7 +3,7 @@
import plotly.graph_objects as go
-from defs import macro_separator_string
+from defs import MACRO_SEPARATOR_STRING
def _prepare_first_and_second_level_significant_macros(
@@ -13,14 +13,14 @@ def _prepare_first_and_second_level_significant_macros(
first_level = {}
second_level = collections.defaultdict(lambda: dict())
for k, v in macro_code_size.items():
- if macro_separator_string not in k:
+ if MACRO_SEPARATOR_STRING not in k:
if v < main_thresh:
continue
first_level[k] = v
else:
if v < secondary_thresh:
continue
- k_split = k.split(macro_separator_string)
+ k_split = k.split(MACRO_SEPARATOR_STRING)
if len(k_split) != 2:
continue
parent, name = k_split
diff --git a/src/ops.py b/src/ops.py
index 89b31c7..fbafee7 100644
--- a/src/ops.py
+++ b/src/ops.py
@@ -1,5 +1,7 @@
from __future__ import annotations
+import dataclasses
+import os
from dataclasses import dataclass
from typing import Union, Dict, Set, List, Tuple
@@ -22,6 +24,9 @@ def __str__(self) -> str:
def short_str(self) -> str:
return f"{self.file_short_name}:l{self.line}"
+ def __repr__(self) -> str:
+ return f"{os.path.basename(self.file)}:{self.line}"
+
class MacroName:
"""
@@ -45,6 +50,9 @@ def __hash__(self):
def __eq__(self, other):
return type(other) == MacroName and self.to_tuple() == other.to_tuple()
+ def __repr__(self):
+ return str(self)
+
# The macro that holds the ops that are outside any macro.
initial_macro_name = MacroName('')
@@ -212,6 +220,7 @@ class RepCall:
"""
def __init__(self, repeat_times: Expr, iterator_name: str, macro_name: str, arguments: List[Expr],
code_position: CodePosition):
+ self.current_index = 0
self.repeat_times = repeat_times
self.iterator_name = iterator_name
self.macro_name = MacroName(macro_name, len(arguments))
@@ -253,11 +262,11 @@ def calculate_arguments(self, iterator_value: int) -> Tuple[Expr, ...]:
except FJExprException as e:
raise FJExprException(f"Can't calculate rep arguments on {self.code_position}") from e
- def trace_str(self, iter_value: int) -> str:
+ def trace_str(self) -> str:
"""
@note assumes calculate_times successfully called before
"""
- return f'rep({self.iterator_name}={iter_value}, out of 0..{int(self.repeat_times)-1}) ' \
+ return f'rep({self.iterator_name}={self.current_index}, out of 0..{int(self.repeat_times)-1}) ' \
f'macro {self.macro_name} ({self.code_position})'
@@ -297,6 +306,21 @@ def get_declared_labels(ops: List[Op]) -> Set[str]:
Op = Union[FlipJump, WordFlip, Pad, Label, MacroCall, RepCall, Segment, Reserve]
+@dataclasses.dataclass
+class Macro:
+ """
+ The python representation of a .fj macro (macro declaration).
+ """
+ params: List[str]
+ local_params: List[str]
+ ops: List[Op]
+ namespace: str
+ code_position: CodePosition
+
+ def __repr__(self) -> str:
+ return f'{self.namespace}.MACRO({", ".join(self.params)}) ({repr(self.code_position)})'
+
+
WFLIP_NOT_INSERTED_YET = -1
diff --git a/src/preprocessor.py b/src/preprocessor.py
index 385022b..2d46a01 100644
--- a/src/preprocessor.py
+++ b/src/preprocessor.py
@@ -1,13 +1,13 @@
from __future__ import annotations
import collections
-from typing import Dict, Tuple, Iterable, Union, Deque
+from typing import Dict, Tuple, Iterable, Union, Deque, Set, List, Optional
from expr import Expr
-from defs import CodePosition, Macro, macro_separator_string
+from defs import MACRO_SEPARATOR_STRING, STARTING_LABEL_IN_MACROS_STRING
from exceptions import FJPreprocessorException, FJExprException
from ops import FlipJump, WordFlip, Label, Segment, Reserve, MacroCall, RepCall, \
- LastPhaseOp, MacroName, NewSegment, ReserveBits, Pad, Padding, \
+ CodePosition, Macro, LastPhaseOp, MacroName, NewSegment, ReserveBits, Pad, Padding, \
initial_macro_name, initial_args, initial_labels_prefix
from macro_usage_graph import show_macro_usage_pie_graph
@@ -48,7 +48,7 @@ def __init__(self, curr_tree: CurrTree,
def __enter__(self):
macro_name = self.calling_op.macro_name
if macro_name not in self.macros:
- macro_resolve_error(self.curr_tree, f"macro {macro_name} is used but isn't defined.")
+ macro_resolve_error(self.curr_tree, f"macro {macro_name} is used but isn't defined. In {self.calling_op.code_position}.")
self.curr_tree.append(self.calling_op)
def __exit__(self, exc_type, exc_val, exc_tb):
@@ -69,6 +69,8 @@ def __init__(self, w: int, macros: Dict[MacroName, Macro]):
self.result_ops: Deque[LastPhaseOp] = collections.deque()
self.labels: Dict[str, int] = {}
+ self.addresses_with_labels: Set[int] = set()
+ self.macro_start_labels: List[Tuple[int, str, CodePosition]] = [] # (address, label, code_position)
first_segment: NewSegment = NewSegment(0)
self.last_new_segment: NewSegment = first_segment
@@ -79,6 +81,7 @@ def patch_last_wflip_address(self) -> None:
def finish(self, show_statistics: bool) -> None:
self.patch_last_wflip_address()
+ self.insert_macro_start_labels_if_their_address_not_used()
if show_statistics:
show_macro_usage_pie_graph(dict(self.macro_code_size), self.curr_address)
@@ -104,13 +107,28 @@ def insert_reserve(self, reserved_bits_size: int) -> None:
self.curr_address += reserved_bits_size
self.result_ops.append(ReserveBits(self.curr_address))
- def insert_label(self, label: str, code_position: CodePosition) -> None:
+ def insert_label(self, label: str, code_position: CodePosition, *, address: Optional[int] = None) -> None:
+ if address is None:
+ address = self.curr_address
+
if label in self.labels:
other_position = self.labels_code_positions[label]
macro_resolve_error(self.curr_tree, f'label declared twice - "{label}" on '
f'{code_position} and {other_position}')
self.labels_code_positions[label] = code_position
- self.labels[label] = self.curr_address
+ self.labels[label] = address
+ self.addresses_with_labels.add(address)
+
+ def insert_macro_start_label(self, label: str, code_position: CodePosition) -> None:
+ """
+ @note must be called at the start of the function.
+ """
+ self.macro_start_labels.append((self.curr_address, label, code_position))
+
+ def insert_macro_start_labels_if_their_address_not_used(self):
+ for address, label, code_position in self.macro_start_labels[::-1]:
+ if address not in self.addresses_with_labels:
+ self.insert_label(label, code_position, address=address)
def register_macro_code_size(self, macro_path: str, init_curr_address: int) -> None:
if 1 <= len(self.curr_tree) <= 2:
@@ -127,14 +145,14 @@ def get_rep_times(op: RepCall, preprocessor_data: PreprocessorData) -> int:
try:
return op.calculate_times(preprocessor_data.labels)
except FJExprException as e:
- macro_resolve_error(preprocessor_data.curr_tree, f'rep {op.macro_name} failed.', orig_exception=e)
+ macro_resolve_error(preprocessor_data.curr_tree, f'rep {op.macro_name} failed. In {op.code_position}.', orig_exception=e)
def get_pad_ops_alignment(op: Pad, preprocessor_data: PreprocessorData) -> int:
try:
return op.calculate_ops_alignment(preprocessor_data.labels)
except FJExprException as e:
- macro_resolve_error(preprocessor_data.curr_tree, f'pad {op.ops_alignment} failed.', orig_exception=e)
+ macro_resolve_error(preprocessor_data.curr_tree, f'pad {op.ops_alignment} failed. In {op.code_position}.', orig_exception=e)
def get_next_segment_start(op: Segment, preprocessor_data: PreprocessorData) -> int:
@@ -145,7 +163,7 @@ def get_next_segment_start(op: Segment, preprocessor_data: PreprocessorData) ->
f'{hex(next_segment_start)}. In {op.code_position}.')
return next_segment_start
except FJExprException as e:
- macro_resolve_error(preprocessor_data.curr_tree, f'segment failed.', orig_exception=e)
+ macro_resolve_error(preprocessor_data.curr_tree, f'segment failed. In {op.code_position}.', orig_exception=e)
def get_reserved_bits_size(op: Reserve, preprocessor_data: PreprocessorData) -> int:
@@ -156,7 +174,7 @@ def get_reserved_bits_size(op: Reserve, preprocessor_data: PreprocessorData) ->
f'{hex(reserved_bits_size)}. In {op.code_position}.')
return reserved_bits_size
except FJExprException as e:
- macro_resolve_error(preprocessor_data.curr_tree, f'reserve failed.', orig_exception=e)
+ macro_resolve_error(preprocessor_data.curr_tree, f'reserve failed. In {op.code_position}.', orig_exception=e)
def get_params_dictionary(current_macro: Macro, args: Iterable[Expr], namespace: str, labels_prefix: str) \
@@ -172,7 +190,7 @@ def get_params_dictionary(current_macro: Macro, args: Iterable[Expr], namespace:
params_dict: Dict[str, Expr] = dict(zip(current_macro.params, args))
for local_param in current_macro.local_params:
- params_dict[local_param] = Expr(f'{labels_prefix}---{local_param}')
+ params_dict[local_param] = Expr(f'{labels_prefix}{MACRO_SEPARATOR_STRING}{local_param}')
if namespace:
for k, v in tuple(params_dict.items()):
@@ -195,6 +213,9 @@ def resolve_macro_aux(preprocessor_data: PreprocessorData,
current_macro = preprocessor_data.macros[macro_name]
params_dict = get_params_dictionary(current_macro, args, current_macro.namespace, labels_prefix)
+ preprocessor_data.insert_macro_start_label(
+ f'{labels_prefix}{MACRO_SEPARATOR_STRING}{STARTING_LABEL_IN_MACROS_STRING}', current_macro.code_position)
+
for op in current_macro.ops:
if isinstance(op, Label):
@@ -213,7 +234,7 @@ def resolve_macro_aux(preprocessor_data: PreprocessorData,
elif isinstance(op, MacroCall):
op = op.eval_new(params_dict)
- next_macro_path = (f"{labels_prefix}{macro_separator_string}" if labels_prefix else "") + \
+ next_macro_path = (f"{labels_prefix}{MACRO_SEPARATOR_STRING}" if labels_prefix else "") + \
f"{op.code_position.short_str()}:{op.macro_name}"
with preprocessor_data.prepare_macro_call(op):
resolve_macro_aux(preprocessor_data,
@@ -224,10 +245,11 @@ def resolve_macro_aux(preprocessor_data: PreprocessorData,
rep_times = get_rep_times(op, preprocessor_data)
if rep_times == 0:
continue
- next_macro_path = (f"{labels_prefix}{macro_separator_string}" if labels_prefix else "") + \
+ next_macro_path = (f"{labels_prefix}{MACRO_SEPARATOR_STRING}" if labels_prefix else "") + \
f"{op.code_position.short_str()}:rep{{}}:{op.macro_name}"
with preprocessor_data.prepare_macro_call(op):
for i in range(rep_times):
+ op.current_index = i
resolve_macro_aux(preprocessor_data,
op.macro_name, op.calculate_arguments(i), next_macro_path.format(i))
diff --git a/stl/README.md b/stl/README.md
index 4591ce1..1544d34 100644
--- a/stl/README.md
+++ b/stl/README.md
@@ -14,33 +14,51 @@ These FlipJump files result from a lot of research, runs, and tests.
### [runlib.fj](runlib.fj)
This file contains constants and initialization macros.
+Offers outputting constant chars/strings.
+
**@note**: It should be the first file in the compilation order.
-### [bitlib.fj](bitlib.fj)
+### [bit/](bit/)
Defines the `bit` data-structure (for binary variables).
-Offers macros for manipulating binary variables and vectors (i.e. numbers).
-
-You can find conditional jumps, memory manipulations, and logical and arithmetical macros.
+Offers macros for manipulating binary variables and vectors (i.e. numbers):
+
+- [memory.fj](bit/memory.fj) - bit/vec, zero, one, mov, swap
+- [cond_jumps.fj](bit/cond_jumps.fj) - if, cmp
+- [logics.fj](bit/logics.fj) - xor, or, and, not
+- [casting.fj](bit/casting.fj) - casting between bits and ascii
+- [input.fj](bit/input.fj) - input into bit variables
+- [output.fj](bit/output.fj) - output bits, bytes; print as hex/decimal
+- [shifts.fj](bit/shifts.fj) - bit-shift left/right, bit-rotate left/right
+- [math.fj](bit/math.fj) - inc, dec, add, sub
+- [pointers.fj](bit/pointers.fj) - bit-vec pointers: flip, jump, xor_to, xor_from, inc/dec; pointers init
+
+### [hex/](hex/)
+Defines the `hex` data-structure (for hexadecimal variables).
+
+**They are smaller and faster than 4 `bit`s.**
+
+Offers macros for manipulating hexadecimal variables and vectors (i.e. numbers):
+
+- [memory.fj](hex/memory.fj) - hex/vec, zero, xor_by, set, mov, swap
+- [cond_jumps.fj](hex/cond_jumps.fj) - if, cmp
+- [logics.fj](hex/logics.fj) - xor, or, and, not
+- [input.fj](hex/input.fj) - input bits into hex, input ascii as hex
+- [output.fj](hex/output.fj) - output hex as bits/bytes; print as hex-number (in ascii)
+- [shifts.fj](hex/shifts.fj) - shift left/right by 1 bit/hex
+- [math_basic.fj](hex/math_basic.fj) - inc/dec, neg, count_bits, sign_extend
+- [math.fj](hex/math.fj) - add/sub, {add/sub}_shifted, {add/sub}_constant
+- [pointers.fj](hex/pointers.fj) - hex-vec pointers: flip, jump, xor_to, xor_from; stack/pointers init
+- [advanced_pointers.fj](hex/advanced_pointers.fj) - hex-vec pointers: ptr/sp - inc/dec/add/sub, all push/pop
+- [tables_init.fj](hex/tables_init.fj) - initializes the "results-tables" for the next hex macros: or,and, add,sub, cmp, mul
### [mathlib.fj](mathlib.fj)
Offers multiplication and division macros for bit/hex variables.
**@note**: The hex.div fails test as for now. You can use the bit version and castings.
-### [hexlib.fj](hexlib.fj)
-Defines the `hex` data-structure (for hexadecimal variables), which is smaller and faster than `bit`.
-
-Offers macros for manipulating hexadecimal variables and vectors (i.e. numbers).
-
-You can find conditional jumps, memory manipulations, and logical and arithmetical macros.
-
-### [iolib.fj](iolib.fj)
-Offers outputting chars, strings. Also outputting bit and hex variables as binary, hexadecimal, ascii, or decimal.
-
-Offers input macros for the bit and hex variables, as numbers or as ascii.
-
-Offers casting between different variable types.
+### [casting.fj](casting.fj)
+Offers casting between bits and hexes.
### [ptrlib.fj](ptrlib.fj)
Offers the concept of pointers, i.e. reading, jumping to, and flipping bits, directly from a pointer (i.e. a bit-variable that holds an address).
@@ -51,6 +69,54 @@ Also offers a stack and functions based on these pointers.
A configurable json file that maintains ordered lists of the standard library files.
+# Documentation
+Every macro is documented with:
+- Its **time complexity** (and if it's significantly different, the **space complexity** as well).
+ - The complexities use the **@** sign, which is the log2 of the total number of fj ops in this program (can be it usually will be between 15-25).
+ - The reason for this _weird_ log complexity, is that `wflip address, value` has the complexity of the number of on-bits in _address_; And it is widely used.
+- An explanation about what the macro does (usually in a python-like syntax).
+- The type of each of the parameters (bit/hex/bit.vec/hex.vec/constant/address and so on).
+ - if a parameter is called bit/hex, it is a bit/hex variable (of size 1).
+ - if a parameter (in a macro declared under the bit/hex namespaces) is used in the documentation as an array (x[:n], ascii[:8], etc.) - it is a bit/hex vector of the specified size; and that size is a size-constant.
+- Optionally, what the macro assumes about the parameters, and what can you assume about the result.
+
+# Thing You Need To Know
+
+## Reserved Names
+The standard library reserves all the labels under the "stl", "bit", and "hex" namespaces.
+
+No other labels are reserved or used by the standard library.
+
+
+## Startup Macros
+FlipJump programs start running at address 0. The IO opcode is placed at address 2w, and a normal program just skips above it and then starts.
+
+To keep things simple, we wrote the ```stl.startup``` macro. It should be the first used macro/op in your program. If you are using multiple files, then **it should only be declared once**, at the start of the first file.
+
+Basically, The first line in a FlipJump program should be ```stl.startup```.
+
+Instead, you can also use the ```stl.startup_and_init_all``` macro, which does the startup, and also every ```init``` macro that's exist in the standard library.
+
+## Padding
+We decided to make the padding a part of the FlipJump assembly.
+
+```pad n``` - A special assembly-op that fills the current address with arbitrary fj ops, until the address is divisible by (n*dw).
+
+We made it a part of the FlipJump assembly, in spite of the fact that padding CAN be defined with the other primitives of the FlipJump assembly:
+```c
+// @note - padding can also be implemented in fj itself! (but the saved-word pad is more compile-time efficient)
+// pad zeros up to the address
+def pad address @ pad_start {
+ pad_start:
+ rep((0-pad_start/(2*w))%address, i) fj 0, 0
+}
+```
+By making the padding a part of the assembly, we can (and do) **utilize the free space** we just gained.
+
+The free space, gained by the padding, is also **being used for storing fj-ops that will be created by future ```wflip```s**.
+
+That way, **using the ```pad n```** macros won't only **not waste up space**, but might even **save space**; That's because ```wflip```s to a padded address are smaller (less 1's in that address binary representation -> less fj-ops will be created for ```wflip```ing there).
+
# Contribute
The FlipJump philosophy is to be the simplest language of all, that can do any modern computation.
@@ -60,11 +126,11 @@ FlipJump should be below the OS, as it's a cpu-architecture after all.
The FlipJump stl should be minimalistic, efficient in both space and time, and offer macros similar to x86 ops.
The generic stl macro should look like `macro_name n dst src` for an n-bit/hex variable, with dst being the destination-variable, and src being the source-variable.
-- e.g. the [hexlib.fj](hexlib.fj) / `hex.add n, dst, src`.
+- e.g. the [hex/math.fj](hex/math.fj) / `hex.add n, dst, src`.
# Read More
You can explore the full list of all macros from the [esolang page](https://esolangs.org/wiki/FlipJump#The_Standard_Library).
-If you are new to the FlipJump standard-library, Start by reading the [bitlib.fj](stl/bitlib.fj) standard library file (start with `xor`, `if`). That's where the FlipJump magic begins.
+If you are new to the FlipJump standard-library, Start by reading the [bit/logics.fj](bit/logics.fj) standard library file (start with `xor`, `if`). That's where the FlipJump magic begins.
diff --git a/stl/bit/casting.fj b/stl/bit/casting.fj
new file mode 100644
index 0000000..1581a30
--- /dev/null
+++ b/stl/bit/casting.fj
@@ -0,0 +1,168 @@
+// ---------- String:
+
+
+ns bit {
+ // create a bit-vector, initialized with the value of 'str', and with the number of bytes needed to store 'str', plus 1.
+ // used to initialize a string, like: bit.str "Hello, World!\n"
+ def str str {
+ .vec (((#str)+15)>>3)<<3, str
+ }
+}
+
+
+
+// ---------- Casting to ascii:
+
+
+ns bit {
+ // Complexity 9@-7
+ // ascii := the ascii representation of the value of bin.
+ // ascii is bit[:8], bin is a bit.
+ def bin2ascii ascii, bin {
+ .zero 8, ascii
+ .not 2, ascii + 4*dw // ascii = 0x30
+ .xor ascii, bin
+ }
+
+
+ // Complexity 12@-10
+ // ascii := the ascii representation of the value of dec.
+ // ascii is bit[:8], dec is bit[:4].
+ def dec2ascii ascii, dec {
+ .zero 8, ascii
+ .not 2, ascii + 4*dw // ascii = 0x30
+ .xor 4, ascii, dec
+ }
+
+
+ // Complexity: 16@+19
+ // Space: 21@+30
+ // ascii := the ascii representation of the value of hex (digits & capital-letters).
+ // ascii is bit[:8], hex is bit[:4].
+ def hex2ascii ascii, hex @ dec_label, hex_label, nine4, end {
+ .zero 8, ascii
+ .xor 3, ascii, hex
+ .cmp 4, hex, nine4, dec_label, dec_label, hex_label
+ dec_label:
+ .xor ascii+3*dw, hex+3*dw
+ .not 2, ascii + 4*dw // ascii = 0x30
+ ;end
+ hex_label:
+ .dec 3, ascii // A-F is now 1-6
+ .not ascii + 6*dw // ascii = 0x40
+ ;end
+ nine4:
+ .vec 4, 9
+ end:
+ }
+}
+
+
+
+// ---------- Casting from ascii:
+
+
+ns bit {
+ // Complexity: 17@+24
+ // if ascii is '0'/'1', set bit to 0/1 (end error=0). else, set error=1.
+ // ascii is bit[:8], and error(output-param),bin are bits.
+ def ascii2bin error, bin, ascii @ half_bin, return_error, copy_binary_value, end {
+ .zero error
+ .zero bin
+
+ .cmp 7, ascii+dw, half_bin, return_error, copy_binary_value, return_error
+
+ return_error:
+ .not error
+ ;end
+
+ copy_binary_value:
+ .xor bin, ascii
+ ;end
+
+ half_bin:
+ .vec 7, 0x30>>1
+
+ end:
+ }
+
+
+ // Complexity: 25@+56
+ // if ascii is '0'-'9', set dec to that decimal digit value (end error=0). else, set error=1.
+ // ascii is bit[:8], dec in bit[:4], and error(output-param) is a bit.
+ def ascii2dec error, dec, ascii @ half_dec, return_error, check_decimal, copy_decimal_value, nine4, end {
+ .zero error
+ .zero 4, dec
+
+ .cmp 4, ascii+4*dw, half_dec, return_error, check_decimal, return_error
+ check_decimal:
+ .cmp 4, ascii, nine4, copy_decimal_value, copy_decimal_value, return_error
+
+ return_error:
+ .not error
+ ;end
+
+ copy_decimal_value:
+ .xor 4, dec, ascii
+ ;end
+
+ half_dec:
+ .vec 4, 0x30>>4
+ nine4:
+ .vec 4, 9
+ end:
+ }
+
+
+ // Complexity: 54@+92
+ // if ascii is '0'-'9'/'a'-'f'/'A'-'F', set hex to that hexadecimal digit value (end error=0). else, set error=1.
+ // ascii is bit[:8], hex in bit[:4], and error(output-param) is a bit.
+ def ascii2hex error, hex, ascii \
+ @ decimal_ascii_msh, uppercase_hexadecimal_ascii_msh, lowercase_hexadecimal_ascii_msh, return_error, \
+ check_uppercase_hex, check_lowercase_hex, dec_first_check, hex_first_check, hex_second_check, \
+ copy_decimal_value, copy_hexadecimal_value, nine4, seven3, two3, end {
+ .zero error
+ .zero 4, hex
+
+ .cmp 4, ascii+4*dw, decimal_ascii_msh, check_uppercase_hex, dec_first_check, check_uppercase_hex
+
+ check_uppercase_hex:
+ .cmp 5, ascii+3*dw, uppercase_hexadecimal_ascii_msh, check_lowercase_hex, hex_first_check, check_lowercase_hex
+ check_lowercase_hex:
+ .cmp 5, ascii+3*dw, lowercase_hexadecimal_ascii_msh, return_error, hex_first_check, return_error
+
+ dec_first_check:
+ .cmp 4, ascii, nine4, copy_decimal_value, copy_decimal_value, return_error
+ copy_decimal_value:
+ .xor 4, hex, ascii
+ ;end
+
+ hex_first_check:
+ .inc 3, ascii
+ .cmp 3, ascii, two3, return_error, hex_second_check, hex_second_check
+ hex_second_check:
+ .cmp 3, ascii, seven3, copy_hexadecimal_value, copy_hexadecimal_value, return_error
+ copy_hexadecimal_value:
+ .xor 3, hex, ascii
+ .not hex+3*dw
+ ;end
+
+ return_error:
+ .not error
+ ;end
+
+ decimal_ascii_msh:
+ .vec 4, 0x30>>4
+ uppercase_hexadecimal_ascii_msh:
+ .vec 5, 0x40>>3
+ lowercase_hexadecimal_ascii_msh:
+ .vec 5, 0x60>>3
+ nine4:
+ .vec 4, 9
+ seven3:
+ .vec 3, 7
+ two3:
+ .vec 3, 2
+ end:
+ }
+}
diff --git a/stl/bit/cond_jumps.fj b/stl/bit/cond_jumps.fj
new file mode 100644
index 0000000..70f55bd
--- /dev/null
+++ b/stl/bit/cond_jumps.fj
@@ -0,0 +1,97 @@
+// ---------- Conditional Jumps
+
+
+ns bit {
+ // Complexity: @+2
+ // if x == 0 jump to l0, else jump to l1
+ // x is a bit, l0,l1 are addresses.
+ def if x, l0, l1 @ label_ptr, base_jump_label {
+ .xor label_ptr, x
+ label_ptr:
+ ;base_jump_label
+ pad 2
+ base_jump_label:
+ ;l0
+ label_ptr + dbit;l1
+ }
+
+ // Complexity: n(@+2)
+ // if x[:n] == 0 jump to l0, else jump to l1
+ // x is bit[:n], l0,l1 are addresses.
+ def if n, x, l0, l1 {
+ rep(n-1, i) .if1 x+i*dw, l1
+ .if x+(n-1)*dw, l0, l1
+ }
+
+ // Complexity: @+2
+ // if x == 1 jump to l1
+ // x is a bit, l1 is an address.
+ def if1 x, l1 @ end {
+ .if x, end, l1
+ end:
+ }
+
+ // Complexity: n(@+2)
+ // if the x[:n] != 0 jump to l1
+ // x is bit[:n], l1 is an address.
+ def if1 n, x, l1 @ end {
+ .if n, x, end, l1
+ end:
+ }
+
+ // Complexity: @+2
+ // if x == 0 jump to l0
+ // x is a bit, l0 is an address.
+ def if0 x, l0 @ end {
+ .if x, l0, end
+ end:
+ }
+
+ // Complexity: n(@+2)
+ // if x[:n] == 0 jump to l0
+ // x is bit[:n], l0 is an address.
+ def if0 n, x, l0 @ end {
+ .if n, x, l0, end
+ end:
+ }
+
+
+ // Complexity: 2@+4
+ // Space: 3@+6
+ // jump to:
+ // a < b: lt
+ // a = b: eq
+ // a > b: gt
+ // a,b are bits, lt,eq,gt are addresses.
+ def cmp a, b, lt, eq, gt @ a_is1_label {
+ .if1 a, a_is1_label
+ .if b, eq, lt
+ a_is1_label:
+ .if b, gt, eq
+ }
+
+ // Complexity: n(2@+4)
+ // Space: n(3@+6)
+ // jump to:
+ // a[:n] < b[:n]: lt
+ // a[:n] = b[:n]: eq
+ // a[:n] > b[:n]: gt
+ // a,b are bit[:n], lt,eq,gt are addresses.
+ def cmp n, a, b, lt, eq, gt {
+ rep(n-1, i) ._.cmp_next_eq a+(n-1-i)*dw, b+(n-1-i)*dw, lt, gt
+ .cmp a, b, lt, eq, gt
+ }
+ ns _ {
+ // Complexity: 2@+4
+ // Space: 3@+6
+ // jump to:
+ // a < b: lt
+ // a = b: continue
+ // a > b: gt
+ // a,b are bits, lt,gt are addresses.
+ def cmp_next_eq a, b, lt, gt @ eq {
+ ..cmp a, b, lt, eq, gt
+ eq:
+ }
+ }
+}
diff --git a/stl/bit/input.fj b/stl/bit/input.fj
new file mode 100644
index 0000000..ed5b379
--- /dev/null
+++ b/stl/bit/input.fj
@@ -0,0 +1,29 @@
+// ---------- Input:
+
+
+
+ns bit {
+ // Complexity: 2@-2
+ // input one bit into the bit-variable, 'dst'.
+ // dst is an output parameter.
+ def input_bit dst < stl.IO {
+ .zero dst
+ .xor dst, stl.IO
+ }
+
+
+ // Complexity: 16@-16
+ // input one byte into dst[:8] (lsb first)
+ // dst is an output parameter.
+ def input dst {
+ rep(8, i) .input_bit dst+i*dw
+ }
+
+
+ // Complexity: n(16@-16)
+ // input n bytes into dst[:8n] (lsb first)
+ // dst is an output parameter.
+ def input n, dst {
+ rep(n, i) .input dst+8*(n-1-i)*dw
+ }
+}
diff --git a/stl/bit/logics.fj b/stl/bit/logics.fj
new file mode 100644
index 0000000..975190d
--- /dev/null
+++ b/stl/bit/logics.fj
@@ -0,0 +1,128 @@
+// ---------- Logical Macros
+
+
+ns bit {
+ // Complexity: @-1
+ // dst ^= src
+ // dst,src are bits.
+ def xor dst, src {
+ .exact_xor dst + dbit, src
+ }
+
+ // Complexity: n(@-1)
+ // dst[:n] ^= src[:n]
+ // dst,src are bit[:n].
+ def xor n, dst, src {
+ rep(n, i) .xor dst+dw*i, src+dw*i
+ }
+
+ // Complexity: @-1
+ // note: pad 2 is needed, but pad 8 is used for wflips-padding optimization and for smaller wflips.
+ // dst(bit_address) ^= src
+ // dst,src are bits.
+ def exact_xor dst, src @ base_jump_label, cleanup {
+ wflip src+w, base_jump_label, src
+ pad 8
+ base_jump_label:
+ ;cleanup
+ dst;
+ cleanup:
+ wflip src+w, base_jump_label
+ }
+
+ // Complexity: @
+ // note: pad 2 is needed, but pad 8 is used for wflips-padding optimization and for smaller wflips.
+ // dst1(bit_address) ^= src
+ // dst2(bit_address) ^= src
+ // dst1,dst2,src are bits.
+ def double_exact_xor dst1, dst2, src @ base_jump_label, cleanup {
+ wflip src+w, base_jump_label, src
+ pad 8
+ base_jump_label:
+ ;cleanup
+ dst1;
+ dst2;
+ cleanup:
+ wflip src+w, base_jump_label
+ }
+
+ // Complexity: n@
+ // address(bit_address) ^= src
+ // var ^= src
+ // var,src are bit[:n], address is an address.
+ def address_and_variable_xor n, address, var, src {
+ rep(n, i) .double_exact_xor address+i, var+dbit+i*dw, src+i*dw
+ }
+
+ // Complexity: @
+ // dst ^= src
+ // src = 0
+ // dst,src are bits.
+ def xor_zero dst, src {
+ .double_exact_xor dst+dbit, src+dbit, src
+ }
+
+ // Complexity: n@
+ // dst[:n] ^= src[:n]
+ // src[:n] = 0
+ // dst,src are bit[:n].
+ def xor_zero n, dst, src {
+ rep(n, i) .xor_zero dst+dw*i, src+dw*i
+ }
+
+
+ // Complexity: 2@+2
+ // dst |= src
+ // dst,src are bits.
+ def or dst, src @ end {
+ .if0 src, end
+ .one dst
+ end:
+ }
+
+ // Complexity: n(2@+2)
+ // dst[:n] |= src[:n]
+ // dst,src are bit[:n].
+ def or n, dst, src {
+ rep(n, i) .or dst+dw*i, src+dw*i
+ }
+
+
+ // Complexity: 2@+2
+ // dst &= src
+ // dst,src are bits.
+ def and dst, src @ end {
+ .if1 src, end
+ .zero dst
+ end:
+ }
+
+ // Complexity: n(2@+2)
+ // dst[:n] &= src[:n]
+ // dst,src are bit[:n].
+ def and n, dst, src {
+ rep(n, i) .and dst+dw*i, src+dw*i
+ }
+
+
+ // Complexity: 1
+ // dst ^= 1
+ // dst is a bit.
+ def not dst {
+ dst + dbit;
+ }
+
+ // Complexity: n
+ // dst[:n] ^= (1<>i)&1
+ }
+ def vec n {
+ rep(n, i) .bit
+ }
+}
+
+
+// ---------- Memory Manipulation
+
+
+ns bit {
+ // Complexity: @-1
+ // bit = 0
+ def zero bit {
+ .xor bit, bit
+ }
+
+ // Complexity: n(@-1)
+ // x[:n] = 0
+ def zero n, x {
+ rep(n, i) .zero x+i*dw
+ }
+
+
+ // Complexity: @
+ // bit = 1
+ def one bit {
+ .zero bit
+ .not bit
+ }
+
+ // Complexity: n@
+ // x[:n] = (1<>(i+1)) & 1
+ }
+
+ // Complexity: @+9
+ // prints x[:n] as n ascii-characters ('0's and '1's, lsb first).
+ // x is a bit[:n], and n is a size constant.
+ def print_as_digit n, x {
+ rep(n, i) .print_as_digit x+(n-1-i)*dw
+ }
+}
+
+
+
+// ---------- Print Hex Int
+
+
+ns bit {
+ // Complexity: n(7@+11)
+ // print x[:n] as an unsigned hexadecimal number, without leading zeros (digits & capital-letters).
+ //
+ // x_prefix (constant): print with the "0x" prefix.
+ //
+ // @Assumes n can be divided by 4.
+ def print_hex_uint n, x, x_prefix @ after_print_x, printed_flag, end {
+ stl.comp_if0 x_prefix, after_print_x
+ stl.output '0'
+ stl.output 'x'
+ after_print_x:
+
+ .zero printed_flag
+ rep(n/4, i) .print_hex_uint.print_digit x+(n/4-1-i)*4*dw, printed_flag
+
+ .if1 printed_flag, end
+ stl.output '0'
+ ;end
+
+ printed_flag:
+ .bit
+ end:
+ }
+ //Comp: 29@+44
+ ns print_hex_uint {
+ def print_digit hex, printed_flag @ continue, ascii, end {
+ ..if1 4, hex, continue
+ ..if1 printed_flag, continue
+ ;end
+
+ continue:
+ ..one printed_flag
+ ..hex2ascii ascii, hex
+ ..print ascii
+ ;end
+
+ ascii:
+ ..vec 8
+ end:
+ }
+ }
+
+
+ // Complexity: n(9@+18)
+ // print x[:n] as a signed hexadecimal number, without leading zeros (digits & capital-letters).
+ //
+ // x_prefix (constant): print with the "0x" prefix.
+ //
+ // @Assumes n can be divided by 4.
+ def print_hex_int n, x, x_prefix @ do_print {
+ .if0 x+(n-1)*dw, do_print
+ stl.output '-'
+ .neg n, x
+ do_print:
+ .print_hex_uint n, x, x_prefix
+ }
+}
+
+
+
+// ---------- Print Dec Int
+
+
+ns bit {
+ // Time Complexity: n^2(2@+4)
+ // Space Complexity: n(14@+16)
+ // prints x[:n] as an unsigned decimal number (without leading zeros).
+ //
+ // The number 28/93 is the ratio of the number of decimal digits and the number of binary digits.
+ // It's bigger than log(2)/log(10) by 0.015%, which is just enough.
+ def print_dec_uint n, x @ start_printing, xor, end_xor, dst, src, print_buffer, print_buffer_flag, \
+ div10, zero_flag, ret_reg, end {
+ .mov n, src, x
+ .zero zero_flag
+
+ // the next three takes ~ (28/93n)*(n(7@+12)) = n^2(2.11@+3.61) ~= n^2(2@+4) time
+ // the next three takes ~ (28/93n)*(@-1 + 11@-3 + 5@+12) = n(5.12@+2.41) ~= n(5@+2.5) space
+
+ .zero n*28/93+1, print_buffer_flag // all chars are off
+ // fill the print buffer with the decimal digits of src
+ rep(n*28/93+1, i) .print_dec_uint.div10_step div10, xor, ret_reg, src, \
+ print_buffer+i*4*dw, print_buffer_flag+i*dw, zero_flag, start_printing
+ start_printing:
+ rep(n*28/93+1, i) .print_dec_uint.print_char \
+ print_buffer+(n*28/93-i)*4*dw, \
+ print_buffer_flag+(n*28/93-i)*dw
+
+ ;end
+
+ div10:
+ .div10 n, dst, src
+ stl.fret ret_reg
+ xor:
+ .xor n, src, dst // can double_exact_xor and zero dst too - so to save the "zero n dst" inside the next div10
+ .if1 n, dst, end_xor
+ .not zero_flag
+ end_xor:
+ stl.fret ret_reg
+
+ // takes n(2+28/93*5) = 3.5n space
+ dst: .vec n
+ src: .vec n
+ print_buffer: .vec (n*28/93+1)*4
+ print_buffer_flag: .vec n*28/93+1
+ zero_flag: .bit
+ ret_reg: 0;0
+ end:
+ }
+ ns print_dec_uint {
+ // Time Complexity: n(7@+12)
+ // Space Complexity: 11@-3
+ // if zero_flag: // if src is already 0:
+ // break the divide repetitions, and go straight to the printing.
+ // set the char_flag (so that this digit will be printed)
+ // ascii_res[:4] = src[:n] % 10 // (n from print_dec_uint)
+ // src[:n] /= 10
+ //
+ //
+ // @Uses the label-functions div10 and xor (print_dec_uint implements them), and the return-register ret_reg.
+ // src and ascii_res are both bit[:4], and char_flag, zero_flag and start_printing are flags.
+ def div10_step div10, xor, ret_reg, src, ascii_res, char_flag, zero_flag, start_printing {
+ ..if1 zero_flag, start_printing
+ stl.fcall div10, ret_reg
+ ..zero 4, ascii_res
+ rep(4, i) ..double_exact_xor ascii_res+dbit+i*dw, src+dbit+i*dw, src+i*dw
+ ..not char_flag
+ stl.fcall xor, ret_reg
+ }
+
+ // Complexity: 5@+12
+ // if char_flag: print the ascii representation of the decimal digit ascii4[:4].
+ // ascii4 is bit[:4], char_flag is a bit.
+ def print_char ascii4, char_flag @ end {
+ ..if0 char_flag, end
+ rep(4, i) ..output ascii4+i*dw
+ rep(4, i) stl.output_bit (0x3>>i)&1
+ end:
+ }
+ }
+
+
+ // Time Complexity: n^2(2@+4)
+ // Space Complexity: n(16@+23)
+ // prints x[:n] as a signed decimal number (without leading zeros).
+ //
+ // The number 28/93 is the ratio of the number of decimal digits and the number of binary digits.
+ // It's bigger than log(2)/log(10) by 0.015%, which is just enough.
+ def print_dec_int n, x @ do_print {
+ .if0 x+(n-1)*dw, do_print
+ stl.output '-'
+ .neg n, x
+ do_print:
+ .print_dec_uint n, x
+ }
+}
diff --git a/stl/bit/pointers.fj b/stl/bit/pointers.fj
new file mode 100644
index 0000000..2c8f82e
--- /dev/null
+++ b/stl/bit/pointers.fj
@@ -0,0 +1,181 @@
+// ---------- Jump:
+
+
+ns bit {
+ ns pointers {
+ // Space Complexity: 2w+2
+ // Inits the global opcodes and pointer-copies required for the pointers macros.
+ //
+ // @output-param to_flip: address of opcode that holds a flipping address in its first word. jumping into it will flip wanted bit.
+ // @output-param to_flip_var: the bit-vector (pointer) that also holds the flipping address.
+ // @output-param to_jump: address of opcode that holds a jumping address in its second word. jumping into it will jump to the wanted address.
+ // @output-param to_jump_var: the bit-vector (pointer) that also holds the jumping address.
+ def ptr_init > to_flip, to_jump, to_flip_var, to_jump_var {
+ to_flip:
+ 0;0
+ to_jump:
+ ;0
+
+ to_flip_var:
+ bit.vec w, 0
+ to_jump_var:
+ bit.vec w, 0
+ }
+
+ // Complexity: 2n@
+ // Sets both to_jump and to_jump_var to point to the given pointer.
+ // ( to_jump{_var} = ptr )
+ // ptr is a bit[:w] that holds an address.
+ def set_jump_pointer ptr < .to_jump, .to_jump_var {
+ ..address_and_variable_xor w, .to_jump+w, .to_jump_var, .to_jump_var
+ ..address_and_variable_xor w, .to_jump+w, .to_jump_var, ptr
+ }
+
+
+ // Complexity: 2n@
+ // Sets both to_flip and to_flip_var to point to the given pointer.
+ // ( to_flip{_var} = ptr )
+ // ptr is a bit[:w] that holds an address.
+ def set_flip_pointer ptr < .to_flip, .to_flip_var {
+ ..address_and_variable_xor w, .to_flip, .to_flip_var, .to_flip_var
+ ..address_and_variable_xor w, .to_flip, .to_flip_var, ptr
+ }
+ }
+}
+
+
+ns bit {
+ // Complexity: 2w@ + 2
+ // like: ;*ptr
+ // Jump to the address the pointer points to.
+ // ptr is a bit[:w] that holds an address.
+ def ptr_jump ptr < bit.pointers.to_jump {
+ .pointers.set_jump_pointer ptr
+ ;bit.pointers.to_jump
+ }
+}
+
+
+
+// ---------- Flip:
+
+
+ns bit {
+ // Complexity: 2w@ + @
+ // like: *ptr;
+ // Flip the address the pointer points to.
+ // ptr is a bit[:w] that holds an address.
+ def ptr_flip ptr @ cleanup < bit.pointers.to_flip {
+ wflip bit.pointers.to_flip+w, cleanup
+
+ .pointers.set_flip_pointer ptr
+ ;bit.pointers.to_flip
+
+ pad 4
+ cleanup:
+ wflip bit.pointers.to_flip+w, cleanup
+ }
+
+
+ // Complexity 2w@ + 2@
+ // The stl.comp_flip_if executes in ~##w, which should be much less than @/2 operations.
+ // like: (*ptr)+dbit;
+ // Flip the address dbit-ahead of what the pointer points to.
+ // ptr is a bit[:w] that holds an address, which we assume is dw-aligned.
+ def ptr_flip_dbit ptr {
+ rep(#dbit, i) stl.comp_flip_if ptr+dbit+i*dw, (dbit>>i)&1
+ .ptr_flip ptr
+ rep(#dbit, i) stl.comp_flip_if ptr+dbit+i*dw, (dbit>>i)&1
+ }
+
+ // Complexity 2w@ + 2@+2
+ // like: bit.xor *ptr, bit
+ // ptr is a bit[:w] that holds an address, which we assume is dw-aligned.
+ def xor_to_ptr ptr, bit @ end {
+ .if0 bit, end
+ .ptr_flip_dbit ptr
+ end:
+ }
+
+
+ // Complexity 3w@ (actually a bit smaller, 2w@+3w + (@-2)^2)
+ // like: wflip *ptr, value
+ // ptr is a bit[:w] that holds an address, which we assume is w-aligned.
+ def ptr_wflip ptr, value {
+ .pointers.set_flip_pointer ptr
+ rep(w, i) .pointers.advance_by_one_and_flip__ptr_wflip (#(i^((i+1)%w))), (value>>i)&1
+ }
+ ns pointers {
+ // Advances *to_flip by 1 (which takes n flips, from bit0 to bit1, bit2,...).
+ // If do_flip (value) isn't 0 - than make a flip, like: to_flip;advance.
+ def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < bit.pointers.to_flip {
+ stl.comp_if0 do_flip, advance
+ wflip bit.pointers.to_flip+w, cleanup, bit.pointers.to_flip
+ cleanup:
+ wflip bit.pointers.to_flip+w, cleanup, advance
+
+ pad 4
+ advance:
+ rep(n, i) bit.exact_not bit.pointers.to_flip+i
+ }
+ }
+
+ // Complexity 3w@ (actually a bit smaller, 2w@+3w+2 + (@-2)^2)
+ // like: wflip (*ptr)+w, value
+ // ptr is a bit[:w] that holds an address, which we assume is dw-aligned.
+ def ptr_wflip_2nd_word ptr, value {
+ .not ptr + dw*((#w)-1)
+ .ptr_wflip ptr, value
+ .not ptr + dw*((#w)-1)
+ }
+}
+
+
+
+// ---------- Xor
+
+
+ns bit {
+ // Complexity 7w@ (actually a bit smaller, 6w@+6w+8 + 2(@-2)^2)
+ // like: bit.xor dst, *ptr
+ // dst is a bit. ptr is a bit[:w] that holds an address, which we assume is dw-aligned.
+ def xor_from_ptr dst, ptr {
+ .exact_xor_from_ptr dst+dbit, ptr
+ }
+
+ // Complexity 7w@ (actually a bit smaller, 6w@+6w+8 + 2(@-2)^2)
+ // like: bit.exact_xor dst, *ptr
+ // dst is a bit-address. ptr is a bit[:w] that holds an address, which we assume is dw-aligned.
+ def exact_xor_from_ptr dst, ptr @ base_jump_label, cleanup {
+ .ptr_wflip_2nd_word ptr, base_jump_label
+
+ .ptr_jump ptr
+ pad 2
+ base_jump_label:
+ ;cleanup
+ dst;
+
+ cleanup:
+ .ptr_wflip_2nd_word ptr, base_jump_label
+
+ }
+}
+
+
+
+// ---------- Stack
+
+
+ns bit {
+ // Complexity: w(2@+6) // actually (w-#w)(2@+6)
+ // ptr[:n] += 2w
+ def ptr_inc ptr {
+ .inc w-#w, ptr+(#w)*dw
+ }
+
+ // Complexity: w(2@+8) // actually (w-#w)(2@+8)
+ // ptr[:n] -= 2w
+ def ptr_dec ptr {
+ .dec w-#w, ptr+(#w)*dw
+ }
+}
diff --git a/stl/bit/shifts.fj b/stl/bit/shifts.fj
new file mode 100644
index 0000000..5bd3c63
--- /dev/null
+++ b/stl/bit/shifts.fj
@@ -0,0 +1,57 @@
+// ---------- Logical Shifts
+
+
+ns bit {
+ // Complexity: n(2@-1)
+ // x[:n] >>= 1
+ def shr n, x {
+ .shr n, 1, x
+ }
+
+ // Complexity: n(2@-1)
+ // x[:n] >>= times
+ // times is a constant.
+ def shr n, times, x {
+ rep(n-times, i) .mov x+i*dw, x+(i+times)*dw
+ .zero times, x+(n-times)*dw
+ }
+
+
+ // Complexity: n(2@-1)
+ // x[:n] <<= 1
+ def shl n, x {
+ .shl n, 1, x
+ }
+
+ // Complexity: n(2@-1)
+ // x[:n] <<= times
+ // times is a constant.
+ def shl n, times, x {
+ rep(n-times, i) .mov x+(n-1-i)*dw, x+(n-1-i-times)*dw
+ .zero times, x
+ }
+
+
+ // Complexity: n(2@-1)
+ // rotate x[:n] right by 1-bit
+ def ror n, x @ temp_bit {
+ .mov temp_bit, x
+ rep(n-1, i) .mov x+i*dw, x+(i+1)*dw
+ .mov x+(n-1)*dw, temp_bit
+ stl.skip
+ temp_bit:
+ .bit
+ }
+
+
+ // Complexity: n(2@-1)
+ // rotate x[:n] left by 1-bit
+ def rol n, x @ temp_bit {
+ .mov temp_bit, x+(n-1)*dw
+ rep(n-1, i) .mov x+(n-1-i)*dw, x+(n-1-i-1)*dw
+ .mov x, temp_bit
+ stl.skip
+ temp_bit:
+ .bit
+ }
+}
diff --git a/stl/bitlib.fj b/stl/bitlib.fj
deleted file mode 100644
index 5da5796..0000000
--- a/stl/bitlib.fj
+++ /dev/null
@@ -1,402 +0,0 @@
-// Every line is (a bit) bananas!
-// Implementation of binary-variables operations, and vectors of it
-
-// should be assembled with the runlib.fj file
-// This file is independent of the bit-width, and uses the consts defined at runlib.fj
-
-// Everything after // is ignored, and every whitespace is ignored (besides new line)
-// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next)
-
-// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op.
-// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity
-
-// The complexities are not updated in this file (should be lower/faster).
-
-
-
-// ---------- Memory Variables:
-// Size Complexity: 1
-
-
-def bit value {
- ; value ? dw : 0
-}
-
-def bit {
- bit 0
-}
-
-
-// Size Complexity: n
-ns bit {
- def vec n, value {
- rep(n, i) bit (value>>i)&1
- }
-
- def vec n {
- rep(n, i) bit
- }
-}
-
-
-// ---------- Memory Manipulation:
-
-
-ns bit {
- // Complexity: phi+2
- def zero x {
- .xor x, x
- }
-
- // Complexity: n(phi+2)
- def zero n, x {
- rep(n, i) .zero x+i*dw
- }
-
-
- // Complexity: phi+3
- def one x {
- .zero x
- .not x
- }
-
- // Complexity: n(phi+3)
- def one n, x {
- rep(n, i) .one x+i*dw
- }
-
-
- ////Complexity: 2phi + 9
- //__if_mov dst src @ l0 l1 flip end {
- // .if src l0 l1
- // l0: .if dst end flip
- // l1: .if dst flip end
- // flip: .not dst
- // end:
- //}
-
-
- // safe even for dst==src !
- // Complexity: 2phi+5
- def mov dst, src @ do_mov, end {
- comp_if1 dst==src, end
- do_mov:
- .zero dst
- .xor dst, src
- end:
- }
-
- // Complexity: n(2phi+5)
- def mov n, dst, src {
- rep(n, i) .mov dst+i*dw, src+i*dw
- }
-
-
- //Complexity: 2phi+10
- def swap a, b @ a0, a1, notnot, end {
- .if a, a0, a1
- a0:
- .if b, end, notnot
- a1:
- .if b, notnot, end
- notnot:
- .not a
- .not b
- end:
- }
-
- // Complexity: n(2phi+10)
- def swap n, a, b {
- rep(n, i) .swap a+i*dw, b+i*dw
- }
-}
-
-
-
-// ---------- Conditional Jump
-
-
-ns bit {
- // Complexity: phi+4
- def if x, l0, l1 @ label_ptr, base_jump_label {
- .xor label_ptr, x
- label_ptr:
- ;base_jump_label
- pad 2
- base_jump_label:
- ;l0
- label_ptr + dbit;l1
- }
-
- // Complexity: n(phi+4)
- def if n, x, l0, l1 {
- rep(n-1, i) ._.if_next_l0 x+i*dw, l1
- .if x+(n-1)*dw, l0, l1
- }
- ns _ {
- def if_next_l0 x, l1 @ l0 {
- ..if x, l0, l1
- l0:
- }
- }
-
- def if1 x, l1 @ end {
- .if x, end, l1
- end:
- }
-
- def if1 n, x, l1 @ end {
- .if n, x, end, l1
- end:
- }
-
- def if0 x, l0 @ end {
- .if x, l0, end
- end:
- }
-
- def if0 n, x, l0 @ end {
- .if n, x, l0, end
- end:
- }
-
-
- // Complexity: 2phi+8
- def cmp a, b, lt, eq, gt @ a_is1_label {
- .if1 a, a_is1_label
- .if b, eq, lt
- a_is1_label:
- .if b, gt, eq
- }
-
- // Complexity: n(2phi+8)
- def cmp n, a, b, lt, eq, gt {
- rep(n-1, i) ._.cmp_next_eq a+(n-1-i)*dw, b+(n-1-i)*dw, lt, gt
- .cmp a, b, lt, eq, gt
- }
- ns _ {
- def cmp_next_eq a, b, lt, gt @ eq {
- ..cmp a, b, lt, eq, gt
- eq:
- }
- }
-}
-
-
-
-// ---------- Logical Macros:
-
-
-ns bit {
- // Complexity: phi+2
- def xor dst, src {
- .exact_xor dst + dbit, src
- }
-
- // Complexity: n(phi+2)
- def xor n, dst, src {
- rep(n, i) .xor dst+dw*i, src+dw*i
- }
-
- def exact_xor dst, src @ base_jump_label, cleanup {
- wflip src+w, base_jump_label, src
- pad 2
- base_jump_label:
- ;cleanup
- dst;
- cleanup:
- wflip src+w, base_jump_label
- }
-
- // Complexity: phi+3
- def double_exact_xor dst1, dst2, src @ base_jump_label, cleanup {
- wflip src+w, base_jump_label, src
- pad 2
- base_jump_label:
- ;cleanup
- dst1;
- dst2;
- cleanup:
- wflip src+w, base_jump_label
- }
-
- // Complexity: n(phi+3)
- def bit_var_xor n, bit, var, src {
- rep(n, i) .double_exact_xor bit+i, var+dbit+i*dw, src+i*dw
- }
-
- def xor_zero dst, src {
- .double_exact_xor dst+dbit, src+dbit, src
- }
-
- // Complexity: n(phi+3)
- def xor_zero n, dst, src {
- rep(n, i) .xor_zero dst+dw*i, src+dw*i
- }
-
-
- // Complexity: 2phi+7
- def or dst, src @ end {
- .if0 src, end
- .one dst
- end:
- }
-
- // Complexity: n(2phi+7)
- def or n, dst, src {
- rep(n, i) .or dst+dw*i, src+dw*i
- }
-
-
- // Complexity: 2phi+6
- def and dst, src @ end {
- .if1 src, end
- .zero dst
- end:
- }
-
- // Complexity: n(2phi+6)
- def and n, dst, src {
- rep(n, i) .and dst+dw*i, src+dw*i
- }
-
-
- // Complexity: 1
- def not dst {
- dst + dbit;
- }
-
- // Complexity: n
- def not n, dst {
- rep(n, i) .not dst+dw*i
- }
-
- def exact_not dst {
- dst;
- }
-}
-
-
-
-// ---------- Logical Shifts
-
-
-ns bit {
- // Complexity: n(2phi+5)
- def shr n, x {
- .shr n, 1, x
- }
-
- // Complexity: n(2phi+5)
- def shr n, times, x {
- rep(n-times, i) .mov x+i*dw, x+(i+times)*dw
- .zero times, x+(n-times)*dw
- }
-
-
- // Complexity: n(2phi+5)
- def shl n, x {
- .shl n, 1, x
- }
-
- // Complexity: n(2phi+5)
- def shl n, times, x {
- rep(n-times, i) .mov x+(n-1-i)*dw, x+(n-1-i-times)*dw
- .zero times, x
- }
-
-
- // Complexity: n(2phi+5)
- def ror n, x @ temp_bit {
- .mov temp_bit, x
- rep(n-1, i) .mov x+i*dw, x+(i+1)*dw
- .mov x+(n-1)*dw, temp_bit
- skip
- temp_bit:
- bit
- }
-
-
- // Complexity: n(2phi+5)
- def rol n, x @ temp_bit {
- .mov temp_bit, x+(n-1)*dw
- rep(n-1, i) .mov x+(n-1-i)*dw, x+(n-1-i-1)*dw
- .mov x, temp_bit
- skip
- temp_bit:
- bit
- }
-}
-
-
-
-// ---------- Arithmetical Macros
-// carry is both input and output
-
-
-ns bit {
- // Unsafe for dst==carry (but there is no reason in calling it that way)
- // Complexity: 2phi+10
- def inc1 dst, carry @ end {
- .if0 carry, end
- .not dst
- .if0 dst, end
- .not carry
- end:
- }
-
- // Complexity: n(2phi+10)
- def inc n, x @ carry {
- .one carry
- rep(n, i) .inc1 x+i*dw, carry
- skip
- carry:
- bit
- }
-
- // Complexity: n(2phi+12)
- def dec n, x {
- .not n, x
- .inc n, x
- .not n, x
- }
-
- // Complexity: n(2phi+11)
- def neg n, x {
- .not n, x
- .inc n, x
- }
-
-
- // Unsafe for dst==carry (but there is no reason in calling it that way)
- // Complexity: 8phi+33
- def add1 dst, src, carry @ _src {
- .mov _src, src
- .inc1 dst, _src
- .inc1 dst, carry
- .or carry, _src
- skip
- _src:
- bit
- }
-
- // Complexity: n(8phi+33)
- def add n, dst, src @ carry {
- .zero carry
- rep(n, i) .add1 dst+i*dw, src+i*dw, carry
- skip
- carry:
- bit
- }
-
- // Complexity: n(8phi+35)
- def sub n, dst, src @ carry {
- .not n, src
- .one carry
- rep(n, i) .add1 dst+i*dw, src+i*dw, carry
- .not n, src
- skip
- carry:
- bit
- }
-}
diff --git a/stl/casting.fj b/stl/casting.fj
new file mode 100644
index 0000000..c8a5831
--- /dev/null
+++ b/stl/casting.fj
@@ -0,0 +1,52 @@
+// ---------- Casting from bit
+
+
+ns stl {
+ // Time Complexity: 2@-1
+ // Space Complexity: 2@+11
+ //
+ // hex = bit
+ //
+ // hex is a hex, bit is a bit.
+ def bit2hex hex, bit {
+ hex.zero hex
+ bit.xor hex, bit
+ }
+
+ // Time Complexity: n(1.25@-1)
+ // Space Complexity: n(1.25@+2)
+ //
+ // hex[:(n+3)/4] = bit[:n]
+ //
+ // n is a size-constant, hex is a hex.vec (n+3)/4, bit is a bit.vec n.
+ def bit2hex n, hex, bit {
+ hex.zero (n+3)/4, hex
+ rep(n, i) bit.exact_xor hex+(i/4)*dw+dbit+(i%4), bit+i*dw
+ }
+
+
+
+ // ---------- Casting from hex
+
+
+ // Time Complexity: 5@-4
+ // Space Complexity: 5@+8
+ //
+ // bit[:4] = hex
+ //
+ // hex is a hex, bit is a bit.vec 4.
+ def hex2bit bit, hex {
+ bit.zero 4, bit
+ hex.exact_xor bit+3*dw+dbit, bit+2*dw+dbit, bit+dw+dbit, bit+dbit, hex
+ }
+
+ // Time Complexity: n(5@-4)
+ // Space Complexity: n(5@+8)
+ //
+ // bit[:4n] = hex[:n]
+ //
+ // n is a size-constant, hex is a hex.vec n, bit is a bit.vec 4*n.
+ def hex2bit n, bit, hex {
+ rep(n, i) .hex2bit bit+4*i*dw, hex+i*dw
+ }
+}
diff --git a/stl/conf.json b/stl/conf.json
index 119344f..eee05e9 100644
--- a/stl/conf.json
+++ b/stl/conf.json
@@ -1,10 +1,31 @@
{
"all": [
"runlib",
- "bitlib",
- "iolib",
+
+ "bit/memory",
+ "bit/logics",
+ "bit/cond_jumps",
+ "bit/shifts",
+ "bit/math",
+ "bit/input",
+ "bit/output",
+ "bit/casting",
+ "bit/pointers",
+
+ "hex/memory",
+ "hex/logics",
+ "hex/math",
+ "hex/math_basic",
+ "hex/shifts",
+ "hex/cond_jumps",
+ "hex/tables_init",
+ "hex/input",
+ "hex/output",
+ "hex/pointers",
+ "hex/advanced_pointers",
+
+ "casting",
"ptrlib",
- "mathlib",
- "hexlib"
+ "mathlib"
]
}
\ No newline at end of file
diff --git a/stl/hex/advanced_pointers.fj b/stl/hex/advanced_pointers.fj
new file mode 100644
index 0000000..c4e4c61
--- /dev/null
+++ b/stl/hex/advanced_pointers.fj
@@ -0,0 +1,153 @@
+// ---------- Ptr ++/--/+=/-=
+
+
+ns hex {
+ // Time Complexity: 9@+14
+ // Space Complexity: w(0.375@ + 3.25) + 5@+55 (for log(w) in 16,32,64,128)
+ // ptr[:w/4] += 2w
+ // @requires hex.add.init (or hex.init)
+ def ptr_inc ptr {
+ hex.add_constant w/4, ptr, dw
+ }
+
+ // Time Complexity: 9@+23
+ // Space Complexity: w(0.375@ + 3.25) + 5@+67 (for log(w) in 16,32,64,128)
+ // ptr[:w/4] -= 2w
+ // @requires hex.sub.init (or hex.init)
+ def ptr_dec ptr {
+ hex.sub_constant w/4, ptr, dw
+ }
+
+ // Time Complexity: 13@+26
+ // Space Complexity: w(0.375@ + 3.25) + 7.5@+94
+ // ptr[:w/4] += value * 2w (advance ptr by value)
+ // @requires hex.add.init (or hex.init)
+ // @note: The complexity is calculated with n_const=2, and for log(w) in 16,32,64,128.
+ def ptr_add ptr, value {
+ hex.add_constant w/4, ptr, value * dw
+ }
+
+ // Time Complexity: 13@+35
+ // Space Complexity: w(0.375@ + 3.25) + 7.5@+106
+ // ptr[:w/4] -= value * 2w (retreat ptr by value)
+ // @requires hex.add.init (or hex.init)
+ // @note: The complexity is calculated with n_const=2, and for log(w) in 16,32,64,128.
+ def ptr_sub ptr, value {
+ hex.sub_constant w/4, ptr, value * dw
+ }
+}
+
+
+
+// ---------- Stack
+
+
+ns hex {
+ // Time Complexity: 9@+14
+ // Space Complexity: w(0.375@ + 3.25) + 5@+55
+ // Like: sp++
+ def sp_inc < hex.pointers.sp {
+ .ptr_inc hex.pointers.sp
+ }
+
+ // Time Complexity: 9@+23
+ // Space Complexity: w(0.375@ + 3.25) + 5@+67
+ // Like: sp--
+ def sp_dec < hex.pointers.sp {
+ .ptr_dec hex.pointers.sp
+ }
+
+ // Time Complexity: 13@+26
+ // Space Complexity: w(0.375@ + 3.25) + 7.5@+94
+ // Like: sp += value
+ def sp_add value < hex.pointers.sp {
+ .ptr_add hex.pointers.sp, value
+ }
+
+ // Time Complexity: 13@+35
+ // Space Complexity: w(0.375@ + 3.25) + 7.5@+106
+ // Like: sp -= value
+ def sp_sub value < hex.pointers.sp {
+ .ptr_sub hex.pointers.sp, value
+ }
+
+ // Time Complexity: 4w@ (actually a bit smaller)
+ // Space Complexity: 4w@ (actually a bit smaller)
+ // Like: stack[++sp] = return_address
+ // Pushes the given return_address to the next cell in the stack (assumes it's zero). Increments sp.
+ // return_address is a fj-op address, so we assume is dw-aligned.
+ def push_ret_address return_address < hex.pointers.sp {
+ .sp_inc
+ .ptr_wflip_2nd_word hex.pointers.sp, return_address
+ }
+
+ // Time Complexity: 4w@ (actually a bit smaller)
+ // Space Complexity: 4w@ (actually a bit smaller)
+ // Like: stack[sp--] = 0
+ // Pops the given return_address from the current cell in the stack (assumes it has the value of the return_address). Decrements sp.
+ // return_address is a fj-op address, so we assume is dw-aligned.
+ def pop_ret_address return_address < hex.pointers.sp {
+ .ptr_wflip_2nd_word hex.pointers.sp, return_address
+ .sp_dec
+ }
+
+
+ // Time Complexity: w(0.5@+2) + 14@+26
+ // Space Complexity: w(0.875@+5.25) + 10@+131
+ // Like: stack[++sp] = hex (assumes stack[++sp] == 0 beforehand, which the stack-macros guarantee).
+ // Pushes the given hex to the next cell in the stack (assumes it's zero). Increments sp.
+ def push hex < hex.pointers.sp {
+ .sp_inc
+ .xor_to_ptr hex.pointers.sp, hex
+ }
+
+ // Time Complexity: n(w(0.5@+2) + 14@+26)
+ // Space Complexity: n(w(0.875@+5.25) + 10@+131)
+ // Like: stack[sp+1:][:n] = hex[:n]; sp += n (assumes stack[sp:sp+n] == 0 beforehand, which the stack-macros guarantee).
+ // Pushes the given hex[:n] to the next n cells in the stack (assumes they're zero). Increments sp by n.
+ def push n, hex {
+ rep(n, i) .push hex+i*dw
+ }
+
+
+ // Time Complexity: w(0.5@+2) + 14@+35
+ // Space Complexity: w(0.875@+17.25) + 10@+143
+ // Like: stack[sp--] = 0 (assumes stack[sp] == unchanged_hex beforehand)
+ // Pops the given unchanged_hex (a hex) from the current cell in the stack (assumes it has the exact value of hex). Decrements sp.
+ def pop_unchanged_parameter unchanged_hex < hex.pointers.sp {
+ .xor_to_ptr hex.pointers.sp, unchanged_hex
+ .sp_dec
+ }
+
+ // Time Complexity: n(w(0.5@+2) + 14@+35)
+ // Space Complexity: n(w(0.875@+17.25) + 10@+143)
+ // Like: sp -= n; stack[sp+1:][:n] = 0 (assumes stack[sp+1-n:][:n] == unchanged_hex[:n] beforehand)
+ // Pops the given unchanged_hex (a hex[:n]) from the current cell in the stack (assumes it has the exact value of hex). Decrements sp by n.
+ def pop_unchanged_parameter n, unchanged_hex {
+ rep(n, i) .pop_unchanged_parameter unchanged_hex+i*dw
+ }
+
+
+ // Time Complexity: w(6@+10) (for w=64. exact: w(5@+10) + 15@+43 + 2(@-2)^2)
+ // Space Complexity: w(6.5@+20) (for w=64. exact: w(5.375@+25.25) + 11@+173 + 2(@-2)^2)
+ // Like: hex = stack[sp]
+ // stack[sp--] = 0
+ // Pops the current stack cell into the the given hex. Decrements sp.
+ // hex is only an output parameter
+ def pop hex < hex.pointers.sp {
+ hex.zero hex
+ .xor_from_ptr hex, hex.pointers.sp
+ .pop_unchanged_parameter hex
+ }
+
+ // Time Complexity: nw(6@+10) (for w=64. exact/n is: w(5@+10) + 15@+43 + 2(@-2)^2)
+ // Space Complexity: nw(6.5@+20) (for w=64. exact/n is: w(5.375@+25.25) + 11@+173 + 2(@-2)^2)
+ // Like: sp -= n
+ // hex[:n] = stack[sp+1][:n]
+ // stack[sp+1:][:n] = 0
+ // Pops the current stack cell into the the given hex[:n]. Decrements sp by n.
+ // hex[:n] is only an output parameter.
+ def pop n, hex {
+ rep(n, i) .pop hex+(n-1-i)*dw
+ }
+}
diff --git a/stl/hex/cond_jumps.fj b/stl/hex/cond_jumps.fj
new file mode 100644
index 0000000..8ec4a07
--- /dev/null
+++ b/stl/hex/cond_jumps.fj
@@ -0,0 +1,161 @@
+// ---------- Conditional Jump
+
+
+ns hex {
+ // Time Complexity: @-1
+ // Space Complexity: @+15
+ // if flags&(1<>i)&1 ? return+dbit+0 : 0, clean
+
+ clean:
+ wflip hex+w, switch
+ return: ;finish
+ pad 2
+ finish:
+ ; l0
+ return+dbit+0; l1
+ }
+
+ // Time Complexity: @-1
+ // Space Complexity: @+15
+ // if hex==0 goto l0, else goto l1.
+ def if hex, l0, l1 {
+ .if_flags hex, 0xfffe, l0, l1
+ }
+ // if hex==0 goto l0, else continue.
+ def if0 hex, l0 @ l1 {
+ .if hex, l0, l1
+ l1:
+ }
+ // if hex!=0 goto l1, else continue.
+ def if1 hex, l1 @ l0 {
+ .if hex, l0, l1
+ l0:
+ }
+
+ // Time Complexity: n(@-1)
+ // Space Complexity: n(@+15)
+ // if hex[:n]==0 goto l0, else goto l1.
+ def if n, hex, l0, l1 {
+ rep(n-1, i) .if1 hex+i*dw, l1
+ .if hex+(n-1)*dw, l0, l1
+ }
+ // if hex[:n]==0 goto l0, else continue.
+ def if0 n, hex, l0 @ l1 {
+ .if n, hex, l0, l1
+ l1:
+ }
+ // if hex[:n]!=0 goto l1, else continue.
+ def if1 n, hex, l1 @ l0 {
+ .if n, hex, l0, l1
+ l0:
+ }
+
+
+ // Time Complexity: @-1
+ // Space Complexity: @+15
+ // if number[:n] < 0 jump to neg, else jump to zpos (Zero POSitive).
+ def sign n, number, neg, zpos {
+ .if_flags number+(n-1)*dw, 0xff00, zpos, neg
+ }
+
+
+ // Time Complexity: 3@+8
+ // Space Complexity: 3@+30
+ // compares a to b.
+ // if a < b: goto lt;
+ // if a == b: goto eq;
+ // if a > b: goto gt;
+ // @requires hex.cmp.init (or hex.init)
+ //
+ // a,b are hexes; lt/eq/gt are addresses.
+ def cmp a, b, lt, eq, gt \
+ @ ret, _eq, _gt, jumper_to_return_table, __lt, __eq, __gt \
+ < .cmp.dst, ._.ret {
+ //part1
+ .xor .cmp.dst , a
+ .xor .cmp.dst+4, b
+ wflip ._.ret+w, ret, .cmp.dst
+
+
+ pad 4
+ //part2
+ ret:
+ wflip ._.ret+w, ret, jumper_to_return_table //part3
+ ._.ret+dbit ;_eq
+ ._.ret+dbit+1;_gt
+
+ _eq: jumper_to_return_table+dbit ;ret //(part2.5)
+ _gt: jumper_to_return_table+dbit+1;ret
+
+ jumper_to_return_table:
+ //part4
+ ;__lt
+
+ pad 4
+ //part5
+ __lt: ;lt
+ __eq: jumper_to_return_table+dbit ;eq
+ __gt: jumper_to_return_table+dbit+1;gt
+ }
+
+ // Time Complexity: m(3@+8) // m=(n-i), where i is the most-significant index such that a[i] != b[i] (if a==b, then m==n).
+ // Space Complexity: n(3@+30)
+ // compares a[:n] to b[:n].
+ // if a[:n] < b[:n]: goto lt;
+ // if a[:n] == b[:n]: goto eq;
+ // if a[:n] > b[:n]: goto gt;
+ // @requires hex.cmp.init (or hex.init)
+ //
+ // n is size-constant; a,b are hexes; lt/eq/gt are addresses.
+ def cmp n, a, b, lt, eq, gt {
+ rep(n-1, i) .cmp.cmp_eq_next a+(n-1-i)*dw, b+(n-1-i)*dw, lt, gt
+ .cmp a, b, lt, eq, gt
+ }
+
+ ns cmp {
+ // compares a to b; if equal just continue.
+ def cmp_eq_next a, b, lt, gt @ eq {
+ ..cmp a, b, lt, eq, gt
+ eq:
+ }
+
+ // Time Complexity: 6 (when jumping to dst, until finished)
+ // Space Complexity: 514
+ // This is where the compare "truth" tables are.
+ // @output-param dst: This variable is an 8-bit variable (in a single op, [dbit,dbit+8)).
+ // Its 8-bits are expected to be {src<<4 | dst} at the jump to it (for the src,dst hexes of the cmp operation).
+ // Its 8-bits are expected to be 0 after the jump to it.
+ def init @ switch, clean_table_entry, end < .._.ret > dst {
+ ;end
+ dst: ;.switch
+
+ pad 256
+ switch:
+ // The next line is the compare flipping-table.
+ // The [src<<4 | dst] entry flips bits in hex._.ret:
+ // if dst > src: flips dbit+1
+ // if dst == src: flips dbit+0
+ // if dst < src: no flips
+ // Upon entering here, .dst was xored with the correct table-entry, and was jumped into.
+ rep(256, d) stl.fj ((d&0xf) > (d>>4)) \
+ ? .._.ret+dbit+1 \
+ : (((d&0xf) == (d>>4)) ? .._.ret+dbit : 0),\
+ clean_table_entry+d*dw
+
+ clean_table_entry:
+ // xors back the table-entry from .dst
+ .._.clean_table_entry__table .dst
+ end:
+ }
+ }
+}
diff --git a/stl/hex/input.fj b/stl/hex/input.fj
new file mode 100644
index 0000000..b895756
--- /dev/null
+++ b/stl/hex/input.fj
@@ -0,0 +1,87 @@
+// ---------- Input Hex
+
+
+ns hex {
+ // Time Complexity: 2@+7
+ // Space Complexity: 2@+18
+ // hex := input(4bits) // lsb first
+ def input_hex hex @ flip0, flip1, flip2, flip3, end < stl.IO {
+ // part0
+ .zero hex
+ wflip stl.IO+w, flip0, stl.IO
+
+ pad 8
+ flip0:
+ stl.IO+dbit+1;stl.IO // part1
+ hex+dbit+0;flip0 //(part0.5)
+ flip1:
+ stl.IO+dbit+2;stl.IO // part2
+ hex+dbit+1;flip1 //(part1.5)
+ flip3:
+ wflip stl.IO+w, flip3, end // part4
+ hex+dbit+3;flip3 //(part3.5)
+ flip2:
+ stl.IO+dbit+1;stl.IO // part3
+ hex+dbit+2;flip2 //(part2.5)
+ end:
+ }
+
+ // Time Complexity: 4@+14
+ // Space Complexity: 4@+36
+ // byte[:2] = input(8bits) // lsb first
+ def input byte {
+ .input_hex byte
+ .input_hex byte+dw
+ }
+
+ // Time Complexity: n(4@+14)
+ // Space Complexity: n(4@+36)
+ // bytes[:2n] = input(8n-bits) // lsb first
+ def input n, bytes {
+ rep(n, i) .input bytes+2*i*dw
+ }
+
+ // Time Complexity: 7@+11
+ // Space Complexity: 8.5@+92
+ // hex = hex_from_ascii(input(1byte))
+ // *supports 0-9,a-f,A-F. if can't cast, jumps to error.
+ def input_as_hex hex, error @ try_dec, do_dec, do_hex, hex_switch, finish_hex, upper, end {
+ .input_hex hex
+ .input_hex upper
+ .if_flags upper, (1<<4)|(1<<6), try_dec, do_hex
+ try_dec:
+ .if_flags upper, (1<<3), error, do_dec
+
+ do_dec: // if input==0x3i for 0<=i<=9, finish; else, goto error.
+ .if_flags hex, (1<<10)-1, error, end
+
+ do_hex: // if input==0x4i or input==0x6i:
+ wflip hex+w, hex_switch, hex
+
+ finish_hex:
+ hex+dbit+3;
+ wflip hex+w, hex_switch, end
+
+ pad 16
+ hex_switch: // if 1<=hex<=6, hex+=9; else, goto error.
+ wflip hex+w, hex_switch, error // 0
+ hex+dbit+1;hex_switch+2*dw // 1
+ hex+dbit+0;finish_hex // 2
+ hex+dbit+2;hex_switch+1*dw // 3
+ hex+dbit+0;finish_hex // 4
+ hex+dbit+1;hex_switch+2*dw // 5
+ hex+dbit+0;finish_hex // 6
+ ;hex_switch // 7
+ ;hex_switch
+ ;hex_switch
+ ;hex_switch
+ ;hex_switch
+ ;hex_switch
+ ;hex_switch
+ ;hex_switch
+ ;hex_switch
+
+ upper: .hex
+ end:
+ }
+}
diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj
new file mode 100644
index 0000000..a70b6ba
--- /dev/null
+++ b/stl/hex/logics.fj
@@ -0,0 +1,255 @@
+// ---------- Logical Macros:
+
+
+ns hex {
+
+ // Time Complexity: @
+ // Space Complexity: @+12
+ // dst ^= src
+ //
+ // both dst,src are hexes
+ def xor dst, src {
+ .exact_xor dst+dbit+3, dst+dbit+2, dst+dbit+1, dst+dbit+0, src
+ }
+
+ // Time Complexity: n@
+ // Space Complexity: n(@+12)
+ // dst[:n] ^= src[:n]
+ def xor n, dst, src {
+ rep (n, i) .xor dst+i*dw, src+i*dw
+ }
+
+
+ // Time Complexity: @
+ // Space Complexity: @+12
+ // {d3,d2,d1,d0} ^= src
+ //
+ // d3,d2,d1,d0 are bit-addresses; src is hex.
+ def exact_xor d3, d2, d1, d0, src @ switch, end {
+ wflip src+w, switch, src
+ pad 16
+ switch:
+ ;end // 0
+ d0;end // 1
+ d1;end // 2
+ d1;switch+1*dw // 3
+ d2;end // 4
+ d2;switch+1*dw // 5
+ d2;switch+2*dw // 6
+ d2;switch+3*dw // 7
+ d3;end // 8
+ d3;switch+1*dw // 9
+ d3;switch+2*dw // 10
+ d3;switch+3*dw // 11
+ d3;switch+4*dw // 12
+ d3;switch+5*dw // 13
+ d3;switch+6*dw // 14
+ d3;switch+7*dw // 15
+ end:
+ wflip src+w, switch
+ }
+
+ // Time Complexity: @+4
+ // Space Complexity: @+28
+ // dst ^= src
+ // src = 0
+ //
+ // both dst,src are hexes
+ def xor_zero dst, src {
+ .double_xor dst, src, src
+ }
+
+ // Time Complexity: n(@+4)
+ // Space Complexity: n(@+28)
+ // dst[:n] ^= src[:n]
+ // src[:n] = 0
+ def xor_zero n, dst, src {
+ rep (n, i) .xor_zero dst+i*dw, src+i*dw
+ }
+
+ // Time Complexity: @+4
+ // Space Complexity: @+28
+ // dst1 ^= src
+ // dst2 ^= src
+ //
+ // dst1,dst2,src are hexes
+ def double_xor dst1, dst2, src {
+ .double_exact_xor \
+ dst1+dbit+3, dst1+dbit+2, dst1+dbit+1, dst1+dbit+0, \
+ dst2+dbit+3, dst2+dbit+2, dst2+dbit+1, dst2+dbit+0, \
+ src
+ }
+
+ // Time Complexity: n(@+4)
+ // Space Complexity: n(@+28)
+ // address(bit_address) ^= src
+ // var ^= src
+ // var,src are hex[:n], address is an address.
+ def address_and_variable_xor n, address, var, src {
+ rep(n, i) .double_exact_xor \
+ address+4*i+3, address+4*i+2, address+4*i+1, address+4*i+0, \
+ var+dbit+i*dw+3, var+dbit+i*dw+2, var+dbit+i*dw+1, var+dbit+i*dw+0, \
+ src+i*dw
+ }
+
+ // Time Complexity: @+4
+ // Space Complexity: @+28
+ // {t3,t2,t1,t0} ^= src
+ // {d3,d2,d1,d0} ^= src
+ //
+ // t3,t2,t1,t0,d3,d2,d1,d0 are bit-addresses; src is hex.
+ def double_exact_xor t3, t2, t1, t0, d3, d2, d1, d0, src @ first_flip, second_flip, end {
+ wflip src+w, first_flip, src
+ pad 16
+ first_flip:
+ ;end // 0
+ d0;second_flip+ 0*dw // 1
+ d1;second_flip+ 1*dw // 2
+ d1;second_flip+ 2*dw // 3
+ d2;second_flip+ 3*dw // 4
+ d2;second_flip+ 4*dw // 5
+ d2;second_flip+ 5*dw // 6
+ d2;second_flip+ 6*dw // 7
+ d3;second_flip+ 7*dw // 8
+ d3;second_flip+ 8*dw // 9
+ d3;second_flip+ 9*dw // 10
+ d3;second_flip+10*dw // 11
+ d3;second_flip+11*dw // 12
+ d3;second_flip+12*dw // 13
+ d3;second_flip+13*dw // 14
+ d3;second_flip+14*dw // 15
+
+ second_flip:
+ t0;end // 1
+ t1;end // 2
+ t1;first_flip+1*dw // 3
+ t2;end // 4
+ t2;first_flip+1*dw // 5
+ t2;first_flip+2*dw // 6
+ t2;first_flip+3*dw // 7
+ t3;end // 8
+ t3;first_flip+1*dw // 9
+ t3;first_flip+2*dw // 10
+ t3;first_flip+3*dw // 11
+ t3;first_flip+4*dw // 12
+ t3;first_flip+5*dw // 13
+ t3;first_flip+6*dw // 14
+ t3;first_flip+7*dw // 15
+ end:
+ wflip src+w, first_flip
+ }
+
+
+ // Complexity: 4
+ // hex = !hex (15-hex)
+ def not hex {
+ hex+dbit+0;
+ hex+dbit+1;
+ hex+dbit+2;
+ hex+dbit+3;
+ }
+
+ // Complexity: 4n
+ // x[:n] = !x[:n]
+ def not n, x {
+ rep(n, i) .not x+i*dw
+ }
+
+
+ // Time Complexity: 4@+10
+ // Space Complexity: 4@+52
+ // dst |= src
+ // @requires hex.or.init (or hex.init)
+ //
+ // both dst,src are hexes.
+ def or dst, src < .or.dst {
+ ._.jump_to_table_entry dst, src, .or.dst
+ }
+
+ // Time Complexity: n(4@+10)
+ // Space Complexity: n(4@+52)
+ // dst[:n] |= src[:n]
+ // @requires hex.or.init (or hex.init)
+ def or n, dst, src {
+ rep(n, i) .or dst+i*dw, src+i*dw
+ }
+
+ ns or {
+ // Time Complexity: 6 (when jumping to dst, until finished)
+ // Space Complexity: 595
+ // This is where the or "truth" tables are.
+ // @output-param dst: This variable is an 8-bit variable (in a single op, [dbit,dbit+8)).
+ // Its 8-bits are expected to be {src<<4 | dst} at the jump to it (for the src,dst hexes of the or operation).
+ // Its 8-bits are expected to be 0 after the jump to it.
+ def init @ switch, clean_table_entry, end < .._.res > dst {
+ ;end
+ dst: ;.switch
+
+ pad 256
+ switch:
+ // The next line is the bitwise-or flipping-table.
+ // The [src<<4 | dst] entry sets hex._.res (assumed to be 0) to (dst | src) ^ dst,
+ // so that xoring it with dst will update it to the or-result.
+ // Upon entering here, .dst was xored with the correct table-entry, and was jumped into.
+ // Space Complexity / total table ops: 337.
+ rep(256, d) stl.wflip_macro \
+ .._.res+w, \
+ (((d&0xf)|(d>>4))^(d&0xf))*dw, \
+ clean_table_entry+d*dw
+
+ clean_table_entry:
+ // xors back the table-entry from .dst
+ .._.clean_table_entry__table .dst
+ end:
+ }
+ }
+
+
+ // Time Complexity: 4@+10
+ // Space Complexity: 4@+52
+ // dst &= src
+ //
+ // both dst,src are hexes.
+ // @requires hex.and.init (or hex.init)
+ def and dst, src < .and.dst {
+ ._.jump_to_table_entry dst, src, .and.dst
+ }
+
+ // Time Complexity: n(4@+10)
+ // Space Complexity: n(4@+52)
+ // dst[:n] &= src[:n]
+ // @requires hex.and.init (or hex.init)
+ def and n, dst, src {
+ rep(n, i) .and dst+i*dw, src+i*dw
+ }
+
+ ns and {
+ // Time Complexity: 6 (when jumping to dst, until finished)
+ // Space Complexity: 595
+ // This is where the and "truth" tables are.
+ // @output-param dst: This variable is an 8-bit variable (in a single op, [dbit,dbit+8)).
+ // Its 8-bits are expected to be {src<<4 | dst} at the jump to it (for the src,dst hexes of the and operation).
+ // Its 8-bits are expected to be 0 after the jump to it.
+ def init @ switch, clean_table_entry, end < .._.res > dst {
+ ;end
+ dst: ;.switch
+
+ pad 256
+ switch:
+ // The next line is the bitwise-and flipping-table.
+ // The [src<<4 | dst] entry sets hex._.res (assumed to be 0) to (dst & src) ^ dst,
+ // so that xoring it with dst will update it to the and-result.
+ // Upon entering here, .dst was xored with the correct table-entry, and was jumped into.
+ // Space Complexity / total table ops: 337.
+ rep(256, d) stl.wflip_macro \
+ .._.res+w, \
+ (((d&0xf)&(d>>4))^(d&0xf))*dw, \
+ clean_table_entry+d*dw
+
+ clean_table_entry:
+ // xors back the table-entry from .dst
+ .._.clean_table_entry__table .dst
+ end:
+ }
+ }
+}
diff --git a/stl/hex/math.fj b/stl/hex/math.fj
new file mode 100644
index 0000000..003818d
--- /dev/null
+++ b/stl/hex/math.fj
@@ -0,0 +1,279 @@
+// ---------- Addition / Subtraction:
+
+
+ns hex {
+ // Time Complexity: 4@+12
+ // Space Complexity: 4@+52
+ // dst += src
+ //
+ // both dst,src are hexes.
+ // Relies on the add-carry, and updates it at the end.
+ // @requires hex.add.init (or hex.init)
+ def add dst, src < .add.dst {
+ ._.jump_to_table_entry dst, src, .add.dst
+ }
+
+ // Time Complexity: n(4@+12)
+ // Space Complexity: n(4@+52)
+ // dst[:n] += src[:n]
+ // @requires hex.add.init (or hex.init)
+ def add n, dst, src {
+ .add.clear_carry
+ rep(n, i) .add dst+i*dw, src+i*dw
+ .add.clear_carry
+ }
+
+ // Time Complexity: src_n(4@+12) + 5@+1 // It's on average, see the note in hex.inc.
+ // Space Complexity: src_n(2.5@+39) + (dst_n - hex_shift)(1.5@+13) + 4@+28
+ // dst[:dst_n] += src[:src_n] << (4*hex_shift)
+ // @requires hex.add.init (or hex.init)
+ def add_shifted dst_n, src_n, dst, src, hex_shift @ do_inc, end {
+ .add.clear_carry
+ rep(src_n, i) .add dst+(hex_shift + i)*dw, src+i*dw
+ .add.clear_carry end, do_inc
+ do_inc:
+ rep(dst_n - (src_n + hex_shift), i) .inc.step dst+(src_n + hex_shift + i)*dw, end
+ end:
+ }
+
+ // Time Complexity: n_const(4@+12) + 5@+2
+ // Space Complexity: n_const(2.5@+39) + (dst_n - hex_shift)(1.5@+13) + 4@+29
+ // dst[:dst_n] += const
+ // @requires hex.add.init (or hex.init)
+ // n_const is the hex-length of const, without all of it's least-significant-hexes zeros.
+ def add_constant n, dst, const {
+ .add.add_constant_with_leading_zeros n, dst, const, (#(const&(0-const)))-1
+ }
+ ns add {
+ def add_constant_with_leading_zeros n, dst, const, leading_lsb_const_zeros {
+ .add_hex_shifted_constant n, dst, const >> (leading_lsb_const_zeros & (0-4)), leading_lsb_const_zeros >> 2
+ }
+ def add_hex_shifted_constant n, dst, const, hex_shift {
+ .add_hex_shifted_constant n, ((#const)+3)/4, dst, const, hex_shift
+ }
+ // Time Complexity: n_const(4@+12) + 5@+2
+ // Space Complexity: n_const(2.5@+39) + (dst_n - hex_shift)(1.5@+13) + 4@+29
+ // dst[:dst_n] += const << (4*hex_shift)
+ // @requires hex.add.init (or hex.init)
+ // const is a constant of size hex[:n_const]
+ def add_hex_shifted_constant n_dst, n_const, dst, const, hex_shift @ shifted_constant, end {
+ hex.add_shifted n_dst, n_const, dst, shifted_constant, hex_shift
+ ;end
+
+ shifted_constant: hex.vec n_const, const
+ end:
+ }
+ }
+
+ ns add {
+ // Time Complexity: 2@
+ // Space Complexity: 2@+12
+ // carry = 0
+ def clear_carry @ ret < .._.ret, .dst, .._.res {
+ wflip .._.ret+w, ret, .dst
+ ret:
+ wflip .._.ret+w, ret
+ ..zero .._.res
+ }
+
+ // Time Complexity: 2@+1
+ // Space Complexity: 2@+16
+ // carry = 0. jump to c0 if it was 0, and to c1 otherwise.
+ def clear_carry c0, c1 @ ret < .._.ret, .dst, .._.res {
+ wflip .._.ret+w, ret, .dst
+ ret:
+ wflip .._.ret+w, ret
+ // carry is 0/1
+ ..if0 .._.res, c0
+ .._.res+dbit; c1
+ }
+
+ // Complexity: 1
+ // carry = !carry
+ def not_carry < .dst {
+ .dst+dbit+8;
+ }
+
+ // Time Complexity: 2@+1
+ // Space Complexity: 2@+13
+ // carry = 1
+ def set_carry {
+ .clear_carry
+ .not_carry
+ }
+
+ // Time Complexity: 8 (when jumping to dst, until finished)
+ // Space Complexity: 1570
+ // This is where the add "truth" tables are.
+ // @output-param dst: This variable is an 9-bit variable (in a single op, [dbit,dbit+9)).
+ // Its 9-bits are expected to be {carry<<8 | src<<4 | dst} at the jump to it (for the src,dst hexes, and the carry bit, of the add operation).
+ // Its 9-bits are expected to be {new_carry<<8} after the jump to it.
+ def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res > dst {
+ ;end
+ dst: ;.switch__without_carry
+
+ pad 512
+ // The next lines are the addition flipping-tables.
+ // The [carry<<8 | src<<4 | dst] entry sets hex._.res (assumed to be 0) to (dst + src + carry) ^ dst,
+ // so that xoring it with dst will update it to the add-result.
+ // also, it updates the carry (.dst+dbit+8) to the next carry.
+ // Upon entering here, .dst was xored with the correct table-entry, and was jumped into.
+ switch__without_carry:
+ // Space Complexity / total table ops: 528.
+ rep(256, d) stl.wflip_macro .._.res+w, \
+ ((((d&0xf)+(d>>4) )&0xf)^(d&0xf))*dw, \
+ (((d&0xf)+(d>>4) > 0xf) ? (flip_carry+d*dw) : (clean_table_entry+d*dw))
+ switch__with_carry:
+ // Space Complexity / total table ops: 528.
+ rep(256, d) stl.wflip_macro .._.res+w, \
+ ((((d&0xf)+(d>>4)+1)&0xf)^(d&0xf))*dw, \
+ (((d&0xf)+(d>>4)+1 > 0xf) ? (clean_table_entry+d*dw) : (flip_carry+d*dw))
+
+ flip_carry:
+ // if got here - flip the carry; then clean the table-entry.
+ // in about half of the times, we'll get here.
+ rep(256, i) stl.fj .dst+dbit+8, clean_table_entry+i*dw
+ clean_table_entry:
+ // xors back the table-entry from .dst
+ .._.clean_table_entry__table .dst
+ end:
+ }
+ }
+
+
+ // Time Complexity: 4@+12
+ // Space Complexity: 4@+52
+ // dst -= src
+ //
+ // both dst,src are hexes.
+ // @requires hex.sub.init (or hex.init)
+ def sub dst, src < .sub.dst {
+ ._.jump_to_table_entry dst, src, .sub.dst
+ }
+
+ // Time Complexity: n(4@+12)
+ // Space Complexity: n(4@+52)
+ // dst[:n] -= src[:n]
+ // @requires hex.sub.init (or hex.init)
+ def sub n, dst, src {
+ .sub.clear_carry
+ rep(n, i) .sub dst+i*dw, src+i*dw
+ .sub.clear_carry
+ }
+
+ // Time Complexity: src_n(4@+12) + 5@+10 // It's on average, see the note in hex.inc.
+ // Space Complexity: src_n(2.5@+39) + (dst_n - hex_shift)(1.5@+13) + 4@+40
+ // dst[:dst_n] -= src[:src_n] << (4*hex_shift)
+ // @requires hex.sub.init (or hex.init)
+ def sub_shifted dst_n, src_n, dst, src, hex_shift @ do_dec, end {
+ .sub.clear_carry
+ rep(src_n, i) .sub dst+(hex_shift + i)*dw, src+i*dw
+ .sub.clear_carry end, do_dec
+ do_dec:
+ rep(dst_n - (src_n + hex_shift), i) .dec.step dst+(src_n + hex_shift + i)*dw, end
+ end:
+ }
+
+ // Time Complexity: n_const(4@+12) + 5@+11
+ // Space Complexity: n_const(2.5@+39) + (dst_n - hex_shift)(1.5@+13) + 4@+41
+ // dst[:dst_n] -= const
+ // @requires hex.sub.init (or hex.init)
+ // n_const is the hex-length of const, without all of it's least-significant-hexes zeros.
+ def sub_constant n, dst, const {
+ .sub.sub_constant_with_leading_zeros n, dst, const, (#(const&(0-const)))-1
+ }
+ ns sub {
+ def sub_constant_with_leading_zeros n, dst, const, leading_lsb_const_zeros {
+ .sub_hex_shifted_constant n, dst, const >> (leading_lsb_const_zeros & (0-4)), leading_lsb_const_zeros >> 2
+ }
+ def sub_hex_shifted_constant n, dst, const, hex_shift {
+ .sub_hex_shifted_constant n, ((#const)+3)/4, dst, const, hex_shift
+ }
+ // Time Complexity: n_const(4@+12) + 5@+2
+ // Space Complexity: n_const(2.5@+39) + (dst_n - hex_shift)(1.5@+13) + 4@+29
+ // dst[:dst_n] -= const << (4*hex_shift)
+ // @requires hex.sub.init (or hex.init)
+ // const is a constant of size hex[:n_const]
+ def sub_hex_shifted_constant n_dst, n_const, dst, const, hex_shift @ shifted_constant, end {
+ hex.sub_shifted n_dst, n_const, dst, shifted_constant, hex_shift
+ ;end
+
+ shifted_constant: hex.vec n_const, const
+ end:
+ }
+ }
+
+ ns sub {
+ // Time Complexity: 2@+5
+ // Space Complexity: 2@+20
+ // carry = 0
+ def clear_carry @ end {
+ .clear_carry end, end
+ end:
+ }
+
+ // Time Complexity: 2@+5
+ // Space Complexity: 2@+20
+ // carry = 0. jump to c0 if it was 0, and to c1 otherwise.
+ def clear_carry c0, c1 @ ret < .._.ret, .dst, .._.res {
+ wflip .._.ret+w, ret, .dst
+ ret:
+ wflip .._.ret+w, ret
+ // carry is 0/f
+ ..if0 .._.res, c0
+ .not_carry
+ wflip .._.res+w, 0xf*dw, c1
+ }
+
+ // Complexity: 1
+ // carry = !carry
+ def not_carry < .dst {
+ .dst+dbit+8;
+ }
+
+ // Time Complexity: 2@+6
+ // Space Complexity: 2@+21
+ // carry = 1
+ def set_carry {
+ .clear_carry
+ .not_carry
+ }
+
+ // Time Complexity: 8 (when jumping to dst, until finished)
+ // Space Complexity: 1570
+ // This is where the sub "truth" tables are. must be called once if you want to use hex.sub (hex.init calls it).
+ // @output-param dst: This variable is an 9-bit variable (in a single op, [dbit,dbit+9)).
+ // Its 9-bits are expected to be {carry<<8 | src<<4 | dst} at the jump to it (for the src,dst hexes, and the carry bit, of the sub operation).
+ // Its 9-bits are expected to be {new_carry<<8} after the jump to it.
+ def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res > dst {
+ ;end
+ dst: ;.switch__without_carry
+
+ pad 512
+ // The next lines are the subtraction flipping-tables.
+ // The [carry<<8 | src<<4 | dst] entry sets hex._.res (assumed to be 0) to (dst - src - carry) ^ dst,
+ // so that xoring it with dst will update it to the sub-result.
+ // also, it updates the carry (.dst+dbit+8) to the next carry. (subtraction's carry is also known as the borrow).
+ // Upon entering here, .dst was xored with the correct table-entry, and was jumped into.
+ switch__without_carry:
+ // Space Complexity / total table ops: 528.
+ rep(256, d) stl.wflip_macro .._.res+w, \
+ ((((d&0xf)-(d>>4) )&0xf)^(d&0xf))*dw, \
+ (((d&0xf)-(d>>4) < 0) ? (flip_carry+d*dw) : (clean_table_entry+d*dw))
+ switch__with_carry:
+ // Space Complexity / total table ops: 528.
+ rep(256, d) stl.wflip_macro .._.res+w, \
+ ((((d&0xf)-(d>>4)-1)&0xf)^(d&0xf))*dw, \
+ (((d&0xf)-(d>>4)-1 < 0) ? (clean_table_entry+d*dw) : (flip_carry+d*dw))
+
+ flip_carry:
+ // if got here - flip the carry; then clean the table-entry.
+ // in about half of the times, we'll get here.
+ rep(256, i) stl.fj .dst+dbit+8, clean_table_entry+i*dw
+ clean_table_entry:
+ // xors back the table-entry from .dst
+ .._.clean_table_entry__table .dst
+ end:
+ }
+ }
+}
diff --git a/stl/hex/math_basic.fj b/stl/hex/math_basic.fj
new file mode 100644
index 0000000..d4fdcc7
--- /dev/null
+++ b/stl/hex/math_basic.fj
@@ -0,0 +1,207 @@
+// ---------- Basic Mathmatics:
+
+
+ns hex {
+ // Time Complexity: 2.27@-1 // (2@-10 + 2 + 4 + 3 + 0.25*[16@/15])
+ // Space Complexity: 0.5@+109 + n(1.5@+13) // (2@-10 + 16(1+4+1+2) + 4 + (n-1)(1.5@+13))
+ // (n=2 when operating on 16-255 bit-numbers)
+ // dst[:n] += src.#on-bits (between 0->4)
+ // dst is hex.vec n, src is hex.
+ def add_count_bits n, dst, src @ count_switch, do_add, add_switch, add4_switch, xor_switch, \
+ after_add, is_carry, should_inc, do_inc, clean {
+ //part1
+ wflip src+w, count_switch, src
+
+ pad 16
+ //part2
+ count_switch:
+ ;clean // 0
+ ;do_add
+ ;do_add
+ dst+dbit+4;do_add
+ ;do_add // 4
+ dst+dbit+4;do_add
+ dst+dbit+4;do_add
+ dst+dbit+5;do_add
+ ;do_add // 8
+ dst+dbit+4;do_add
+ dst+dbit+4;do_add
+ dst+dbit+5;do_add
+ dst+dbit+4;do_add // 12
+ dst+dbit+5;do_add
+ dst+dbit+5;do_add
+ dst+dbit+5;count_switch+3*dw
+
+ //part3
+ do_add:
+ wflip dst+w, add_switch, dst
+
+ pad 64
+ //part4
+ add_switch:
+ rep(16, d) stl.fj 0, xor_switch+(d^(d+1))*dw
+ rep(16, d) stl.fj dst+dbit+4, xor_switch+(d^(d+2))*dw
+ rep(16, d) stl.fj dst+dbit+5, xor_switch+(d^(d+3))*dw
+ rep(16, d) stl.fj dst+dbit+5, add4_switch+d*dw
+ add4_switch:
+ rep(16, d) stl.fj dst+dbit+4, xor_switch+(d^(d+4))*dw
+
+ pad 32
+ //part5
+ xor_switch:
+ ._.clean_table_entry__table 16, dst, after_add
+ rep(16, i) stl.fj is_carry+dbit, xor_switch+i*dw
+
+ after_add:
+ //part6
+ wflip dst+w, add_switch, is_carry
+ is_carry:
+ //part7
+ ;should_inc
+ pad 2
+ should_inc:
+ //part8
+ ;clean
+ is_carry+dbit;do_inc
+ do_inc:
+ //part9 (optional)
+ .inc n-1, dst+dw
+ ;clean
+
+ clean:
+ //part10
+ wflip src+w, count_switch
+ }
+
+ // Time Complexity: n(2.27@-1)
+ // Space Complexity: n(3.5@+135) // on 16-255 bit-numbers. (a bit bigger on bigger numbers).
+ // dst[:small_n] = x[:n].#on-bits
+ //
+ // x is hex.vec n, and dst is hex.vec small_n.
+ // small_n (it's 2 for 16-255 bit-numbers) is the smallest number of bits that can hold the number n: ((#(n*4))+3)/4
+ def count_bits n, dst, x {
+ .zero ((#(n*4))+3)/4, dst
+ rep(n, i) .add_count_bits ((#(n*4))+3)/4, dst, x+i*dw
+ }
+}
+
+
+
+// ---------- Arithmetical Macros
+// carry is both input and output, and is saved in the 8th bit in hex.{add/sub}.dst
+
+
+ns hex {
+ // Time Complexity: @
+ // Space Complexity: 1.5@+13
+ // hex++ (if overflows - jump to carry1; else jump to carry0)
+ def inc1 hex, carry0, carry1 @ switch, end {
+ wflip hex+w, switch, hex
+ pad 16
+ switch:
+ hex+dbit+0;end // 0
+ hex+dbit+1;switch+0*dw // 1
+ hex+dbit+0;end // 2
+ hex+dbit+2;switch+1*dw // 3
+ hex+dbit+0;end // 4
+ hex+dbit+1;switch+0*dw // 5
+ hex+dbit+0;end // 6
+ hex+dbit+3;switch+3*dw // 7
+ hex+dbit+0;end // 8
+ hex+dbit+1;switch+0*dw // 9
+ hex+dbit+0;end // 10
+ hex+dbit+2;switch+1*dw // 11
+ hex+dbit+0;end // 12
+ hex+dbit+1;switch+0*dw // 13
+ hex+dbit+0;end // 14
+ hex+dbit+3; // 15
+ hex+dbit+2;
+ hex+dbit+1;
+ hex+dbit+0;
+ wflip hex+w, switch, carry1
+ end:
+ wflip hex+w, switch, carry0
+ }
+
+ // Time Complexity: 1.067@ // It's on average. To be exact: 16/15 * @.
+ // Space Complexity: n(1.5@+13)
+ // hex[:n]++
+ def inc n, hex @ end {
+ rep(n, i) .inc.step hex+i*dw, end
+ end:
+ }
+ ns inc {
+ def step hex, end @ next {
+ ..inc1 hex, end, next
+ next:
+ }
+ }
+
+
+ // Time Complexity: @
+ // Space Complexity: 1.5@+13
+ // hex-- (if underflows - jump to borrow1; else jump to borrow0)
+ def dec1 hex, borrow0, borrow1 @ switch, borrow, end {
+ wflip hex+w, switch, hex
+ pad 16
+ switch:
+ hex+dbit+3;borrow // 0
+ hex+dbit+0;end // 1
+ hex+dbit+1;switch+1*dw // 2
+ hex+dbit+0;end // 3
+ hex+dbit+2;switch+2*dw // 4
+ hex+dbit+0;end // 5
+ hex+dbit+1;switch+1*dw // 6
+ hex+dbit+0;end // 7
+ hex+dbit+3;switch+4*dw // 8
+ hex+dbit+0;end // 9
+ hex+dbit+1;switch+1*dw // 10
+ hex+dbit+0;end // 11
+ hex+dbit+2;switch+2*dw // 12
+ hex+dbit+0;end // 13
+ hex+dbit+1;switch+1*dw // 14
+ hex+dbit+0;end // 15
+ borrow:
+ hex+dbit+2;
+ hex+dbit+1;
+ hex+dbit+0;
+ wflip hex+w, switch, borrow1
+ end:
+ wflip hex+w, switch, borrow0
+ }
+
+ // Time Complexity: 1.067@ // It's on average. To be exact: 16/15 * @.
+ // Space Complexity: n(1.5@+13)
+ // hex[:n]--
+ def dec n, hex @ end {
+ rep(n, i) .dec.step hex+i*dw, end
+ end:
+ }
+ ns dec {
+ def step hex, end @ next {
+ ..dec1 hex, end, next
+ next:
+ }
+ }
+
+
+ // Time Complexity: ~@+4n
+ // Space Complexity: n(1.5@+17)
+ // x[:n] = -x[:n]
+ def neg n, x {
+ .not n, x
+ .inc n, x
+ }
+
+
+ // Time Complexity: (full_n - signed_n)(@+4)
+ // Space Complexity: (full_n - signed_n)(@+16)
+ // sign-extends hex[:signed_n] into hex[:full_n]
+ def sign_extend full_n, signed_n, hex @ negative, positive {
+ .zero full_n - signed_n, hex + signed_n * dw
+ .sign signed_n, hex, negative, positive
+ negative:
+ .not full_n - signed_n, hex + signed_n * dw
+ positive:
+ }
+}
diff --git a/stl/hex/memory.fj b/stl/hex/memory.fj
new file mode 100644
index 0000000..0be8fc5
--- /dev/null
+++ b/stl/hex/memory.fj
@@ -0,0 +1,122 @@
+// ---------- Memory Variables:
+
+
+ns hex {
+ // Size Complexity: 1
+ //
+ // This is another basic variable in the FlipJump standard library - a hexadecimal (can contain only 0-15).
+ // you can't place it as any other standard library macro, as "running" this line is undefined behavior.
+ // The hex (and hex.vec) should be placed in a place that won't run.
+ def hex val {
+ ;(val > 0xf ? 0xf : (val < 0 ? 0 : val)) * dw
+ }
+ def hex {
+ .hex 0
+ }
+
+
+ // Size Complexity: n
+ // read the comment for the hex macro.
+ def vec n, value {
+ rep(n, i) .hex (value>>(4*i))&0xf
+ }
+ def vec n {
+ rep(n, i) .hex
+ }
+}
+
+
+// ---------- Memory Manipulation:
+
+
+ns hex {
+
+ // Time Complexity: @
+ // Space Complexity: @+12
+ // hex = 0
+ def zero hex {
+ .xor hex, hex
+ }
+
+ // Time Complexity: n@
+ // Space Complexity: n(@+12)
+ // x[:n] = 0
+ def zero n, x {
+ rep (n, i) .zero x+i*dw
+ }
+
+ // Time Complexity: 2@+1
+ // Space Complexity: 2@+25
+ // dst = src
+ //
+ // both dst,src are hexes.
+ def mov dst, src @ end {
+ stl.comp_if1 dst==src, end
+ .zero dst
+ .xor dst, src
+ end:
+ }
+
+ // Time Complexity: n(2@)
+ // Space Complexity: n(2@+24)
+ // Unsafe if dst and src overlap! but safe if they are the exact same address.
+ // dst[:n] = src[:n]
+ def mov n, dst, src @ end {
+ stl.comp_if1 dst==src, end
+ .zero n, dst
+ .xor n, dst, src
+ end:
+ }
+
+ // Complexity: 4 (avg. 2: #on-bits)
+ // hex ^= val (constant)
+ def xor_by hex, val {
+ wflip hex+w, (val > 0xf ? 0xf : (val < 0 ? 0 : val)) * dw
+ }
+
+ // Complexity: 4n (avg. 2n: #on-bits)
+ // hex[:n] ^= val (constant)
+ def xor_by n, hex, val {
+ rep(n, i) .xor_by hex+i*dw, (val>>(4*i))&0xf
+ }
+
+ // Time Complexity: @+4
+ // Space Complexity: @+16
+ // hex = val (constant)
+ def set hex, val {
+ .zero hex
+ .xor_by hex, val
+ }
+
+ // Time Complexity: n(@+4)
+ // Space Complexity: n(@+16)
+ // hex[:n] = val (constant)
+ def set n, hex, val {
+ rep(n, i) .set hex+i*dw, (val>>(4*i))&0xf
+ }
+
+ // Time Complexity: 3@+1
+ // Space Complexity: 3@+37
+ // hex1, hex2 = hex2, hex1
+ //
+ // both hex1,hex2 are hexes.
+ def swap hex1, hex2 @ end {
+ stl.comp_if1 hex1==hex2, end
+ .xor hex1, hex2
+ .xor hex2, hex1
+ .xor hex1, hex2
+ end:
+ }
+
+ // Time Complexity: n(3@)
+ // Space Complexity: n(3@+36)
+ // Unsafe if dst and src overlap! but safe if they are the exact same address.
+ // hex1[:n], hex2[:n] = hex2[:n], hex1[:n]
+ def swap n, hex1, hex2 @ end {
+ stl.comp_if1 hex1==hex2, end
+ .xor n, hex1, hex2
+ .xor n, hex2, hex1
+ .xor n, hex1, hex2
+ end:
+ }
+}
diff --git a/stl/hex/output.fj b/stl/hex/output.fj
new file mode 100644
index 0000000..b4840f1
--- /dev/null
+++ b/stl/hex/output.fj
@@ -0,0 +1,214 @@
+// ---------- Output Hex
+
+
+// print raw bits
+ns hex {
+ // Time Complexity: @
+ // Space Complexity: @+26
+ // output 4 bits from hex (lsb first)
+ def output hex @ switch, print_0, print_2, print_4, print_6, print_8, print_a, print_c, print_e, end < stl.IO {
+ wflip hex+w, switch, hex
+ pad 16
+ switch:
+ stl.IO+0;print_0 // 0
+ stl.IO+1;print_0 // 1
+ stl.IO+0;print_2 // 2
+ stl.IO+1;print_2 // 3
+ stl.IO+0;print_4 // 4
+ stl.IO+1;print_4 // 5
+ stl.IO+0;print_6 // 6
+ stl.IO+1;print_6 // 7
+ stl.IO+0;print_8 // 8
+ stl.IO+1;print_8 // 9
+
+ stl.IO+0;print_a // a
+ stl.IO+1;print_a // b
+ stl.IO+0;print_c // c
+ stl.IO+1;print_c // d
+ stl.IO+0;print_e // e
+ stl.IO+1;print_e // f
+
+
+ print_0:
+ stl.IO+0;
+ stl.IO+0;
+ stl.IO+0;end
+ print_2:
+ stl.IO+1;print_0+1*dw
+ print_4:
+ stl.IO+0;
+ stl.IO+1;print_0+2*dw
+ print_6:
+ stl.IO+1;print_4+1*dw
+ print_8:
+ stl.IO+0;
+ stl.IO+0;
+ stl.IO+1;end
+ print_a:
+ stl.IO+1;print_8+1*dw
+ print_c:
+ stl.IO+0;
+ stl.IO+1;print_8+2*dw
+ print_e:
+ stl.IO+1;print_c+1*dw
+
+ end:
+ wflip hex+w, switch
+ }
+
+
+ // Time Complexity: 2@
+ // Space Complexity: 2@+52
+ // output 8 bits from x[:2] (lsb first)
+ def print x {
+ .output x
+ .output x+dw
+ }
+
+ // Time Complexity: n(2@)
+ // Space Complexity: n(2@+52)
+ // output n bytes from x[:2n] (lsb first)
+ def print n, x {
+ rep(n, i) .print x+2*i*dw
+ }
+}
+
+
+
+// print the hexadecimal number representation
+ns hex {
+ // Time Complexity: @+4
+ // Space Complexity: @+36
+ // prints the ascii of the hexadecimal representation of hex.
+ //
+ // use_uppercase (constant): if true, print in uppercase (else lowercase).
+ def print_as_digit hex, use_uppercase @ switch, print_0, print_2, print_4, print_6, print_8, \
+ print_a, print_b, print_d, print_f, end < stl.IO {
+ wflip hex+w, switch, hex
+ pad 16
+ switch:
+ stl.IO+0;print_0 // 0
+ stl.IO+1;print_0 // 1
+ stl.IO+0;print_2 // 2
+ stl.IO+1;print_2 // 3
+ stl.IO+0;print_4 // 4
+ stl.IO+1;print_4 // 5
+ stl.IO+0;print_6 // 6
+ stl.IO+1;print_6 // 7
+ stl.IO+0;print_8 // 8
+ stl.IO+1;print_8 // 9
+
+ stl.IO+1;print_a // a
+ stl.IO+0;print_b // b
+ stl.IO+1;print_b // c
+ stl.IO+0;print_d // d
+ stl.IO+1;print_d // e
+ stl.IO+0;print_f // f
+
+ print_0: // outputs 0x30
+ stl.IO+0;
+ stl.IO+0;
+ stl.IO+0;
+ stl.IO+1;
+ stl.IO+1;
+ stl.IO+0;
+ stl.IO+0;end
+ print_2:
+ stl.IO+1;print_0+1*dw
+ print_4:
+ stl.IO+0;
+ stl.IO+1;print_0+2*dw
+ print_6:
+ stl.IO+1;print_4+1*dw
+ print_8:
+ stl.IO+0;
+ stl.IO+0;
+ stl.IO+1;print_0+3*dw
+ print_a: // outputs 0x40 / 0x60
+ stl.IO+0;
+ stl.IO+0;
+ stl.IO+0;
+ stl.IO+0;
+ stl.IO+(use_uppercase ? 0 : 1);
+ stl.IO+1;print_0+6*dw
+ print_b:
+ stl.IO+1;print_a+1*dw
+ print_d:
+ stl.IO+0;
+ stl.IO+1;print_a+2*dw
+ print_f:
+ stl.IO+1;print_d+1*dw
+
+ end:
+ wflip hex+w, switch
+ }
+
+ // Time Complexity: n(@+4)
+ // Space Complexity: n(@+36)
+ // prints the ascii of the hexadecimal representation of x[:n].
+ //
+ // use_uppercase (constant): if true, print in uppercase (else lowercase).
+ def print_as_digit n, x, use_uppercase {
+ rep (n, i) .print_as_digit x+(n-1-i)*dw, use_uppercase
+ }
+
+ // Time Complexity: n(2@+6)
+ // Space Complexity: n(3@+54)
+ // print the unsigned x[:n], without leading zeros.
+ //
+ // x_prefix (constant): print with the "0x" prefix.
+ // use_uppercase (constant): if true, print in uppercase (else lowercase).
+ def print_uint n, x, x_prefix, use_uppercase @ after_prefix, printed_something, end {
+ bit.zero printed_something
+ stl.comp_if0 x_prefix, after_prefix
+ stl.output "0x"
+
+ after_prefix:
+ rep(n, i) .print_uint.print_digit x+(n-1-i)*dw, printed_something, use_uppercase
+ bit.if1 printed_something, end
+ stl.output '0'
+ ;end
+
+ printed_something: bit.bit
+ end:
+ }
+ ns print_uint {
+ // Time Complexity: 2@+6
+ // Space Complexity: 3@+54
+ // print the ascii of the hexadecimal representation of hex (skip leading zeros, based on printed_something)
+ //
+ // printed_something (bit [inout]): have any digit printed yet? (the macro also updates it)
+ // use_uppercase (constant): if true, print in uppercase (else lowercase).
+ def print_digit hex, printed_something, use_uppercase @ print, end {
+ bit.if1 printed_something, print
+ ..if0 hex, end
+ bit.not printed_something
+ print:
+ ..print_as_digit hex, use_uppercase
+ end:
+ }
+ }
+
+ // Time Complexity: n(2@+10)
+ // Space Complexity: n(4.5@+71)
+ // print the signed x[:n], without leading zeros.
+ //
+ // x_prefix (constant): print with the "0x" prefix.
+ // use_uppercase (constant): if true, print in uppercase (else lowercase).
+ def print_int n, x, x_prefix, use_uppercase @ do_neg, print, neg, end {
+ bit.zero neg
+ .sign n, x, do_neg, print
+ do_neg:
+ bit.not neg
+ .neg n, x
+ stl.output '-'
+ print:
+ .print_uint n, x, x_prefix, use_uppercase
+ bit.if0 neg, end
+ .neg n, x
+ ;end
+
+ neg: bit.bit
+ end:
+ }
+}
diff --git a/stl/hex/pointers.fj b/stl/hex/pointers.fj
new file mode 100644
index 0000000..9b51b30
--- /dev/null
+++ b/stl/hex/pointers.fj
@@ -0,0 +1,227 @@
+// ---------- Jump:
+
+
+
+ns hex {
+ ns pointers {
+ // Space Complexity: w/2+2
+ // Inits the global opcodes and pointer-copies required for the pointers macros.
+ //
+ // @output-param to_flip: address of opcode that holds a flipping address in its first word. jumping into it will flip wanted bit.
+ // @output-param to_flip_var: the hex-vector (pointer) that also holds the flipping address.
+ // @output-param to_jump: address of opcode that holds a jumping address in its second word. jumping into it will jump to the wanted address.
+ // @output-param to_jump_var: the hex-vector (pointer) that also holds the jumping address.
+ def ptr_init > to_flip, to_jump, to_flip_var, to_jump_var {
+ to_flip:
+ 0;0
+ to_jump:
+ ;0
+
+ to_flip_var:
+ hex.vec w/4, 0
+ to_jump_var:
+ hex.vec w/4, 0
+ }
+
+ // Time Complexity: w(0.5@+2)
+ // Space Complexity: w(0.5@+14)
+ // Sets both to_jump and to_jump_var to point to the given pointer.
+ // ( to_jump{_var} = ptr )
+ // ptr is a hex[:w/4] that holds an address.
+ def set_jump_pointer ptr < .to_jump, .to_jump_var {
+ ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, .to_jump_var
+ ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, ptr
+ }
+
+ // Time Complexity: w(0.5@+2)
+ // Space Complexity: w(0.5@+14)
+ // Sets both to_flip and to_flip_var to point to the given pointer.
+ // ( to_flip{_var} = ptr )
+ // ptr is a hex[:w/4] that holds an address.
+ def set_flip_pointer ptr < .to_flip, .to_flip_var {
+ ..address_and_variable_xor w/4, .to_flip, .to_flip_var, .to_flip_var
+ ..address_and_variable_xor w/4, .to_flip, .to_flip_var, ptr
+ }
+
+ // Space Complexity: n+w/4 + 330
+ // Initializes a stack of size n (maximal capacity of n hexs / return-addresses).
+ // n is the size of the stack.
+ // @output-param sp: the stack pointer. sp always points to the last pushed value (at start - to stack[-1])
+ // @output-param stack: the global stack.
+ def stack_init n @ stack_error_handler > sp, stack {
+ sp:
+ hex.vec w/4, .stack
+
+ pad w
+ stack:
+ hex.hex stack_error_handler
+ hex.vec n, 0
+
+ stack_error_handler:
+ stl.output "\n\nERROR: You returned on an empty stack.\n"
+ ;0 // (would fail, so the stack trace would be printed).
+ }
+ }
+}
+
+
+ns hex {
+ // Time Complexity: w(0.5@+2)
+ // Space Complexity: w(0.5@+14)
+ // like: ;*ptr
+ // Jump to the address the pointer points to.
+ // ptr is a hex[:w/4] that holds an address.
+ def ptr_jump ptr < hex.pointers.to_jump {
+ .pointers.set_jump_pointer ptr
+ ;hex.pointers.to_jump
+ }
+}
+
+
+
+// ---------- Flip:
+
+
+ns hex {
+ // Time Complexity: w(0.5@+2) + @
+ // Space Complexity: w(0.5@+14) + @
+ // like: *ptr;
+ // Flip the address the pointer points to.
+ // ptr is a hex[:w/4] that holds an address.
+ def ptr_flip ptr @ cleanup < hex.pointers.to_flip {
+ wflip hex.pointers.to_flip+w, cleanup
+
+ .pointers.set_flip_pointer ptr
+ ;hex.pointers.to_flip
+
+ pad 4
+ cleanup:
+ wflip hex.pointers.to_flip+w, cleanup
+ }
+
+
+ // Time Complexity: w(0.5@+2) + @+6
+ // Space Complexity: w(0.5@+14) + @+6
+ // The stl.comp_flip_if executes in ~##w, which should be much less than @/2 operations.
+ // like: (*ptr)+dbit;
+ // Flip the address dbit-ahead of what the pointer points to.
+ // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned.
+ def ptr_flip_dbit ptr < .pointers.to_flip {
+ wflip .pointers.to_flip, dbit
+ .ptr_flip ptr
+ wflip .pointers.to_flip, dbit
+ }
+
+
+ // Time Complexity: w(0.5@+2) + 5@+12
+ // Space Complexity: w(0.5@+14) + 5@+76
+ // like: hex.xor *ptr, hex
+ // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned.
+ def xor_to_ptr ptr, hex @ prepare_flip_bit0, prepare_flip_bit1, prepare_flip_bit2, prepare_flip_bit3, \
+ after_flip_bit0, after_flip_bit1, after_flip_bit2, after_flip_bit3, cleanup < hex.pointers.to_flip {
+ .pointers.set_flip_pointer ptr
+ wflip hex.pointers.to_flip+w, after_flip_bit0, prepare_flip_bit0
+
+ prepare_flip_bit0:
+ wflip hex.pointers.to_flip, dbit+0
+ hex.if_flags hex, 0xAAAA, after_flip_bit0, hex.pointers.to_flip
+ prepare_flip_bit1:
+ wflip hex.pointers.to_flip, (dbit+0)^(dbit+1)
+ hex.if_flags hex, 0xCCCC, after_flip_bit1, hex.pointers.to_flip
+ prepare_flip_bit3:
+ wflip hex.pointers.to_flip, (dbit+1)^(dbit+3)
+ hex.if_flags hex, 0xFF00, after_flip_bit3, hex.pointers.to_flip
+ prepare_flip_bit2:
+ wflip hex.pointers.to_flip, (dbit+3)^(dbit+2)
+ hex.if_flags hex, 0xF0F0, after_flip_bit2, hex.pointers.to_flip
+
+ pad 4
+ after_flip_bit0:
+ hex.pointers.to_flip+dbit+0;prepare_flip_bit1
+ after_flip_bit1:
+ hex.pointers.to_flip+dbit+1;prepare_flip_bit3
+ after_flip_bit2:
+ wflip hex.pointers.to_flip, dbit+2, cleanup
+ after_flip_bit3:
+ hex.pointers.to_flip+dbit+0;prepare_flip_bit2
+
+ cleanup:
+ wflip hex.pointers.to_flip+w, after_flip_bit2
+ }
+
+ // Complexity 3w@ (actually a bit smaller, 2w@+3w + (@-2)^2)
+ // like: wflip *ptr, value
+ // ptr is a hex[:w/4] that holds an address, which we assume is w-aligned.
+ def ptr_wflip ptr, value {
+ .pointers.set_flip_pointer ptr
+ rep(w, i) .pointers.advance_by_one_and_flip__ptr_wflip (#(i^((i+1)%w))), (value>>i)&1
+ }
+ ns pointers {
+ // Advances *to_flip by 1 (which takes n flips, from bit0 to bit1, bit2,...).
+ // If do_flip (value) isn't 0 - than make a flip, like: to_flip;advance.
+ def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < hex.pointers.to_flip {
+ stl.comp_if0 do_flip, advance
+ wflip hex.pointers.to_flip+w, cleanup, hex.pointers.to_flip
+ cleanup:
+ wflip hex.pointers.to_flip+w, cleanup, advance
+
+ pad 4
+ advance:
+ rep(n, i) bit.exact_not hex.pointers.to_flip+i
+ }
+ }
+
+ // Complexity 3w@ (actually a bit smaller, 2w@+3w+2 + (@-2)^2)
+ // like: wflip (*ptr)+w, value
+ // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned.
+ def ptr_wflip_2nd_word ptr, value {
+ ptr+dbit + ((#w-1)/4)*dw + (#w-1)%4;
+ hex.ptr_wflip ptr, value
+ ptr+dbit + ((#w-1)/4)*dw + (#w-1)%4;
+ }
+}
+
+
+
+// ---------- Xor
+
+
+ns hex {
+ // Complexity 5.5w@
+ // like: dst ^= *ptr
+ // dst is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned.
+ def xor_from_ptr dst, ptr {
+ .exact_xor_from_ptr dst+dbit+3, dst+dbit+2, dst+dbit+1, dst+dbit+0, ptr
+ }
+
+ // Time Complexity: 5.5w@ (exact: 4.5w@+8w+11 + 2(@-2)^2)
+ // Space Complexity: 5.5w@ (exact: 4.5w@+8w+34 + 2(@-2)^2)
+ // like: {d3,d2,d1,d0} ^= *ptr
+ // d3,d2,d1,d0 are bit-addresses. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned.
+ def exact_xor_from_ptr d3, d2, d1, d0, ptr @ switch, end {
+ .ptr_wflip_2nd_word ptr, switch
+ .ptr_jump ptr
+
+ pad 16
+ switch:
+ ;end // 0
+ d0;end // 1
+ d1;end // 2
+ d1;switch+1*dw // 3
+ d2;end // 4
+ d2;switch+1*dw // 5
+ d2;switch+2*dw // 6
+ d2;switch+3*dw // 7
+ d3;end // 8
+ d3;switch+1*dw // 9
+ d3;switch+2*dw // 10
+ d3;switch+3*dw // 11
+ d3;switch+4*dw // 12
+ d3;switch+5*dw // 13
+ d3;switch+6*dw // 14
+ d3;switch+7*dw // 15
+
+ end:
+ .ptr_wflip_2nd_word ptr, switch
+ }
+}
diff --git a/stl/hex/shifts.fj b/stl/hex/shifts.fj
new file mode 100644
index 0000000..06e1c23
--- /dev/null
+++ b/stl/hex/shifts.fj
@@ -0,0 +1,83 @@
+// ---------- Logical Shifts:
+
+
+ns hex {
+ // Time Complexity: n(@+1)
+ // Space Complexity: n(@+28)
+ // dst[:n] <<= 1
+ def shl_bit n, dst {
+ .shifts.shl_bit_once dst+(n-1)*dw, 0
+ rep(n-1, i) .shifts.shl_bit_once dst+(n-2-i)*dw, dst+(n-1-i)*dw
+ }
+
+
+ // Time Complexity: n(@+1)
+ // Space Complexity: n(@+28)
+ // dst[:n] >>= 1
+ def shr_bit n, dst {
+ .shifts.shr_bit_once dst, 0
+ rep(n-1, i) .shifts.shr_bit_once dst+(i+1)*dw, dst+i*dw
+ }
+
+
+ // Time Complexity: n(@+4)
+ // Space Complexity: n(@+28)
+ // dst[:n] <<= 4
+ def shl_hex n, dst {
+ .zero dst+(n-1)*dw
+ rep(n-1, i) .xor_zero dst+(n-1-i)*dw, dst+(n-2-i)*dw
+ }
+
+
+ // Time Complexity: n(@+4)
+ // Space Complexity: n(@+28)
+ // dst[:n] >>= 4
+ def shr_hex n, dst {
+ .zero dst
+ rep(n-1, i) .xor_zero dst+i*dw, dst+(i+1)*dw
+ }
+}
+
+
+ns hex {
+ ns shifts {
+ // Time Complexity: @+1
+ // Space Complexity: @+28
+ // {next(1bit),dst(1hex)} = dst << 1
+ //
+ // next is the bit-address of the next msb, dst is a hex.
+ // @note, this should be called in reverse order (so that the "next" is already shifted).
+ def shl_bit_once dst, next @ switch, xor_by, end {
+ wflip dst+w, switch, dst
+
+ pad 16
+ switch:
+ rep(16, i) stl.fj i&8 ? next+dbit+0 : 0, xor_by+(i^((i<<1)&0xf))*dw
+ xor_by:
+ .._.clean_table_entry__table 16, dst, end
+
+ end:
+ wflip dst+w, switch
+ }
+
+
+ // Time Complexity: @+1
+ // Space Complexity: @+28
+ // {next(1bit),dst(1hex)} = dst >> 1
+ //
+ // next is the bit-address of the next msb, dst is a hex.
+ // @note, this should be called in a regular order (so that the "next" is already shifted).
+ def shr_bit_once dst, next @ switch, xor_by, end {
+ wflip dst+w, switch, dst
+
+ pad 16
+ switch:
+ rep(16, i) stl.fj i&1 ? next+dbit+3 : 0, xor_by+(i^((i>>1)&0xf))*dw
+ xor_by:
+ .._.clean_table_entry__table 16, dst, end
+
+ end:
+ wflip dst+w, switch
+ }
+ }
+}
diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj
new file mode 100644
index 0000000..5df5f68
--- /dev/null
+++ b/stl/hex/tables_init.fj
@@ -0,0 +1,74 @@
+// ---------- Init The Truth Tables:
+
+
+ns hex {
+ // Space Complexity: 6500 (6460+@)
+ // It is 50/100KB (for w=32/64 bits)
+ // It is 5KB in --version 3 (for both w=32/64 bits)
+ // This macro inits all truth tables for the hex-macros.
+ // Use this macro exactly once, and don't use it alongside any other hex.*.init macros, as it will declare those twice.
+ // @output-param ret: The return address. Jumps to it after finishing going through a table.
+ // @output-param res: The result of the table calculation is written here.
+ def init {
+ ._.init
+ }
+
+ ns _ {
+ // This is the inner-macro of hex.init, and it's identical to it. see hex.init documentation.
+ def init @ end > ret, res {
+ ;end
+ ret: ;0
+ res: ..hex
+ ..or.init // 595
+ ..and.init // 595
+ ..mul.init // 1616+@
+ ..cmp.init // 514
+ ..add.init // 1570
+ ..sub.init // 1570
+ end:
+ }
+
+ // @Assumes: n must be a power of 2, and it must be (1<>1)) ? ret : clean+(d^((1<<(#d))>>1))*dw
+ }
+
+ // A table. When jumping to entry d - it xors d into dst, and jumps to hex._.ret
+ //
+ // Time Complexity: 4
+ // Space Complexity: 256
+ //
+ // dst is a hex.
+ def clean_table_entry__table dst < .ret {
+ .clean_table_entry__table 256, dst, .ret
+ }
+
+ // The macro assumes that jumper_to_table is a fj-op that jumps to a 256-padded table.
+ // This macro is used as a jumper to a table that sets hex._.res to some (calc(dst, src) ^ dst), and jumps back.
+ //
+ // Time Complexity: 4@+4
+ // Space Complexity: 4@+52
+ //
+ // It jumps to the table, at entry (src<<4 | dst).
+ // At last, it xors the value of hex._.res into dst.
+ //
+ // both dst,src are hexes, and jumper_to_table is an address.
+ def jump_to_table_entry dst, src, jumper_to_table @ return < .ret, .res {
+ ..xor jumper_to_table , dst
+ ..xor jumper_to_table+4, src
+ wflip .ret+w, return, jumper_to_table
+ return:
+ wflip .ret+w ,return
+ ..xor_zero dst, .res
+ }
+ }
+}
diff --git a/stl/hexlib.fj b/stl/hexlib.fj
deleted file mode 100644
index 8e1411b..0000000
--- a/stl/hexlib.fj
+++ /dev/null
@@ -1,1080 +0,0 @@
-// Every line is (16) bananas!
-// Implementation of hexadecimal-variables operations, and vectors of it
-
-// should be assembled with the runlib.fj file
-// This file is independent of the bit-width, and uses the consts defined at runlib.fj
-
-// Everything after // is ignored, and every whitespace is ignored (besides new line)
-// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next)
-
-// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op.
-// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity
-
-// Space complexity might not be exact
-
-
-
-// ---------- Memory Variables:
-// Size Complexity: 1
-
-
-def hex val {
- ;(val > 0xf ? 0xf : (val < 0 ? 0 : val)) * dw
-}
-
-def hex {
- hex 0
-}
-
-
-ns hex {
- def vec n, value {
- rep(n, i) hex (value>>(4*i))&0xf
- }
-
- def vec n {
- rep(n, i) hex
- }
-}
-
-
-// ---------- Logical Macros:
-
-
-ns hex {
-
- // Time Complexity: phi
- // Space Complexity: phi+27
- def xor dst, src {
- .exact_xor dst+dbit+3, dst+dbit+2, dst+dbit+1, dst+dbit+0, src
- }
-
- // Time Complexity: n*phi
- // Space Complexity: n*(phi+26)
- def xor n, dst, src {
- rep (n, i) .xor dst+i*dw, src+i*dw
- }
-
-
- // Time Complexity: phi
- // Space Complexity: phi+27
- def exact_xor d3, d2, d1, d0, src @ switch, end {
- wflip src+w, switch, src
- pad 16
- switch:
- ;end // 0
- d0;end // 1
- d1;end // 2
- d1;switch+1*dw // 3
- d2;end // 4
- d2;switch+1*dw // 5
- d2;switch+2*dw // 6
- d2;switch+3*dw // 7
- d3;end // 8
- d3;switch+1*dw // 9
- d3;switch+2*dw // 10
- d3;switch+3*dw // 11
- d3;switch+4*dw // 12
- d3;switch+5*dw // 13
- d3;switch+6*dw // 14
- d3;switch+7*dw // 15
- end:
- wflip src+w, switch
- }
-
- // Time Complexity: phi+4
- // Space Complexity: phi+42
- def xor_zero dst, src {
- .double_xor dst, src, src
- }
-
- // Time Complexity: n(phi+4)
- // Space Complexity: n(phi+42)
- def xor_zero n, dst, src {
- rep (n, i) .xor_zero dst+i*dw, src+i*dw
- }
-
- // Time Complexity: phi+4
- // Space Complexity: phi+42
- def double_xor dst1, dst2, src {
- .double_exact_xor dst1+dbit+3, dst1+dbit+2, dst1+dbit+1, dst1+dbit+0, dst2+dbit+3, dst2+dbit+2, dst2+dbit+1, dst2+dbit+0, src
- }
-
- // Time Complexity: phi+4
- // Space Complexity: phi+42
- def double_exact_xor t3, t2, t1, t0, d3, d2, d1, d0, src @ switch, second_flip, end {
- wflip src+w, switch, src
- pad 16
- switch:
- ;end // 0
- d0;second_flip+ 0*dw // 1
- d1;second_flip+ 1*dw // 2
- d1;second_flip+ 2*dw // 3
- d2;second_flip+ 3*dw // 4
- d2;second_flip+ 4*dw // 5
- d2;second_flip+ 5*dw // 6
- d2;second_flip+ 6*dw // 7
- d3;second_flip+ 7*dw // 8
- d3;second_flip+ 8*dw // 9
- d3;second_flip+ 9*dw // 10
- d3;second_flip+10*dw // 11
- d3;second_flip+11*dw // 12
- d3;second_flip+12*dw // 13
- d3;second_flip+13*dw // 14
- d3;second_flip+14*dw // 15
-
- second_flip:
- t0;end // 1
- t1;end // 2
- t1;switch+1*dw // 3
- t2;end // 4
- t2;switch+1*dw // 5
- t2;switch+2*dw // 6
- t2;switch+3*dw // 7
- t3;end // 8
- t3;switch+1*dw // 9
- t3;switch+2*dw // 10
- t3;switch+3*dw // 11
- t3;switch+4*dw // 12
- t3;switch+5*dw // 13
- t3;switch+6*dw // 14
- t3;switch+7*dw // 15
- end:
- wflip src+w, switch
- }
-
-
- // Complexity: 4
- def not hex {
- hex+dbit+0;
- hex+dbit+1;
- hex+dbit+2;
- hex+dbit+3;
- }
-
- // Complexity: 4n
- def not n, hex {
- rep(n, i) .not hex+i*dw
- }
-
-
- // Time Complexity: 4phi+16
- // Space Complexity: 4phi+96
- def or dst, src < .or.dst {
- ._.table_query dst, src, .or.dst
- }
-
- // Time Complexity: n(4phi+17)
- // Space Complexity: n(4phi+96)
- def or n, dst, src {
- rep(n, i) .or dst+i*dw, src+i*dw
- }
-
- ns or {
- // Space Complexity: 600
- def init @ switch, clean, end < .._.res, .._.ret > dst {
- ;end
- dst: ;.switch
-
- pad 256
- switch:
- rep(256, d) wflip_macro .._.res+w, (((d&0xf)|(d>>4))^(d&0xf))*dw, clean+d*dw
-
- clean:
- .._.clean_table .dst
- end:
- }
- }
-
-
- // Time Complexity: 4phi+16
- // Space Complexity: 4phi+96
- def and dst, src < .and.dst {
- ._.table_query dst, src, .and.dst
- }
-
- // Time Complexity: n(4phi+17)
- // Space Complexity: n(4phi+96)
- def and n, dst, src {
- rep(n, i) .and dst+i*dw, src+i*dw
- }
-
- ns and {
- // Space Complexity: 600
- def init @ switch, clean, end < .._.res, .._.ret > dst {
- ;end
- dst: ;.switch
-
- pad 256
- switch:
- rep(256, d) wflip_macro .._.res+w, (((d&0xf)&(d>>4))^(d&0xf))*dw, clean+d*dw
-
- clean:
- .._.clean_table .dst
- end:
- }
- }
-
-
- // Time Complexity: 2.13phi+2
- // Space Complexity: n(1.5phi+23) + 2phi+121 (+padding)
- // dst[n] += x.#on-bits
- def add_count_bits n, dst, x @ count_switch, do_add, add_switch, add4_switch, xor_switch, after_add, is_carry, should_inc, do_inc, clean {
- wflip x+w, count_switch, x
-
- pad 16
- count_switch:
- ;clean // 0
- ;do_add
- ;do_add
- dst+dbit+4;do_add
- ;do_add // 4
- dst+dbit+4;do_add
- dst+dbit+4;do_add
- dst+dbit+5;do_add
- ;do_add // 8
- dst+dbit+4;do_add
- dst+dbit+4;do_add
- dst+dbit+5;do_add
- dst+dbit+4;do_add // 12
- dst+dbit+5;do_add
- dst+dbit+5;do_add
- dst+dbit+5;count_switch+3*dw
-
- do_add:
- wflip dst+w, add_switch, dst
-
- pad 64
- add_switch:
- rep(16, d) fj 0, xor_switch+(d^(d+1))*dw
- rep(16, d) fj dst+dbit+4, xor_switch+(d^(d+2))*dw
- rep(16, d) fj dst+dbit+5, xor_switch+(d^(d+3))*dw
- rep(16, d) fj dst+dbit+5, add4_switch+d*dw
- add4_switch:
- rep(16, d) fj dst+dbit+4, xor_switch+(d^(d+4))*dw
-
- pad 32
- xor_switch:
- ._.clean_table 16, dst, after_add
- rep(16, i) fj is_carry+dbit, xor_switch+i*dw
-
- after_add:
- wflip dst+w, add_switch, is_carry
- is_carry: ;should_inc
- pad 2
- should_inc:
- ;clean
- is_carry+dbit;do_inc
- do_inc:
- .inc n-1, dst+dw
- ;clean
-
- clean:
- wflip x+w, count_switch
- }
-
- // Time Complexity: n(2.13phi+2)
- // Space Complexity: n(#n(0.4phi+6) + 2phi+121)
- def count_bits n, dst, x {
- .zero ((#(n*4))+3)/4, dst
- rep(n, i) .add_count_bits ((#(n*4))+3)/4, dst, x+i*dw
- }
-
-
- // Time Complexity: phi+1
- // Space Complexity: phi+28
- def shl_bit_once dst, next @ switch, xor_by, end {
- wflip dst+w, switch, dst
-
- pad 16
- switch:
- rep(16, i) fj i&8 ? next+dbit+0 : 0, xor_by+(i^((i<<1)&0xf))*dw
- xor_by:
- ._.clean_table 16, dst, end
-
- end:
- wflip dst+w, switch
- }
-
- // Time Complexity: n(phi+1)
- // Space Complexity: n(phi+28)
- def shl_bit n, dst {
- .shl_bit_once dst+(n-1)*dw, 0
- rep(n-1, i) .shl_bit_once dst+(n-2-i)*dw, dst+(n-1-i)*dw
- }
-
-
- // Time Complexity: phi+1
- // Space Complexity: phi+28
- def shr_bit_once dst, next @ switch, xor_by, end {
- wflip dst+w, switch, dst
-
- pad 16
- switch:
- rep(16, i) fj i&1 ? next+dbit+3 : 0, xor_by+(i^((i>>1)&0xf))*dw
- xor_by:
- ._.clean_table 16, dst, end
-
- end:
- wflip dst+w, switch
- }
-
- // Time Complexity: n(phi+1)
- // Space Complexity: n(phi+28)
- def shr_bit n, dst {
- .shr_bit_once dst, 0
- rep(n-1, i) .shr_bit_once dst+(i+1)*dw, dst+i*dw
- }
-
-
- // Time Complexity: n(phi+4)
- // Space Complexity: n(phi+42)
- // shift left by 4bits (1hex)
- def shl_hex n, dst {
- .zero dst+(n-1)*dw
- rep(n-1, i) .xor_zero dst+(n-1-i)*dw, dst+(n-2-i)*dw
- }
-
-
- // Time Complexity: n(phi+4)
- // Space Complexity: n(phi+42)
- // shift right by 4bits (1hex)
- def shr_hex n, dst {
- .zero dst
- rep(n-1, i) .xor_zero dst+i*dw, dst+(i+1)*dw
- }
-}
-
-
-
-// ---------- Arithmetical Macros
-// carry is both input and output, and is saved in the 8th bit in hex.{add/sub}.dst
-
-
-ns hex {
- // Time Complexity: phi
- // Space Complexity: 1.5phi+28
- def inc1 hex, carry0, carry1 @ switch, end {
- wflip hex+w, switch, hex
- pad 16
- switch:
- hex+dbit+0;end // 0
- hex+dbit+1;switch+0*dw // 1
- hex+dbit+0;end // 2
- hex+dbit+2;switch+1*dw // 3
- hex+dbit+0;end // 4
- hex+dbit+1;switch+0*dw // 5
- hex+dbit+0;end // 6
- hex+dbit+3;switch+3*dw // 7
- hex+dbit+0;end // 8
- hex+dbit+1;switch+0*dw // 9
- hex+dbit+0;end // 10
- hex+dbit+2;switch+1*dw // 11
- hex+dbit+0;end // 12
- hex+dbit+1;switch+0*dw // 13
- hex+dbit+0;end // 14
- hex+dbit+3; // 15
- hex+dbit+2;
- hex+dbit+1;
- hex+dbit+0;
- wflip hex+w, switch, carry1
- end:
- wflip hex+w, switch, carry0
- }
-
- // Time Complexity: 16/15*phi
- // Space Complexity: n(1.5phi+23)
- def inc n, hex @ end {
- rep(n, i) .inc.step hex+i*dw, end
- end:
- }
- ns inc {
- def step hex, end @ next {
- ..inc1 hex, end, next
- next:
- }
- }
-
-
- // Time Complexity: phi
- // Space Complexity: 1.5phi+28
- def dec1 hex, borrow0, borrow1 @ switch, borrow, end {
- wflip hex+w, switch, hex
- pad 16
- switch:
- hex+dbit+3;borrow // 0
- hex+dbit+0;end // 1
- hex+dbit+1;switch+1*dw // 2
- hex+dbit+0;end // 3
- hex+dbit+2;switch+2*dw // 4
- hex+dbit+0;end // 5
- hex+dbit+1;switch+1*dw // 6
- hex+dbit+0;end // 7
- hex+dbit+3;switch+4*dw // 8
- hex+dbit+0;end // 9
- hex+dbit+1;switch+1*dw // 10
- hex+dbit+0;end // 11
- hex+dbit+2;switch+2*dw // 12
- hex+dbit+0;end // 13
- hex+dbit+1;switch+1*dw // 14
- hex+dbit+0;end // 15
- borrow:
- hex+dbit+2;
- hex+dbit+1;
- hex+dbit+0;
- wflip hex+w, switch, borrow1
- end:
- wflip hex+w, switch, borrow0
- }
-
- // Time Complexity: n*phi
- // Space Complexity: n(1.5phi+23)
- def dec n, hex @ end {
- rep(n, i) .dec.step hex+i*dw, end
- end:
- }
- ns dec {
- def step hex, end @ next {
- ..dec1 hex, end, next
- next:
- }
- }
-
-
- // Time Complexity: 4n
- // Space Complexity: n(1.5phi+27)
- def neg n, hex {
- .not n, hex
- .inc n, hex
- }
-
-
- // Time Complexity: 4phi+17
- // Space Complexity: 4phi+96
- def add dst, src < .add.dst {
- ._.table_query dst, src, .add.dst
- }
-
- // Time Complexity: n(4phi+17)
- // Space Complexity: n(4phi+96)
- def add n, dst, src {
- .add.clear_carry
- rep(n, i) .add dst+i*dw, src+i*dw
- .add.clear_carry
- }
-
- ns add {
- // Time Complexity: 2phi+2
- // Space Complexity: 2phi+27
- def clear_carry @ ret < .._.ret, .dst, .._.res {
- wflip .._.ret+w, ret, .dst
- ret:
- wflip .._.ret+w, ret
- ..zero .._.res
- }
-
- // Time Complexity: 2phi+3
- // Space Complexity: 2.5phi+26
- def clear_carry c0, c1 @ ret < .._.ret, .dst, .._.res {
- wflip .._.ret+w, ret, .dst
- ret:
- wflip .._.ret+w, ret
- ..if0 .._.res, c0
- .._.res+dbit; c1
- }
-
- // Complexity: 1
- def not_carry < .dst {
- .dst+dbit+8;
- }
-
- // Time Complexity: 2phi+3
- // Space Complexity: 2phi+28
- def set_carry {
- .clear_carry
- .not_carry
- }
-
- // Space Complexity: 1800
- def init @ switch0, switch1, flip_carry, clean, end < .._.res, .._.ret > dst {
- ;end
- dst: ;.switch0
-
- pad 512
- switch0:
- rep(256, d) wflip_macro .._.res+w, ((((d&0xf)+(d>>4) )&0xf)^(d&0xf))*dw, (((d&0xf)+(d>>4) > 0xf) ? (flip_carry+d*dw) : (clean+d*dw))
- switch1:
- rep(256, d) wflip_macro .._.res+w, ((((d&0xf)+(d>>4)+1)&0xf)^(d&0xf))*dw, (((d&0xf)+(d>>4)+1 > 0xf) ? (clean+d*dw) : (flip_carry+d*dw))
-
- flip_carry:
- rep(256, i) fj .dst+dbit+8, clean+i*dw
- clean:
- .._.clean_table .dst
- end:
- }
- }
-
-
- // Time Complexity: 4phi+17
- // Space Complexity: 4phi+96
- def sub dst, src < .sub.dst {
- ._.table_query dst, src, .sub.dst
- }
-
- // Time Complexity: n(4phi+17)
- // Space Complexity: n(4phi+96)
- def sub n, dst, src {
- .sub.clear_carry
- rep(n, i) .sub dst+i*dw, src+i*dw
- .sub.clear_carry
- }
-
- ns sub {
- // Time Complexity: 2phi+14
- // Space Complexity: 2.5phi+30
- def clear_carry @ end {
- .clear_carry end, end
- end:
- }
-
- // Time Complexity: 2phi+14
- // Space Complexity: 2.5phi+30
- def clear_carry c0, c1 @ ret < .._.ret, .dst, .._.res {
- wflip .._.ret+w, ret, .dst
- ret:
- wflip .._.ret+w, ret
- ..if0 .._.res, c0
- .not_carry
- wflip .._.res+w, 0xf*dw, c1
- }
-
- // Complexity: 1
- def not_carry < .dst {
- .dst+dbit+8;
- }
-
- // Time Complexity: 2phi+15
- // Space Complexity: 2.5phi+31
- def set_carry {
- .clear_carry
- .not_carry
- }
-
- // Space Complexity: 1600
- def init @ switch0, switch1, flip_carry, clean, end < .._.res, .._.ret > dst {
- ;end
- dst: ;.switch0
-
- pad 512
- switch0:
- rep(256, d) wflip_macro .._.res+w, ((((d&0xf)-(d>>4) )&0xf)^(d&0xf))*dw, (((d&0xf)-(d>>4) < 0) ? (flip_carry+d*dw) : (clean+d*dw))
- switch1:
- rep(256, d) wflip_macro .._.res+w, ((((d&0xf)-(d>>4)-1)&0xf)^(d&0xf))*dw, (((d&0xf)-(d>>4)-1 < 0) ? (clean+d*dw) : (flip_carry+d*dw))
-
- flip_carry:
- rep(256, i) fj .dst+dbit+8, clean+i*dw
- clean:
- .._.clean_table .dst
- end:
- }
- }
-}
-
-
-
-// ---------- Memory Manipulation:
-
-
-ns hex {
-
- // Time Complexity: phi
- // Space Complexity: phi+27
- def zero x {
- .xor x, x
- }
-
- // Time Complexity: n*phi
- // Space Complexity: n*(phi+26)
- def zero n, x {
- rep (n, i) .zero x+i*dw
- }
-
- // Time Complexity: 2phi+1
- // Space Complexity: phi+54
- def mov dst, src @ end {
- comp_if1 dst==src, end
- .zero dst
- .xor dst, src
- end:
- }
-
- // Time Complexity: n*(2phi+1)
- // Space Complexity: n*(phi+52)
- def mov n, dst, src {
- rep(n, i) .mov dst+i*dw, src+i*dw
- }
-
- // Complexity: 4 (avg. 2. #on-bits)
- def xor_by hex, val {
- wflip hex+w, (val > 0xf ? 0xf : (val < 0 ? 0 : val)) * dw
- }
-
- // Complexity: 4n (#on-bits)
- def xor_by n, hex, val {
- rep(n, i) .xor_by hex+i*dw, (val>>(4*i))&0xf
- }
-
- // Time Complexity: phi+4
- // Space Complexity: phi+31
- def set hex, val {
- .zero hex
- .xor_by hex, val
- }
-
- def set n, hex, val {
- rep(n, i) .set hex+i*dw, (val>>(4*i))&0xf
- }
-
- // Time Complexity: 3phi
- // Space Complexity: 3phi+79
- def swap hex1, hex2 @ end {
- comp_if1 hex1==hex2, end
- .xor hex1, hex2
- .xor hex2, hex1
- .xor hex1, hex2
- end:
- }
-
- // Time Complexity: n*(3phi)
- // Space Complexity: n*(3phi+78)
- def swap n, hex1, hex2 {
- rep(n, i) .swap hex1+i*dw, hex2+i*dw
- }
-}
-
-
-
-// ---------- Conditional Jump
-
-
-ns hex {
- // Time Complexity: phi-1
- // Space Complexity: phi+15
- def if_flags hex, flags, l0, l1 @ switch, clean, return, finish {
- wflip hex+w, switch, hex
-
- pad 16
- switch:
- rep(16, i) fj (flags>>i)&1 ? return+dbit+0 : 0, clean
-
- clean:
- wflip hex+w, switch
- return: ;finish
- pad 2
- finish:
- ; l0
- return+dbit+0; l1
- }
-
- // Time Complexity: phi-1
- // Space Complexity: phi+15
- def if hex, l0, l1 {
- .if_flags hex, 0xfffe, l0, l1
- }
- def if0 hex, l0 @ l1 {
- .if hex, l0, l1
- l1:
- }
- def if1 hex, l1 @ l0 {
- .if hex, l0, l1
- l0:
- }
-
- // Time Complexity: n(phi-1)
- // Space Complexity: n(phi+15)
- def if n, hex, l0, l1 {
- rep(n-1, i) .if1 hex+i*dw, l1
- .if hex+(n-1)*dw, l0, l1
- }
- def if0 n, hex, l0 @ l1 {
- .if n, hex, l0, l1
- l1:
- }
- def if1 n, hex, l1 @ l0 {
- .if n, hex, l0, l1
- l0:
- }
-
-
- // Time Complexity: phi-1
- // Space Complexity: phi+15
- def sign n, x, neg, zpos {
- .if_flags x+(n-1)*dw, 0xff00, zpos, neg
- }
-
-
- // Time Complexity: 3phi+12
- // Space Complexity: 3phi+51
- def cmp a, b, lt, eq, gt @ ret, _eq, _gt, real_ret, __lt, __eq, __gt, second_xor < .cmp.dst, ._.ret {
- .xor .cmp.dst, a // 1
- ;second_xor
-
-
- pad 4
- ret: // 4
- wflip ._.ret+w, ret, real_ret // 5
- ._.ret+dbit ;_eq
- ._.ret+dbit+1;_gt
-
- _eq: real_ret+dbit ;ret // (4.5)
- _gt: real_ret+dbit+1;ret
-
- real_ret: // 6
- ;__lt
-
- pad 4
- __lt: ;lt // 7 (and last)
- __eq: real_ret+dbit ;eq
- __gt: real_ret+dbit+1;gt
-
-
- second_xor:
- .xor .cmp.dst+4, b // 2
- wflip ._.ret+w, ret, .cmp.dst // 3
- }
-
- def cmp n, a, b, lt, eq, gt {
- rep(n-1, i) .cmp.cmp_eq_next a+(n-1-i)*dw, b+(n-1-i)*dw, lt, gt
- .cmp a, b, lt, eq, gt
- }
-
- ns cmp {
- def cmp_eq_next a, b, lt, gt @ eq {
- ..cmp a, b, lt, eq, gt
- eq:
- }
-
- // Space Complexity: 500
- def init @ switch, clean, end < .._.ret > dst {
- ;end
- dst: ;.switch
-
- pad 256
- switch:
- rep(256, d) fj ((d&0xf) > (d>>4)) ? .._.ret+dbit+1 : (((d&0xf) == (d>>4)) ? .._.ret+dbit : 0), clean+d*dw
-
- clean:
- .._.clean_table .dst
- end:
- }
- }
-}
-
-
-ns hex {
- def init {
- ._.init
- }
-
- ns _ {
- // Space Complexity: 6700
- def init @ end > ret, res {
- ;end
- ret: ;0
- res: hex
- ..cmp.init // 1600
- ..add.init // 1800
- ..sub.init // 500
- ..or.init // 600
- ..and.init // 600
- ..mul.init // 1600
- end:
- }
-
- // n must be a power of 2
- def clean_table n, dst, ret @ clean {
- clean:
- rep(n, d) fj d==0?0: (dst+dbit+(#d)-1), (d==((1<<(#d))>>1)) ? ret : clean+(d^((1<<(#d))>>1))*dw
- }
-
- // Space Complexity: 256
- def clean_table dst, ret {
- .clean_table 256, dst, ret
- }
-
- // Space Complexity: 256
- def clean_table dst < .ret {
- .clean_table dst, .ret
- }
-
- def table_query dst, src, dst_switch @ return < .ret, .res {
- ..xor dst_switch , dst
- ..xor dst_switch+4, src
- wflip .ret+w, return, dst_switch
- return:
- wflip .ret+w ,return
- ..xor_zero dst, .res
- }
- }
-}
-
-
-
-// ---------- IO
-
-
-ns hex {
- def output hex @ switch, print_0, print_2, print_4, print_6, print_8, print_a, print_c, print_e, end < IO {
- wflip hex+w, switch, hex
- pad 16
- switch:
- IO+0;print_0 // 0
- IO+1;print_0 // 1
- IO+0;print_2 // 2
- IO+1;print_2 // 3
- IO+0;print_4 // 4
- IO+1;print_4 // 5
- IO+0;print_6 // 6
- IO+1;print_6 // 7
- IO+0;print_8 // 8
- IO+1;print_8 // 9
- IO+0;print_a // 4
- IO+1;print_a // 5
- IO+0;print_c // 6
- IO+1;print_c // 7
- IO+0;print_e // 8
- IO+1;print_e // 9
-
-
- print_0:
- IO+0;
- IO+0;
- IO+0;end
- print_2:
- IO+1;print_0+1*dw
- print_4:
- IO+0;
- IO+1;print_0+2*dw
- print_6:
- IO+1;print_4+1*dw
- print_8:
- IO+0;
- IO+0;
- IO+1;end
- print_a:
- IO+1;print_8+1*dw
- print_c:
- IO+0;
- IO+1;print_8+2*dw
- print_e:
- IO+1;print_c+1*dw
-
- end:
- wflip hex+w, switch
- }
-
-
- def print x {
- .output x
- .output x+dw
- }
-
- def print n, x {
- rep(n, i) .print x+2*i*dw
- }
-
-
- // Time Complexity: phi+4
- // Space Complexity: phi+51 phi-4+15+16+24
- def print_as_digit hex, big_flag @ switch, print_0, print_2, print_4, print_6, print_8, print_a, print_b, print_d, print_f, end < IO {
- wflip hex+w, switch, hex
- pad 16
- switch:
- IO+0;print_0 // 0
- IO+1;print_0 // 1
- IO+0;print_2 // 2
- IO+1;print_2 // 3
- IO+0;print_4 // 4
- IO+1;print_4 // 5
- IO+0;print_6 // 6
- IO+1;print_6 // 7
- IO+0;print_8 // 8
- IO+1;print_8 // 9
-
- IO+1;print_a // a
- IO+0;print_b // b
- IO+1;print_b // c
- IO+0;print_d // d
- IO+1;print_d // e
- IO+0;print_f // f
-
- print_0:
- IO+0;
- IO+0;
- IO+0;
- IO+1;
- IO+1;
- IO+0;
- IO+0;end
- print_2:
- IO+1;print_0+1*dw
- print_4:
- IO+0;
- IO+1;print_0+2*dw
- print_6:
- IO+1;print_4+1*dw
- print_8:
- IO+0;
- IO+0;
- IO+1;print_0+3*dw
- print_a:
- IO+0;
- IO+0;
- IO+0;
- IO+0;
- IO+(big_flag ? 0 : 1);
- IO+1;print_0+6*dw
- print_b:
- IO+1;print_a+1*dw
- print_d:
- IO+0;
- IO+1;print_a+2*dw
- print_f:
- IO+1;print_d+1*dw
-
- end:
- wflip hex+w, switch
- }
-
- // Time Complexity: phi+4
- // Space Complexity: phi+42
- def print_as_digit n, x, big_flag {
- rep (n, i) .print_as_digit x+(n-1-i)*dw, big_flag
- }
-
- // Time Complexity: n(2phi+8)
- // Space Complexity: n(3.5phi+72)
- def print_uint n, x, x_prefix, big_flag @ after_prefix, printed_something, end {
- bit.zero printed_something
- comp_if0 x_prefix, after_prefix
- output "0x"
-
- after_prefix:
- rep(n, i) .print_uint.print_digit x+(n-1-i)*dw, printed_something, big_flag
- bit.if1 printed_something, end
- output '0'
- ;end
-
- printed_something: bit
- end:
- }
- ns print_uint {
- // Time Complexity: 2phi+8 (once: 3phi+9)
- // Space Complexity: 3.5phi+72
- def print_digit hex, printed_something, big_flag @ print, end {
- bit.if1 printed_something, print
- ..if0 hex, end
- bit.not printed_something
- print:
- ..print_as_digit hex, big_flag
- end:
- }
- }
-
- // Time Complexity: n(2phi+16)
- // Space Complexity: n(6.5phi+126)
- def print_int n, x, x_prefix, big_flag @ do_neg, print, neg, end {
- bit.zero neg
- .if_flags x+(n-1)*dw, 0xff00, print, do_neg
- do_neg:
- bit.not neg
- .neg n, x
- output '-'
- print:
- .print_uint n, x, x_prefix, big_flag
- bit.if0 neg, end
- .neg n, x
- ;end
-
- neg: bit
- end:
- }
-
- // Time Complexity: 2phi+7
- // Space Complexity: 2phi+39
- def input_hex hex @ flip0, flip1, flip2, flip3, end < IO {
- .zero hex
- wflip IO+w, flip0, IO
-
- pad 8
- flip0:
- IO+dbit+1;IO
- hex+dbit+0;flip0
- flip1:
- IO+dbit+2;IO
- hex+dbit+1;flip1
- flip3:
- wflip IO+w, flip3, end
- hex+dbit+3;flip3
- flip2:
- IO+dbit+1;IO
- hex+dbit+2;flip2
- end:
- }
-
- // Time Complexity: 4phi+14
- // Space Complexity: 4phi+70
- def input x {
- .input_hex x
- .input_hex x+dw
- }
-
- // Time Complexity: n(4phi+14)
- // Space Complexity: n(4phi+70)
- def input n, x {
- rep(n, i) .input x+2*i*dw
- }
-
-
- // Time Complexity: 6phi+14
- // Space Complexity: 9.5phi+168
- def input_as_hex hex, error @ try_dec, do_dec, do_hex, switch, finish_hex, upper, end {
- .input_hex hex
- .input_hex upper
- .if_flags upper, (1<<4)|(1<<6), try_dec, do_hex
- try_dec:
- .if_flags upper, (1<<3), error, do_dec
-
- do_dec:
- .if_flags hex, (1<<10)-1, error, end
-
- do_hex:
- wflip hex+w, switch, hex
-
- finish_hex:
- hex+dbit+3;
- wflip hex+w, switch, end
-
- pad 16
- switch:
- wflip hex+w, switch, error // 0
- hex+dbit+1;switch+2*dw // 1
- hex+dbit+0;finish_hex // 2
- hex+dbit+2;switch+1*dw // 3
- hex+dbit+0;finish_hex // 4
- hex+dbit+1;switch+2*dw // 5
- hex+dbit+0;finish_hex // 6
- ;switch // 7
- ;switch
- ;switch
- ;switch
- ;switch
- ;switch
- ;switch
- ;switch
- ;switch
-
- upper: hex
- end:
- }
-}
diff --git a/stl/iolib.fj b/stl/iolib.fj
deleted file mode 100644
index 67fd3f0..0000000
--- a/stl/iolib.fj
+++ /dev/null
@@ -1,498 +0,0 @@
-// Every line is (Input/Output of) bananas!
-// Implementation of input/output and casting operations
-
-// should be assembled with both bitlib.fj and runlib.fj files
-// This file is independent of the bit-width, and uses the consts defined at runlib.fj
-
-// Everything after // is ignored, and every whitespace is ignored (besides new line)
-// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next)
-
-// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op.
-// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity
-
-// The complexities are not updated in this file (should be lower/faster).
-
-
-
-// ---------- String:
-
-
-ns bit {
- def str str {
- .vec (((#str)+15)>>3)<<3, str
- }
-}
-
-
-
-// ---------- Input:
-
-
-
-ns bit {
- // Complexity: 2phi+4
- def input_bit dst < IO {
- .zero dst
- .xor dst, IO
- }
-
-
- // Complexity: 16phi+32
- def input dst {
- rep(8, i) .input_bit dst+i*dw
- }
-
-
- // Complexity: n(16phi+32)
- def input n, dst {
- rep(n, i) .input dst+8*(n-1-i)*dw
- }
-}
-
-
-
-// ---------- Output:
-
-
-def output_bit bit < IO {
- IO + (bit ? 1 : 0);
-}
-
-// Complexity: 8
-def output_char ascii {
- rep(8, i) output_bit (ascii>>i)&1
-}
-
-def output str {
- rep(((#str)+7)>>3, i) output_char (str>>(8*i))&0xff
-}
-
-
-ns bit {
- // Complexity phi+5
- def output x @ label_ptr, base_jump_label, end < IO {
- .xor label_ptr, x
- label_ptr:
- ;base_jump_label
- pad 2
- base_jump_label:
- IO+0;end
- IO+1;
- .not label_ptr
- end:
- }
-
-
- // Complexity 8phi+40
- def print x {
- rep(8, i) .output x+i*dw
- }
-
- // Complexity n(8phi+40)
- def print n, x {
- rep(n, i) .print x+8*i*dw
- }
-
-
-
- // print string of max size n.
- // Complexity min(n, len+1)*(16phi+72)
- def print_str n, x @ end {
- rep(n, i) ._.print_str_one_char x+8*i*dw, end
- end:
- }
- ns _ {
- def print_str_one_char char, end {
- ..if0 8, char, end
- ..print char
- }
- }
-
-
- def print_as_digit x {
- .output x
- rep(7, i) output_bit ('0'>>(i+1)) & 1
- }
-
- def print_as_digit n, x {
- rep(n, i) .print_as_digit x+(n-1-i)*dw
- }
-}
-
-
-// ---------- Casting to ascii:
-
-
-ns bit {
- // Complexity 9phi+20
- def bin2ascii ascii, bin {
- .zero 8, ascii
- .not 2, ascii + 4*dw // ascii = 0x30
- .xor ascii, bin
- }
-
-
- // Complexity 12phi+26
- def dec2ascii ascii, dec {
- .zero 8, ascii
- .not 2, ascii + 4*dw // ascii = 0x30
- .xor 4, ascii, dec
- }
-
-
- // Complexity 25phi+92
- def hex2ascii ascii, hex @ dec_label, hex_label, nine4, end {
- .zero 8, ascii
- .xor 3, ascii, hex
- hex;
- .cmp 4, hex, nine4, dec_label, dec_label, hex_label
- dec_label:
- .xor ascii+3*dw, hex+3*dw
- .not 2, ascii + 4*dw // ascii = 0x30
- ;end
- hex_label:
- .dec 3, ascii // A-F is now 1-6
- .not ascii + 6*dw // ascii = 0x40
- ;end
- nine4:
- .vec 4, 9
- end:
- }
-}
-
-
-
-// ---------- Casting from ascii:
-
-
-ns bit {
-// Complexity: 17phi+63
- def ascii2bin error, bin, ascii @ half_bin, return_error, good, end {
- .zero error
- .zero bin
-
- .cmp 7, ascii+dw, half_bin, return_error, good, return_error
-
- return_error:
- .not error
- ;end
-
- good:
- .xor bin, ascii
- ;end
-
- half_bin:
- .vec 7, 0x30>>1
-
- end:
- }
-
-
- // Complexity: 25phi+83
- def ascii2dec error, dec, ascii @ half_dec, return_error, first_good, good, nine4, end {
- .zero error
- .zero 4, dec
-
- .cmp 4, ascii+4*dw, half_dec, return_error, first_good, return_error
- first_good:
- .cmp 4, ascii, nine4, good, good, return_error
-
- return_error:
- .not error
- ;end
-
- good:
- .xor 4, dec, ascii
- ;end
-
- half_dec:
- .vec 4, 0x30>>4
- nine4:
- .vec 4, 9
- end:
- }
-
-
- // Complexity: 48phi+184
- def ascii2hex error, hex, ascii @ half_dec, half_big_hex, half_small_hex, return_error, try_big_hex, try_small_hex, dec_first_good, hex_first_good, dec_good, hex_good, nine4, two3, end {
- .zero error
- .zero 4, hex
-
- .cmp 4, ascii+4*dw, half_dec, try_big_hex, dec_first_good, try_big_hex
-
- try_big_hex:
- .cmp 5, ascii+3*dw, half_big_hex, try_small_hex, hex_first_good, try_small_hex
- try_small_hex:
- .cmp 5, ascii+3*dw, half_small_hex, return_error, hex_first_good, return_error
-
- dec_first_good:
- .cmp 4, ascii, nine4, dec_good, dec_good, return_error
- dec_good:
- .xor 4, hex, ascii
- ;end
-
- hex_first_good:
- .inc 3, ascii
- .cmp 3, ascii, two3, return_error, hex_good, hex_good
- hex_good:
- .xor 3, hex, ascii
- .not hex+3*dw
- ;end
-
- return_error:
- .not error
- ;end
-
- half_dec:
- .vec 4, 0x30>>4
- half_big_hex:
- .vec 5, 0x40>>3
- half_small_hex:
- .vec 5, 0x60>>3
- nine4:
- .vec 4, 9
- two3:
- .vec 3, 2
- end:
- }
-}
-
-
-
-// ---------- Casting from bit
-
-
-def bit2hex hex, bit {
- hex.zero hex
- bit.xor hex, bit
-}
-
-def bit2hex n, hex, bit {
- hex.zero (n+3)/4, hex
- rep(n, i) bit.exact_xor hex+(i/4)*dw+dbit+(i%4), bit+i*dw
-}
-
-
-
-// ---------- Casting from hex
-
-
-def hex2bit bit, hex {
- bit.zero 4, bit
- hex.exact_xor bit+3*dw+dbit, bit+2*dw+dbit, bit+dw+dbit, bit+dbit, hex
-}
-
-def hex2bit n, bit, hex {
- rep(n, i) hex2bit bit+4*i*dw, hex+i*dw
-}
-
-
-
-// ---------- Print Hex Int
-
-
-ns bit {
- // Assumes n divides by 4.
- // Complexity: n(10phi+39)
- def print_hex_uint n, x, print_x @ after_print_x, printed_flag, end {
- comp_if0 print_x, after_print_x
- output '0'
- output 'x'
- after_print_x:
-
- .zero printed_flag
- rep(n/4, i) ._.print_hex_uint_char x+(n/4-1-i)*4*dw, printed_flag
-
- .if1 printed_flag, end
- output '0'
- ;end
-
- printed_flag:
- bit
- end:
- }
- //Comp: 39phi+155
- ns _ {
- def print_hex_uint_char hex, printed_flag @ continue, ascii, end {
- ..if1 4, hex, continue
- ..if1 printed_flag, continue
- ;end
-
- continue:
- ..one printed_flag
- ..hex2ascii ascii, hex
- ..print ascii
- ;end
-
- ascii:
- ..vec 8
- end:
- }
- }
-
-
-
- def print_hex_int n, x, print_x @ do_print {
- .if0 x+(n-1)*dw, do_print
- output '-'
- .neg n, x
- do_print:
- .print_hex_uint n, x, print_x
- }
-}
-
-
-
-// ---------- Print Dec Int
-
-
-ns bit {
-//// Complexity: n^2(8phi+29) + nb(17phi+74)
- //// Space Complexity: ~O(130n^2)
- //def print_dec_uint n, x @ printed_flag, curr_ten, tens, val, r, end {
- // .zero printed_flag
- //
- // .zero n+4, curr_ten
- // .not curr_ten
- //
- // .zero n+7, val
- // .xor n, val, x
- //
- // rep(n*28/93+2, i) ._.print_dec_uint_put_pow_ten n+4, tens+i*(n+4)*dw, curr_ten, val
- //
- // rep(n*28/93+2, i) ._.print_dec_uint_char n+4, val, tens+(n*28/93+2-1-i)*(n+4)*dw, printed_flag
- //
- // .if1 printed_flag, end
- // output '0'
- // ;end
- //
- // printed_flag:
- // bit
- // curr_ten:
- // .vec n+4
- // tens:
- // .vec (n*28/93+2)*(n+4) // 28/93 is very close from above to log10(2)
- // val:
- // .vec n+7
- // r:
- // .vec n
- // end:
- //}
- //ns _ {
- // //Comp: n(18phi+60)
- // def print_dec_uint_put_pow_ten n, dst, curr_ten, top @ put, end {
- // .zero n, dst
- // .cmp n, curr_ten, top, put, put, end
- // put:
- // .xor n, dst, curr_ten
- // .mul10 n, curr_ten
- // end:
- // }
- // //Comp: n(9phi+36) + 7b*(8phi+35)
- // def print_dec_uint_char n, v, curr_ten, printed_flag @ do_print, dec, ascii, end {
- // .if0 n, curr_ten, end
- // .zero 4, dec
- // rep(4, i) ._.print_dec_uint_sub_curr_ten n, v, curr_ten, dec, 3-i
- //
- // .if1 4, dec, do_print
- // .if1 printed_flag, do_print
- // ;end
- //
- // do_print:
- // .one printed_flag
- // dec2ascii ascii, dec
- // print ascii
- // ;end
- //
- // dec:
- // .vec 4
- // ascii:
- // .vec 8
- // end:
- // }
- // //Comp: worst: n(2phi+8) + 3.3b*(8phi+35), avg: n(2phi+8) + 1.7b*(8phi+35)
- // def print_dec_uint_sub_curr_ten n, v, curr_ten, dec, index @ do_sub, end {
- // .cmp n, v+index*dw, curr_ten, end, do_sub, do_sub
- // do_sub:
- // .sub n, v+index*dw, curr_ten
- // .not dec+index*dw
- // end:
- // }
- //}
- //
- //
- //
- //def print_dec_int n, x @ do_print {
- // .if0 x+(n-1)*dw, do_print
- // output '-'
- // .neg n, x
- // do_print:
- // .print_dec_uint n, x
- //}
-
-
- // Time Complexity: n^2(2phi+8)
- // Space Complexity: n(14phi+51)
- def print_dec_uint n, x @ start_printing, xor, end_xor, dst, src, print_buffer, print_buffer_flag, div10, zero_flag, ret_reg, end {
- .mov n, src, x
- .zero zero_flag
-
- // the next three takes ~ (28/93n)*(phi+2 + 11phi+27 + 5phi+28) = n(5.12phi+17.17) < n(6phi+17.5) space
- .zero n*28/93+1, print_buffer_flag // all chars are off
- rep(n*28/93+1, i) ._.print_dec_uint.div10_step div10, xor, ret_reg, src, print_buffer+i*4*dw, print_buffer_flag+i*dw, zero_flag, start_printing
- start_printing:
- rep(n*28/93+1, i) ._.print_dec_uint.print_char print_buffer+(n*28/93-i)*4*dw, print_buffer_flag+(n*28/93-i)*dw
-
- ;end
-
- div10:
- .div10 n, dst, src
- fret ret_reg
- xor:
- .xor n, src, dst // TODO: can double_exact_xor and zero dst too - so to save the "zero n dst" inside the next div10 (save ~n/3(phi+1))
- .if1 n, dst, end_xor
- .not zero_flag
- end_xor:
- fret ret_reg
-
- // takes n(2+28/93*5) = 3.5n space
- dst: .vec n
- src: .vec n
- print_buffer: .vec (n*28/93+1)*4
- print_buffer_flag: .vec n*28/93+1
- zero_flag: bit
- ret_reg: 0;0
- end:
- }
- ns _ {
- ns print_dec_uint {
- // Time Complexity: n(6phi+25)
- // Space Complexity: 11phi+27
- def div10_step div10, xor, ret_reg, src, ascii_res, char_flag, zero_flag, start_printing {
- ...if1 zero_flag, start_printing
- fcall div10, ret_reg
- ...zero 4, ascii_res
- rep(4, i) ...double_exact_xor ascii_res+dbit+i*dw, src+dbit+i*dw, src+i*dw
- ...not char_flag
- fcall xor, ret_reg
- }
-
- // Complexity: 5phi+28
- def print_char ascii4, char_flag @ end {
- ...if0 char_flag, end
- rep(4, i) ...output ascii4+i*dw
- rep(4, i) output_bit (0x3>>i)&1
- end:
- }
- }
- }
-
-
- def print_dec_int n, x @ do_print {
- .if0 x+(n-1)*dw, do_print
- output '-'
- .neg n, x
- do_print:
- .print_dec_uint n, x
- }
-}
diff --git a/stl/mathlib.fj b/stl/mathlib.fj
index fa3bbc0..1c534cf 100644
--- a/stl/mathlib.fj
+++ b/stl/mathlib.fj
@@ -1,7 +1,10 @@
+// TODO refactor this file into: bit/mul.fj, bit/div.fj, hex/mul.fj, hex/div.fj, and update complexities
+
+
// Every line is (advanced math) bananas!
// Implementation of advanced math operation over bit-vectors
-// should be assembled with both bitlib.fj and runlib.fj files
+// should be assembled with both bit/ and runlib.fj files
// This file is independent of the bit-width, and uses the consts defined at runlib.fj
// Everything after // is ignored, and every whitespace is ignored (besides new line)
@@ -18,7 +21,8 @@
ns bit {
- // Complexity n(14phi+48)
+ // Complexity n(14@+10)
+ // x[:n] *= 10
def mul10 n, x @ twice, end {
.shl n, x
.mov n, twice, x
@@ -32,42 +36,44 @@ ns bit {
}
- // dst, src = src/10, src%10.
- // Complexity: n(5phi+23)
+ // Complexity: n(5@+11)
+ // dst[:n], src[:n] = src[:n] / 10, src[:n] % 10.
def div10 n, dst, src @ zero, end {
.zero n, dst
._.cmp_sub_10 zero, src+(n-4)*dw, dst+(n-4)*dw
rep(n-4, i) ._.cmp_sub_10 src+(n-1-i)*dw, src+(n-5-i)*dw, dst+(n-5-i)*dw
;end
- zero: bit 0
+ zero: .bit 0
end:
}
ns _ {
- // if (val > 10) { val-=10; res=!res; }, (for val4:val[3,2,1,0] of length 5, and val <= 18).
- // Complexity: 4phi+21
- def cmp_sub_10 val4, val, res @ yes, no, _1xxxx, _1xx0x, _1xx1x, _01x1x {
+ // Complexity: 4@+12
+ // if (val > 10) {
+ // val -= 10;
+ // res = !res;
+ // }
+ // for val4:val[3,2,1,0] of length 5, and Assumes val <= 19.
+ // This macro is getting called on consecutive 5-bits, shifting the 5-bit-frame 1 bit right at a time.
+ def cmp_sub_10 val4, val, res @ yes, no, _1xxxx, _1xx0x, _1xx1x, _01x1x, _0110x {
..if1 val4, _1xxxx
..if0 val+3*dw, no
..if1 val+ dw, _01x1x
..if0 val+2*dw, no
+ _0110x:
..not val+2*dw
- ..not val+3*dw
- ;yes
+ val+3*dw+dbit; yes
_01x1x:
- ..not val+3*dw
- ;yes
+ val+3*dw+dbit; yes
_1xxxx:
..not val4
..if val+dw, _1xx0x, _1xx1x
_1xx0x:
- ..not val+2*dw
- ;yes
+ val+2*dw+dbit; yes
_1xx1x:
- ..not val+3*dw
- ;yes
+ val+3*dw+dbit; yes
yes:
..not val+dw
@@ -134,6 +140,8 @@ ns hex {
// Time Complexity: 5phi+32
// Space Complexity: 4phi+96
// .mul.add_carry_dst : res += x * .mul.dst + .mul.add_carry_dst
+ //
+ // @requires hex.or.init (or hex.init)
def add_mul res, x @ ret < .mul.dst, .add.dst, .mul.ret, ._.res {
.xor .mul.dst+4, x
.xor .add.dst, res
@@ -146,6 +154,8 @@ ns hex {
// Time Complexity: n(5phi+32)
// Space Complexity: n(4phi+96)
// res[n] += a[n] * b[1]
+ //
+ // @requires hex.or.init (or hex.init)
def add_mul n, res, a, b < .mul.dst {
.mul.clear_carry
.xor .mul.dst, b
@@ -158,6 +168,8 @@ ns hex {
// (for n==b/2): n^2(5.5phi+24)
// Space Complexity: n(#n(0.75phi+12) + 18.5phi+636)
// res[n] = a[n] * b[n]
+ //
+ // @requires hex.or.init (or hex.init)
def mul n, res, a, b @ a_less_1bits, b_less_1bits, loop, after_add, dst, src, a_1bits, b_1bits, end {
.zero n, dst
.zero n, src
@@ -204,8 +216,13 @@ ns hex {
wflip .ret+w, return
}
- // Space Complexity: 1600
- def init @ add_res, after_add, switch_small_table, add_carry_small_table, set_carry_small_table, clean_small_table, switch, set_carry_0, set_carry_1, clean, add_carry, clean_add, clean_carry, end < ..add.dst, .._.ret > ret, dst, add_carry_dst {
+ // Space Complexity: 1616+@
+ // @output-param ret: ... TODO document the output params
+ // @output-param dst: ...
+ // @output-param add_carry_dst: ...
+ def init @ add_res, after_add, end, switch_small_table, add_carry_small_table, set_carry_small_table, \
+ clean_small_table, switch, set_carry_0, set_carry_1, clean, add_carry, clean_add, clean_carry \
+ < ..add.dst, .._.ret > ret, dst, add_carry_dst {
// general progression (after jumping to hex.mul.dst with value d):
// dst -> switch+d (set lower4 mul result in add_carry_dst+4) (5)
// add_carry_dst -> add_carry+? (set add result in hex.add.dst +4. sets dst to set_carry_{0/1}. sets add_carry_dst to clean_add) (6)
@@ -233,33 +250,47 @@ ns hex {
pad 16 // not really needed
switch_small_table:
- rep(16, d) fj (d==0)?0: (.add_carry_dst+dbit+(#d)+3), (d==((1<<(#d))>>1)) ? .add_carry_dst : switch_small_table +(d^((1<<(#d))>>1))*dw
+ rep(16, d) stl.fj \
+ (d==0) ? 0 : (.add_carry_dst + dbit + (#d) + 3), \
+ (d==((1<<(#d))>>1)) ? .add_carry_dst : switch_small_table + (d^((1<<(#d)) >> 1))*dw
set_carry_small_table:
- rep(16, d) fj (d==0)?0: (.add_carry_dst+dbit+(#d)-1), (d==((1<<(#d))>>1)) ? add_res : set_carry_small_table+(d^((1<<(#d))>>1))*dw
+ rep(16, d) stl.fj \
+ (d==0) ? 0 : (.add_carry_dst+dbit+(#d)-1), \
+ (d==((1<<(#d))>>1)) ? add_res : set_carry_small_table + (d^((1<<(#d)) >> 1))*dw
add_carry_small_table:
- rep(16, d) fj (d==0) ? .add_carry_dst+dbit+8 : (..add.dst+dbit+(#d)+3), (d==0) ? .add_carry_dst : add_carry_small_table+(d^((1<<(#d))>>1))*dw
+ rep(16, d) stl.fj \
+ (d==0) ? .add_carry_dst+dbit+8 : (..add.dst+dbit+(#d)+3), \
+ (d==0) ? .add_carry_dst : add_carry_small_table+(d^((1<<(#d))>>1))*dw
clean_small_table:
- rep(16, d) fj (d==0) ? .dst+dbit+9 : ( .dst+dbit+(#d)+3), (d==0) ? .ret : clean_small_table +(d^((1<<(#d))>>1))*dw
+ rep(16, d) stl.fj \
+ (d==0) ? .dst+dbit+9 : (.dst+dbit+(#d)+3), \
+ (d==0) ? .ret : clean_small_table + (d^((1<<(#d)) >> 1))*dw
pad 1024
switch:
- rep(256, d) fj 0, switch_small_table + (((d&0xf)*(d>>4)) & 0xf) * dw
+ rep(256, d) stl.fj 0, switch_small_table + (((d&0xf)*(d>>4)) & 0xf) * dw
set_carry_0:
- rep(256, d) fj .dst+dbit+9, set_carry_small_table + (((d&0xf)*(d>>4)) >> 4) * dw
+ rep(256, d) stl.fj .dst+dbit+9, set_carry_small_table + (((d&0xf)*(d>>4)) >> 4) * dw
set_carry_1:
- rep(256, d) fj .dst+dbit+8, set_carry_small_table + ((((d&0xf)*(d>>4)) >> 4)+1) * dw
+ rep(256, d) stl.fj .dst+dbit+8, set_carry_small_table + ((((d&0xf)*(d>>4)) >> 4)+1) * dw
clean:
- rep(256, d) fj .dst+dbit+8, clean_small_table + (d>>4) * dw
+ rep(256, d) stl.fj .dst+dbit+8, clean_small_table + (d>>4) * dw
// needs to be 1024-padded
add_carry:
- rep(256, d) fj .dst+dbit + (((d&0xf)+(d>>4) > 0xf) ? 9 : 8), add_carry_small_table + (((d&0xf)+(d>>4)) & 0xf) * dw
+ rep(256, d) stl.fj \
+ .dst+dbit + (((d&0xf)+(d>>4) > 0xf) ? 9 : 8), \
+ add_carry_small_table + (((d&0xf)+(d>>4)) & 0xf) * dw
clean_add:
- rep(256, d) fj (d==0) ? .add_carry_dst+dbit+8 : (.add_carry_dst+dbit+(#d)-1), (d==0) ? .dst : clean_add +(d^((1<<(#d))>>1))*dw
+ rep(256, d) stl.fj \
+ (d==0) ? .add_carry_dst+dbit+8 : (.add_carry_dst+dbit+(#d)-1), \
+ (d==0) ? .dst : clean_add +(d^((1<<(#d))>>1))*dw
clean_carry:
- rep( 16, d) fj (d==0) ? .add_carry_dst+dbit+9 : (.add_carry_dst+dbit+(#d)-1), (d==0) ? .dst : clean_carry+(d^((1<<(#d))>>1))*dw
+ rep( 16, d) stl.fj \
+ (d==0) ? .add_carry_dst+dbit+9 : (.add_carry_dst+dbit+(#d)-1), \
+ (d==0) ? .dst : clean_carry+(d^((1<<(#d))>>1))*dw
end:
@@ -300,11 +331,11 @@ ns bit {
;end
negative_a:
- bit
+ .bit
negative_b:
- bit
+ .bit
one_negative:
- bit
+ .bit
end:
}
@@ -316,7 +347,7 @@ ns bit {
.zero 2*n, R
.zero n, Q
- rep(n, i) _.div_step n, a+(n-1-i)*dw, b, R+(n-1-i)*dw, Q+(n-1-i)*dw
+ rep(n, i) _.div_step n, a+(n-1-i)*dw, b, R+(n-1-i)*dw, Q+(n-1-i)*dw
.mov n, r, R
.mov n, q, Q
@@ -368,11 +399,11 @@ ns bit {
;end
negative_a:
- bit
+ .bit
negative_b:
- bit
+ .bit
one_negative:
- bit
+ .bit
end:
}
@@ -422,7 +453,8 @@ ns bit {
ns hex {
// TODO - hex.div fails tests. for example, 0xc3 / 0xe fails.
- def div n, nb, q, _r, _a, _b, div0 @ loop, after_loop, do_cmp_sub_func, do_sub, jump_to_flip, flip_op, r, b, a, i, ret, end {
+ def div n, nb, q, _r, _a, _b, div0 @ loop, after_loop, do_cmp_sub_func, do_sub, jump_to_flip, flip_op, \
+ r, b, a, i, ret, end {
.if0 nb, _b, div0
.zero q
@@ -439,13 +471,13 @@ ns hex {
.shl_hex n, r
.xor r, a+(n-1)*dw
- fcall do_cmp_sub_func, ret
+ stl.fcall do_cmp_sub_func, ret
jump_to_flip+dbit+0;
- fcall do_cmp_sub_func, ret
+ stl.fcall do_cmp_sub_func, ret
jump_to_flip+dbit+1;
- fcall do_cmp_sub_func, ret
+ stl.fcall do_cmp_sub_func, ret
jump_to_flip+dbit+0;
- fcall do_cmp_sub_func, ret
+ stl.fcall do_cmp_sub_func, ret
jump_to_flip+dbit+1;
.shl_hex n, a
diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj
index 414e647..b10446a 100644
--- a/stl/ptrlib.fj
+++ b/stl/ptrlib.fj
@@ -1,298 +1,87 @@
-// Every line is (pointing) bananas!
-// Implementation of pointers (variables which represents a memory-place), stack and functions.
-
-// should be assembled with both bitlib.fj and runlib.fj files
-// This file is independent of the bit-width, and uses the consts defined at runlib.fj
-
-// Everything after // is ignored, and every whitespace is ignored (besides new line)
-// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next)
-
-// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op.
-// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity
-
-// The complexities are not updated in this file (should be lower/faster).
-
-
-
-// TODO read 4-bit values (good for bit/hex/dec) values from pointers.
-// it might be cool to implement hex pointers if it can improve speed easily, but it's not needed.
-
-
-
// ---------- Init
-ns bit {
+ns stl {
+ // Complexity: 2.5w+4
def ptr_init {
- ._.ptr_init
- }
-
- ns _ {
- def ptr_init > to_flip, to_jump, to_flip_var, to_flip_return_var, to_jump_var {
- pad 1
- to_flip:
- 0;0
- to_jump:
- ;0
-
- to_flip_var:
- bit.vec w, 0
- to_flip_return_var:
- bit.vec w, 0
- to_jump_var:
- bit.vec w, 0
- }
+ bit.pointers.ptr_init
+ hex.pointers.ptr_init
}
-}
-
-
-
-// ---------- Jump:
-
-ns bit {
- // like: ;*ptr
- // Complexity w(2phi+6)
- def ptr_jump ptr < ._.to_jump, ._.to_jump_var {
- .bit_var_xor w, ._.to_jump+w, ._.to_jump_var, ._.to_jump_var
- .bit_var_xor w, ._.to_jump+w, ._.to_jump_var, ptr
- ;._.to_jump
+ // Space Complexity: n+w/4
+ // Initializes a stack of size n (maximal capacity of n bits / hexs / return-addresses).
+ // n is the size of the stack.
+ def stack_init n {
+ hex.pointers.stack_init n
}
}
-// ---------- Flip:
-
-
-ns bit {
- // like: *ptr;
- // Complexity w(2phi+6)
- def ptr_flip ptr @ cleanup < ._.to_flip, ._.to_flip_var {
- wflip ._.to_flip+w, cleanup
-
- .bit_var_xor w, ._.to_flip, ._.to_flip_var, ._.to_flip_var
- .bit_var_xor w, ._.to_flip, ._.to_flip_var, ptr
- ;._.to_flip
-
- cleanup:
- wflip ._.to_flip+w, cleanup
- }
-
- // like: (*ptr)+dbit;
- // Assumes *ptr is dw-aligned
- // Complexity w(2phi+7)
- // The comp_flip_if executes much less than w/2 operations.
- def ptr_flip_dbit ptr {
- rep(#dbit, i) comp_flip_if ptr+dbit+i*dw, (dbit>>i)&1
- .ptr_flip ptr
- rep(#dbit, i) comp_flip_if ptr+dbit+i*dw, (dbit>>i)&1
- }
-
- // Assumes *ptr is dw-aligned
- def xor_to_ptr ptr, bit @ end {
- .if0 bit, end
- .ptr_flip_dbit ptr
- end:
- }
-
-
- // like: wflip *ptr, value
- // Assumes *ptr is w-aligned, and value is 2dw-aligned
- // Complexity w(3phi+11)
- def ptr_wflip ptr, value < ._.to_flip, ._.to_flip_var{
- .bit_var_xor w, ._.to_flip, ._.to_flip_var, ._.to_flip_var
- .bit_var_xor w, ._.to_flip, ._.to_flip_var, ptr
- rep(w, i) ._.advance_by_one_and_flip__ptr_wflip (#(i^((i+1)%w))), (value>>i)&1
- }
- ns _ {
- def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < .to_flip {
- comp_if0 do_flip, advance
- wflip .to_flip+w, cleanup, .to_flip
- cleanup:
- wflip .to_flip+w, cleanup
- advance:
- rep(n, i) ..exact_not .to_flip+i
- }
- }
-
- // Assumes *ptr is dw-aligned, and value is 2dw-aligned
- def ptr_wflip_2nd_word ptr, value {
- .not ptr + dw*ww
- .ptr_wflip ptr, value
- .not ptr + dw*ww
- }
-}
-
-
-
-// ---------- Xor
-
+// ---------- Functions
-ns bit {
- // like: .xor dst *ptr
- // assumes *ptr is dw-aligned
- // Complexity w(8phi+28)
- def xor_from_ptr dst, ptr {
- .exact_xor_from_ptr dst+dbit, ptr
- }
- def exact_xor_from_ptr dst, ptr @ base_jump_label, cleanup {
- .ptr_wflip_2nd_word ptr, base_jump_label
+ns stl {
+ // Time Complexity: 4w@ (actually a bit smaller)
+ // Space Complexity: 8w@ (actually a bit smaller)
+ // note: the pop_ret_address is for the future return (counts as space, but not time, complexity).
+ def call address @ return_label {
+ hex.push_ret_address return_label
+ ;address
- .ptr_jump ptr
pad 2
- base_jump_label:
- ;cleanup
- dst;
-
- cleanup:
- .ptr_wflip_2nd_word ptr, base_jump_label
-
- }
-}
-
-
-
-// ---------- Stack
-
-
-ns bit {
- def stack n {
- ._.stack n
- }
- ns _ {
- // sp always points to the last pushed value (at start - to stack[-1])
- def stack n > sp, stack{
- pad 1
- sp:
- bit.vec w, .stack-dw
- stack:
- bit.vec n, 0
- }
- }
- def get_sp dst < ._.sp {
- .mov w, dst, ._.sp
- }
-
-
- // Complexity w(2phi+10)
- def inc_ptr ptr {
- .inc w-dww, ptr+dww*dw
- }
-
-
- // Complexity w(2phi+12)
- def dec_ptr ptr {
- .dec w-dww, ptr+dww*dw
+ return_label:
+ hex.pop_ret_address return_label
}
+ // Time Complexity: 4w@ (actually a bit smaller)
+ // Space Complexity: 8.5w@ (actually a bit smaller)
+ //
+ // note: the pop_ret_address is for the future return (counts as space, but not time, complexity).
+ def call address, params_hex_length @ return_label {
+ hex.push_ret_address return_label
+ ;address
- // Assumes address is 2dw-aligned
- // Complexity w(5phi+21)
- def push_ret_address address < ._.sp {
- .inc_ptr ._.sp
- .ptr_wflip_2nd_word ._.sp, address
- }
-
- // Assumes address is 2dw-aligned
- // Complexity w(5phi+23)
- def pop_ret_address address < ._.sp {
- .ptr_wflip_2nd_word ._.sp, address
- .dec_ptr ._.sp
+ pad 2
+ return_label:
+ hex.pop_ret_address return_label
+ hex.sp_sub params_hex_length
}
- // Complexity: w(4phi+17)
- def push bit < ._.sp {
- .inc_ptr ._.sp
- .xor_to_ptr ._.sp, bit
+ // Time Complexity: w(7phi+29)
+ // Space Complexity: 2w@
+ // note: jumps to the last-call's pop_ret_address (which counts as time, but not space, complexity).
+ def return < hex.pointers.sp {
+ hex.ptr_jump hex.pointers.sp
}
- // Assumes *sp==bit.
- // Complexity: w(4phi+19)
- def pop bit < ._.sp {
- .xor_to_ptr ._.sp, bit
- .dec_ptr ._.sp
- }
- // Complexity: w(12phi+47)
- def pop_res bit < ._.sp {
- .zero bit
- .xor_from_ptr bit, ._.sp
- .pop bit
+ // Time Complexity: n(2@)
+ // Space Complexity: n(2@+24)
+ // (Unsafe if dst is hex.pointers.sp).
+ // dst[:w/4] = sp
+ def get_sp dst < hex.pointers.sp {
+ hex.mov w/4, dst, hex.pointers.sp
}
}
-// ---------- Functions
-
+// ---------- Fast Call
-ns bit {
- // Complexity: w(5phi+21)
- // the pop_ret_address is counted for the future return
- def call address @ return_label {
- .push_ret_address return_label
- ;address
+ns stl {
+ // Complexity: @-1
+ def fcall label, ret_reg @ ret {
+ wflip ret_reg+w, ret, label
pad 2
- return_label:
- .pop_ret_address return_label
- }
-
-
- // Complexity: w(7phi+29)
- // the last-call's pop_ret_address is counted for this return
- def return < ._.sp {
- .ptr_jump ._.sp
+ ret:
+ wflip ret_reg+w, ret
}
-}
-
-
-// ---------- Fast Call
-
-
-def fcall_init {
- _.fcall_init
-}
-ns _ {
- def fcall_init > ret_addr1, ret_addr2, ret_addr3 {
- ret_addr1: bit 0
- ret_addr2: bit 0
- ret_addr3: bit 0
+ // Complexity: 1
+ def fret ret_reg {
+ ;ret_reg
}
}
-
-// Complexity: phi+1
-def fcall label, ret_reg @ ret {
- wflip ret_reg+w, ret, label
- pad 2
- ret:
- wflip ret_reg+w, ret
-}
-
-// Complexity: 1
-def fret ret_reg {
- ;ret_reg
-}
-
-def fcall1 label < _.ret_addr1 {
- fcall label, _.ret_addr1
-}
-def fcall2 label < _.ret_addr2 {
- fcall label, _.ret_addr2
-}
-def fcall3 label < _.ret_addr3 {
- fcall label, _.ret_addr3
-}
-def fret1 < _.ret_addr1 {
- fret _.ret_addr1
-}
-def fret2 < _.ret_addr2 {
- fret _.ret_addr2
-}
-def fret3 < _.ret_addr3 {
- fret _.ret_addr3
-}
diff --git a/stl/runlib.fj b/stl/runlib.fj
index e21ddbb..5f6f5e7 100644
--- a/stl/runlib.fj
+++ b/stl/runlib.fj
@@ -1,119 +1,163 @@
-// Every line is (running) bananas!
-// This file contains a width-independent code
+// w = ?? // memory and operands width. Is defined at compile time.
+dw = 2 * w // double word size
+dbit = w + #w // the bit-distance from the variable's start, to the bit value (w + w_width)
-// This file contains constants and labels used by other standard library files.
-// Everything after // is ignored, and every whitespace is ignored (besides new line)
-// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next)
+ns stl {
+ // Complexity: 2
+ // startup Macro - should be the first piece of code in your program.
+ // @output-param IO: the address of the opcode that's reserved for Input/Output. More info in https://esolangs.org/wiki/FlipJump#Input_/_Output
+ def startup @ code_start > IO {
+ ;.code_start // 0w;1w : first code to run
+ IO:
+ ;0 // 2w;3w : sets the io_handler to address 0 (good for a future wflip)
-// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op.
-// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity
+ code_start:
+ // 4w;5w : start of code
+ }
-// The complexities are not updated in this file (should be lower/faster).
+ // Complexity: ~7000 (7094 for w=64, 6962 for w=16)
+ // startup Macro, that initialize anything needed for the standard library - should be the first piece of code in your program.
+ // @output-param IO: the address of the opcode that's reserved for Input/Output. More info in https://esolangs.org/wiki/FlipJump#Input_/_Output
+ def startup_and_init_all {
+ .startup_and_init_all 100
+ }
+ // Complexity: 6793 + 2.75w+@ + n
+ // startup Macro, that initialize anything needed for the standard library - should be the first piece of code in your program.
+ // stack_bit_size is the size of the global-stack (will hold this number of bits / return-addresses).
+ // @output-param IO: the address of the opcode that's reserved for Input/Output. More info in https://esolangs.org/wiki/FlipJump#Input_/_Output
+ def startup_and_init_all stack_bit_size @ code_start > IO {
+ ;.code_start // 0w;1w : first code to run
+ IO:
+ ;0 // 2w;3w : sets the io_handler to address 0 (good for a future wflip)
-// w = ?? // memory and operands width. Is defined at compile time.
-dww = #w // double-w-width (log2(2w))
-ww = dww-1 // w-width (log2(w))
-dw = 2 * w // double word size
-dbit = w + dww // bit-distance from variable start to bit value (w+dww)
+ hex.init
+ stl.ptr_init
+ stl.stack_init stack_bit_size
+ code_start:
+ }
-// ---------- Startup Code
+ // ---------- Basic Functionality
-def startup > IO, code_start {
- ;code_start // 0w;1w : code start
- IO:
- ;0 // 2w;3w : now points to io_handler
- code_start:
- // 4w;5w : start of code
-}
+ // Complexity: 1
+ // macro for 1 flip-jump op
+ def fj f, j {
+ f;j
+ }
-def startup in0_handler, in1_handler {
- startup
- default_input in0_handler, in1_handler
-}
+ // Complexity: @
+ // macro for 1 wflip op
+ def wflip_macro dst, val {
+ wflip dst, val
+ }
+ // Complexity: @
+ // macro for 1 wflip op (with jump)
+ def wflip_macro dst, val, jmp_addr {
+ wflip dst, val, jmp_addr
+ }
-// ---------- Basic Functionality
-def zero_op {
- 0;0
-}
+ // ---------- Compilation Time Comparisons:
+ // Complexity: 1
-def fj f, j {
- f;j
-}
-def wflip_macro dst, val {
- wflip dst, val
-}
+ // if expression is 0 (compilation time), jump to l0. else jump to l1
+ def comp_if expr, l0, l1 {
+ ; expr ? l1 : l0
+ }
-def wflip_macro dst, val, jmp_addr {
- wflip dst, val, jmp_addr
-}
+ // if expression is 0 (compilation time), jump to l0. else continue
+ def comp_if0 expr, l0 @ continue {
+ .comp_if expr, l0, continue
+ continue:
+ }
-//// @note - padding can also be implemented in fj itself! (but the saved-word pad is more compile-time efficient)
-//def pad x @ pad_start {
-// pad_start:
-// rep((0-pad_start/(2*w))%x, i) zero_op
-//}
+ // if expression is not 0 (compilation time), jump to l1. else continue
+ def comp_if1 expr, l1 @ continue {
+ .comp_if expr, continue, l1
+ continue:
+ }
-// ---------- Compilation Time:
-// Complexity: 1
+ // if expr != 0 (compilation time), flip the given bit.
+ //
+ // expr is a constant, and bit is a general bit-address.
+ def comp_flip_if bit, expr {
+ (expr ? bit : 0);
+ }
-def comp_if expr, l0, l1 {
- ; expr ? l1 : l0
-}
-def comp_if0 expr, l0 @ l1 {
- comp_if expr, l0, l1
- l1:
-}
+ // ---------- Unconditional Jumps
+ // Complexity: 1
-def comp_if1 expr, l1 @ l0 {
- comp_if expr, l0, l1
- l0:
-}
+ // skip the next flip-jump op
+ def skip {
+ ;$ + dw
+ }
-def comp_flip_if bit, expr {
- (expr ? bit : 0);
-}
+ // finish (loop to self)
+ def loop {
+ ;$ - dw
+ }
-// ---------- Unconditional Jump
-// Complexity: 1
+ // ---------- Input Handler
-def skip {
- ;$ + dw
-}
+
+ // sets the input handlers. When inputting 0 - in0_handler will be called, and for 1 - in1_handler will be called.
+ //
+ // @note, most of the programs won't use this macro, as they'll use (at the place they want to input) bit.input_bit,
+ // or most likely, something like the next code:
+ // wflip stl.IO+w, input_0, stl.IO
+ // pad 2
+ // input_0:
+ // wflip stl.IO+w, input_0, jump_to_input_0_handling
+ // input_1:
+ // wflip stl.IO+w, input_0, jump_to_input_0_handling
+ //
+ // @note that if you use this macro, you can't touch stl.IO yourself, or use macros that does it; so know what you are doing.
+ def default_input in0_handler, in1_handler @ io_handler, end < .IO {
+ wflip .IO+w, io_handler, end
+ pad 2
+ io_handler:
+ ;in0_handler
+ ;in1_handler
+ end:
+ }
-def loop {
- ;$ - dw
-}
+ // ---------- Output constants:
-// ---------- Input Handler
+ // Complexity: 1
+ // bit is a constant. 0 will output o, anything else will output 1.
+ def output_bit bit < .IO {
+ .IO + (bit ? 1 : 0);
+ }
+ // Complexity: 8
+ // ascii is a constant. The macro outputs the byte (ascii & 0xff)
+ def output_char ascii {
+ rep(8, i) .output_bit (ascii>>i)&1
+ }
-def default_input in0_handler, in1_handler @ io_handler, end < IO {
- wflip IO+w, io_handler, end
- pad 2
- io_handler:
- ;in0_handler
- ;in1_handler
- end:
+ // Complexity: 8 * string_length
+ // str is a constant. The macro outputs the bytes of it (from lsB to msB) until it becomes all zeros.
+ def output str {
+ rep(((#str)+7)>>3, i) .output_char (str>>(8*i))&0xff
+ }
}
diff --git a/tests/README.md b/tests/README.md
index ae44953..226f790 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -19,7 +19,37 @@ You can execute the `test_parallel` / `test_parallel.bat` to run parallel compil
![Running the test_parallel script with --regular](../res/test_parallel.gif)
-Please note that the 7 `hexlib-div-*` tests currently fail.
+### Debugging info
+When updating the codebase or adding new tests - Tests may fail, and it's a good thing. That way we can learn more about the code behavior.
+To get useful information out of failed tests (something like their macro-stack), you can use the `--debuginfo [LEN]` flag (Doesn't work when run in parallel).
+
+When tests fail to complete their run (i.e. finished not by looping) the testing environment shows the last 10 executed addresses.
+Using the `--debuginfo` flag adds debugging info, i.e. labels information; In that case, each of the 10 executed address will be followed by a label name like the one below.
+You can also use this flag with a positive number `--debuginfo LEN` - that way the last `LEN` executed addresses will be saved (with their extensive label-names) and not just 10.
+
+Using this flag makes the test run ~25% slower, and the compiled tests are 3-times larger (because of the debugging information).
+Yet, it's nothing compared to the debugging information you are getting:
+
+###### Example label name you'll get with using `--debuginfo [LEN]`:
+```
+ 0x2c6000:
+ f1:l13:hex.pop_res(1) ->
+ s20:l268:hex.xor_from_ptr(2) ->
+ s20:l159:hex.exact_xor_from_ptr(2) ->
+ s20:l175:hex.ptr_wflip_2nd_word(2) ->
+ s20:l144:hex.ptr_wflip(2) ->
+ s20:l121:hex.pointers.set_flip_pointer(1) ->
+ s20:l43:hex.address_and_variable_xor(4) ->
+ s12:l86:rep0:hex.double_exact_xor(9) ->
+ first_flip
+```
+That means that address 0x2c6000 is the label _first_flip_ in the _double_exact_xor_ macro (that gets 9 parameters).
+This macro got "called" from the _address_and_variable_xor_ macro (4 params) in the 86th line in the 12th stl file (in the compilation order; s stands for stl, while f stands for other files).
+The current macro-expansion started in the first non-stl compiled file, in line 13, where hex.pop_res is called with 1 param.
+
+You can get the entire "macro-stack" of the last executed addresses to get a better understanding of what happened.
+
+More information about the labels can be found [here](../src/README.md#generated-label-names).
### Filter tests by their name
Using the next tests together will take the union of the relevant tests.
@@ -46,6 +76,8 @@ Then add a new line to the relevant compile-csv and run-csv files, according to
### Compile CSVs format:
+(files with the next format: ```test_compile_*.csv```)
+
| test name | .fj paths | out .fjm path | memory width | version | flags | use stl | treat warnings as errors |
|--------------|-------------------------------------------------------------|------------------------------|--------------|---------|-------|---------|--------------------------|
| example_test | path/to/example_1.fj | ... | path/to/example_n.fj | path/to/compiled/example.fjm | 64 | 1 | 0 | True | True |
@@ -54,8 +86,16 @@ Note that you can specify a single file, or a '|' separated list of files in the
### Run CSVs format:
+(files with the next format: ```test_run_*.csv```)
+
| test name | .fjm path | input file path | output file path | is input a binary file | is output a binary file |
|--------------|------------------------------|---------------------------|-----------------------------|------------------------|-------------------------|
| example_test | path/to/compiled/example.fjm | path/to/inputs/example.in | path/to/outputs/example.out | False | False |
Note that you can also emit specifying a file in the input/output cell, and leave it empty. In that case an empty input/output will be used.
+
+### Xfail Lists
+
+If you want to add your test, but you want it to [xfail](https://docs.pytest.org/en/7.1.x/how-to/skipping.html#xfail-mark-test-functions-as-expected-to-fail), you can add your test name to:
+- ```xfail_compile.csv``` - to mark its compilation as expected to fail.
+- ```xfail_run.csv``` - to mark its run as expected to fail.
diff --git a/tests/conf.json b/tests/conf.json
index e2bea44..fcf99d4 100644
--- a/tests/conf.json
+++ b/tests/conf.json
@@ -8,7 +8,7 @@
"all_speed_ordered": [
"fast",
"medium",
- "slow",
- "hexlib"
+ "hexlib",
+ "slow"
]
}
diff --git a/tests/conftest.py b/tests/conftest.py
index bca8656..fca3b48 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,3 +1,4 @@
+import argparse
import csv
import json
from os import environ
@@ -8,7 +9,8 @@
import pytest
-from tests.test_fj import CompileTestArgs, RunTestArgs
+from defs import check_int_positive
+from tests.test_fj import CompileTestArgs, RunTestArgs, LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH
build_tests_lock = Lock()
@@ -40,6 +42,7 @@
RUN_ORDER_INDEX = 2
+DEBUG_INFO_FLAG = 'debuginfo'
ALL_FLAG = 'all'
REGULAR_FLAG = 'regular'
COMPILE_FLAG = 'compile'
@@ -74,40 +77,53 @@ def argument_line_iterator(csv_file_path: Path, num_of_args: int) -> Iterable[Li
if line:
assert len(line) == num_of_args, f'expects {num_of_args} args, got {len(line)} ' \
f'(file {Path(csv_file_path).absolute()}, line {line_index + 1})'
- yield map(str.strip, line)
+ yield list(map(str.strip, line))
-def get_compile_tests_params_from_csv(csv_file_path: Path) -> List:
+def get_compile_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str], save_debug_info: bool) -> List:
"""
read the compile-tests from the csv
@param csv_file_path: read tests from this csv
+ @param xfail_list: list of tests names to mark with xfail (expected to fail)
+ @param save_debug_info: should save the debugging info file
+
@return: the list of pytest.params(CompileTestArgs, )
"""
params = []
- for line in argument_line_iterator(csv_file_path, CompileTestArgs.num_of_args):
- args = CompileTestArgs(*line)
- params.append(pytest.param(args, marks=pytest.mark.run(order=COMPILE_ORDER_INDEX)))
+ for line in argument_line_iterator(csv_file_path, CompileTestArgs.num_of_csv_line_args):
+ args = CompileTestArgs(save_debug_info, *line)
+ test_marks = [pytest.mark.run(order=COMPILE_ORDER_INDEX)]
+ if args.test_name in xfail_list:
+ test_marks.append(pytest.mark.xfail())
+ params.append(pytest.param(args, marks=test_marks))
return params
-def get_run_tests_params_from_csv(csv_file_path: Path) -> List:
+def get_run_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str],
+ save_debug_file: bool, debug_info_length: int) -> List:
"""
read the run-tests from the csv
@param csv_file_path: read tests from this csv
+ @param xfail_list: list of tests names to mark with xfail (expected to fail)
+ @param save_debug_file: If not True: should use the debugging info file,
+ @param debug_info_length: show the last {debug_info_length} fj-ops if the program failed running.
@return: the list of pytest.params(RunTestArgs, depends=)
"""
params = []
- for line in argument_line_iterator(csv_file_path, RunTestArgs.num_of_args):
- args = RunTestArgs(*line)
- params.append(pytest.param(args, marks=pytest.mark.run(order=RUN_ORDER_INDEX)))
+ for line in argument_line_iterator(csv_file_path, RunTestArgs.num_of_csv_line_args):
+ args = RunTestArgs(save_debug_file, debug_info_length, *line)
+ test_marks = [pytest.mark.run(order=RUN_ORDER_INDEX)]
+ if args.test_name in xfail_list:
+ test_marks.append(pytest.mark.xfail())
+ params.append(pytest.param(args, marks=test_marks))
return params
-def pytest_addoption(parser) -> None:
+def pytest_addoption(parser: pytest.Parser) -> None:
"""
add the costume flags to pytest
@param parser: the parser
@@ -115,10 +131,26 @@ def pytest_addoption(parser) -> None:
colliding_keywords = set(TEST_TYPES) & SAVED_KEYWORDS
assert not colliding_keywords
+ def check_int_positive_with_true(value):
+ int_value = int(value)
+ if int_value <= 0:
+ raise argparse.ArgumentTypeError(f"{value} is an invalid positive int value")
+ return True, int_value
+
+ # This is a tuple: (should_compile_tests_save_debugging_info, run_tests_debugging_ops_list_length)
+ parser.addoption(f"--{DEBUG_INFO_FLAG}", metavar='LENGTH', type=check_int_positive_with_true, nargs='?',
+ const=(True, LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH),
+ default=(False, LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH),
+ help=f"show the last LENGTH executed opcodes on tests that failed during their run "
+ f"({LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH} by default). "
+ f"(if this option is unspecified"
+ f" - the tests will be ~20% faster, and will takes ~30% of their size). "
+ f"This option is irrelevant (doesn't show last executed opcodes) on parallel tests.")
+
for test_type in TEST_TYPES:
parser.addoption(f"--{test_type}", action="store_true", help=f"run {test_type} tests")
parser.addoption(f"--{REGULAR_FLAG}", action="store_true", help=f"run all regular tests ({', '.join(REGULAR_TYPES)})")
- parser.addoption(f"--{ALL_FLAG}", action="store_true", help=f"run all tests")
+ parser.addoption(f"--{ALL_FLAG}", action="store_true", help="run all tests")
parser.addoption(f"--{COMPILE_FLAG}", action='store_true', help='only test compiling .fj files')
parser.addoption(f"--{RUN_FLAG}", action='store_true', help='only test running .fjm files')
@@ -295,12 +327,20 @@ def get_tests_from_csvs(get_option: Callable[[str], Any]) -> Tuple[List, List]:
types_to_run__heavy_first = get_test_types_to_run__heavy_first(get_option)
+ compile_xfail_list = [line[0] for line in argument_line_iterator(TESTS_PATH / "xfail_compile.csv", 1)]
+ run_xfail_list = [line[0] for line in argument_line_iterator(TESTS_PATH / "xfail_run.csv", 1)]
+
+ save_debug_file, debug_info_length = get_option(DEBUG_INFO_FLAG)
+ if is_parallel_active():
+ save_debug_file = False
+
compile_tests = []
if check_compile_tests:
compiles_csvs = {test_type: TESTS_PATH / f"test_compile_{test_type}.csv"
for test_type in types_to_run__heavy_first}
for test_type in types_to_run__heavy_first:
- compile_tests.extend(get_compile_tests_params_from_csv(compiles_csvs[test_type]))
+ compile_tests.extend(get_compile_tests_params_from_csv(compiles_csvs[test_type], compile_xfail_list,
+ save_debug_file))
compile_tests = filter_by_test_name(compile_tests, get_option)
run_tests = []
@@ -308,7 +348,8 @@ def get_tests_from_csvs(get_option: Callable[[str], Any]) -> Tuple[List, List]:
run_csvs = {test_type: TESTS_PATH / f"test_run_{test_type}.csv"
for test_type in types_to_run__heavy_first}
for test_type in types_to_run__heavy_first:
- run_tests.extend(get_run_tests_params_from_csv(run_csvs[test_type]))
+ run_tests.extend(get_run_tests_params_from_csv(run_csvs[test_type], run_xfail_list,
+ save_debug_file, debug_info_length))
run_tests = filter_by_test_name(run_tests, get_option)
return compile_tests, run_tests
diff --git a/tests/inout/concept_checks/ptr.out b/tests/inout/concept_checks/bit_ptr.out
similarity index 100%
rename from tests/inout/concept_checks/ptr.out
rename to tests/inout/concept_checks/bit_ptr.out
diff --git a/tests/inout/concept_checks/hex_ptr.out b/tests/inout/concept_checks/hex_ptr.out
new file mode 100644
index 0000000..7dcccfa
--- /dev/null
+++ b/tests/inout/concept_checks/hex_ptr.out
@@ -0,0 +1 @@
+17NB
\ No newline at end of file
diff --git a/tests/inout/func_tests/func6.out b/tests/inout/func_tests/func6.out
new file mode 100644
index 0000000..065cfd3
--- /dev/null
+++ b/tests/inout/func_tests/func6.out
@@ -0,0 +1 @@
+26EA
diff --git a/tests/inout/func_tests/func7.out b/tests/inout/func_tests/func7.out
new file mode 100644
index 0000000..f3bc954
--- /dev/null
+++ b/tests/inout/func_tests/func7.out
@@ -0,0 +1,15 @@
+ABCDa-123-b-123456-cd
+Ea-123-b-123456-cd
+F-123-GHIJ
+dist[p1, p2] ** 2 = 0x3EDA
+
+ABCDa-123-b-123456-cd
+Ea-123-b-123456-cd
+F-123-GHIJ
+dist[p1, p3] ** 2 = 0x2C95
+
+ABCDa-123-b-123456-cd
+Ea-123-b-123456-cd
+F-123-GHIJ
+dist[p2, p3] ** 2 = 0x3C79
+
diff --git a/tests/inout/hexlib_tests/2params/108equals.out b/tests/inout/hexlib_tests/2params/108equals.out
new file mode 100644
index 0000000..cce9378
--- /dev/null
+++ b/tests/inout/hexlib_tests/2params/108equals.out
@@ -0,0 +1,108 @@
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
+=
diff --git a/tests/inout/sanity_checks/startup_init_all.out b/tests/inout/sanity_checks/startup_init_all.out
new file mode 100644
index 0000000..6ddb8ce
--- /dev/null
+++ b/tests/inout/sanity_checks/startup_init_all.out
@@ -0,0 +1,2 @@
+0xAC6
+1010
diff --git a/tests/test_compile_fast.csv b/tests/test_compile_fast.csv
index af5ce13..97a3287 100644
--- a/tests/test_compile_fast.csv
+++ b/tests/test_compile_fast.csv
@@ -8,6 +8,7 @@ nadd, programs/simple_math_checks/nadd.fj,tests/compiled/simple_math_checks/nadd
ncat, programs/print_tests/ncat.fj,tests/compiled/print_tests/ncat.fjm, 64,3,0, True,True
ncmp, programs/simple_math_checks/ncmp.fj,tests/compiled/simple_math_checks/ncmp.fjm, 64,3,0, True,True
not, programs/sanity_checks/not.fj,tests/compiled/sanity_checks/not.fjm, 64,3,0, True,True
+test_startup_init_all, programs/sanity_checks/startup_init_all.fj,tests/compiled/sanity_checks/startup_init_all.fjm, 64,3,0, True,True
print_as_digit, programs/print_tests/print_as_digit.fj,tests/compiled/print_tests/print_as_digit.fjm, 64,3,0, True,True
quine16, programs/quine16.fj,tests/compiled/quine16.fjm, 16,0,0, True,True
rep, programs/sanity_checks/rep.fj,tests/compiled/sanity_checks/rep.fjm, 64,3,0, True,True
diff --git a/tests/test_compile_hexlib.csv b/tests/test_compile_hexlib.csv
index 00320bf..0b6676b 100644
--- a/tests/test_compile_hexlib.csv
+++ b/tests/test_compile_hexlib.csv
@@ -20,8 +20,10 @@ hexlib-cmp, programs/hexlib_tests/2params/cmp.fj,tests/compiled/hexlib_tests/2pa
hexlib-cmp_n, programs/hexlib_tests/2params/cmp_n.fj,tests/compiled/hexlib_tests/2params/cmp_n.fjm, 64,3,0, True,True
hexlib-add, programs/hexlib_tests/2params/add.fj,tests/compiled/hexlib_tests/2params/add.fjm, 64,3,0, True,True
hexlib-add_n, programs/hexlib_tests/2params/add_n.fj,tests/compiled/hexlib_tests/2params/add_n.fjm, 64,3,0, True,True
+hexlib-add_shifted, programs/hexlib_tests/2params/add_shifted.fj,tests/compiled/hexlib_tests/2params/add_shifted.fjm, 64,3,0, True,True
hexlib-sub, programs/hexlib_tests/2params/sub.fj,tests/compiled/hexlib_tests/2params/sub.fjm, 64,3,0, True,True
hexlib-sub_n, programs/hexlib_tests/2params/sub_n.fj,tests/compiled/hexlib_tests/2params/sub_n.fjm, 64,3,0, True,True
+hexlib-sub_shifted, programs/hexlib_tests/2params/sub_shifted.fj,tests/compiled/hexlib_tests/2params/sub_shifted.fjm, 64,3,0, True,True
hexlib-or, programs/hexlib_tests/2params/or.fj,tests/compiled/hexlib_tests/2params/or.fjm, 64,3,0, True,True
hexlib-or_n, programs/hexlib_tests/2params/or_n.fj,tests/compiled/hexlib_tests/2params/or_n.fjm, 64,3,0, True,True
hexlib-and, programs/hexlib_tests/2params/and.fj,tests/compiled/hexlib_tests/2params/and.fjm, 64,3,0, True,True
diff --git a/tests/test_compile_medium.csv b/tests/test_compile_medium.csv
index 0a6b132..efce267 100644
--- a/tests/test_compile_medium.csv
+++ b/tests/test_compile_medium.csv
@@ -3,5 +3,6 @@ div10, programs/simple_math_checks/div10.fj,tests/compiled/simple_math_checks/di
hello_world_with_str, programs/print_tests/hello_world_with_str.fj,tests/compiled/print_tests/hello_world_with_str.fjm, 64,3,0, True,True
print_dec, programs/print_tests/print_dec.fj,tests/compiled/print_tests/print_dec.fjm, 64,3,0, True,True
print_hex_int, programs/print_tests/print_hex_int.fj,tests/compiled/print_tests/print_hex_int.fjm, 64,3,0, True,True
-ptr, programs/concept_checks/ptr.fj,tests/compiled/concept_checks/ptr.fjm, 64,3,0, True,True
+bit_ptr, programs/concept_checks/bit_ptr.fj,tests/compiled/concept_checks/bit_ptr.fjm, 64,3,0, True,True
+hex_ptr, programs/concept_checks/hex_ptr.fj,tests/compiled/concept_checks/hex_ptr.fjm, 64,3,0, True,True
segments, programs/concept_checks/segments.fj,tests/compiled/concept_checks/segments.fjm, 64,3,0, True,True
diff --git a/tests/test_compile_slow.csv b/tests/test_compile_slow.csv
index f7fe493..3227dff 100644
--- a/tests/test_compile_slow.csv
+++ b/tests/test_compile_slow.csv
@@ -1,10 +1,13 @@
+hex_func7, programs/func_tests/func7.fj,tests/compiled/func_tests/func7.fjm, 64,3,0, True,True
+
calc, programs/calc.fj,tests/compiled/calc.fjm, 64,3,0, True,True
-func1, programs/func_tests/func1.fj,tests/compiled/func_tests/func1.fjm, 64,3,0, True,True
-func2, programs/func_tests/func2.fj,tests/compiled/func_tests/func2.fjm, 64,3,0, True,True
-func3, programs/func_tests/func3.fj,tests/compiled/func_tests/func3.fjm, 64,3,0, True,True
-func4, programs/func_tests/func4.fj,tests/compiled/func_tests/func4.fjm, 64,3,0, True,True
-func5, programs/func_tests/func5.fj,tests/compiled/func_tests/func5.fjm, 64,3,0, True,True
+hex_func1, programs/func_tests/func1.fj,tests/compiled/func_tests/func1.fjm, 64,3,0, True,True
+hex_func2, programs/func_tests/func2.fj,tests/compiled/func_tests/func2.fjm, 64,3,0, True,True
+hex_func3, programs/func_tests/func3.fj,tests/compiled/func_tests/func3.fjm, 64,3,0, True,True
+hex_func4, programs/func_tests/func4.fj,tests/compiled/func_tests/func4.fjm, 64,3,0, True,True
+hex_func5, programs/func_tests/func5.fj,tests/compiled/func_tests/func5.fjm, 64,3,0, True,True
+hex_func6, programs/func_tests/func6.fj,tests/compiled/func_tests/func6.fjm, 64,3,0, True,True
pair_ns1, programs/concept_checks/pair_ns.fj | programs/pair_ns_tests/test1.fj,tests/compiled/pair_ns_tests/test1.fjm, 64,3,0, True,True
pair_ns2, programs/concept_checks/pair_ns.fj | programs/pair_ns_tests/test2.fj,tests/compiled/pair_ns_tests/test2.fjm, 64,3,0, True,True
diff --git a/tests/test_fj.py b/tests/test_fj.py
index 8005a25..66e3ecb 100644
--- a/tests/test_fj.py
+++ b/tests/test_fj.py
@@ -2,10 +2,12 @@
from queue import Queue
from threading import Lock
from pathlib import Path
+from typing import Optional
+from breakpoints import BreakpointHandler, load_labels_dictionary
from src import assembler, fjm
from src import fjm_run
-from src.defs import TerminationCause, get_stl_paths, io_bytes_encoding
+from src.defs import TerminationCause, get_stl_paths, io_bytes_encoding, LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH
from src.io_devices.FixedIO import FixedIO
CSV_TRUE = 'True'
@@ -13,6 +15,9 @@
CSV_BOOLEAN = (CSV_TRUE, CSV_FALSE)
+DEBUGGING_FILE_SUFFIX = '.fj_debugging_info'
+
+
ROOT_PATH = Path(__file__).parent.parent
@@ -25,9 +30,9 @@ class CompileTestArgs:
Arguments class for a compile test
"""
- num_of_args = 8
+ num_of_csv_line_args = 8
- def __init__(self, test_name: str, fj_paths: str, fjm_out_path: str,
+ def __init__(self, save_debug_info: bool, test_name: str, fj_paths: str, fjm_out_path: str,
word_size__str: str, version__str: str, flags__str: str,
use_stl__str: str, warning_as_errors__str: str):
"""
@@ -38,6 +43,8 @@ def __init__(self, test_name: str, fj_paths: str, fjm_out_path: str,
self.use_stl = use_stl__str == CSV_TRUE
self.warning_as_errors = warning_as_errors__str == CSV_TRUE
+ self.save_debug_info = save_debug_info
+
self.test_name = test_name
included_files = get_stl_paths() if self.use_stl else []
@@ -77,8 +84,14 @@ def test_compile(compile_args: CompileTestArgs) -> None:
fjm_writer = fjm.Writer(compile_args.fjm_out_path, compile_args.word_size, compile_args.version,
flags=compile_args.flags, lzma_preset=lzma.PRESET_DEFAULT)
+
+ debugging_file_path = None
+ if compile_args.save_debug_info:
+ debugging_file_path = Path(f'{compile_args.fjm_out_path}{DEBUGGING_FILE_SUFFIX}')
+
assembler.assemble(compile_args.fj_files_tuples, compile_args.word_size, fjm_writer,
- warning_as_errors=compile_args.warning_as_errors)
+ warning_as_errors=compile_args.warning_as_errors,
+ debugging_file_path=debugging_file_path)
class RunTestArgs:
@@ -86,11 +99,12 @@ class RunTestArgs:
Arguments class for a run test
"""
- num_of_args = 6
+ num_of_csv_line_args = 6
- def __init__(self, test_name: str, fjm_path: str,
+ def __init__(self, save_debug_file: bool, debug_info_length: int, test_name: str, fjm_path: str,
in_file_path: str, out_file_path: str,
- read_in_as_binary__str: str, read_out_as_binary__str: str):
+ read_in_as_binary__str: str, read_out_as_binary__str: str
+ ):
"""
@note handling a line.split() (each is stripped) from a csv file
"""
@@ -99,6 +113,9 @@ def __init__(self, test_name: str, fjm_path: str,
self.read_in_as_binary = read_in_as_binary__str == CSV_TRUE
self.read_out_as_binary = read_out_as_binary__str == CSV_TRUE
+ self.save_debug_file = save_debug_file
+ self.debug_info_length = debug_info_length
+
self.test_name = test_name
self.fjm_path = ROOT_PATH / fjm_path
@@ -154,11 +171,20 @@ def test_run(run_args: RunTestArgs) -> None:
print(f'Running test {run_args.test_name}:')
io_device = FixedIO(run_args.get_defined_input())
+
+ breakpoint_handler = None
+ if run_args.save_debug_file:
+ label_to_address = load_labels_dictionary(Path(f'{run_args.fjm_path}{DEBUGGING_FILE_SUFFIX}'), True)
+ breakpoint_handler = BreakpointHandler({}, {label_to_address[label]: label
+ for label in tuple(label_to_address)[::-1]})
+
termination_statistics = fjm_run.run(run_args.fjm_path,
io_device=io_device,
- time_verbose=True)
+ time_verbose=True,
+ last_ops_debugging_list_length=run_args.debug_info_length)
- print(termination_statistics)
+ termination_statistics.print(labels_handler=breakpoint_handler,
+ output_to_print=io_device.get_output(allow_incomplete_output=True))
expected_termination_cause = TerminationCause.Looping
assert termination_statistics.termination_cause == expected_termination_cause
diff --git a/tests/test_run_fast.csv b/tests/test_run_fast.csv
index 75c260f..e84d729 100644
--- a/tests/test_run_fast.csv
+++ b/tests/test_run_fast.csv
@@ -8,6 +8,7 @@ nadd, tests/compiled/simple_math_checks/nadd.fjm, ,tests/inout/simple_math_check
ncat, tests/compiled/print_tests/ncat.fjm, tests/inout/print_tests/ncat.in,tests/inout/print_tests/ncat.out, True,True
ncmp, tests/compiled/simple_math_checks/ncmp.fjm, ,tests/inout/simple_math_checks/ncmp.out, False,False
not, tests/compiled/sanity_checks/not.fjm, ,, False,False
+test_startup_init_all, tests/compiled/sanity_checks/startup_init_all.fjm, ,tests/inout/sanity_checks/startup_init_all.out, False,False
print_as_digit, tests/compiled/print_tests/print_as_digit.fjm, ,tests/inout/print_tests/print_as_digit.out, False,False
quine16, tests/compiled/quine16.fjm, ,tests/compiled/quine16.fjm, True,True
rep, tests/compiled/sanity_checks/rep.fjm, ,, False,False
diff --git a/tests/test_run_hexlib.csv b/tests/test_run_hexlib.csv
index 5a6155b..4a60926 100644
--- a/tests/test_run_hexlib.csv
+++ b/tests/test_run_hexlib.csv
@@ -20,8 +20,10 @@ hexlib-cmp, tests/compiled/hexlib_tests/2params/cmp.fjm, ,tests/inout/hexlib_tes
hexlib-cmp_n, tests/compiled/hexlib_tests/2params/cmp_n.fjm, ,tests/inout/hexlib_tests/2params/cmp_n.out, False,False
hexlib-add, tests/compiled/hexlib_tests/2params/add.fjm, ,tests/inout/hexlib_tests/2params/add.out, False,False
hexlib-add_n, tests/compiled/hexlib_tests/2params/add_n.fjm, ,tests/inout/hexlib_tests/2params/100equals.out, False,False
+hexlib-add_shifted, tests/compiled/hexlib_tests/2params/add_shifted.fjm, ,tests/inout/hexlib_tests/2params/108equals.out, False,False
hexlib-sub, tests/compiled/hexlib_tests/2params/sub.fjm, ,tests/inout/hexlib_tests/2params/sub.out, False,False
hexlib-sub_n, tests/compiled/hexlib_tests/2params/sub_n.fjm, ,tests/inout/hexlib_tests/2params/100equals.out, False,False
+hexlib-sub_shifted, tests/compiled/hexlib_tests/2params/sub_shifted.fjm, ,tests/inout/hexlib_tests/2params/108equals.out, False,False
hexlib-or, tests/compiled/hexlib_tests/2params/or.fjm, ,tests/inout/hexlib_tests/2params/or.out, False,False
hexlib-or_n, tests/compiled/hexlib_tests/2params/or_n.fjm, ,tests/inout/hexlib_tests/2params/100equals.out, False,False
hexlib-and, tests/compiled/hexlib_tests/2params/and.fjm, ,tests/inout/hexlib_tests/2params/and.out, False,False
diff --git a/tests/test_run_medium.csv b/tests/test_run_medium.csv
index f3e15c3..a448287 100644
--- a/tests/test_run_medium.csv
+++ b/tests/test_run_medium.csv
@@ -3,5 +3,6 @@ div10, tests/compiled/simple_math_checks/div10.fjm, ,tests/inout/simple_math_che
hello_world_with_str, tests/compiled/print_tests/hello_world_with_str.fjm, ,tests/inout/print_tests/hello_world_with_str.out, False,False
print_dec, tests/compiled/print_tests/print_dec.fjm, ,tests/inout/print_tests/print_dec.out, False,False
print_hex_int, tests/compiled/print_tests/print_hex_int.fjm, ,tests/inout/print_tests/print_hex_int.out, False,False
-ptr, tests/compiled/concept_checks/ptr.fjm, ,tests/inout/concept_checks/ptr.out, False,False
+bit_ptr, tests/compiled/concept_checks/bit_ptr.fjm, ,tests/inout/concept_checks/bit_ptr.out, False,False
+hex_ptr, tests/compiled/concept_checks/hex_ptr.fjm, ,tests/inout/concept_checks/hex_ptr.out, False,False
segments, tests/compiled/concept_checks/segments.fjm, tests/inout/concept_checks/segments.in,tests/inout/concept_checks/segments.out, False,False
diff --git a/tests/test_run_slow.csv b/tests/test_run_slow.csv
index 5a50157..31404fa 100644
--- a/tests/test_run_slow.csv
+++ b/tests/test_run_slow.csv
@@ -1,3 +1,5 @@
+hex_func7, tests/compiled/func_tests/func7.fjm, ,tests/inout/func_tests/func7.out, False,False
+
calc1, tests/compiled/calc.fjm, tests/inout/calc_tests/calc1.in,tests/inout/calc_tests/calc1.out, False,False
calc2, tests/compiled/calc.fjm, tests/inout/calc_tests/calc2.in,tests/inout/calc_tests/calc2.out, False,False
calc3, tests/compiled/calc.fjm, tests/inout/calc_tests/calc3.in,tests/inout/calc_tests/calc3.out, False,False
@@ -11,11 +13,12 @@ calc10, tests/compiled/calc.fjm, tests/inout/calc_tests/calc10.in,tests/inout/ca
calc_empty, tests/compiled/calc.fjm, tests/inout/calc_tests/calc_empty.in,tests/inout/calc_tests/calc_empty.out, False,False
calc_many, tests/compiled/calc.fjm, tests/inout/calc_tests/calc_many.in,tests/inout/calc_tests/calc_many.out, False,False
-func1, tests/compiled/func_tests/func1.fjm, ,tests/inout/func_tests/func1.out, False,False
-func2, tests/compiled/func_tests/func2.fjm, ,tests/inout/func_tests/func2.out, False,False
-func3, tests/compiled/func_tests/func3.fjm, ,tests/inout/func_tests/func3.out, False,False
-func4, tests/compiled/func_tests/func4.fjm, ,tests/inout/func_tests/func4.out, False,False
-func5, tests/compiled/func_tests/func5.fjm, ,tests/inout/func_tests/func5.out, False,False
+hex_func1, tests/compiled/func_tests/func1.fjm, ,tests/inout/func_tests/func1.out, False,False
+hex_func2, tests/compiled/func_tests/func2.fjm, ,tests/inout/func_tests/func2.out, False,False
+hex_func3, tests/compiled/func_tests/func3.fjm, ,tests/inout/func_tests/func3.out, False,False
+hex_func4, tests/compiled/func_tests/func4.fjm, ,tests/inout/func_tests/func4.out, False,False
+hex_func5, tests/compiled/func_tests/func5.fjm, ,tests/inout/func_tests/func5.out, False,False
+hex_func6, tests/compiled/func_tests/func6.fjm, ,tests/inout/func_tests/func6.out, False,False
pair_ns1, tests/compiled/pair_ns_tests/test1.fjm, ,tests/inout/pair_ns_tests/pair_ns1.out, False,False
pair_ns2, tests/compiled/pair_ns_tests/test2.fjm, ,tests/inout/pair_ns_tests/pair_ns2.out, False,False
diff --git a/tests/xfail_compile.csv b/tests/xfail_compile.csv
new file mode 100644
index 0000000..e69de29
diff --git a/tests/xfail_run.csv b/tests/xfail_run.csv
new file mode 100644
index 0000000..a15a9af
--- /dev/null
+++ b/tests/xfail_run.csv
@@ -0,0 +1,7 @@
+hexlib-div-4_1
+hexlib-div-4_2
+hexlib-div-4_4
+hexlib-div-8_1
+hexlib-div-8_2
+hexlib-div-8_4
+hexlib-div-8_8