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