From c4166457f5c51d459ad3de4fb096756627e5746d Mon Sep 17 00:00:00 2001 From: Tomhe Date: Tue, 4 Oct 2022 15:10:31 +0300 Subject: [PATCH 01/62] stl/bitlib.fj transformed => stl/bit/* --- README.md | 6 +- stl/README.md | 4 +- stl/bit/cond_jumps.fj | 88 +++++++++ stl/bit/logics.fj | 114 ++++++++++++ stl/bit/math.fj | 70 ++++++++ stl/bit/memory.fj | 105 +++++++++++ stl/bit/shifts.fj | 55 ++++++ stl/bitlib.fj | 402 ------------------------------------------ stl/conf.json | 8 +- stl/iolib.fj | 2 +- stl/mathlib.fj | 2 +- stl/ptrlib.fj | 2 +- 12 files changed, 447 insertions(+), 411 deletions(-) create mode 100644 stl/bit/cond_jumps.fj create mode 100644 stl/bit/logics.fj create mode 100644 stl/bit/math.fj create mode 100644 stl/bit/memory.fj create mode 100644 stl/bit/shifts.fj delete mode 100644 stl/bitlib.fj diff --git a/README.md b/README.md index 7815a3f..00d5695 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Look at the [hello_world.fj](programs/print_tests/hello_world.fj) program for mo 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) +- end_loop in [bit/math.fj](stl/bit/math.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!") @@ -125,7 +125,7 @@ Hello, World! **[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). + - bit/ - macros for manipulating binary variables and vectors (i.e. numbers). - mathlib.fj - advanced math macros (mul/div). - hexlib.fj - macros for manipulating hexadecimal variables and vectors. - declib.fj - macros for manipulating decimal variables and vectors (to be implemented). @@ -163,7 +163,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/stl/README.md b/stl/README.md index 99d39c4..15ea950 100644 --- a/stl/README.md +++ b/stl/README.md @@ -16,7 +16,7 @@ This file contains constants and initialization macros. **@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). @@ -72,4 +72,4 @@ The generic stl macro should look like `macro_name n dst src` for an n-bit/hex v 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](stl/bit/logics.fj) standard library file (start with `xor`, `if`). That's where the FlipJump magic begins. diff --git a/stl/bit/cond_jumps.fj b/stl/bit/cond_jumps.fj new file mode 100644 index 0000000..94789b8 --- /dev/null +++ b/stl/bit/cond_jumps.fj @@ -0,0 +1,88 @@ +// ---------- Conditional Jumps + + +ns bit { + // Complexity: @+2 + // if x == 0 jump to l0, else jump to l1 + 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 the n-bit x == 0 jump to l0, else jump to l1 + 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 + def if1 x, l1 @ end { + .if x, end, l1 + end: + } + + // Complexity: n(@+2) + // if the x[:n] != 0 jump to l1 + def if1 n, x, l1 @ end { + .if n, x, end, l1 + end: + } + + // Complexity: @+2 + // if x == 0 jump to l0 + def if0 x, l0 @ end { + .if x, l0, end + end: + } + + // Complexity: n(@+2) + // if x[:n] == 0 jump to l0 + 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 + 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 + 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 + def cmp_next_eq a, b, lt, gt @ eq { + ..cmp a, b, lt, eq, gt + eq: + } + } +} diff --git a/stl/bit/logics.fj b/stl/bit/logics.fj new file mode 100644 index 0000000..6d8d6a7 --- /dev/null +++ b/stl/bit/logics.fj @@ -0,0 +1,114 @@ +// ---------- Logical Macros + + +ns bit { + // Complexity: @-1 + // dst ^= src + def xor dst, src { + .exact_xor dst + dbit, src + } + + // Complexity: n(@-1) + // dst[:n] ^= src[: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 + 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 + 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@ + // bit(bit_address) ^= src + // var ^= src + def bit_var_xor n, bit, var, src { + rep(n, i) .double_exact_xor bit+i, var+dbit+i*dw, src+i*dw + } + + // Complexity: n@ + // dst ^= src + // src = 0 + def xor_zero dst, src { + .double_exact_xor dst+dbit, src+dbit, src + } + + // Complexity: n@ + // dst[:n] ^= src[:n] + // src[:n] = 0 + def xor_zero n, dst, src { + rep(n, i) .xor_zero dst+dw*i, src+dw*i + } + + + // Complexity: 2@+2 + // dst |= src + def or dst, src @ end { + .if0 src, end + .one dst + end: + } + + // Complexity: n(2@+2) + // dst[:n] |= src[:n] + def or n, dst, src { + rep(n, i) .or dst+dw*i, src+dw*i + } + + + // Complexity: 2@+2 + // dst &= src + def and dst, src @ end { + .if1 src, end + .zero dst + end: + } + + // Complexity: n(2@+2) + // dst[:n] &= src[:n] + def and n, dst, src { + rep(n, i) .and dst+dw*i, src+dw*i + } + + + // Complexity: 1 + // dst ^= 1 + def not dst { + dst + dbit; + } + + // Complexity: n + // dst[i] ^= (1<>i)&1 + } + + def vec n { + rep(n, i) bit + } +} + + +// ---------- Memory Manipulation + + +ns bit { + // Complexity: @-1 + // x = 0 + def zero x { + .xor x, x + } + + // Complexity: n(@-1) + // x[:n] = 0 + def zero n, x { + rep(n, i) .zero x+i*dw + } + + + // Complexity: @ + // x = 1 + def one x { + .zero x + .not x + } + + // Complexity: n@ + // x[:n] = (1<>= 1 + def shr n, x { + .shr n, 1, x + } + + // Complexity: n(2@-1) + // x[:n] >>= times + 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 + 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 right by 1-bit the x[:n] + 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(2@-1) + // rotate left by 1-bit the x[:n] + 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 + } +} 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/conf.json b/stl/conf.json index 464c401..9f0bc80 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -1,7 +1,13 @@ { "all": [ "runlib", - "bitlib", + + "bit/memory", + "bit/logics", + "bit/cond_jumps", + "bit/shifts", + "bit/math", + "iolib", "ptrlib", "mathlib", diff --git a/stl/iolib.fj b/stl/iolib.fj index 67fd3f0..58fe3ec 100644 --- a/stl/iolib.fj +++ b/stl/iolib.fj @@ -1,7 +1,7 @@ // 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 +// 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) diff --git a/stl/mathlib.fj b/stl/mathlib.fj index fa3bbc0..b43d88f 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -1,7 +1,7 @@ // 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) diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index 414e647..2d6de18 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -1,7 +1,7 @@ // 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 +// 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) From 4a2ce519b215d96bf4b6bf7ea6842d2adf4712bc Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sun, 25 Dec 2022 13:09:10 +0200 Subject: [PATCH 02/62] finish stl-bit refactor --- stl/bit/math.fj | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/stl/bit/math.fj b/stl/bit/math.fj index 2834761..96e7b12 100644 --- a/stl/bit/math.fj +++ b/stl/bit/math.fj @@ -4,7 +4,8 @@ ns bit { // Unsafe for dst==carry (but there is no reason in calling it that way) - // Complexity: 2phi+10 + // Complexity: 2@+6 + // {carry:dst}++ def inc1 dst, carry @ end { .if0 carry, end .not dst @@ -13,7 +14,8 @@ ns bit { end: } - // Complexity: n(2phi+10) + // Complexity: n(2@+6) + // x[:n]++ def inc n, x @ carry { .one carry rep(n, i) .inc1 x+i*dw, carry @@ -22,14 +24,16 @@ ns bit { bit } - // Complexity: n(2phi+12) + // Complexity: n(2@+8) + // x[:n]-- def dec n, x { .not n, x .inc n, x .not n, x } - // Complexity: n(2phi+11) + // Complexity: n(2@+7) + // x[:n]-- def neg n, x { .not n, x .inc n, x @@ -37,7 +41,8 @@ ns bit { // Unsafe for dst==carry (but there is no reason in calling it that way) - // Complexity: 8phi+33 + // Complexity: 8@+14 + // {carry:dst} += src def add1 dst, src, carry @ _src { .mov _src, src .inc1 dst, _src @@ -48,7 +53,8 @@ ns bit { bit } - // Complexity: n(8phi+33) + // Complexity: n(8@+14) + // dst[:n] += src[:n] def add n, dst, src @ carry { .zero carry rep(n, i) .add1 dst+i*dw, src+i*dw, carry @@ -57,7 +63,8 @@ ns bit { bit } - // Complexity: n(8phi+35) + // Complexity: n(8@+16) + // dst[:n] -= src[:n] def sub n, dst, src @ carry { .not n, src .one carry From 791111469853dba1c1a690f04b813426899c4954 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Mon, 26 Dec 2022 13:06:11 +0200 Subject: [PATCH 03/62] finish stl-run refactor update runlib comment --- programs/simple_math_checks/ncmp.fj | 5 +- src/fjm_run.py | 2 +- stl/ptrlib.fj | 8 ++-- stl/runlib.fj | 74 +++++++++++++---------------- 4 files changed, 41 insertions(+), 48 deletions(-) diff --git a/programs/simple_math_checks/ncmp.fj b/programs/simple_math_checks/ncmp.fj index ca73c2c..4cc86f5 100644 --- a/programs/simple_math_checks/ncmp.fj +++ b/programs/simple_math_checks/ncmp.fj @@ -1,4 +1,7 @@ -startup 0, 0 +startup +default_input 0, 0 + + n=4 bit.cmp n, a, b, lt, eq, gt diff --git a/src/fjm_run.py b/src/fjm_run.py index f81d725..c33ec3a 100644 --- a/src/fjm_run.py +++ b/src/fjm_run.py @@ -38,7 +38,7 @@ def __str__(self): 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: diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index 2d6de18..ba8ee52 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -118,9 +118,9 @@ ns bit { // Assumes *ptr is dw-aligned, and value is 2dw-aligned def ptr_wflip_2nd_word ptr, value { - .not ptr + dw*ww + .not ptr + dw*(#w-1) .ptr_wflip ptr, value - .not ptr + dw*ww + .not ptr + dw*(#w-1) } } @@ -178,13 +178,13 @@ ns bit { // Complexity w(2phi+10) def inc_ptr ptr { - .inc w-dww, ptr+dww*dw + .inc w-#w, ptr+#w*dw } // Complexity w(2phi+12) def dec_ptr ptr { - .dec w-dww, ptr+dww*dw + .dec w-#w, ptr+#w*dw } diff --git a/stl/runlib.fj b/stl/runlib.fj index e21ddbb..56f773d 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -1,105 +1,94 @@ -// Every line is (running) bananas! -// This file contains a width-independent code - -// 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) - -// 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). - - // 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) - +dbit = w + #w // the bit-distance from the variable's start, to the bit value (w + w_width) -// ---------- Startup Code - +// Startup Macro - should be the first piece of code in your program. def startup > IO, code_start { - ;code_start // 0w;1w : code start + ;code_start // 0w;1w : first code to run IO: - ;0 // 2w;3w : now points to io_handler + ;0 // 2w;3w : sets the io_handler to address 0 (good for a future wflip) code_start: // 4w;5w : start of code } -def startup in0_handler, in1_handler { - startup - default_input in0_handler, in1_handler -} - - // ---------- Basic Functionality -def zero_op { - 0;0 -} - +// Complexity: 1 +// macro for 1 flip-jump op def fj f, j { f;j } + +// 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 } + //// @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 zeros up to the address +//def pad address @ pad_start { // pad_start: -// rep((0-pad_start/(2*w))%x, i) zero_op +// rep((0-pad_start/(2*w))%address, i) fj 0, 0 //} -// ---------- Compilation Time: + +// ---------- Compilation Time Comparisons: // Complexity: 1 +// if expression is 0 (compilation time), jump to l0. else jump to l1 def comp_if expr, l0, l1 { ; expr ? l1 : l0 } -def comp_if0 expr, l0 @ l1 { - comp_if expr, l0, l1 - l1: +// if expression is 0 (compilation time), jump to l0. else continue +def comp_if0 expr, l0 @ continue { + comp_if expr, l0, continue + continue: } -def comp_if1 expr, l1 @ l0 { - comp_if expr, l0, l1 - l0: +// if expression is not 0 (compilation time), jump to l1. else continue +def comp_if1 expr, l1 @ continue { + comp_if expr, continue, l1 + continue: } +// if expr != 0 (compilation time), flip the given bit def comp_flip_if bit, expr { (expr ? bit : 0); } -// ---------- Unconditional Jump +// ---------- Unconditional Jumps // Complexity: 1 +// skip the next flip-jump op def skip { ;$ + dw } +// finish (loop to self) def loop { ;$ - dw } @@ -109,6 +98,7 @@ def loop { // ---------- Input Handler +// sets the input handlers. When inputting 0 - in0_handler will be called, and for 1 - in1_handler will be called. def default_input in0_handler, in1_handler @ io_handler, end < IO { wflip IO+w, io_handler, end pad 2 From 151dff24245abf9709c9fbb6e9a5aed804a256fa Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Tue, 27 Dec 2022 16:34:46 +0200 Subject: [PATCH 04/62] document & rename the 256 table-jumps in hexlib --- stl/hexlib.fj | 170 +++++++++++++++++++++++++++----------------------- 1 file changed, 93 insertions(+), 77 deletions(-) diff --git a/stl/hexlib.fj b/stl/hexlib.fj index 8e1411b..2dbbe44 100644 --- a/stl/hexlib.fj +++ b/stl/hexlib.fj @@ -1,19 +1,3 @@ -// 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 @@ -156,14 +140,14 @@ ns hex { 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 + ._.jump_to_table_entry dst, src, .or.dst } - + // Time Complexity: n(4phi+17) // Space Complexity: n(4phi+96) def or n, dst, src { @@ -172,27 +156,32 @@ ns hex { ns or { // Space Complexity: 600 - def init @ switch, clean, end < .._.res, .._.ret > dst { + def init @ switch, clean_table_entry, 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 + // 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. + rep(256, d) 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: 4phi+16 // Space Complexity: 4phi+96 def and dst, src < .and.dst { - ._.table_query dst, src, .and.dst + ._.jump_to_table_entry dst, src, .and.dst } - + // Time Complexity: n(4phi+17) // Space Complexity: n(4phi+96) def and n, dst, src { @@ -201,16 +190,21 @@ ns hex { ns and { // Space Complexity: 600 - def init @ switch, clean, end < .._.res, .._.ret > dst { + def init @ switch, clean_table_entry, 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 + // 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. + rep(256, d) 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: } } @@ -255,7 +249,7 @@ ns hex { pad 32 xor_switch: - ._.clean_table 16, dst, after_add + ._.clean_table_entry__table 16, dst, after_add rep(16, i) fj is_carry+dbit, xor_switch+i*dw after_add: @@ -290,7 +284,7 @@ ns hex { 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 + ._.clean_table_entry__table 16, dst, end end: wflip dst+w, switch @@ -313,7 +307,7 @@ ns hex { 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 + ._.clean_table_entry__table 16, dst, end end: wflip dst+w, switch @@ -452,7 +446,7 @@ ns hex { // Time Complexity: 4phi+17 // Space Complexity: 4phi+96 def add dst, src < .add.dst { - ._.table_query dst, src, .add.dst + ._.jump_to_table_entry dst, src, .add.dst } // Time Complexity: n(4phi+17) @@ -496,29 +490,36 @@ ns hex { } // Space Complexity: 1800 - def init @ switch0, switch1, flip_carry, clean, end < .._.res, .._.ret > dst { + def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > dst { ;end - dst: ;.switch0 + dst: ;.switch__without_carry 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)) + // 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: + 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_table_entry+d*dw)) + switch__with_carry: + rep(256, d) 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: - rep(256, i) fj .dst+dbit+8, clean+i*dw - clean: - .._.clean_table .dst + // if got here - flip the carry; then clean the table-entry. + rep(256, i) 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: 4phi+17 // Space Complexity: 4phi+96 def sub dst, src < .sub.dst { - ._.table_query dst, src, .sub.dst + ._.jump_to_table_entry dst, src, .sub.dst } // Time Complexity: n(4phi+17) @@ -561,20 +562,27 @@ ns hex { } // Space Complexity: 1600 - def init @ switch0, switch1, flip_carry, clean, end < .._.res, .._.ret > dst { + def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > dst { ;end - dst: ;.switch0 + dst: ;.switch__without_carry 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)) + // 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: + 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_table_entry+d*dw)) + switch__with_carry: + rep(256, d) 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: - rep(256, i) fj .dst+dbit+8, clean+i*dw - clean: - .._.clean_table .dst + // if got here - flip the carry; then clean the table-entry. + rep(256, i) 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: } } @@ -755,16 +763,23 @@ ns hex { } // Space Complexity: 500 - def init @ switch, clean, end < .._.ret > dst { + def init @ switch, clean_table_entry, 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 + // 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) 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: } } @@ -791,26 +806,27 @@ ns hex { end: } - // n must be a power of 2 - def clean_table n, dst, ret @ clean { + // @Assumes: n must be a power of 2, and it must be (1<>1)) ? ret : clean+(d^((1<<(#d))>>1))*dw } // Space Complexity: 256 - def clean_table dst, ret { - .clean_table 256, dst, ret + def clean_table_entry__table dst < .ret { + .clean_table_entry__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 + // 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. + // + // It jumps to the table, at entry (src<<4 | dst). + // At last, it xors the value of hex._.res into dst. + 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 From f9a7d8e383b8fe8731d23bf7358eabf0a4d02368 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Wed, 28 Dec 2022 10:30:18 +0200 Subject: [PATCH 05/62] refactor hex/memory.fj --- stl/conf.json | 6 ++- stl/hex/memory.fj | 113 ++++++++++++++++++++++++++++++++++++++++++++++ stl/hexlib.fj | 108 +++----------------------------------------- 3 files changed, 123 insertions(+), 104 deletions(-) create mode 100644 stl/hex/memory.fj diff --git a/stl/conf.json b/stl/conf.json index 3d386c2..2d9863a 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -8,9 +8,11 @@ "bit/shifts", "bit/math", + "hex/memory", + "hexlib", + "iolib", "ptrlib", - "mathlib", - "hexlib" + "mathlib" ] } \ No newline at end of file diff --git a/stl/hex/memory.fj b/stl/hex/memory.fj new file mode 100644 index 0000000..82e29a4 --- /dev/null +++ b/stl/hex/memory.fj @@ -0,0 +1,113 @@ +// ---------- Memory Variables: + + +// Size Complexity: 1 +def hex val { + ;(val > 0xf ? 0xf : (val < 0 ? 0 : val)) * dw +} +def hex { + hex 0 +} + + +// Size Complexity: n +ns hex { + 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 + // x = 0 + def zero x { + .xor x, x + } + + // 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 + def mov dst, src @ end { + 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 { + 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 + def swap hex1, hex2 @ end { + 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 { + comp_if1 hex1==hex2, end + .xor n, hex1, hex2 + .xor n, hex2, hex1 + .xor n, hex1, hex2 + end: + } +} diff --git a/stl/hexlib.fj b/stl/hexlib.fj index 2dbbe44..1711b44 100644 --- a/stl/hexlib.fj +++ b/stl/hexlib.fj @@ -1,47 +1,23 @@ -// ---------- 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 + // Time Complexity: @ + // Space Complexity: @+12 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) + // Time Complexity: n@ + // Space Complexity: n(@+12) def xor n, dst, src { rep (n, i) .xor dst+i*dw, src+i*dw } - // Time Complexity: phi - // Space Complexity: phi+27 + // Time Complexity: @ + // Space Complexity: @+12 def exact_xor d3, d2, d1, d0, src @ switch, end { wflip src+w, switch, src pad 16 @@ -590,78 +566,6 @@ ns hex { -// ---------- 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 From 978dd7d9117218cd967dab49bb361b47c63d23f2 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Wed, 28 Dec 2022 14:16:05 +0200 Subject: [PATCH 06/62] refactor stl hex/logics.fj --- stl/bit/logics.fj | 2 +- stl/conf.json | 1 + stl/hex/logics.fj | 207 ++++++++++++++++++++++++++++++++++++++++++++++ stl/hexlib.fj | 188 +---------------------------------------- 4 files changed, 213 insertions(+), 185 deletions(-) create mode 100644 stl/hex/logics.fj diff --git a/stl/bit/logics.fj b/stl/bit/logics.fj index 6d8d6a7..51af237 100644 --- a/stl/bit/logics.fj +++ b/stl/bit/logics.fj @@ -49,7 +49,7 @@ ns bit { rep(n, i) .double_exact_xor bit+i, var+dbit+i*dw, src+i*dw } - // Complexity: n@ + // Complexity: @ // dst ^= src // src = 0 def xor_zero dst, src { diff --git a/stl/conf.json b/stl/conf.json index 2d9863a..cacd341 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -9,6 +9,7 @@ "bit/math", "hex/memory", + "hex/logics", "hexlib", "iolib", diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj new file mode 100644 index 0000000..898a96a --- /dev/null +++ b/stl/hex/logics.fj @@ -0,0 +1,207 @@ +// ---------- Logical Macros: + + +ns hex { + + // Time Complexity: @ + // Space Complexity: @+12 + // dst ^= src + 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 + 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 + 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 + 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: @+4 + // Space Complexity: @+28 + // {t3,t2,t1,t0} ^= src + // {d3,d2,d1,d0} ^= src + 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 + // Complexity: 4 + // hex = !hex + def not n, hex { + rep(n, i) .not hex+i*dw + } + + + // Time Complexity: 4@+13 + // Space Complexity: 4@+52 + // dst |= src + def or dst, src < .or.dst { + ._.jump_to_table_entry dst, src, .or.dst + } + + // Time Complexity: n(4@+13) + // Space Complexity: n(4@+52) + // dst[:n] |= src[:n] + def or n, dst, src { + rep(n, i) .or dst+i*dw, src+i*dw + } + + ns or { + // Time Complexity: 9 (when jumping to dst, until finished) + // Space Complexity: 514 + def init @ switch, clean_table_entry, end < .._.res, .._.ret > 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. + rep(256, d) 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@+13 + // Space Complexity: 4@+52 + // dst &= src + def and dst, src < .and.dst { + ._.jump_to_table_entry dst, src, .and.dst + } + + // Time Complexity: n(4@+13) + // Space Complexity: n(4@+52) + // dst[:n] &= src[:n] + def and n, dst, src { + rep(n, i) .and dst+i*dw, src+i*dw + } + + ns and { + // Time Complexity: 9 (when jumping to dst, until finished) + // Space Complexity: 514 + def init @ switch, clean_table_entry, end < .._.res, .._.ret > 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. + rep(256, d) 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/hexlib.fj b/stl/hexlib.fj index 1711b44..6916012 100644 --- a/stl/hexlib.fj +++ b/stl/hexlib.fj @@ -2,190 +2,6 @@ ns hex { - - // Time Complexity: @ - // Space Complexity: @+12 - 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) - def xor n, dst, src { - rep (n, i) .xor dst+i*dw, src+i*dw - } - - - // Time Complexity: @ - // Space Complexity: @+12 - 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 { - ._.jump_to_table_entry 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_table_entry, end < .._.res, .._.ret > 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. - rep(256, d) 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: 4phi+16 - // Space Complexity: 4phi+96 - def and dst, src < .and.dst { - ._.jump_to_table_entry 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_table_entry, end < .._.res, .._.ret > 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. - rep(256, d) 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: 2.13phi+2 // Space Complexity: n(1.5phi+23) + 2phi+121 (+padding) // dst[n] += x.#on-bits @@ -725,6 +541,9 @@ ns hex { // 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. def jump_to_table_entry dst, src, jumper_to_table @ return < .ret, .res { @@ -740,6 +559,7 @@ ns hex { + // ---------- IO From 983f9b593791cd0adf6e0023944785b0f0b5d47e Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Wed, 28 Dec 2022 23:14:07 +0200 Subject: [PATCH 07/62] update stl hex/logics documentation --- stl/hex/logics.fj | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj index 898a96a..f06834d 100644 --- a/stl/hex/logics.fj +++ b/stl/hex/logics.fj @@ -125,21 +125,20 @@ ns hex { } // Complexity: 4n - // Complexity: 4 - // hex = !hex + // hex[:n] = !hex[:n] def not n, hex { rep(n, i) .not hex+i*dw } - // Time Complexity: 4@+13 + // Time Complexity: 4@+10 // Space Complexity: 4@+52 // dst |= src def or dst, src < .or.dst { ._.jump_to_table_entry dst, src, .or.dst } - // Time Complexity: n(4@+13) + // Time Complexity: n(4@+10) // Space Complexity: n(4@+52) // dst[:n] |= src[:n] def or n, dst, src { @@ -147,8 +146,8 @@ ns hex { } ns or { - // Time Complexity: 9 (when jumping to dst, until finished) - // Space Complexity: 514 + // Time Complexity: 6 (when jumping to dst, until finished) + // Space Complexity: 595 def init @ switch, clean_table_entry, end < .._.res, .._.ret > dst { ;end dst: ;.switch @@ -159,6 +158,7 @@ ns hex { // 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) wflip_macro .._.res+w, (((d&0xf)|(d>>4))^(d&0xf))*dw, clean_table_entry+d*dw clean_table_entry: @@ -169,14 +169,14 @@ ns hex { } - // Time Complexity: 4@+13 + // Time Complexity: 4@+10 // Space Complexity: 4@+52 // dst &= src def and dst, src < .and.dst { ._.jump_to_table_entry dst, src, .and.dst } - // Time Complexity: n(4@+13) + // Time Complexity: n(4@+10) // Space Complexity: n(4@+52) // dst[:n] &= src[:n] def and n, dst, src { @@ -184,8 +184,8 @@ ns hex { } ns and { - // Time Complexity: 9 (when jumping to dst, until finished) - // Space Complexity: 514 + // Time Complexity: 6 (when jumping to dst, until finished) + // Space Complexity: 595 def init @ switch, clean_table_entry, end < .._.res, .._.ret > dst { ;end dst: ;.switch @@ -196,6 +196,7 @@ ns hex { // 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) wflip_macro .._.res+w, (((d&0xf)&(d>>4))^(d&0xf))*dw, clean_table_entry+d*dw clean_table_entry: From 13eab028e69833979dfe0fe5d31b3caed2942732 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Wed, 28 Dec 2022 23:14:49 +0200 Subject: [PATCH 08/62] refactor stl hex/math.fj --- stl/conf.json | 1 + stl/hex/math.fj | 361 ++++++++++++++++++++++++++++++++++++++++++++++++ stl/hexlib.fj | 324 +------------------------------------------ 3 files changed, 367 insertions(+), 319 deletions(-) create mode 100644 stl/hex/math.fj diff --git a/stl/conf.json b/stl/conf.json index cacd341..375d498 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -10,6 +10,7 @@ "hex/memory", "hex/logics", + "hex/math", "hexlib", "iolib", diff --git a/stl/hex/math.fj b/stl/hex/math.fj new file mode 100644 index 0000000..cc1cc3d --- /dev/null +++ b/stl/hex/math.fj @@ -0,0 +1,361 @@ +// ---------- Logical Macros: + + +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) + 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) 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 + //part5 + xor_switch: + ._.clean_table_entry__table 16, dst, after_add + rep(16, i) 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 + // 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@ // (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@ // (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) + // hex[:n] = -hex[:n] + def neg n, hex { + .not n, hex + .inc n, hex + } + + + // Time Complexity: 4@+12 + // Space Complexity: 4@+52 + // dst += src + // Relies on the add-carry, and updates it at the end. + 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] + 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: 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. must be called once if you want to use hex.add (hex.init calls it). + def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > 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) 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) 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) 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 + 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] + 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: 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 add "truth" tables are. must be called once if you want to use hex.sub (hex.init calls it). + def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > 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) 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) 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) 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/hexlib.fj b/stl/hexlib.fj index 6916012..48dc05d 100644 --- a/stl/hexlib.fj +++ b/stl/hexlib.fj @@ -2,71 +2,6 @@ ns hex { - // 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_entry__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 { @@ -132,262 +67,13 @@ ns hex { } - -// ---------- 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 { - ._.jump_to_table_entry 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 @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > 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: - 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_table_entry+d*dw)) - switch__with_carry: - rep(256, d) 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. - rep(256, i) 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: 4phi+17 - // Space Complexity: 4phi+96 - def sub dst, src < .sub.dst { - ._.jump_to_table_entry 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 @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > 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: - 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_table_entry+d*dw)) - switch__with_carry: - rep(256, d) 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. - rep(256, i) 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: - } - } -} - - - // ---------- Conditional Jump ns hex { - // Time Complexity: phi-1 - // Space Complexity: phi+15 + // Time Complexity: @-1 + // Space Complexity: @+15 + // def if_flags hex, flags, l0, l1 @ switch, clean, return, finish { wflip hex+w, switch, hex @@ -404,8 +90,8 @@ ns hex { return+dbit+0; l1 } - // Time Complexity: phi-1 - // Space Complexity: phi+15 + // Time Complexity: @-1 + // Space Complexity: @+15 def if hex, l0, l1 { .if_flags hex, 0xfffe, l0, l1 } From b4be5490399d6bd15bf56cc706fb8fd78833b578 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 30 Dec 2022 01:03:50 +0200 Subject: [PATCH 09/62] refactor stl hex/shifts.fj --- stl/conf.json | 1 + stl/hex/shifts.fj | 79 +++++++++++++++++++++++++++++++++++++++++++++++ stl/hexlib.fj | 69 ----------------------------------------- 3 files changed, 80 insertions(+), 69 deletions(-) create mode 100644 stl/hex/shifts.fj diff --git a/stl/conf.json b/stl/conf.json index 375d498..b510c17 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -11,6 +11,7 @@ "hex/memory", "hex/logics", "hex/math", + "hex/shifts", "hexlib", "iolib", diff --git a/stl/hex/shifts.fj b/stl/hex/shifts.fj new file mode 100644 index 0000000..5b17954 --- /dev/null +++ b/stl/hex/shifts.fj @@ -0,0 +1,79 @@ +// ---------- Logical Macros: + + +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(bit),dst(hex)} = dst << 1 + // @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) 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 + // {dst(hex),next(bit)} = dst >> 1 + // @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) 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/hexlib.fj b/stl/hexlib.fj index 48dc05d..1610b3f 100644 --- a/stl/hexlib.fj +++ b/stl/hexlib.fj @@ -1,72 +1,3 @@ -// ---------- Logical Macros: - - -ns hex { - // 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_entry__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_entry__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 - } -} - - // ---------- Conditional Jump From 06b4b19d75e257d3e4e66e67e99b3e28a9ba3667 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 30 Dec 2022 12:40:15 +0200 Subject: [PATCH 10/62] refactor stl hex/cond_jumps.fj --- stl/conf.json | 1 + stl/hex/cond_jumps.fj | 146 ++++++++++++++++++++++++++++++++++++++++++ stl/hex/logics.fj | 6 ++ stl/hex/math.fj | 8 ++- stl/hexlib.fj | 125 ------------------------------------ 5 files changed, 159 insertions(+), 127 deletions(-) create mode 100644 stl/hex/cond_jumps.fj diff --git a/stl/conf.json b/stl/conf.json index b510c17..4d34b58 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -12,6 +12,7 @@ "hex/logics", "hex/math", "hex/shifts", + "hex/cond_jumps", "hexlib", "iolib", diff --git a/stl/hex/cond_jumps.fj b/stl/hex/cond_jumps.fj new file mode 100644 index 0000000..9c506b2 --- /dev/null +++ b/stl/hex/cond_jumps.fj @@ -0,0 +1,146 @@ +// ---------- 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 x[:n] < 0 jump to neg, else jump to zpos (Zero POSitive). + def sign n, x, neg, zpos { + .if_flags x+(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) + 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) + 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: + } + + // Time Complexity: 6 (when jumping to dst, until finished) + // Space Complexity: 514 + // This is where the compare "truth" tables are. + 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) 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/logics.fj b/stl/hex/logics.fj index f06834d..7d5cd38 100644 --- a/stl/hex/logics.fj +++ b/stl/hex/logics.fj @@ -134,6 +134,7 @@ ns hex { // Time Complexity: 4@+10 // Space Complexity: 4@+52 // dst |= src + // @requires hex.or.init (or hex.init) def or dst, src < .or.dst { ._.jump_to_table_entry dst, src, .or.dst } @@ -141,6 +142,7 @@ ns hex { // 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 } @@ -148,6 +150,7 @@ ns hex { ns or { // Time Complexity: 6 (when jumping to dst, until finished) // Space Complexity: 595 + // This is where the or "truth" tables are. def init @ switch, clean_table_entry, end < .._.res, .._.ret > dst { ;end dst: ;.switch @@ -172,6 +175,7 @@ ns hex { // Time Complexity: 4@+10 // Space Complexity: 4@+52 // dst &= src + // @requires hex.and.init (or hex.init) def and dst, src < .and.dst { ._.jump_to_table_entry dst, src, .and.dst } @@ -179,6 +183,7 @@ ns hex { // 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 } @@ -186,6 +191,7 @@ ns hex { ns and { // Time Complexity: 6 (when jumping to dst, until finished) // Space Complexity: 595 + // This is where the and "truth" tables are. def init @ switch, clean_table_entry, end < .._.res, .._.ret > dst { ;end dst: ;.switch diff --git a/stl/hex/math.fj b/stl/hex/math.fj index cc1cc3d..e71f707 100644 --- a/stl/hex/math.fj +++ b/stl/hex/math.fj @@ -194,6 +194,7 @@ ns hex { // Space Complexity: 4@+52 // dst += src // 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 } @@ -201,6 +202,7 @@ ns hex { // 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 @@ -246,7 +248,7 @@ ns hex { // Time Complexity: 8 (when jumping to dst, until finished) // Space Complexity: 1570 - // This is where the add "truth" tables are. must be called once if you want to use hex.add (hex.init calls it). + // This is where the add "truth" tables are. def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > dst { ;end dst: ;.switch__without_carry @@ -279,6 +281,7 @@ ns hex { // Time Complexity: 4@+12 // Space Complexity: 4@+52 // dst -= src + // @requires hex.sub.init (or hex.init) def sub dst, src < .sub.dst { ._.jump_to_table_entry dst, src, .sub.dst } @@ -286,6 +289,7 @@ ns hex { // 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 @@ -330,7 +334,7 @@ ns hex { // Time Complexity: 8 (when jumping to dst, until finished) // Space Complexity: 1570 - // This is where the add "truth" tables are. must be called once if you want to use hex.sub (hex.init calls it). + // This is where the sub "truth" tables are. must be called once if you want to use hex.sub (hex.init calls it). def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > dst { ;end dst: ;.switch__without_carry diff --git a/stl/hexlib.fj b/stl/hexlib.fj index 1610b3f..b44b0fc 100644 --- a/stl/hexlib.fj +++ b/stl/hexlib.fj @@ -1,128 +1,3 @@ -// ---------- Conditional Jump - - -ns hex { - // Time Complexity: @-1 - // Space Complexity: @+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: @-1 - // Space Complexity: @+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_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) 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: - } - } -} - - ns hex { def init { ._.init From 5ad6108a1d04b6b079cf8798ed37f8ffd2e18b37 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 30 Dec 2022 13:32:17 +0200 Subject: [PATCH 11/62] refactor stl hex/tables_init.fj --- stl/conf.json | 1 + stl/hex/tables_init.fj | 60 ++++++++++++++++++++++++++++++++++++++++++ stl/hexlib.fj | 54 ------------------------------------- stl/mathlib.fj | 2 +- 4 files changed, 62 insertions(+), 55 deletions(-) create mode 100644 stl/hex/tables_init.fj diff --git a/stl/conf.json b/stl/conf.json index 4d34b58..873d03a 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -13,6 +13,7 @@ "hex/math", "hex/shifts", "hex/cond_jumps", + "hex/tables_init", "hexlib", "iolib", diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj new file mode 100644 index 0000000..f855abf --- /dev/null +++ b/stl/hex/tables_init.fj @@ -0,0 +1,60 @@ +ns hex { + def init { + ._.init + } + + ns _ { + // 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. + 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 + 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. + 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 index b44b0fc..3cde4d2 100644 --- a/stl/hexlib.fj +++ b/stl/hexlib.fj @@ -1,57 +1,3 @@ -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: - } - - // @Assumes: n must be a power of 2, and it must be (1<>1)) ? ret : clean+(d^((1<<(#d))>>1))*dw - } - - // Space Complexity: 256 - 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. - 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 - } - } -} - - - - // ---------- IO diff --git a/stl/mathlib.fj b/stl/mathlib.fj index b43d88f..aa87e0c 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -204,7 +204,7 @@ ns hex { wflip .ret+w, return } - // Space Complexity: 1600 + // Space Complexity: 1616+@ 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 { // general progression (after jumping to hex.mul.dst with value d): // dst -> switch+d (set lower4 mul result in add_carry_dst+4) (5) From 37ca6848b43711c0c338253efad2c5e9de70bb5f Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 30 Dec 2022 13:48:29 +0200 Subject: [PATCH 12/62] split stl/hex/math into math_basic --- stl/conf.json | 1 + stl/hex/math.fj | 190 +--------------------------------------- stl/hex/math_basic.fj | 191 +++++++++++++++++++++++++++++++++++++++++ stl/hex/shifts.fj | 2 +- stl/hex/tables_init.fj | 3 + 5 files changed, 197 insertions(+), 190 deletions(-) create mode 100644 stl/hex/math_basic.fj diff --git a/stl/conf.json b/stl/conf.json index 873d03a..352d43e 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -11,6 +11,7 @@ "hex/memory", "hex/logics", "hex/math", + "hex/math_basic", "hex/shifts", "hex/cond_jumps", "hex/tables_init", diff --git a/stl/hex/math.fj b/stl/hex/math.fj index e71f707..d3097a4 100644 --- a/stl/hex/math.fj +++ b/stl/hex/math.fj @@ -1,195 +1,7 @@ -// ---------- Logical Macros: +// ---------- Addition / Subtraction: 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) - 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) 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 - //part5 - xor_switch: - ._.clean_table_entry__table 16, dst, after_add - rep(16, i) 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 - // 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@ // (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@ // (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) - // hex[:n] = -hex[:n] - def neg n, hex { - .not n, hex - .inc n, hex - } - - // Time Complexity: 4@+12 // Space Complexity: 4@+52 // dst += src diff --git a/stl/hex/math_basic.fj b/stl/hex/math_basic.fj new file mode 100644 index 0000000..c8db934 --- /dev/null +++ b/stl/hex/math_basic.fj @@ -0,0 +1,191 @@ +// ---------- 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) + 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) 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 + //part5 + xor_switch: + ._.clean_table_entry__table 16, dst, after_add + rep(16, i) 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 + // 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@ // (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@ // (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) + // hex[:n] = -hex[:n] + def neg n, hex { + .not n, hex + .inc n, hex + } +} diff --git a/stl/hex/shifts.fj b/stl/hex/shifts.fj index 5b17954..928f288 100644 --- a/stl/hex/shifts.fj +++ b/stl/hex/shifts.fj @@ -1,4 +1,4 @@ -// ---------- Logical Macros: +// ---------- Logical Shifts: ns hex { diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj index f855abf..0bf8761 100644 --- a/stl/hex/tables_init.fj +++ b/stl/hex/tables_init.fj @@ -1,3 +1,6 @@ +// ---------- Init The Truth Tables: + + ns hex { def init { ._.init From 76f172f9e1a584f5c1b15008820646130a7700ef Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 30 Dec 2022 13:55:50 +0200 Subject: [PATCH 13/62] move stl/hexlib into hex/input, hex/output --- stl/README.md | 6 +-- stl/conf.json | 3 +- stl/hex/input.fj | 82 ++++++++++++++++++++++++++++++++ stl/{hexlib.fj => hex/output.fj} | 80 +------------------------------ 4 files changed, 88 insertions(+), 83 deletions(-) create mode 100644 stl/hex/input.fj rename stl/{hexlib.fj => hex/output.fj} (69%) diff --git a/stl/README.md b/stl/README.md index a7a9fbd..2199d0b 100644 --- a/stl/README.md +++ b/stl/README.md @@ -28,8 +28,8 @@ 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`. +### [hexlib.fj](hex/) +Defines the `hex` data-structure (for hexadecimal variables), which is smaller and faster than using 4 `bit`s. Offers macros for manipulating hexadecimal variables and vectors (i.e. numbers). @@ -60,7 +60,7 @@ 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 diff --git a/stl/conf.json b/stl/conf.json index 352d43e..3f4b648 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -15,7 +15,8 @@ "hex/shifts", "hex/cond_jumps", "hex/tables_init", - "hexlib", + "hex/input", + "hex/output", "iolib", "ptrlib", diff --git a/stl/hex/input.fj b/stl/hex/input.fj new file mode 100644 index 0000000..4b3e12e --- /dev/null +++ b/stl/hex/input.fj @@ -0,0 +1,82 @@ +// ---------- Input Hex + + +ns hex { + // 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/hexlib.fj b/stl/hex/output.fj similarity index 69% rename from stl/hexlib.fj rename to stl/hex/output.fj index 3cde4d2..3f23a84 100644 --- a/stl/hexlib.fj +++ b/stl/hex/output.fj @@ -1,4 +1,4 @@ -// ---------- IO +// ---------- Output Hex ns hex { @@ -177,82 +177,4 @@ ns hex { 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: - } } From 780cc790656c6bf05cb7e00c434d4b802d4ea1bb Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 30 Dec 2022 15:12:25 +0200 Subject: [PATCH 14/62] refactor stl hex/input.fj --- stl/hex/input.fj | 83 +++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/stl/hex/input.fj b/stl/hex/input.fj index 4b3e12e..7057dc7 100644 --- a/stl/hex/input.fj +++ b/stl/hex/input.fj @@ -2,79 +2,84 @@ ns hex { - // Time Complexity: 2phi+7 - // Space Complexity: 2phi+39 + // Time Complexity: 2@+7 + // Space Complexity: 2@+18 + // hex = input(4bits) // lsb first def input_hex hex @ flip0, flip1, flip2, flip3, end < IO { + // part0 .zero hex wflip IO+w, flip0, IO pad 8 flip0: - IO+dbit+1;IO - hex+dbit+0;flip0 + IO+dbit+1;IO // part1 + hex+dbit+0;flip0 //(part0.5) flip1: - IO+dbit+2;IO - hex+dbit+1;flip1 + IO+dbit+2;IO // part2 + hex+dbit+1;flip1 //(part1.5) flip3: - wflip IO+w, flip3, end - hex+dbit+3;flip3 + wflip IO+w, flip3, end // part4 + hex+dbit+3;flip3 //(part3.5) flip2: - IO+dbit+1;IO - hex+dbit+2;flip2 + IO+dbit+1;IO // part3 + hex+dbit+2;flip2 //(part2.5) end: } - // Time Complexity: 4phi+14 - // Space Complexity: 4phi+70 + // Time Complexity: 4@+14 + // Space Complexity: 4@+36 + // x[:2] = input(8bits) // lsb first def input x { .input_hex x .input_hex x+dw } - // Time Complexity: n(4phi+14) - // Space Complexity: n(4phi+70) + // Time Complexity: n(4@+14) + // Space Complexity: n(4@+36) + // x[:2n] = input(8n-bits) // lsb first 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 { + // 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: + do_dec: // if input==0x3i for 0<=i<=9, finish; else, goto error. .if_flags hex, (1<<10)-1, error, end - do_hex: - wflip hex+w, switch, hex + do_hex: // if input==0x4i or input==0x6i: + wflip hex+w, hex_switch, hex finish_hex: hex+dbit+3; - wflip hex+w, switch, end + wflip hex+w, hex_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 + 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: From 4b6305bfbdca9a126539d7b10a5af356e5f00b2a Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 30 Dec 2022 19:00:30 +0200 Subject: [PATCH 15/62] refactor stl hex/output.fj --- stl/hex/output.fj | 92 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/stl/hex/output.fj b/stl/hex/output.fj index 3f23a84..98ee4c0 100644 --- a/stl/hex/output.fj +++ b/stl/hex/output.fj @@ -1,7 +1,11 @@ // ---------- 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 < IO { wflip hex+w, switch, hex pad 16 @@ -16,12 +20,13 @@ ns hex { 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 + + IO+0;print_a // a + IO+1;print_a // b + IO+0;print_c // c + IO+1;print_c // d + IO+0;print_e // e + IO+1;print_e // f print_0: @@ -52,19 +57,32 @@ ns hex { } + // 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 } +} + - // 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 { +// 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 < IO { wflip hex+w, switch, hex pad 16 switch: @@ -86,7 +104,7 @@ ns hex { IO+1;print_d // e IO+0;print_f // f - print_0: + print_0: // outputs 0x30 IO+0; IO+0; IO+0; @@ -105,12 +123,12 @@ ns hex { IO+0; IO+0; IO+1;print_0+3*dw - print_a: + print_a: // outputs 0x40 / 0x60 IO+0; IO+0; IO+0; IO+0; - IO+(big_flag ? 0 : 1); + IO+(use_uppercase ? 0 : 1); IO+1;print_0+6*dw print_b: IO+1;print_a+1*dw @@ -124,21 +142,28 @@ ns hex { 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(@+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(2phi+8) - // Space Complexity: n(3.5phi+72) - def print_uint n, x, x_prefix, big_flag @ after_prefix, printed_something, end { + // 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 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 + rep(n, i) .print_uint.print_digit x+(n-1-i)*dw, printed_something, use_uppercase bit.if1 printed_something, end output '0' ;end @@ -147,29 +172,38 @@ ns hex { 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 { + // Time Complexity: 2@+6 + // Space Complexity: 3@+54 + // print the ascii of the hexadecimal representation of hex (skip leading zeros, based on printed_something) + // + // hex (hex): the number to be printed + // 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, big_flag + ..print_as_digit hex, use_uppercase 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 { + // 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 - .if_flags x+(n-1)*dw, 0xff00, print, do_neg + .sign n, x, do_neg, print do_neg: bit.not neg .neg n, x output '-' print: - .print_uint n, x, x_prefix, big_flag + .print_uint n, x, x_prefix, use_uppercase bit.if0 neg, end .neg n, x ;end From 2591df8f143b87098362ed29f5b74a4191448dbf Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 30 Dec 2022 22:04:18 +0200 Subject: [PATCH 16/62] refactor stl: add params-"types" documentaries --- stl/hex/cond_jumps.fj | 13 ++++++++++--- stl/hex/input.fj | 16 ++++++++-------- stl/hex/logics.fj | 20 +++++++++++++++++--- stl/hex/math.fj | 4 ++++ stl/hex/math_basic.fj | 11 +++++++---- stl/hex/memory.fj | 10 +++++++--- stl/hex/output.fj | 1 - stl/hex/shifts.fj | 8 ++++++-- stl/hex/tables_init.fj | 6 ++++++ stl/mathlib.fj | 6 ++++++ 10 files changed, 71 insertions(+), 24 deletions(-) diff --git a/stl/hex/cond_jumps.fj b/stl/hex/cond_jumps.fj index 9c506b2..f5e263a 100644 --- a/stl/hex/cond_jumps.fj +++ b/stl/hex/cond_jumps.fj @@ -7,6 +7,8 @@ ns hex { // if flags&(1< 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 @@ -109,12 +113,15 @@ ns hex { // 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: diff --git a/stl/hex/input.fj b/stl/hex/input.fj index 7057dc7..339d0e6 100644 --- a/stl/hex/input.fj +++ b/stl/hex/input.fj @@ -4,7 +4,7 @@ ns hex { // Time Complexity: 2@+7 // Space Complexity: 2@+18 - // hex = input(4bits) // lsb first + // hex := input(4bits) // lsb first def input_hex hex @ flip0, flip1, flip2, flip3, end < IO { // part0 .zero hex @@ -28,17 +28,17 @@ ns hex { // Time Complexity: 4@+14 // Space Complexity: 4@+36 - // x[:2] = input(8bits) // lsb first - def input x { - .input_hex x - .input_hex x+dw + // 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) - // x[:2n] = input(8n-bits) // lsb first - def input n, x { - rep(n, i) .input x+2*i*dw + // bytes[:2n] = input(8n-bits) // lsb first + def input n, bytes { + rep(n, i) .input bytes+2*i*dw } // Time Complexity: 7@+11 diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj index 7d5cd38..bfc3a64 100644 --- a/stl/hex/logics.fj +++ b/stl/hex/logics.fj @@ -6,6 +6,8 @@ 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 } @@ -21,6 +23,8 @@ ns hex { // 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 @@ -49,6 +53,8 @@ ns hex { // Space Complexity: @+28 // dst ^= src // src = 0 + // + // both dst,src are hexes def xor_zero dst, src { .double_xor dst, src, src } @@ -65,6 +71,8 @@ ns hex { // 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 } @@ -73,6 +81,8 @@ ns hex { // 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 @@ -125,9 +135,9 @@ ns hex { } // Complexity: 4n - // hex[:n] = !hex[:n] - def not n, hex { - rep(n, i) .not hex+i*dw + // x[:n] = !x[:n] + def not n, x { + rep(n, i) .not x+i*dw } @@ -135,6 +145,8 @@ ns hex { // 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 } @@ -175,6 +187,8 @@ ns hex { // 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 diff --git a/stl/hex/math.fj b/stl/hex/math.fj index d3097a4..644ce80 100644 --- a/stl/hex/math.fj +++ b/stl/hex/math.fj @@ -5,6 +5,8 @@ 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 { @@ -93,6 +95,8 @@ ns hex { // 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 diff --git a/stl/hex/math_basic.fj b/stl/hex/math_basic.fj index c8db934..9176551 100644 --- a/stl/hex/math_basic.fj +++ b/stl/hex/math_basic.fj @@ -6,6 +6,7 @@ ns hex { // 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 @@ -74,6 +75,8 @@ ns hex { // 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 @@ -183,9 +186,9 @@ ns hex { // Time Complexity: ~@+4n // Space Complexity: n(1.5@+17) - // hex[:n] = -hex[:n] - def neg n, hex { - .not n, hex - .inc n, hex + // x[:n] = -x[:n] + def neg n, x { + .not n, x + .inc n, x } } diff --git a/stl/hex/memory.fj b/stl/hex/memory.fj index 82e29a4..446197d 100644 --- a/stl/hex/memory.fj +++ b/stl/hex/memory.fj @@ -28,9 +28,9 @@ ns hex { // Time Complexity: @ // Space Complexity: @+12 - // x = 0 - def zero x { - .xor x, x + // hex = 0 + def zero hex { + .xor hex, hex } // Time Complexity: n@ @@ -43,6 +43,8 @@ ns hex { // Time Complexity: 2@+1 // Space Complexity: 2@+25 // dst = src + // + // both dst,src are hexes. def mov dst, src @ end { comp_if1 dst==src, end .zero dst @@ -91,6 +93,8 @@ ns hex { // Time Complexity: 3@+1 // Space Complexity: 3@+37 // hex1, hex2 = hex2, hex1 + // + // both hex1,hex2 are hexes. def swap hex1, hex2 @ end { comp_if1 hex1==hex2, end .xor hex1, hex2 diff --git a/stl/hex/output.fj b/stl/hex/output.fj index 98ee4c0..2f739f3 100644 --- a/stl/hex/output.fj +++ b/stl/hex/output.fj @@ -176,7 +176,6 @@ ns hex { // Space Complexity: 3@+54 // print the ascii of the hexadecimal representation of hex (skip leading zeros, based on printed_something) // - // hex (hex): the number to be printed // 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 { diff --git a/stl/hex/shifts.fj b/stl/hex/shifts.fj index 928f288..7a30641 100644 --- a/stl/hex/shifts.fj +++ b/stl/hex/shifts.fj @@ -43,7 +43,9 @@ ns hex { ns shifts { // Time Complexity: @+1 // Space Complexity: @+28 - // {next(bit),dst(hex)} = dst << 1 + // {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 @@ -61,7 +63,9 @@ ns hex { // Time Complexity: @+1 // Space Complexity: @+28 - // {dst(hex),next(bit)} = dst >> 1 + // {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 diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj index 0bf8761..fac204a 100644 --- a/stl/hex/tables_init.fj +++ b/stl/hex/tables_init.fj @@ -30,6 +30,8 @@ ns hex { // // Time Complexity: log(n) / 2 (an overage over all entries, of jumping to an entry in this table) // Space Complexity: n + // + // n is a size-constant, dst/ret are hexes. def clean_table_entry__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 @@ -39,6 +41,8 @@ ns hex { // // Time Complexity: 4 // Space Complexity: 256 + // + // dst is a hex. def clean_table_entry__table dst < .ret { .clean_table_entry__table 256, dst, .ret } @@ -51,6 +55,8 @@ ns hex { // // 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 diff --git a/stl/mathlib.fj b/stl/mathlib.fj index aa87e0c..89bf78d 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -134,6 +134,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 +148,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 +162,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 From 62eba982b4c991d3159a0ec9bd374e39b34936a9 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 31 Dec 2022 10:56:29 +0200 Subject: [PATCH 17/62] stl: split iolib into casting, bit/{input,output,casting}, update README --- README.md | 18 +-- stl/README.md | 16 +-- stl/bit/casting.fj | 147 ++++++++++++++++++++ stl/bit/input.fj | 23 ++++ stl/{iolib.fj => bit/output.fj} | 237 -------------------------------- stl/casting.fj | 50 +++++++ stl/conf.json | 5 +- stl/runlib.fj | 38 ++++- 8 files changed, 277 insertions(+), 257 deletions(-) create mode 100644 stl/bit/casting.fj create mode 100644 stl/bit/input.fj rename stl/{iolib.fj => bit/output.fj} (58%) create mode 100644 stl/casting.fj diff --git a/README.md b/README.md index b8e4287..481644d 100644 --- a/README.md +++ b/README.md @@ -64,11 +64,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 [bit/math.fj](stl/bit/math.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? @@ -126,11 +126,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. - - bit/ - 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. diff --git a/stl/README.md b/stl/README.md index 2199d0b..21eab7b 100644 --- a/stl/README.md +++ b/stl/README.md @@ -14,6 +14,8 @@ 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. ### [bit/](bit/) @@ -21,26 +23,22 @@ 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. +You can find conditional jumps, memory manipulations, inputs, outputs, and logical and arithmetical macros. ### [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](hex/) +### [hex/](hex/) Defines the `hex` data-structure (for hexadecimal variables), which is smaller and faster than using 4 `bit`s. 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. +You can find conditional jumps, memory manipulations, input, output, and logical and arithmetical macros. -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). diff --git a/stl/bit/casting.fj b/stl/bit/casting.fj new file mode 100644 index 0000000..77589bf --- /dev/null +++ b/stl/bit/casting.fj @@ -0,0 +1,147 @@ +// ---------- String: + + +ns bit { + def str str { + .vec (((#str)+15)>>3)<<3, str + } +} + + + +// ---------- 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: + } +} diff --git a/stl/bit/input.fj b/stl/bit/input.fj new file mode 100644 index 0000000..1ddee62 --- /dev/null +++ b/stl/bit/input.fj @@ -0,0 +1,23 @@ +// ---------- 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 + } +} diff --git a/stl/iolib.fj b/stl/bit/output.fj similarity index 58% rename from stl/iolib.fj rename to stl/bit/output.fj index 58fe3ec..e7a215f 100644 --- a/stl/iolib.fj +++ b/stl/bit/output.fj @@ -1,73 +1,3 @@ -// Every line is (Input/Output of) bananas! -// Implementation of input/output and casting operations - -// 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) -// 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 { @@ -120,173 +50,6 @@ ns bit { } -// ---------- 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 diff --git a/stl/casting.fj b/stl/casting.fj new file mode 100644 index 0000000..1d1fa3c --- /dev/null +++ b/stl/casting.fj @@ -0,0 +1,50 @@ +// ---------- Casting from bit + + +// 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 3f4b648..20c17bc 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -7,6 +7,9 @@ "bit/cond_jumps", "bit/shifts", "bit/math", + "bit/input", + "bit/output", + "bit/casting", "hex/memory", "hex/logics", @@ -18,7 +21,7 @@ "hex/input", "hex/output", - "iolib", + "casting", "ptrlib", "mathlib" ] diff --git a/stl/runlib.fj b/stl/runlib.fj index 56f773d..ffad476 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -71,7 +71,9 @@ def comp_if1 expr, l1 @ continue { } -// if expr != 0 (compilation time), flip the given bit +// 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); } @@ -99,6 +101,17 @@ def loop { // 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 IO+w, input_0, IO +// pad 2 +// input_0: +// wflip IO+w, input_0, jump_to_input_0_handling +// input_1: +// wflip IO+w, input_0, jump_to_input_0_handling +// +// @note that if you use this macro, you can't touch 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 @@ -107,3 +120,26 @@ def default_input in0_handler, in1_handler @ io_handler, end < IO { ;in1_handler end: } + + + +// ---------- Output constants: + + +// 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 +} + +// 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 +} From c1aa8f3e15ff3cbfe9e6226f5566d008ad846bcd Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Thu, 5 Jan 2023 23:49:17 +0200 Subject: [PATCH 18/62] refactor stl/bit/input --- stl/bit/input.fj | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/stl/bit/input.fj b/stl/bit/input.fj index 1ddee62..e5ae394 100644 --- a/stl/bit/input.fj +++ b/stl/bit/input.fj @@ -3,20 +3,26 @@ ns bit { - // Complexity: 2phi+4 + // Complexity: 2@-2 + // input one bit into the bit-variable, 'dst'. + // dst is an output parameter. def input_bit dst < IO { .zero dst .xor dst, IO } - // Complexity: 16phi+32 + // 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(16phi+32) + // 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 } From 5620db2d7e92d5afc273c456631ea4e64f8473e1 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Thu, 5 Jan 2023 23:49:25 +0200 Subject: [PATCH 19/62] refactor stl/bit/casting --- stl/bit/casting.fj | 98 +++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/stl/bit/casting.fj b/stl/bit/casting.fj index 77589bf..cb73689 100644 --- a/stl/bit/casting.fj +++ b/stl/bit/casting.fj @@ -2,6 +2,8 @@ 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 } @@ -13,7 +15,9 @@ ns bit { ns bit { - // Complexity 9phi+20 + // 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 @@ -21,7 +25,9 @@ ns bit { } - // Complexity 12phi+26 + // 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 @@ -29,18 +35,20 @@ ns bit { } - // Complexity 25phi+92 + // Complexity: 16@+19 + // Space: 21@+30 + // ascii := the ascii representation of the value of hex. + // 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 - 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 + .not 2, ascii + 4*dw // ascii = 0x30 ;end hex_label: - .dec 3, ascii // A-F is now 1-6 + .dec 3, ascii // A-F is now 1-6 .not ascii + 6*dw // ascii = 0x40 ;end nine4: @@ -55,18 +63,20 @@ ns bit { ns bit { -// Complexity: 17phi+63 - def ascii2bin error, bin, ascii @ half_bin, return_error, good, end { + // 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, good, return_error + .cmp 7, ascii+dw, half_bin, return_error, copy_binary_value, return_error return_error: .not error ;end - good: + copy_binary_value: .xor bin, ascii ;end @@ -77,20 +87,22 @@ ns bit { } - // Complexity: 25phi+83 - def ascii2dec error, dec, ascii @ half_dec, return_error, first_good, good, nine4, 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, first_good, return_error - first_good: - .cmp 4, ascii, nine4, good, good, return_error + .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 - good: + copy_decimal_value: .xor 4, dec, ascii ;end @@ -102,44 +114,50 @@ ns bit { } - // 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 { + // 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, half_dec, try_big_hex, dec_first_good, try_big_hex + .cmp 4, ascii+4*dw, decimal_ascii_msh, check_uppercase_hex, dec_first_check, check_uppercase_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 + 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_good: - .cmp 4, ascii, nine4, dec_good, dec_good, return_error - dec_good: - .xor 4, hex, ascii - ;end + 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_good: + hex_first_check: .inc 3, ascii - .cmp 3, ascii, two3, return_error, hex_good, hex_good - hex_good: - .xor 3, hex, ascii - .not hex+3*dw - ;end + .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 + return_error: + .not error + ;end - half_dec: + decimal_ascii_msh: .vec 4, 0x30>>4 - half_big_hex: + uppercase_hexadecimal_ascii_msh: .vec 5, 0x40>>3 - half_small_hex: + lowercase_hexadecimal_ascii_msh: .vec 5, 0x60>>3 nine4: .vec 4, 9 + seven3: + .vec 3, 7 two3: .vec 3, 2 end: From b5f3405775c54ebbb21515ce84294c13c3290980 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 6 Jan 2023 18:30:42 +0200 Subject: [PATCH 20/62] refactor bit+hex in stl/bit/output.fj --- stl/bit/casting.fj | 2 +- stl/bit/output.fj | 50 +++++++++++++++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/stl/bit/casting.fj b/stl/bit/casting.fj index cb73689..e486e2d 100644 --- a/stl/bit/casting.fj +++ b/stl/bit/casting.fj @@ -37,7 +37,7 @@ ns bit { // Complexity: 16@+19 // Space: 21@+30 - // ascii := the ascii representation of the value of hex. + // 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 diff --git a/stl/bit/output.fj b/stl/bit/output.fj index e7a215f..91d9c1c 100644 --- a/stl/bit/output.fj +++ b/stl/bit/output.fj @@ -1,5 +1,6 @@ ns bit { - // Complexity phi+5 + // Complexity @+2 + // outputs the bit 'x'. def output x @ label_ptr, base_jump_label, end < IO { .xor label_ptr, x label_ptr: @@ -13,20 +14,22 @@ ns bit { } - // Complexity 8phi+40 + // Complexity 8@+16 + // outputs a byte from x[:8] (a bit vector. from lsb to msb). def print x { rep(8, i) .output x+i*dw } - // Complexity n(8phi+40) + // Complexity n(8@+16) + // outputs n bytes from x[:8n] (a bit vector. from lsb to msb). 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) + // Complexity min(n, len+1)*(16@+32) + // prints the string at x[:8n], or until the reaches the first '\0' (the earlier). def print_str n, x @ end { rep(n, i) ._.print_str_one_char x+8*i*dw, end end: @@ -39,11 +42,17 @@ ns bit { } + // Complexity: @+9 + // prints the ascii character '0'/'1', based on x's value. + // x is a bit. def print_as_digit x { .output x rep(7, i) output_bit ('0'>>(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 } @@ -55,16 +64,20 @@ ns bit { 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 + // 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 { + comp_if0 x_prefix, 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 + rep(n/4, i) .print_hex_uint.print_digit x+(n/4-1-i)*4*dw, printed_flag .if1 printed_flag, end output '0' @@ -74,9 +87,9 @@ ns bit { bit end: } - //Comp: 39phi+155 - ns _ { - def print_hex_uint_char hex, printed_flag @ continue, ascii, 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 @@ -94,13 +107,18 @@ ns bit { } - - def print_hex_int n, x, print_x @ do_print { + // 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 output '-' .neg n, x do_print: - .print_hex_uint n, x, print_x + .print_hex_uint n, x, x_prefix } } From 4d3a24253a45f14d2568af665add5c42bf747dac Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 7 Jan 2023 10:27:50 +0200 Subject: [PATCH 21/62] fix bug of error-printing the macro-tree --- src/ops.py | 5 +++-- src/preprocessor.py | 11 ++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ops.py b/src/ops.py index 89b31c7..97d8a6c 100644 --- a/src/ops.py +++ b/src/ops.py @@ -212,6 +212,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 +254,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})' diff --git a/src/preprocessor.py b/src/preprocessor.py index 385022b..1dc9e02 100644 --- a/src/preprocessor.py +++ b/src/preprocessor.py @@ -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): @@ -127,14 +127,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 +145,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 +156,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) \ @@ -228,6 +228,7 @@ def resolve_macro_aux(preprocessor_data: PreprocessorData, 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)) From 38bbda7a0056d9bed03d4f96db97f40ea1a8ef0c Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 7 Jan 2023 11:11:16 +0200 Subject: [PATCH 22/62] refactor mul10 / div10 --- stl/mathlib.fj | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/stl/mathlib.fj b/stl/mathlib.fj index 89bf78d..f1fc542 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -18,7 +18,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,8 +33,8 @@ 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 @@ -43,31 +44,33 @@ ns bit { 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 From 1b53c26deb6264572d6a23109be20b3fa856ac3e Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 7 Jan 2023 15:12:41 +0200 Subject: [PATCH 23/62] refactor stl/bit/output.fj --- stl/bit/output.fj | 156 ++++++++++++++-------------------------------- 1 file changed, 47 insertions(+), 109 deletions(-) diff --git a/stl/bit/output.fj b/stl/bit/output.fj index 91d9c1c..69f6085 100644 --- a/stl/bit/output.fj +++ b/stl/bit/output.fj @@ -128,101 +128,24 @@ ns bit { 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 + // Time Complexity: n^2(2@+4) + // Space Complexity: n(14@+16) + // prints x[:n] as an unsigned decimal number (without leading zeros). // - // .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) + // 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)*(phi+2 + 11phi+27 + 5phi+28) = n(5.12phi+17.17) < n(6phi+17.5) space + // 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 - 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 + // 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 + 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 @@ -230,7 +153,7 @@ ns bit { .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)) + .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: @@ -245,30 +168,45 @@ ns 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: - } + 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 + 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: 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) 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 output '-' From 091824a30302861a9ff16d192dc8ab239c49e10e Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 7 Jan 2023 16:05:13 +0200 Subject: [PATCH 24/62] remove const fcalls --- stl/ptrlib.fj | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index ba8ee52..84b6506 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -254,18 +254,7 @@ ns bit { // ---------- 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: phi+1 +// Complexity: @-1 def fcall label, ret_reg @ ret { wflip ret_reg+w, ret, label pad 2 @@ -277,22 +266,3 @@ def fcall label, ret_reg @ ret { 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 -} From 2ca877bf047d52057f2853f75a3ca18837322603 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 13 Jan 2023 10:22:51 +0200 Subject: [PATCH 25/62] add stl/bit/ parameters documentation --- stl/bit/cond_jumps.fj | 11 ++++++++++- stl/bit/logics.fj | 16 +++++++++++++++- stl/bit/math.fj | 7 +++++++ stl/bit/memory.fj | 26 ++++++++++++++++++-------- stl/bit/shifts.fj | 6 ++++-- stl/hex/memory.fj | 5 +++++ 6 files changed, 59 insertions(+), 12 deletions(-) diff --git a/stl/bit/cond_jumps.fj b/stl/bit/cond_jumps.fj index 94789b8..70f55bd 100644 --- a/stl/bit/cond_jumps.fj +++ b/stl/bit/cond_jumps.fj @@ -4,6 +4,7 @@ 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: @@ -15,7 +16,8 @@ ns bit { } // Complexity: n(@+2) - // if the n-bit x == 0 jump to l0, else jump to l1 + // 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 @@ -23,6 +25,7 @@ ns bit { // 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: @@ -30,6 +33,7 @@ ns bit { // 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: @@ -37,6 +41,7 @@ ns bit { // 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: @@ -44,6 +49,7 @@ ns bit { // 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: @@ -56,6 +62,7 @@ ns bit { // 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 @@ -69,6 +76,7 @@ ns bit { // 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 @@ -80,6 +88,7 @@ ns bit { // 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/logics.fj b/stl/bit/logics.fj index 51af237..02981a7 100644 --- a/stl/bit/logics.fj +++ b/stl/bit/logics.fj @@ -4,12 +4,14 @@ 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 } @@ -17,6 +19,7 @@ ns bit { // 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 @@ -31,6 +34,7 @@ ns bit { // 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 @@ -45,6 +49,7 @@ ns bit { // Complexity: n@ // bit(bit_address) ^= src // var ^= src + // dst,var,src are bit[:n]. def bit_var_xor n, bit, var, src { rep(n, i) .double_exact_xor bit+i, var+dbit+i*dw, src+i*dw } @@ -52,6 +57,7 @@ ns bit { // Complexity: @ // dst ^= src // src = 0 + // dst,src are bits. def xor_zero dst, src { .double_exact_xor dst+dbit, src+dbit, src } @@ -59,6 +65,7 @@ ns bit { // 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 } @@ -66,6 +73,7 @@ ns bit { // Complexity: 2@+2 // dst |= src + // dst,src are bits. def or dst, src @ end { .if0 src, end .one dst @@ -74,6 +82,7 @@ ns bit { // 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 } @@ -81,6 +90,7 @@ ns bit { // Complexity: 2@+2 // dst &= src + // dst,src are bits. def and dst, src @ end { .if1 src, end .zero dst @@ -89,6 +99,7 @@ ns bit { // 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 } @@ -96,18 +107,21 @@ ns bit { // Complexity: 1 // dst ^= 1 + // dst is a bit. def not dst { dst + dbit; } // Complexity: n - // dst[i] ^= (1<>i)&1 @@ -28,9 +33,9 @@ ns bit { ns bit { // Complexity: @-1 - // x = 0 - def zero x { - .xor x, x + // bit = 0 + def zero bit { + .xor bit, bit } // Complexity: n(@-1) @@ -41,10 +46,10 @@ ns bit { // Complexity: @ - // x = 1 - def one x { - .zero x - .not x + // bit = 1 + def one bit { + .zero bit + .not bit } // Complexity: n@ @@ -57,6 +62,7 @@ ns bit { // Complexity: 2@-2 // note: doesn't work if dst==src. // dst = src + // dst,src are bits. def unsafe_mov dst, src { .zero dst .xor dst, src @@ -65,6 +71,7 @@ ns bit { // Complexity: 2@-1 // note: works if dst==src. // dst = src + // dst,src are bits. def mov dst, src @ end { comp_if1 dst==src, end .unsafe_mov dst, src @@ -74,6 +81,7 @@ ns bit { // Complexity: n(2@-2) // note: doesn't work if dst and src overlap. works if dst==src. // dst[:n] = src[:n] + // dst,src are bit.vec[:n]. def mov n, dst, src @ end { comp_if1 dst==src, end rep(n, i) .unsafe_mov dst+i*dw, src+i*dw @@ -84,6 +92,7 @@ ns bit { // Complexity: 2@+5 // Space: 3@+8 // a, b = b, a + // a,b are bits. def swap a, b @ a0, a1, notnot, end { .if a, a0, a1 a0: @@ -99,6 +108,7 @@ ns bit { // Complexity: n(2@+5) // Space: n(3@+8) // a[:n], b[:n] = b[:n], a[:n] + // a,b are bit.vec[:n]. def swap n, a, b { rep(n, i) .swap a+i*dw, b+i*dw } diff --git a/stl/bit/shifts.fj b/stl/bit/shifts.fj index 83f791e..00a7bce 100644 --- a/stl/bit/shifts.fj +++ b/stl/bit/shifts.fj @@ -10,6 +10,7 @@ ns bit { // 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 @@ -24,6 +25,7 @@ ns bit { // 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 @@ -31,7 +33,7 @@ ns bit { // Complexity: n(2@-1) - // rotate right by 1-bit the x[:n] + // 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 @@ -43,7 +45,7 @@ ns bit { // Complexity: n(2@-1) - // rotate left by 1-bit the x[:n] + // 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 diff --git a/stl/hex/memory.fj b/stl/hex/memory.fj index 446197d..569371a 100644 --- a/stl/hex/memory.fj +++ b/stl/hex/memory.fj @@ -2,6 +2,10 @@ // Size Complexity: 1 +// +// This is the basic variable in the FlipJump standard library - a bit (can contain only 0/1). +// you can't place it as any other standard library macro, as "running" this line is undefined behavior. +// The bit (and bit.vec) should be placed in a place that won't run. def hex val { ;(val > 0xf ? 0xf : (val < 0 ? 0 : val)) * dw } @@ -11,6 +15,7 @@ def hex { // Size Complexity: n +// read the comment for the bit macro. ns hex { def vec n, value { rep(n, i) hex (value>>(4*i))&0xf From b8de996bc03fed3d5371420a4c65718b6077a837 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 13 Jan 2023 10:23:52 +0200 Subject: [PATCH 26/62] explain the stl-documentation in its README --- stl/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stl/README.md b/stl/README.md index 21eab7b..1ae43a9 100644 --- a/stl/README.md +++ b/stl/README.md @@ -49,6 +49,18 @@ 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). +- For every one of its parameters, states its type (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. + + # Contribute The FlipJump philosophy is to be the simplest language of all, that can do any modern computation. From 09ba1aef407f8a7c4664e0d0b7c29cf505b0aaf4 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Thu, 19 Jan 2023 14:11:13 +0200 Subject: [PATCH 27/62] split part of stl/pointers into stl/bit/pointers --- stl/bit/pointers.fj | 206 +++++++++++++++++++++++++++++++++++++++ stl/conf.json | 1 + stl/ptrlib.fj | 229 +------------------------------------------- 3 files changed, 209 insertions(+), 227 deletions(-) create mode 100644 stl/bit/pointers.fj diff --git a/stl/bit/pointers.fj b/stl/bit/pointers.fj new file mode 100644 index 0000000..922afab --- /dev/null +++ b/stl/bit/pointers.fj @@ -0,0 +1,206 @@ +// ---------- Init + + +ns bit { + def ptr_init { + .pointers.ptr_init + } + + ns pointers { + 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 + } + } +} + + + +// ---------- Jump: + + +ns bit { + // like: ;*ptr + // Complexity w(2phi+6) + def ptr_jump ptr < .pointers.to_jump, .pointers.to_jump_var { + .bit_var_xor w, .pointers.to_jump+w, .pointers.to_jump_var, .pointers.to_jump_var + .bit_var_xor w, .pointers.to_jump+w, .pointers.to_jump_var, ptr + ;.pointers.to_jump + } +} + + + +// ---------- Flip: + + +ns bit { + // like: *ptr; + // Complexity w(2phi+6) + def ptr_flip ptr @ cleanup < .pointers.to_flip, .pointers.to_flip_var { + wflip .pointers.to_flip+w, cleanup + + .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, .pointers.to_flip_var + .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, ptr + ;.pointers.to_flip + + cleanup: + wflip .pointers.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 < .pointers.to_flip, .pointers.to_flip_var{ + .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, .pointers.to_flip_var + .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, ptr + rep(w, i) .pointers.advance_by_one_and_flip__ptr_wflip (#(i^((i+1)%w))), (value>>i)&1 + } + ns pointers { + 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*(#w-1) + .ptr_wflip ptr, value + .not ptr + dw*(#w-1) + } +} + + + +// ---------- Xor + + +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 + + .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 { + .pointers.stack n + } + + ns pointers { + // 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 < .pointers.sp { + .mov w, dst, .pointers.sp + } + + + // Complexity w(2phi+10) + def inc_ptr ptr { + .inc w-#w, ptr+#w*dw + } + + + // Complexity w(2phi+12) + def dec_ptr ptr { + .dec w-#w, ptr+#w*dw + } + + + // Assumes address is 2dw-aligned + // Complexity w(5phi+21) + def push_ret_address address < .pointers.sp { + .inc_ptr .pointers.sp + .ptr_wflip_2nd_word .pointers.sp, address + } + + // Assumes address is 2dw-aligned + // Complexity w(5phi+23) + def pop_ret_address address < .pointers.sp { + .ptr_wflip_2nd_word .pointers.sp, address + .dec_ptr .pointers.sp + } + + + // Complexity: w(4phi+17) + def push bit < .pointers.sp { + .inc_ptr .pointers.sp + .xor_to_ptr .pointers.sp, bit + } + + // Assumes *sp==bit. + // Complexity: w(4phi+19) + def pop bit < .pointers.sp { + .xor_to_ptr .pointers.sp, bit + .dec_ptr .pointers.sp + } + + // Complexity: w(12phi+47) + def pop_res bit < .pointers.sp { + .zero bit + .xor_from_ptr bit, .pointers.sp + .pop bit + } +} diff --git a/stl/conf.json b/stl/conf.json index 20c17bc..98f1226 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -10,6 +10,7 @@ "bit/input", "bit/output", "bit/casting", + "bit/pointers", "hex/memory", "hex/logics", diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index 84b6506..900a029 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -1,229 +1,4 @@ -// Every line is (pointing) bananas! -// Implementation of pointers (variables which represents a memory-place), stack and functions. - -// 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) -// 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 { - 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 - } - } -} - - - -// ---------- 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 - } -} - - - -// ---------- 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*(#w-1) - .ptr_wflip ptr, value - .not ptr + dw*(#w-1) - } -} - - - -// ---------- Xor - - -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 - - .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-#w, ptr+#w*dw - } - - - // Complexity w(2phi+12) - def dec_ptr ptr { - .dec w-#w, ptr+#w*dw - } - - - // 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 - } - - - // Complexity: w(4phi+17) - def push bit < ._.sp { - .inc_ptr ._.sp - .xor_to_ptr ._.sp, bit - } - - // 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 - } -} - // ---------- Functions @@ -244,8 +19,8 @@ ns bit { // Complexity: w(7phi+29) // the last-call's pop_ret_address is counted for this return - def return < ._.sp { - .ptr_jump ._.sp + def return < .pointers.sp { + .ptr_jump .pointers.sp } } From 9ef4ca1c5ff1644469e0e61342d23b827a4760bf Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Tue, 7 Mar 2023 09:59:44 +0200 Subject: [PATCH 28/62] add reserved names documentation --- stl/README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/stl/README.md b/stl/README.md index 1ae43a9..e1f6658 100644 --- a/stl/README.md +++ b/stl/README.md @@ -51,16 +51,26 @@ A configurable json file that maintains ordered lists of the standard library fi # Documentation Every macro is documented with: -- Its **time complexity** (and if it's significantly different, the **space complexity** as well) +- 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). -- For every one of its parameters, states its type (bit/hex/bit.vec/hex.vec/constant/address and so on). +- 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. +## 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 + + + # Contribute The FlipJump philosophy is to be the simplest language of all, that can do any modern computation. From c6fe2d322549a9e650526542bcecc054ec547ced Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Tue, 7 Mar 2023 15:58:31 +0200 Subject: [PATCH 29/62] move the bit macro to the bit namespace --- programs/calc.fj | 10 +++---- programs/concept_checks/casting.fj | 4 +-- programs/concept_checks/pair_ns.fj | 2 +- programs/concept_checks/ptr.fj | 8 +++--- programs/concept_checks/segments.fj | 2 +- programs/func_tests/func3.fj | 2 +- programs/func_tests/func4.fj | 2 +- programs/func_tests/func5.fj | 8 +++--- programs/print_tests/print_as_digit.fj | 4 +-- programs/sanity_checks/mathbit.fj | 4 +-- programs/sanity_checks/not.fj | 2 +- programs/sanity_checks/rep.fj | 2 +- programs/sanity_checks/simple.fj | 2 +- programs/sanity_checks/testbit.fj | 2 +- programs/sanity_checks/testbit_with_nops.fj | 6 ++-- programs/simple_math_checks/series_sum.fj | 2 +- stl/bit/math.fj | 8 +++--- stl/bit/memory.fj | 32 ++++++++++----------- stl/bit/output.fj | 4 +-- stl/bit/shifts.fj | 4 +-- stl/hex/memory.fj | 6 ++-- stl/hex/output.fj | 4 +-- stl/mathlib.fj | 14 ++++----- 23 files changed, 67 insertions(+), 67 deletions(-) diff --git a/programs/calc.fj b/programs/calc.fj index ebb7839..baa1113 100644 --- a/programs/calc.fj +++ b/programs/calc.fj @@ -105,7 +105,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 @@ -159,7 +159,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 +206,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/casting.fj b/programs/concept_checks/casting.fj index a262f6d..1862fb1 100644 --- a/programs/concept_checks/casting.fj +++ b/programs/concept_checks/casting.fj @@ -23,8 +23,8 @@ output '\n' loop -b0: bit 0 -b1: bit 1 +b0: bit.bit 0 +b1: bit.bit 1 h: hex bits: bit.vec 12, 0x123 hex: hex.vec 3 diff --git a/programs/concept_checks/pair_ns.fj b/programs/concept_checks/pair_ns.fj index 5e1bc94..df38e22 100644 --- a/programs/concept_checks/pair_ns.fj +++ b/programs/concept_checks/pair_ns.fj @@ -62,7 +62,7 @@ ns Pair { bit.print_hex_int ..len, .temp1, 1 fret .ret_reg - ret_reg: bit 0 + ret_reg: bit.bit 0 temp1: bit.vec ..len, 0 temp2: bit.vec ..len, 0 diff --git a/programs/concept_checks/ptr.fj b/programs/concept_checks/ptr.fj index d396201..4bd258b 100644 --- a/programs/concept_checks/ptr.fj +++ b/programs/concept_checks/ptr.fj @@ -51,7 +51,7 @@ test3: 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 +63,11 @@ 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 diff --git a/programs/concept_checks/segments.fj b/programs/concept_checks/segments.fj index 19a7b2a..7a1ae1a 100644 --- a/programs/concept_checks/segments.fj +++ b/programs/concept_checks/segments.fj @@ -22,7 +22,7 @@ back: error: - bit + bit.bit str_hi: bit.str "Hi!\n" diff --git a/programs/func_tests/func3.fj b/programs/func_tests/func3.fj index 09541c6..b801367 100644 --- a/programs/func_tests/func3.fj +++ b/programs/func_tests/func3.fj @@ -20,7 +20,7 @@ func3: x3: - bit 0 + bit.bit 0 bit.ptr_init bit.stack 10 diff --git a/programs/func_tests/func4.fj b/programs/func_tests/func4.fj index 42f0c35..7fef708 100644 --- a/programs/func_tests/func4.fj +++ b/programs/func_tests/func4.fj @@ -34,7 +34,7 @@ func4: x4: - bit 0 + bit.bit 0 ascii: bit.vec 8 diff --git a/programs/func_tests/func5.fj b/programs/func_tests/func5.fj index 253ed85..ce73f8d 100644 --- a/programs/func_tests/func5.fj +++ b/programs/func_tests/func5.fj @@ -51,17 +51,17 @@ func5: bit.return __func5_res: - bit + bit.bit __func5_arg_ptr: bit.vec w x5: - bit 1 + bit.bit 1 y5: - bit 1 + bit.bit 1 res5: - bit 0 + bit.bit 0 ascii: bit.vec 8 diff --git a/programs/print_tests/print_as_digit.fj b/programs/print_tests/print_as_digit.fj index 25ec9ac..bc85d52 100644 --- a/programs/print_tests/print_as_digit.fj +++ b/programs/print_tests/print_as_digit.fj @@ -11,6 +11,6 @@ output '\n' loop -b0: bit 0 -b1: bit 1 +b0: bit.bit 0 +b1: bit.bit 1 h: rep(16, i) hex i diff --git a/programs/sanity_checks/mathbit.fj b/programs/sanity_checks/mathbit.fj index 8b0ee1c..0da4fee 100644 --- a/programs/sanity_checks/mathbit.fj +++ b/programs/sanity_checks/mathbit.fj @@ -3,6 +3,6 @@ loop x: - bit 0 + bit.bit 0 carry: - bit 1 + bit.bit 1 diff --git a/programs/sanity_checks/not.fj b/programs/sanity_checks/not.fj index c855c8c..8780f13 100644 --- a/programs/sanity_checks/not.fj +++ b/programs/sanity_checks/not.fj @@ -3,4 +3,4 @@ loop x: - bit 0 + bit.bit 0 diff --git a/programs/sanity_checks/rep.fj b/programs/sanity_checks/rep.fj index 3abd406..bed16b0 100644 --- a/programs/sanity_checks/rep.fj +++ b/programs/sanity_checks/rep.fj @@ -3,4 +3,4 @@ loop x: - bit 0 + bit.bit 0 diff --git a/programs/sanity_checks/simple.fj b/programs/sanity_checks/simple.fj index e7c2771..0d460ad 100644 --- a/programs/sanity_checks/simple.fj +++ b/programs/sanity_checks/simple.fj @@ -6,4 +6,4 @@ loop x: - bit 0 + bit.bit 0 diff --git a/programs/sanity_checks/testbit.fj b/programs/sanity_checks/testbit.fj index 32ec5dd..8f4f4fd 100644 --- a/programs/sanity_checks/testbit.fj +++ b/programs/sanity_checks/testbit.fj @@ -9,4 +9,4 @@ l1: 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..3652dde 100644 --- a/programs/sanity_checks/testbit_with_nops.fj +++ b/programs/sanity_checks/testbit_with_nops.fj @@ -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/series_sum.fj b/programs/simple_math_checks/series_sum.fj index 7dbd785..fe032d2 100644 --- a/programs/simple_math_checks/series_sum.fj +++ b/programs/simple_math_checks/series_sum.fj @@ -44,7 +44,7 @@ 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/stl/bit/math.fj b/stl/bit/math.fj index ed53e5f..8ec9d93 100644 --- a/stl/bit/math.fj +++ b/stl/bit/math.fj @@ -23,7 +23,7 @@ ns bit { rep(n, i) .inc1 x+i*dw, carry skip carry: - bit + .bit } // Complexity: n(2@+8) @@ -55,7 +55,7 @@ ns bit { .or carry, _src skip _src: - bit + .bit } // Complexity: n(8@+14) @@ -66,7 +66,7 @@ ns bit { rep(n, i) .add1 dst+i*dw, src+i*dw, carry skip carry: - bit + .bit } // Complexity: n(8@+16) @@ -79,6 +79,6 @@ ns bit { .not n, src skip carry: - bit + .bit } } diff --git a/stl/bit/memory.fj b/stl/bit/memory.fj index 096d657..f3e346f 100644 --- a/stl/bit/memory.fj +++ b/stl/bit/memory.fj @@ -1,29 +1,29 @@ // ---------- Memory Variables -// 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 bit value { - ; value ? dw : 0 -} +ns bit { + // Size Complexity: 1 + // + // This is the basic variable in the FlipJump standard library - a bit (can contain only 0/1). + // you can't place it as any other standard library macro, as "running" this line is undefined behavior. + // The bit (and bit.vec) should be placed in a place that won't run. + def bit value { + ; value ? dw : 0 + } -def bit { - bit 0 -} + def bit { + .bit 0 + } -// Size Complexity: n -// read the comment for the bit macro. -ns bit { + // Size Complexity: n + // read the comment for the bit macro. def vec n, value { - rep(n, i) bit (value>>i)&1 + rep(n, i) .bit (value>>i)&1 } def vec n { - rep(n, i) bit + rep(n, i) .bit } } diff --git a/stl/bit/output.fj b/stl/bit/output.fj index 69f6085..640fd34 100644 --- a/stl/bit/output.fj +++ b/stl/bit/output.fj @@ -84,7 +84,7 @@ ns bit { ;end printed_flag: - bit + .bit end: } //Comp: 29@+44 @@ -164,7 +164,7 @@ ns bit { src: .vec n print_buffer: .vec (n*28/93+1)*4 print_buffer_flag: .vec n*28/93+1 - zero_flag: bit + zero_flag: .bit ret_reg: 0;0 end: } diff --git a/stl/bit/shifts.fj b/stl/bit/shifts.fj index 00a7bce..e51792b 100644 --- a/stl/bit/shifts.fj +++ b/stl/bit/shifts.fj @@ -40,7 +40,7 @@ ns bit { .mov x+(n-1)*dw, temp_bit skip temp_bit: - bit + .bit } @@ -52,6 +52,6 @@ ns bit { .mov x, temp_bit skip temp_bit: - bit + .bit } } diff --git a/stl/hex/memory.fj b/stl/hex/memory.fj index 569371a..9812ccc 100644 --- a/stl/hex/memory.fj +++ b/stl/hex/memory.fj @@ -3,9 +3,9 @@ // Size Complexity: 1 // -// This is the basic variable in the FlipJump standard library - a bit (can contain only 0/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 bit (and bit.vec) should be placed in a place that won't run. +// 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 } @@ -15,7 +15,7 @@ def hex { // Size Complexity: n -// read the comment for the bit macro. +// read the comment for the hex macro. ns hex { def vec n, value { rep(n, i) hex (value>>(4*i))&0xf diff --git a/stl/hex/output.fj b/stl/hex/output.fj index 2f739f3..e94e85d 100644 --- a/stl/hex/output.fj +++ b/stl/hex/output.fj @@ -168,7 +168,7 @@ ns hex { output '0' ;end - printed_something: bit + printed_something: bit.bit end: } ns print_uint { @@ -207,7 +207,7 @@ ns hex { .neg n, x ;end - neg: bit + neg: bit.bit end: } } diff --git a/stl/mathlib.fj b/stl/mathlib.fj index f1fc542..4112003 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -40,7 +40,7 @@ ns bit { ._.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 _ { @@ -309,11 +309,11 @@ ns bit { ;end negative_a: - bit + .bit negative_b: - bit + .bit one_negative: - bit + .bit end: } @@ -377,11 +377,11 @@ ns bit { ;end negative_a: - bit + .bit negative_b: - bit + .bit one_negative: - bit + .bit end: } From 85b2edd4f444e5e2b62de2cc4f3cb5e9799cee01 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Tue, 7 Mar 2023 16:04:29 +0200 Subject: [PATCH 30/62] move the hex macro to the bit namespace --- programs/concept_checks/casting.fj | 2 +- programs/hexlib_tests/2params/add.fj | 6 ++-- programs/hexlib_tests/2params/and.fj | 6 ++-- programs/hexlib_tests/2params/cmp.fj | 4 +-- programs/hexlib_tests/2params/or.fj | 6 ++-- programs/hexlib_tests/2params/sub.fj | 6 ++-- programs/hexlib_tests/basics1/basic_math.fj | 6 ++-- programs/hexlib_tests/basics1/basic_memory.fj | 4 +-- programs/hexlib_tests/basics1/if.fj | 2 +- programs/hexlib_tests/basics1/input.fj | 2 +- .../hexlib_tests/basics1/print_as_digit.fj | 2 +- programs/print_tests/print_as_digit.fj | 2 +- stl/bit/memory.fj | 2 -- stl/hex/input.fj | 2 +- stl/hex/memory.fj | 32 +++++++++---------- stl/hex/tables_init.fj | 2 +- 16 files changed, 42 insertions(+), 44 deletions(-) diff --git a/programs/concept_checks/casting.fj b/programs/concept_checks/casting.fj index 1862fb1..86a1ff1 100644 --- a/programs/concept_checks/casting.fj +++ b/programs/concept_checks/casting.fj @@ -25,7 +25,7 @@ loop b0: bit.bit 0 b1: bit.bit 1 -h: hex +h: hex.hex bits: bit.vec 12, 0x123 hex: hex.vec 3 diff --git a/programs/hexlib_tests/2params/add.fj b/programs/hexlib_tests/2params/add.fj index 4109f7c..ad3fdad 100644 --- a/programs/hexlib_tests/2params/add.fj +++ b/programs/hexlib_tests/2params/add.fj @@ -34,8 +34,8 @@ def test_add a, b @ c0_1st, c1_1st, print_1st, c0_2nd, c1_2nd, print_2nd, ah_1st 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/and.fj b/programs/hexlib_tests/2params/and.fj index 51d9717..ddc4fc5 100644 --- a/programs/hexlib_tests/2params/and.fj +++ b/programs/hexlib_tests/2params/and.fj @@ -16,8 +16,8 @@ def test_and a, b @ ah, ah_copy, bh, end { 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/cmp.fj b/programs/hexlib_tests/2params/cmp.fj index cead52e..08ccb87 100644 --- a/programs/hexlib_tests/2params/cmp.fj +++ b/programs/hexlib_tests/2params/cmp.fj @@ -20,8 +20,8 @@ def test_cmp a, b @ lt, eq, gt, ah, bh, end { gt: output '>' ;end - ah: hex a - bh: hex b + ah: hex.hex a + bh: hex.hex b end: output '\n' } diff --git a/programs/hexlib_tests/2params/or.fj b/programs/hexlib_tests/2params/or.fj index c8148c5..dc33a53 100644 --- a/programs/hexlib_tests/2params/or.fj +++ b/programs/hexlib_tests/2params/or.fj @@ -16,8 +16,8 @@ def test_or a, b @ ah, ah_copy, bh, end { 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/sub.fj b/programs/hexlib_tests/2params/sub.fj index 0fbe73a..5e0ac06 100644 --- a/programs/hexlib_tests/2params/sub.fj +++ b/programs/hexlib_tests/2params/sub.fj @@ -34,8 +34,8 @@ def test_sub a, b @ c0_1st, c1_1st, print_1st, c0_2nd, c1_2nd, print_2nd, ah_1st 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/basics1/basic_math.fj b/programs/hexlib_tests/basics1/basic_math.fj index 5114582..3b5e5a7 100644 --- a/programs/hexlib_tests/basics1/basic_math.fj +++ b/programs/hexlib_tests/basics1/basic_math.fj @@ -81,9 +81,9 @@ output "\n\n" 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 { diff --git a/programs/hexlib_tests/basics1/basic_memory.fj b/programs/hexlib_tests/basics1/basic_memory.fj index ce2cbea..21cb185 100644 --- a/programs/hexlib_tests/basics1/basic_memory.fj +++ b/programs/hexlib_tests/basics1/basic_memory.fj @@ -52,9 +52,9 @@ output "\n\n" 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 { diff --git a/programs/hexlib_tests/basics1/if.fj b/programs/hexlib_tests/basics1/if.fj index 0c09a12..672383b 100644 --- a/programs/hexlib_tests/basics1/if.fj +++ b/programs/hexlib_tests/basics1/if.fj @@ -76,7 +76,7 @@ vars: hex.vec 16 def print_if_flags hex_flags_val @ l0, l1, hex < 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 l1: diff --git a/programs/hexlib_tests/basics1/input.fj b/programs/hexlib_tests/basics1/input.fj index 7d34a07..c4693ad 100644 --- a/programs/hexlib_tests/basics1/input.fj +++ b/programs/hexlib_tests/basics1/input.fj @@ -42,7 +42,7 @@ def input_hex_print_error @ hex, error, end { hex.print_as_digit hex, 0 ;end - hex: hex + hex: hex.hex error: 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..4cfa573 100644 --- a/programs/hexlib_tests/basics1/print_as_digit.fj +++ b/programs/hexlib_tests/basics1/print_as_digit.fj @@ -8,4 +8,4 @@ output '\n' loop -vars: rep(16, j) hex j +vars: rep(16, j) hex.hex j diff --git a/programs/print_tests/print_as_digit.fj b/programs/print_tests/print_as_digit.fj index bc85d52..d20052a 100644 --- a/programs/print_tests/print_as_digit.fj +++ b/programs/print_tests/print_as_digit.fj @@ -13,4 +13,4 @@ loop b0: bit.bit 0 b1: bit.bit 1 -h: rep(16, i) hex i +h: rep(16, i) hex.hex i diff --git a/stl/bit/memory.fj b/stl/bit/memory.fj index f3e346f..0984320 100644 --- a/stl/bit/memory.fj +++ b/stl/bit/memory.fj @@ -10,7 +10,6 @@ ns bit { def bit value { ; value ? dw : 0 } - def bit { .bit 0 } @@ -21,7 +20,6 @@ ns bit { def vec n, value { rep(n, i) .bit (value>>i)&1 } - def vec n { rep(n, i) .bit } diff --git a/stl/hex/input.fj b/stl/hex/input.fj index 339d0e6..ec9f2e4 100644 --- a/stl/hex/input.fj +++ b/stl/hex/input.fj @@ -81,7 +81,7 @@ ns hex { ;hex_switch ;hex_switch - upper: hex + upper: .hex end: } } diff --git a/stl/hex/memory.fj b/stl/hex/memory.fj index 9812ccc..d341545 100644 --- a/stl/hex/memory.fj +++ b/stl/hex/memory.fj @@ -1,27 +1,27 @@ // ---------- Memory Variables: -// 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 -} +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. -ns hex { + // Size Complexity: n + // read the comment for the hex macro. def vec n, value { - rep(n, i) hex (value>>(4*i))&0xf + rep(n, i) .hex (value>>(4*i))&0xf } def vec n { - rep(n, i) hex + rep(n, i) .hex } } diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj index fac204a..7189afa 100644 --- a/stl/hex/tables_init.fj +++ b/stl/hex/tables_init.fj @@ -15,7 +15,7 @@ ns hex { def init @ end > ret, res { ;end ret: ;0 - res: hex + res: ..hex ..or.init // 595 ..and.init // 595 ..mul.init // 1616+@ From 56a3320f2d65030e644a27685c614deb8557cd5d Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Tue, 7 Mar 2023 19:20:27 +0200 Subject: [PATCH 31/62] show syntax/lexing errors on exceptions' messages --- src/fj_parser.py | 60 ++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/fj_parser.py b/src/fj_parser.py index d2e90f8..a267732 100644 --- a/src/fj_parser.py +++ b/src/fj_parser.py @@ -13,7 +13,7 @@ CodePosition, MacroName, Op, 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 +21,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 @@ -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 @@ -304,13 +309,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 +647,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 +687,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() From 8b47adb1c15af56906de2ff158744c1b504f0d49 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Tue, 7 Mar 2023 19:21:08 +0200 Subject: [PATCH 32/62] move all dangling macros in runlib.fj into the stl namespace --- programs/calc.fj | 6 +- programs/concept_checks/casting.fj | 16 +- programs/concept_checks/pair_ns.fj | 24 +-- programs/concept_checks/ptr.fj | 22 +- programs/concept_checks/segments.fj | 4 +- programs/func_tests/func1.fj | 12 +- programs/func_tests/func2.fj | 20 +- programs/func_tests/func3.fj | 16 +- programs/func_tests/func4.fj | 24 +-- programs/func_tests/func5.fj | 40 ++-- programs/hexlib_tests/2params/add.fj | 16 +- programs/hexlib_tests/2params/add_n.fj | 12 +- programs/hexlib_tests/2params/and.fj | 6 +- programs/hexlib_tests/2params/and_n.fj | 12 +- programs/hexlib_tests/2params/cmp.fj | 12 +- programs/hexlib_tests/2params/cmp_n.fj | 12 +- programs/hexlib_tests/2params/or.fj | 6 +- programs/hexlib_tests/2params/or_n.fj | 12 +- programs/hexlib_tests/2params/sub.fj | 16 +- programs/hexlib_tests/2params/sub_n.fj | 12 +- programs/hexlib_tests/basics1/basic_math.fj | 54 ++--- programs/hexlib_tests/basics1/basic_memory.fj | 42 ++-- programs/hexlib_tests/basics1/if.fj | 68 +++--- programs/hexlib_tests/basics1/input.fj | 18 +- .../hexlib_tests/basics1/print_as_digit.fj | 8 +- programs/hexlib_tests/basics1/print_int.fj | 28 +-- .../hexlib_tests/basics2/add_count_bits.fj | 16 +- programs/hexlib_tests/basics2/count_bits.fj | 16 +- programs/hexlib_tests/basics2/shift_utils.fj | 32 +-- programs/hexlib_tests/basics2/shl_bit.fj | 4 +- programs/hexlib_tests/basics2/shl_bit_n.fj | 4 +- programs/hexlib_tests/basics2/shl_hex.fj | 4 +- programs/hexlib_tests/basics2/shl_hex_n.fj | 4 +- programs/hexlib_tests/basics2/shr_bit.fj | 4 +- programs/hexlib_tests/basics2/shr_bit_n.fj | 4 +- programs/hexlib_tests/basics2/shr_hex.fj | 4 +- programs/hexlib_tests/basics2/shr_hex_n.fj | 4 +- programs/hexlib_tests/div/hexlib_div.fj | 44 ++-- programs/hexlib_tests/div/test4_1.fj | 4 +- programs/hexlib_tests/div/test4_2.fj | 4 +- programs/hexlib_tests/div/test4_4.fj | 4 +- programs/hexlib_tests/div/test8_1.fj | 4 +- programs/hexlib_tests/div/test8_2.fj | 4 +- programs/hexlib_tests/div/test8_4.fj | 4 +- programs/hexlib_tests/div/test8_8.fj | 4 +- programs/hexlib_tests/mul/add_mul_test.fj | 46 ++-- programs/hexlib_tests/mul/mul_test.fj | 38 ++-- programs/multi_comp/a.fj | 4 +- programs/multi_comp/a_no_stl.fj | 14 +- programs/multi_comp/c.fj | 4 +- programs/pair_ns_tests/test1.fj | 4 +- programs/pair_ns_tests/test2.fj | 4 +- programs/pair_ns_tests/test3.fj | 6 +- programs/print_tests/cat.fj | 4 +- programs/print_tests/hello_world.fj | 6 +- programs/print_tests/hello_world_with_str.fj | 4 +- programs/print_tests/hexprint.fj | 4 +- programs/print_tests/ncat.fj | 4 +- programs/print_tests/print_as_digit.fj | 10 +- programs/print_tests/print_dec.fj | 10 +- programs/print_tests/print_hex_int.fj | 4 +- programs/sanity_checks/mathbit.fj | 4 +- programs/sanity_checks/mathvec.fj | 4 +- programs/sanity_checks/not.fj | 4 +- programs/sanity_checks/rep.fj | 4 +- programs/sanity_checks/simple.fj | 10 +- programs/sanity_checks/testbit.fj | 10 +- programs/sanity_checks/testbit_with_nops.fj | 10 +- programs/simple_math_checks/div10.fj | 8 +- programs/simple_math_checks/nadd.fj | 4 +- programs/simple_math_checks/ncmp.fj | 16 +- programs/simple_math_checks/series_sum.fj | 22 +- stl/bit/input.fj | 4 +- stl/bit/math.fj | 8 +- stl/bit/memory.fj | 4 +- stl/bit/output.fj | 30 +-- stl/bit/pointers.fj | 8 +- stl/bit/shifts.fj | 4 +- stl/hex/cond_jumps.fj | 4 +- stl/hex/input.fj | 12 +- stl/hex/logics.fj | 4 +- stl/hex/math.fj | 12 +- stl/hex/math_basic.fj | 12 +- stl/hex/memory.fj | 8 +- stl/hex/output.fj | 156 +++++++------- stl/hex/shifts.fj | 4 +- stl/hex/tables_init.fj | 2 +- stl/mathlib.fj | 30 +-- stl/ptrlib.fj | 22 +- stl/runlib.fj | 201 +++++++++--------- 90 files changed, 740 insertions(+), 733 deletions(-) diff --git a/programs/calc.fj b/programs/calc.fj index baa1113..4f088e6 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 diff --git a/programs/concept_checks/casting.fj b/programs/concept_checks/casting.fj index 86a1ff1..4a680e0 100644 --- a/programs/concept_checks/casting.fj +++ b/programs/concept_checks/casting.fj @@ -1,26 +1,26 @@ -startup +stl.startup bit2hex h, b0 hex.print_as_digit h, 0 bit2hex h, b1 hex.print_as_digit h, 0 -output '\n' +stl.output '\n' 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 hex.print_as_digit 10, hex2, 0 -output '\n' +stl.output '\n' 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.bit 0 diff --git a/programs/concept_checks/pair_ns.fj b/programs/concept_checks/pair_ns.fj index df38e22..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,11 +56,11 @@ 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.bit 0 temp1: 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/ptr.fj b/programs/concept_checks/ptr.fj index 4bd258b..b5f3781 100644 --- a/programs/concept_checks/ptr.fj +++ b/programs/concept_checks/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,11 +38,11 @@ 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 diff --git a/programs/concept_checks/segments.fj b/programs/concept_checks/segments.fj index 7a1ae1a..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 @@ -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..58510cb 100644 --- a/programs/func_tests/func1.fj +++ b/programs/func_tests/func1.fj @@ -1,17 +1,17 @@ -startup +stl.startup // Prints "ABC" test1: - output 'A' + stl.output 'A' bit.call func1 - output 'C' + stl.output 'C' - output '\n' - loop + stl.output '\n' + stl.loop func1: - output 'B' + stl.output 'B' bit.return diff --git a/programs/func_tests/func2.fj b/programs/func_tests/func2.fj index 8041108..f4e6a64 100644 --- a/programs/func_tests/func2.fj +++ b/programs/func_tests/func2.fj @@ -1,28 +1,28 @@ -startup +stl.startup // Prints "AB~CD~EF" test2: - output 'A' + stl.output 'A' bit.call func2a bit.call func2b - output 'F' + stl.output 'F' - output '\n' - loop + stl.output '\n' + stl.loop func2a: - output 'B' + stl.output 'B' bit.call func2c - output 'C' + stl.output 'C' bit.return func2b: - output 'D' + stl.output 'D' bit.call func2c - output 'E' + stl.output 'E' bit.return func2c: - output '~' + stl.output '~' bit.return diff --git a/programs/func_tests/func3.fj b/programs/func_tests/func3.fj index b801367..f8eaba9 100644 --- a/programs/func_tests/func3.fj +++ b/programs/func_tests/func3.fj @@ -1,21 +1,21 @@ -startup +stl.startup // Prints "ABCDE" test3: - output 'A' + stl.output 'A' bit.push x3 - output 'B' + stl.output 'B' bit.call func3 - output 'D' + stl.output 'D' bit.pop x3 - output 'E' + stl.output 'E' - output '\n' - loop + stl.output '\n' + stl.loop func3: - output 'C' + stl.output 'C' bit.return diff --git a/programs/func_tests/func4.fj b/programs/func_tests/func4.fj index 7fef708..2b9ce12 100644 --- a/programs/func_tests/func4.fj +++ b/programs/func_tests/func4.fj @@ -1,32 +1,32 @@ -startup +stl.startup // Prints "ABCDEFGH-" and then 0/1, the invert of x4 test4: - output 'A' + stl.output 'A' bit.push x4 - output 'B' + stl.output 'B' bit.call func4 - output 'G' + stl.output 'G' bit.pop_res x4 - output 'H' + stl.output 'H' bit.bin2ascii ascii, x4 - output '-' + stl.output '-' bit.print ascii - output '\n' - loop + stl.output '\n' + stl.loop func4: - output 'C' + stl.output 'C' bit.get_sp __func4_arg_ptr - output 'D' + stl.output 'D' bit.dec_ptr __func4_arg_ptr - output 'E' + stl.output 'E' bit.ptr_flip_dbit __func4_arg_ptr - output 'F' + stl.output 'F' bit.return __func4_arg_ptr: bit.vec w, 0 diff --git a/programs/func_tests/func5.fj b/programs/func_tests/func5.fj index ce73f8d..4c915f7 100644 --- a/programs/func_tests/func5.fj +++ b/programs/func_tests/func5.fj @@ -1,53 +1,53 @@ -startup +stl.startup // Prints "ABC abcdefg ABCD-", and then 0/1, the xor of x5,y5 test5: - output 'A' + stl.output 'A' bit.push res5 - output 'B' + stl.output 'B' bit.push x5 - output 'C' + stl.output 'C' bit.push y5 - output ' ' + stl.output ' ' bit.call func5 - output ' ' + stl.output ' ' - output 'A' + stl.output 'A' bit.pop y5 - output 'B' + stl.output 'B' bit.pop x5 - output 'C' + stl.output 'C' bit.pop_res res5 - output 'D' + 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.output 'a' bit.dec_ptr __func5_arg_ptr - output 'b' + stl.output 'b' bit.xor_from_ptr __func5_res, __func5_arg_ptr - output 'c' + stl.output 'c' bit.dec_ptr __func5_arg_ptr - output 'd' + stl.output 'd' bit.xor_from_ptr __func5_res, __func5_arg_ptr - output 'e' + stl.output 'e' bit.dec_ptr __func5_arg_ptr - output 'f' + stl.output 'f' bit.xor_to_ptr __func5_arg_ptr, __func5_res - output 'g' + stl.output 'g' bit.return __func5_res: diff --git a/programs/hexlib_tests/2params/add.fj b/programs/hexlib_tests/2params/add.fj index ad3fdad..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,25 +13,25 @@ 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.hex a 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/and.fj b/programs/hexlib_tests/2params/and.fj index ddc4fc5..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,7 +13,7 @@ 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.hex a 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 08ccb87..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.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 dc33a53..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,7 +13,7 @@ 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.hex a 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 5e0ac06..ed7080c 100644 --- a/programs/hexlib_tests/2params/sub.fj +++ b/programs/hexlib_tests/2params/sub.fj @@ -1,8 +1,8 @@ -startup +stl.startup rep(256, i) test_sub i&0xf, i>>4 -loop +stl.loop hex.init @@ -13,25 +13,25 @@ def test_sub a, b @ c0_1st, c1_1st, print_1st, c0_2nd, c1_2nd, print_2nd, ah_1st 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.hex a 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/basics1/basic_math.fj b/programs/hexlib_tests/basics1/basic_math.fj index 3b5e5a7..882149c 100644 --- a/programs/hexlib_tests/basics1/basic_math.fj +++ b/programs/hexlib_tests/basics1/basic_math.fj @@ -1,84 +1,84 @@ -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.hex j @@ -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 21cb185..91489f4 100644 --- a/programs/hexlib_tests/basics1/basic_memory.fj +++ b/programs/hexlib_tests/basics1/basic_memory.fj @@ -1,55 +1,55 @@ -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.hex j @@ -60,5 +60,5 @@ 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 672383b..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 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 c4693ad..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 @@ -44,7 +44,7 @@ def input_hex_print_error @ hex, error, end { 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 4cfa573..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.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..9380881 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,25 @@ 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 + 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..6578509 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,64 @@ 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 { 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..8063024 100644 --- a/programs/hexlib_tests/mul/add_mul_test.fj +++ b/programs/hexlib_tests/mul/add_mul_test.fj @@ -1,11 +1,11 @@ -startup +stl.startup HexSize = NumSize / 4 Flag = ((1<>(BlockSize*i))&Flag, (Data>>(BlockSize*i + NumSize))&Flag, (Data>>(BlockSize*i + 2*NumSize))&0xf -loop +stl.loop hex.init @@ -26,59 +26,59 @@ 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 + 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..caf1452 100644 --- a/programs/hexlib_tests/mul/mul_test.fj +++ b/programs/hexlib_tests/mul/mul_test.fj @@ -1,11 +1,11 @@ -startup +stl.startup HexSize = NumSize / 4 Flag = (1<>(BlockSize*i))&Flag, (Data>>(BlockSize*i+NumSize))&Flag -loop +stl.loop hex.init @@ -21,50 +21,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/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 d20052a..c6fb52c 100644 --- a/programs/print_tests/print_as_digit.fj +++ b/programs/print_tests/print_as_digit.fj @@ -1,15 +1,15 @@ -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.bit 0 b1: bit.bit 1 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 0da4fee..4afbffb 100644 --- a/programs/sanity_checks/mathbit.fj +++ b/programs/sanity_checks/mathbit.fj @@ -1,6 +1,6 @@ - startup + stl.startup bit.inc1 x, carry - loop + stl.loop x: bit.bit 0 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 8780f13..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.bit 0 diff --git a/programs/sanity_checks/rep.fj b/programs/sanity_checks/rep.fj index bed16b0..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.bit 0 diff --git a/programs/sanity_checks/simple.fj b/programs/sanity_checks/simple.fj index 0d460ad..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.bit 0 diff --git a/programs/sanity_checks/testbit.fj b/programs/sanity_checks/testbit.fj index 8f4f4fd..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.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 3652dde..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 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 4cc86f5..e5da42d 100644 --- a/programs/simple_math_checks/ncmp.fj +++ b/programs/simple_math_checks/ncmp.fj @@ -1,19 +1,19 @@ -startup -default_input 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 fe032d2..9e2067c 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,26 +18,26 @@ 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.fcall print_num, ret } print_num: diff --git a/stl/bit/input.fj b/stl/bit/input.fj index e5ae394..ed5b379 100644 --- a/stl/bit/input.fj +++ b/stl/bit/input.fj @@ -6,9 +6,9 @@ ns bit { // Complexity: 2@-2 // input one bit into the bit-variable, 'dst'. // dst is an output parameter. - def input_bit dst < IO { + def input_bit dst < stl.IO { .zero dst - .xor dst, IO + .xor dst, stl.IO } diff --git a/stl/bit/math.fj b/stl/bit/math.fj index 8ec9d93..4281986 100644 --- a/stl/bit/math.fj +++ b/stl/bit/math.fj @@ -21,7 +21,7 @@ ns bit { def inc n, x @ carry { .one carry rep(n, i) .inc1 x+i*dw, carry - skip + stl.skip carry: .bit } @@ -53,7 +53,7 @@ ns bit { .inc1 dst, _src .inc1 dst, carry .or carry, _src - skip + stl.skip _src: .bit } @@ -64,7 +64,7 @@ ns bit { def add n, dst, src @ carry { .zero carry rep(n, i) .add1 dst+i*dw, src+i*dw, carry - skip + stl.skip carry: .bit } @@ -77,7 +77,7 @@ ns bit { .one carry rep(n, i) .add1 dst+i*dw, src+i*dw, carry .not n, src - skip + stl.skip carry: .bit } diff --git a/stl/bit/memory.fj b/stl/bit/memory.fj index 0984320..b0fa7ad 100644 --- a/stl/bit/memory.fj +++ b/stl/bit/memory.fj @@ -71,7 +71,7 @@ ns bit { // dst = src // dst,src are bits. def mov dst, src @ end { - comp_if1 dst==src, end + stl.comp_if1 dst==src, end .unsafe_mov dst, src end: } @@ -81,7 +81,7 @@ ns bit { // dst[:n] = src[:n] // dst,src are bit.vec[:n]. def mov n, dst, src @ end { - comp_if1 dst==src, end + stl.comp_if1 dst==src, end rep(n, i) .unsafe_mov dst+i*dw, src+i*dw end: } diff --git a/stl/bit/output.fj b/stl/bit/output.fj index 640fd34..2a7efb5 100644 --- a/stl/bit/output.fj +++ b/stl/bit/output.fj @@ -1,14 +1,14 @@ ns bit { // Complexity @+2 // outputs the bit 'x'. - def output x @ label_ptr, base_jump_label, end < IO { + def output x @ label_ptr, base_jump_label, end < stl.IO { .xor label_ptr, x label_ptr: ;base_jump_label pad 2 base_jump_label: - IO+0;end - IO+1; + stl.IO+0;end + stl.IO+1; .not label_ptr end: } @@ -47,7 +47,7 @@ ns bit { // x is a bit. def print_as_digit x { .output x - rep(7, i) output_bit ('0'>>(i+1)) & 1 + rep(7, i) stl.output_bit ('0'>>(i+1)) & 1 } // Complexity: @+9 @@ -71,16 +71,16 @@ ns bit { // // @Assumes n can be divided by 4. def print_hex_uint n, x, x_prefix @ after_print_x, printed_flag, end { - comp_if0 x_prefix, after_print_x - output '0' - output 'x' + 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 - output '0' + stl.output '0' ;end printed_flag: @@ -115,7 +115,7 @@ ns bit { // @Assumes n can be divided by 4. def print_hex_int n, x, x_prefix @ do_print { .if0 x+(n-1)*dw, do_print - output '-' + stl.output '-' .neg n, x do_print: .print_hex_uint n, x, x_prefix @@ -151,13 +151,13 @@ ns bit { div10: .div10 n, dst, src - fret ret_reg + 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: - fret ret_reg + stl.fret ret_reg // takes n(2+28/93*5) = 3.5n space dst: .vec n @@ -182,11 +182,11 @@ ns bit { // 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 - fcall div10, ret_reg + 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 - fcall xor, ret_reg + stl.fcall xor, ret_reg } // Complexity: 5@+12 @@ -195,7 +195,7 @@ ns bit { 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 + rep(4, i) stl.output_bit (0x3>>i)&1 end: } } @@ -209,7 +209,7 @@ ns bit { // 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 - output '-' + stl.output '-' .neg n, x do_print: .print_dec_uint n, x diff --git a/stl/bit/pointers.fj b/stl/bit/pointers.fj index 922afab..1e50379 100644 --- a/stl/bit/pointers.fj +++ b/stl/bit/pointers.fj @@ -61,11 +61,11 @@ ns bit { // like: (*ptr)+dbit; // Assumes *ptr is dw-aligned // Complexity w(2phi+7) - // The comp_flip_if executes much less than w/2 operations. + // The stl.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 + rep(#dbit, i) stl.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 + rep(#dbit, i) stl.comp_flip_if ptr+dbit+i*dw, (dbit>>i)&1 } // Assumes *ptr is dw-aligned @@ -86,7 +86,7 @@ ns bit { } ns pointers { def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < .to_flip { - comp_if0 do_flip, advance + stl.comp_if0 do_flip, advance wflip .to_flip+w, cleanup, .to_flip cleanup: wflip .to_flip+w, cleanup diff --git a/stl/bit/shifts.fj b/stl/bit/shifts.fj index e51792b..5bd3c63 100644 --- a/stl/bit/shifts.fj +++ b/stl/bit/shifts.fj @@ -38,7 +38,7 @@ ns 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 + stl.skip temp_bit: .bit } @@ -50,7 +50,7 @@ ns 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 + stl.skip temp_bit: .bit } diff --git a/stl/hex/cond_jumps.fj b/stl/hex/cond_jumps.fj index f5e263a..ac4abc5 100644 --- a/stl/hex/cond_jumps.fj +++ b/stl/hex/cond_jumps.fj @@ -14,7 +14,7 @@ ns hex { pad 16 switch: - rep(16, i) fj (flags>>i)&1 ? return+dbit+0 : 0, clean + rep(16, i) stl.fj (flags>>i)&1 ? return+dbit+0 : 0, clean clean: wflip hex+w, switch @@ -142,7 +142,7 @@ ns hex { // 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) fj ((d&0xf) > (d>>4)) ? .._.ret+dbit+1 : (((d&0xf) == (d>>4)) ? .._.ret+dbit : 0), clean_table_entry+d*dw + 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 diff --git a/stl/hex/input.fj b/stl/hex/input.fj index ec9f2e4..b895756 100644 --- a/stl/hex/input.fj +++ b/stl/hex/input.fj @@ -5,23 +5,23 @@ ns hex { // Time Complexity: 2@+7 // Space Complexity: 2@+18 // hex := input(4bits) // lsb first - def input_hex hex @ flip0, flip1, flip2, flip3, end < IO { + def input_hex hex @ flip0, flip1, flip2, flip3, end < stl.IO { // part0 .zero hex - wflip IO+w, flip0, IO + wflip stl.IO+w, flip0, stl.IO pad 8 flip0: - IO+dbit+1;IO // part1 + stl.IO+dbit+1;stl.IO // part1 hex+dbit+0;flip0 //(part0.5) flip1: - IO+dbit+2;IO // part2 + stl.IO+dbit+2;stl.IO // part2 hex+dbit+1;flip1 //(part1.5) flip3: - wflip IO+w, flip3, end // part4 + wflip stl.IO+w, flip3, end // part4 hex+dbit+3;flip3 //(part3.5) flip2: - IO+dbit+1;IO // part3 + stl.IO+dbit+1;stl.IO // part3 hex+dbit+2;flip2 //(part2.5) end: } diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj index bfc3a64..451bf04 100644 --- a/stl/hex/logics.fj +++ b/stl/hex/logics.fj @@ -174,7 +174,7 @@ ns hex { // 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) wflip_macro .._.res+w, (((d&0xf)|(d>>4))^(d&0xf))*dw, clean_table_entry+d*dw + 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 @@ -217,7 +217,7 @@ ns hex { // 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) wflip_macro .._.res+w, (((d&0xf)&(d>>4))^(d&0xf))*dw, clean_table_entry+d*dw + 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 diff --git a/stl/hex/math.fj b/stl/hex/math.fj index 644ce80..0617c30 100644 --- a/stl/hex/math.fj +++ b/stl/hex/math.fj @@ -75,15 +75,15 @@ ns hex { // 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) 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)) + 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) 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)) + 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) fj .dst+dbit+8, clean_table_entry+i*dw + 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 @@ -163,15 +163,15 @@ ns hex { // 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) 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)) + 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) 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)) + 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) fj .dst+dbit+8, clean_table_entry+i*dw + 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 diff --git a/stl/hex/math_basic.fj b/stl/hex/math_basic.fj index 9176551..84abdf4 100644 --- a/stl/hex/math_basic.fj +++ b/stl/hex/math_basic.fj @@ -38,18 +38,18 @@ ns hex { pad 64 //part4 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 + 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) fj dst+dbit+4, xor_switch+(d^(d+4))*dw + 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) fj is_carry+dbit, xor_switch+i*dw + rep(16, i) stl.fj is_carry+dbit, xor_switch+i*dw after_add: //part6 diff --git a/stl/hex/memory.fj b/stl/hex/memory.fj index d341545..0be8fc5 100644 --- a/stl/hex/memory.fj +++ b/stl/hex/memory.fj @@ -51,7 +51,7 @@ ns hex { // // both dst,src are hexes. def mov dst, src @ end { - comp_if1 dst==src, end + stl.comp_if1 dst==src, end .zero dst .xor dst, src end: @@ -62,7 +62,7 @@ ns hex { // 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 { - comp_if1 dst==src, end + stl.comp_if1 dst==src, end .zero n, dst .xor n, dst, src end: @@ -101,7 +101,7 @@ ns hex { // // both hex1,hex2 are hexes. def swap hex1, hex2 @ end { - comp_if1 hex1==hex2, end + stl.comp_if1 hex1==hex2, end .xor hex1, hex2 .xor hex2, hex1 .xor hex1, hex2 @@ -113,7 +113,7 @@ ns hex { // 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 { - comp_if1 hex1==hex2, end + stl.comp_if1 hex1==hex2, end .xor n, hex1, hex2 .xor n, hex2, hex1 .xor n, hex1, hex2 diff --git a/stl/hex/output.fj b/stl/hex/output.fj index e94e85d..5794062 100644 --- a/stl/hex/output.fj +++ b/stl/hex/output.fj @@ -6,51 +6,51 @@ 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 < IO { + 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: - 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 // a - IO+1;print_a // b - IO+0;print_c // c - IO+1;print_c // d - IO+0;print_e // e - IO+1;print_e // f + 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: - IO+0; - IO+0; - IO+0;end + stl.IO+0; + stl.IO+0; + stl.IO+0;end print_2: - IO+1;print_0+1*dw + stl.IO+1;print_0+1*dw print_4: - IO+0; - IO+1;print_0+2*dw + stl.IO+0; + stl.IO+1;print_0+2*dw print_6: - IO+1;print_4+1*dw + stl.IO+1;print_4+1*dw print_8: - IO+0; - IO+0; - IO+1;end + stl.IO+0; + stl.IO+0; + stl.IO+1;end print_a: - IO+1;print_8+1*dw + stl.IO+1;print_8+1*dw print_c: - IO+0; - IO+1;print_8+2*dw + stl.IO+0; + stl.IO+1;print_8+2*dw print_e: - IO+1;print_c+1*dw + stl.IO+1;print_c+1*dw end: wflip hex+w, switch @@ -82,61 +82,61 @@ ns hex { // 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 < IO { + 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: - 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 + 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 - IO+0; - IO+0; - IO+0; - IO+1; - IO+1; - IO+0; - IO+0;end + stl.IO+0; + stl.IO+0; + stl.IO+0; + stl.IO+1; + stl.IO+1; + stl.IO+0; + stl.IO+0;end print_2: - IO+1;print_0+1*dw + stl.IO+1;print_0+1*dw print_4: - IO+0; - IO+1;print_0+2*dw + stl.IO+0; + stl.IO+1;print_0+2*dw print_6: - IO+1;print_4+1*dw + stl.IO+1;print_4+1*dw print_8: - IO+0; - IO+0; - IO+1;print_0+3*dw + stl.IO+0; + stl.IO+0; + stl.IO+1;print_0+3*dw print_a: // outputs 0x40 / 0x60 - IO+0; - IO+0; - IO+0; - IO+0; - IO+(use_uppercase ? 0 : 1); - IO+1;print_0+6*dw + 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: - IO+1;print_a+1*dw + stl.IO+1;print_a+1*dw print_d: - IO+0; - IO+1;print_a+2*dw + stl.IO+0; + stl.IO+1;print_a+2*dw print_f: - IO+1;print_d+1*dw + stl.IO+1;print_d+1*dw end: wflip hex+w, switch @@ -159,13 +159,13 @@ ns hex { // 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 - comp_if0 x_prefix, after_prefix - output "0x" + 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 - output '0' + stl.output '0' ;end printed_something: bit.bit @@ -200,7 +200,7 @@ ns hex { do_neg: bit.not neg .neg n, x - output '-' + stl.output '-' print: .print_uint n, x, x_prefix, use_uppercase bit.if0 neg, end diff --git a/stl/hex/shifts.fj b/stl/hex/shifts.fj index 7a30641..06e1c23 100644 --- a/stl/hex/shifts.fj +++ b/stl/hex/shifts.fj @@ -52,7 +52,7 @@ ns hex { pad 16 switch: - rep(16, i) fj i&8 ? next+dbit+0 : 0, xor_by+(i^((i<<1)&0xf))*dw + 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 @@ -72,7 +72,7 @@ ns hex { pad 16 switch: - rep(16, i) fj i&1 ? next+dbit+3 : 0, xor_by+(i^((i>>1)&0xf))*dw + 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 diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj index 7189afa..33871e9 100644 --- a/stl/hex/tables_init.fj +++ b/stl/hex/tables_init.fj @@ -34,7 +34,7 @@ ns hex { // n is a size-constant, dst/ret are hexes. def clean_table_entry__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 + rep(n, d) stl.fj d==0?0: (dst+dbit+(#d)-1), (d==((1<<(#d))>>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 diff --git a/stl/mathlib.fj b/stl/mathlib.fj index 4112003..8b115a8 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -242,33 +242,33 @@ 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: @@ -448,13 +448,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 900a029..f176cb6 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -29,15 +29,17 @@ ns bit { // ---------- Fast Call -// Complexity: @-1 -def fcall label, ret_reg @ ret { - wflip ret_reg+w, ret, label - pad 2 - ret: - wflip ret_reg+w, ret -} +ns stl { + // Complexity: @-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 + // Complexity: 1 + def fret ret_reg { + ;ret_reg + } } diff --git a/stl/runlib.fj b/stl/runlib.fj index ffad476..0169d76 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -3,143 +3,144 @@ dw = 2 * w // double word size dbit = w + #w // the bit-distance from the variable's start, to the bit value (w + w_width) +ns stl { + // startup Macro - should be the first piece of code in your program. + def startup > IO, code_start { + ;.code_start // 0w;1w : first code to run + IO: + ;0 // 2w;3w : sets the io_handler to address 0 (good for a future wflip) -// Startup Macro - should be the first piece of code in your program. -def startup > IO, code_start { - ;code_start // 0w;1w : first code to run - IO: - ;0 // 2w;3w : sets the io_handler to address 0 (good for a future wflip) + code_start: + // 4w;5w : start of code + } - code_start: - // 4w;5w : start of code -} + // ---------- Basic Functionality -// ---------- Basic Functionality + // Complexity: 1 + // macro for 1 flip-jump op + def fj f, j { + f;j + } -// Complexity: 1 -// macro for 1 flip-jump op -def fj f, j { - f;j -} + // Complexity: @ + // macro for 1 wflip op + def wflip_macro dst, val { + wflip dst, val + } -// 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 + } -// Complexity: @ -// macro for 1 wflip op (with jump) -def wflip_macro dst, val, jmp_addr { - wflip dst, val, jmp_addr -} + //// @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 + //} -//// @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 -//} + // ---------- Compilation Time Comparisons: + // Complexity: 1 -// ---------- Compilation Time Comparisons: -// Complexity: 1 + // if expression is 0 (compilation time), jump to l0. else jump to l1 + def comp_if expr, l0, l1 { + ; expr ? l1 : l0 + } -// if expression is 0 (compilation time), jump to l0. else jump to l1 -def comp_if expr, l0, l1 { - ; expr ? l1 : l0 -} + // if expression is 0 (compilation time), jump to l0. else continue + def comp_if0 expr, l0 @ continue { + .comp_if expr, l0, continue + continue: + } -// if expression is 0 (compilation time), jump to l0. else continue -def comp_if0 expr, l0 @ continue { - comp_if expr, l0, continue - continue: -} + // if expression is not 0 (compilation time), jump to l1. else continue + def comp_if1 expr, l1 @ continue { + .comp_if expr, continue, l1 + continue: + } -// if expression is not 0 (compilation time), jump to l1. else continue -def comp_if1 expr, l1 @ continue { - comp_if expr, continue, l1 - continue: -} + // 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); + } -// 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); -} + // ---------- Unconditional Jumps + // Complexity: 1 -// ---------- Unconditional Jumps -// Complexity: 1 + // skip the next flip-jump op + def skip { + ;$ + dw + } -// skip the next flip-jump op -def skip { - ;$ + dw -} + // finish (loop to self) + def loop { + ;$ - dw + } -// finish (loop to self) -def loop { - ;$ - dw -} + // ---------- Input Handler -// ---------- Input Handler - - -// 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 IO+w, input_0, IO -// pad 2 -// input_0: -// wflip IO+w, input_0, jump_to_input_0_handling -// input_1: -// wflip IO+w, input_0, jump_to_input_0_handling -// -// @note that if you use this macro, you can't touch 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: -} + // 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: + } -// ---------- Output constants: + // ---------- Output constants: -// 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 -} + // 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 + } -// 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 + // 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 + } } From f84dc82dc52a2bf25fcc57a89b511b48016a37a4 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Tue, 7 Mar 2023 19:25:56 +0200 Subject: [PATCH 33/62] move casting macros into the stl namespace --- programs/concept_checks/casting.fj | 10 +-- programs/simple_math_checks/series_sum.fj | 2 +- stl/casting.fj | 94 ++++++++++++----------- 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/programs/concept_checks/casting.fj b/programs/concept_checks/casting.fj index 4a680e0..a32346c 100644 --- a/programs/concept_checks/casting.fj +++ b/programs/concept_checks/casting.fj @@ -1,20 +1,20 @@ 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 stl.output '\n' -bit2hex 12, hex, bits +stl.bit2hex 12, hex, bits hex.print_as_digit 3, hex, 0 stl.output '\n' stl.output '\n' -hex2bit 10, bits2, hex2 +stl.hex2bit 10, bits2, hex2 hex.print_as_digit 10, hex2, 0 stl.output '\n' -bit2hex 40, hex2, bits2 +stl.bit2hex 40, hex2, bits2 bit.print_hex_uint 40, bits2, 0 stl.output '\n' bit.print_as_digit 40, bits2 diff --git a/programs/simple_math_checks/series_sum.fj b/programs/simple_math_checks/series_sum.fj index 9e2067c..d9c9b2d 100644 --- a/programs/simple_math_checks/series_sum.fj +++ b/programs/simple_math_checks/series_sum.fj @@ -36,7 +36,7 @@ hex.init // inits the hex.mul def print_hex_as_decimal hexxx < num, ret, print_num { - hex2bit N, num, hexxx + stl.hex2bit N, num, hexxx stl.fcall print_num, ret } diff --git a/stl/casting.fj b/stl/casting.fj index 1d1fa3c..c8a5831 100644 --- a/stl/casting.fj +++ b/stl/casting.fj @@ -1,50 +1,52 @@ // ---------- Casting from bit -// 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 +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 + } } From 9efe26b8300d642f8c70709d5f942d66b69e1eff Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Wed, 5 Apr 2023 12:08:15 +0300 Subject: [PATCH 34/62] add the startup_and_init_all macro --- programs/sanity_checks/startup_init_all.fj | 33 +++++++++++++++++++ stl/README.md | 6 ++++ stl/runlib.fj | 11 +++++++ .../inout/sanity_checks/startup_init_all.out | 2 ++ tests/test_compile_fast.csv | 1 + tests/test_run_fast.csv | 1 + 6 files changed, 54 insertions(+) create mode 100644 programs/sanity_checks/startup_init_all.fj create mode 100644 tests/inout/sanity_checks/startup_init_all.out diff --git a/programs/sanity_checks/startup_init_all.fj b/programs/sanity_checks/startup_init_all.fj new file mode 100644 index 0000000..e0ea271 --- /dev/null +++ b/programs/sanity_checks/startup_init_all.fj @@ -0,0 +1,33 @@ +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/stl/README.md b/stl/README.md index e1f6658..e2dbb6a 100644 --- a/stl/README.md +++ b/stl/README.md @@ -68,7 +68,13 @@ 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. # Contribute diff --git a/stl/runlib.fj b/stl/runlib.fj index 0169d76..cb80633 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -14,6 +14,17 @@ ns stl { // 4w;5w : start of code } + def startup_and_init_all > IO, code_start { + ;.code_start // 0w;1w : first code to run + IO: + ;0 // 2w;3w : sets the io_handler to address 0 (good for a future wflip) + + hex.init + bit.ptr_init + + code_start: + } + // ---------- Basic Functionality 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_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 From f8e9bb6b33373094ddda07eeaaf0c50e65ef214d Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Wed, 5 Apr 2023 13:54:14 +0300 Subject: [PATCH 35/62] add padding documentation --- stl/README.md | 20 ++++++++++++++++++++ stl/runlib.fj | 8 -------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/stl/README.md b/stl/README.md index e2dbb6a..4eebb77 100644 --- a/stl/README.md +++ b/stl/README.md @@ -60,6 +60,7 @@ Every macro is documented with: - 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. @@ -76,6 +77,25 @@ 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 diff --git a/stl/runlib.fj b/stl/runlib.fj index cb80633..382cd76 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -51,14 +51,6 @@ ns stl { } - //// @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 - //} - - // ---------- Compilation Time Comparisons: // Complexity: 1 From a96d57fd510cff8b9f46d80c98f6b4fd00029bc1 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Wed, 5 Apr 2023 15:13:27 +0300 Subject: [PATCH 36/62] add xfail support, xfail the hexlib-div-* runs --- tests/README.md | 10 ++++++++++ tests/conftest.py | 25 ++++++++++++++++++------- tests/xfail_compile.csv | 0 tests/xfail_run.csv | 7 +++++++ 4 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 tests/xfail_compile.csv create mode 100644 tests/xfail_run.csv diff --git a/tests/README.md b/tests/README.md index ae44953..743ee2a 100644 --- a/tests/README.md +++ b/tests/README.md @@ -46,6 +46,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 +56,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/conftest.py b/tests/conftest.py index bca8656..70230fe 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -74,35 +74,43 @@ 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]) -> 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) @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))) + 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]) -> 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) @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))) + 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 @@ -295,12 +303,15 @@ 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)] + 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)) compile_tests = filter_by_test_name(compile_tests, get_option) run_tests = [] @@ -308,7 +319,7 @@ 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)) run_tests = filter_by_test_name(run_tests, get_option) return compile_tests, run_tests 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 From 05c503baa827408ca27498702a2a0c7d9cc0f4df Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Mon, 10 Apr 2023 20:11:24 +0300 Subject: [PATCH 37/62] refactor pointers, stiffer unused params rules, update startup_init_all Now global params must be used, and extern params must be declared. also, documented all output-params. --- programs/func_tests/func1.fj | 2 +- programs/func_tests/func2.fj | 2 +- programs/func_tests/func3.fj | 2 +- programs/func_tests/func4.fj | 2 +- programs/func_tests/func5.fj | 2 +- programs/hexlib_tests/2params/sub.fj | 2 +- programs/multi_comp/defs.fj | 2 +- src/fj_parser.py | 17 +++- stl/bit/pointers.fj | 138 +++++++++++++++++++-------- stl/hex/cond_jumps.fj | 3 + stl/hex/logics.fj | 10 +- stl/hex/math.fj | 10 +- stl/hex/tables_init.fj | 2 + stl/mathlib.fj | 3 + stl/runlib.fj | 19 +++- 15 files changed, 155 insertions(+), 61 deletions(-) diff --git a/programs/func_tests/func1.fj b/programs/func_tests/func1.fj index 58510cb..79f247a 100644 --- a/programs/func_tests/func1.fj +++ b/programs/func_tests/func1.fj @@ -16,4 +16,4 @@ func1: bit.ptr_init -bit.stack 10 +bit.stack_init 10 diff --git a/programs/func_tests/func2.fj b/programs/func_tests/func2.fj index f4e6a64..cf38f16 100644 --- a/programs/func_tests/func2.fj +++ b/programs/func_tests/func2.fj @@ -27,4 +27,4 @@ func2c: bit.ptr_init -bit.stack 10 +bit.stack_init 10 diff --git a/programs/func_tests/func3.fj b/programs/func_tests/func3.fj index f8eaba9..5b00e8d 100644 --- a/programs/func_tests/func3.fj +++ b/programs/func_tests/func3.fj @@ -23,4 +23,4 @@ x3: bit.bit 0 bit.ptr_init -bit.stack 10 +bit.stack_init 10 diff --git a/programs/func_tests/func4.fj b/programs/func_tests/func4.fj index 2b9ce12..b44810d 100644 --- a/programs/func_tests/func4.fj +++ b/programs/func_tests/func4.fj @@ -40,4 +40,4 @@ ascii: bit.vec 8 bit.ptr_init -bit.stack 10 +bit.stack_init 10 diff --git a/programs/func_tests/func5.fj b/programs/func_tests/func5.fj index 4c915f7..b6e71cd 100644 --- a/programs/func_tests/func5.fj +++ b/programs/func_tests/func5.fj @@ -67,4 +67,4 @@ ascii: bit.vec 8 bit.ptr_init -bit.stack 10 +bit.stack_init 10 diff --git a/programs/hexlib_tests/2params/sub.fj b/programs/hexlib_tests/2params/sub.fj index ed7080c..fc52964 100644 --- a/programs/hexlib_tests/2params/sub.fj +++ b/programs/hexlib_tests/2params/sub.fj @@ -8,7 +8,7 @@ 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 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/src/fj_parser.py b/src/fj_parser.py index a267732..de6ff6c 100644 --- a/src/fj_parser.py +++ b/src/fj_parser.py @@ -216,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], @@ -234,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: diff --git a/stl/bit/pointers.fj b/stl/bit/pointers.fj index 1e50379..26fe416 100644 --- a/stl/bit/pointers.fj +++ b/stl/bit/pointers.fj @@ -2,13 +2,19 @@ ns bit { + // Comp def ptr_init { .pointers.ptr_init } ns pointers { - def ptr_init > to_flip, to_jump, to_flip_var, to_flip_return_var, to_jump_var { - pad 1 + // Space Complexity: 3w+2 + // Inits the + // @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: @@ -16,8 +22,6 @@ ns bit { to_flip_var: bit.vec w, 0 - to_flip_return_var: - bit.vec w, 0 to_jump_var: bit.vec w, 0 } @@ -30,8 +34,11 @@ ns bit { ns bit { - // like: ;*ptr - // Complexity w(2phi+6) + // Complexity: 2w@ + 2 + // like: ;*ptr + // Jump to the address the pointer points to. + // ( to_jump{_var} = ptr. ==> ;to_jump ) + // ptr is a bit[:w] that holds an address. def ptr_jump ptr < .pointers.to_jump, .pointers.to_jump_var { .bit_var_xor w, .pointers.to_jump+w, .pointers.to_jump_var, .pointers.to_jump_var .bit_var_xor w, .pointers.to_jump+w, .pointers.to_jump_var, ptr @@ -45,8 +52,11 @@ ns bit { ns bit { - // like: *ptr; - // Complexity w(2phi+6) + // Complexity: 2w@ + @ + // like: *ptr; + // Flip the address the pointer points to. + // ( to_flip{_var} = ptr. ==> ;to_flip ) + // ptr is a bit[:w] that holds an address. def ptr_flip ptr @ cleanup < .pointers.to_flip, .pointers.to_flip_var { wflip .pointers.to_flip+w, cleanup @@ -54,21 +64,26 @@ ns bit { .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, ptr ;.pointers.to_flip + pad 4 cleanup: wflip .pointers.to_flip+w, cleanup } - // like: (*ptr)+dbit; - // Assumes *ptr is dw-aligned - // Complexity w(2phi+7) - // The stl.comp_flip_if executes much less than w/2 operations. + + // 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 } - // Assumes *ptr is dw-aligned + // 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 @@ -76,26 +91,32 @@ ns bit { } - // like: wflip *ptr, value - // Assumes *ptr is w-aligned, and value is 2dw-aligned - // Complexity w(3phi+11) - def ptr_wflip ptr, value < .pointers.to_flip, .pointers.to_flip_var{ + // 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.to_flip, .pointers.to_flip_var { .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, .pointers.to_flip_var .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, 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 < .to_flip { stl.comp_if0 do_flip, advance wflip .to_flip+w, cleanup, .to_flip cleanup: - wflip .to_flip+w, cleanup + wflip .to_flip+w, cleanup, advance + + pad 4 advance: rep(n, i) ..exact_not .to_flip+i } } - // Assumes *ptr is dw-aligned, and value is 2dw-aligned + // 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 @@ -109,13 +130,16 @@ ns bit { ns bit { - // like: .xor dst *ptr - // assumes *ptr is dw-aligned - // Complexity w(8phi+28) + // 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 @@ -137,14 +161,20 @@ ns bit { ns bit { - def stack n { - .pointers.stack n + // Space Complexity: n+w + // Initializes a stack of size n (maximal capacity of n bits / return-addresses). + // n is the size of the stack. + def stack_init n { + .pointers.stack_init n } ns pointers { - // sp always points to the last pushed value (at start - to stack[-1]) - def stack n > sp, stack { - pad 1 + // Space Complexity: n+w + // Initializes a stack of size n (maximal capacity of n bits / 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 > sp, stack { sp: bit.vec w, .stack-dw stack: @@ -152,52 +182,76 @@ ns bit { } } + // Time Complexity: n(2@) + // Space Complexity: n(2@+24) + // Unsafe if dst is .pointers.sp. + // dst[:n] = sp def get_sp dst < .pointers.sp { .mov w, dst, .pointers.sp } - // Complexity w(2phi+10) + // Time Complexity: 1.067@ // (16/15 * @) + // Space Complexity: w(1.5@+13) // actually (w-#w)(1.5@+13) + // ptr[:n] += 2w def inc_ptr ptr { .inc w-#w, ptr+#w*dw } - - // Complexity w(2phi+12) + // Time Complexity: 1.067@ // (16/15 * @) + // Space Complexity: w(1.5@+13) // actually (w-#w)(1.5@+13) + // ptr[:n] -= 2w def dec_ptr ptr { .dec w-#w, ptr+#w*dw } - // Assumes address is 2dw-aligned - // Complexity w(5phi+21) - def push_ret_address address < .pointers.sp { + // Time Complexity: 4w@ (actually a bit smaller) + // Space Complexity: 5w@ (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 < .pointers.sp { .inc_ptr .pointers.sp - .ptr_wflip_2nd_word .pointers.sp, address + .ptr_wflip_2nd_word .pointers.sp, return_address } - // Assumes address is 2dw-aligned - // Complexity w(5phi+23) - def pop_ret_address address < .pointers.sp { - .ptr_wflip_2nd_word .pointers.sp, address + // Time Complexity: 4w@ (actually a bit smaller) + // Space Complexity: 5w@ (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 < .pointers.sp { + .ptr_wflip_2nd_word .pointers.sp, return_address .dec_ptr .pointers.sp } - // Complexity: w(4phi+17) + // Time Complexity: 2w@ + 3@+2 + // Space Complexity: w(3.5@+13) + // Like: stack[++sp] = bit + // Pushes the given bit to the next cell in the stack (assumes it's zero). Increments sp. def push bit < .pointers.sp { .inc_ptr .pointers.sp .xor_to_ptr .pointers.sp, bit } - // Assumes *sp==bit. - // Complexity: w(4phi+19) + // Time Complexity: 2w@ + 3@+2 + // Space Complexity: w(3.5@+13) + // Like: stack[sp--] = 0 + // Pops the given bit from the current cell in the stack (assumes it has the value of bit). Decrements sp. def pop bit < .pointers.sp { .xor_to_ptr .pointers.sp, bit .dec_ptr .pointers.sp } - // Complexity: w(12phi+47) + + // Time Complexity: w(10@+10) (actually a bit smaller, 8w@ + 10w+9 + 2(@-2)^2) + // Space Complexity: w(11@+20) (actually a bit smaller, w(9.5@+19) + 2(@-2)^2 + @-1) + // Like: bit = stack[sp] + // stack[sp--] = 0 + // Pops the current stack cell into the the given bit. Decrements sp. + // bit is only an output parameter def pop_res bit < .pointers.sp { .zero bit .xor_from_ptr bit, .pointers.sp diff --git a/stl/hex/cond_jumps.fj b/stl/hex/cond_jumps.fj index ac4abc5..e8a7492 100644 --- a/stl/hex/cond_jumps.fj +++ b/stl/hex/cond_jumps.fj @@ -130,6 +130,9 @@ ns hex { // 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 diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj index 451bf04..1e3eeb2 100644 --- a/stl/hex/logics.fj +++ b/stl/hex/logics.fj @@ -163,7 +163,10 @@ ns hex { // Time Complexity: 6 (when jumping to dst, until finished) // Space Complexity: 595 // This is where the or "truth" tables are. - def init @ switch, clean_table_entry, end < .._.res, .._.ret > dst { + // @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 @@ -206,7 +209,10 @@ ns hex { // Time Complexity: 6 (when jumping to dst, until finished) // Space Complexity: 595 // This is where the and "truth" tables are. - def init @ switch, clean_table_entry, end < .._.res, .._.ret > dst { + // @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 diff --git a/stl/hex/math.fj b/stl/hex/math.fj index 0617c30..302049d 100644 --- a/stl/hex/math.fj +++ b/stl/hex/math.fj @@ -63,7 +63,10 @@ ns hex { // Time Complexity: 8 (when jumping to dst, until finished) // Space Complexity: 1570 // This is where the add "truth" tables are. - def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > dst { + // @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 @@ -151,7 +154,10 @@ ns hex { // 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). - def init @ switch__without_carry, switch__with_carry, flip_carry, clean_table_entry, end < .._.res, .._.ret > dst { + // @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 diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj index 33871e9..5fd3736 100644 --- a/stl/hex/tables_init.fj +++ b/stl/hex/tables_init.fj @@ -12,6 +12,8 @@ ns hex { // 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 @ end > ret, res { ;end ret: ;0 diff --git a/stl/mathlib.fj b/stl/mathlib.fj index 8b115a8..7dd2143 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -214,6 +214,9 @@ ns hex { } // 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, 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 { // general progression (after jumping to hex.mul.dst with value d): // dst -> switch+d (set lower4 mul result in add_carry_dst+4) (5) diff --git a/stl/runlib.fj b/stl/runlib.fj index 382cd76..7934926 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -5,8 +5,9 @@ dbit = w + #w // the bit-distance from the variable's start, to the bit value ns stl { // startup Macro - should be the first piece of code in your program. - def startup > IO, code_start { - ;.code_start // 0w;1w : first code to run + // @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) @@ -14,13 +15,23 @@ ns stl { // 4w;5w : start of code } - def startup_and_init_all > IO, code_start { - ;.code_start // 0w;1w : first code to run + // 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 + } + + // 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) hex.init bit.ptr_init + bit.stack_init stack_bit_size code_start: } From cf692f69c98dafe53c2ff5fb3256a99b243cd668 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 21 Apr 2023 16:55:27 +0300 Subject: [PATCH 38/62] duplicate bit/pointers (with its tests) to hex/pointers, tested. --- .../concept_checks/{ptr.fj => bit_ptr.fj} | 2 +- programs/concept_checks/hex_ptr.fj | 73 ++++++ programs/func_tests/{ => bit_ptr}/func1.fj | 8 +- programs/func_tests/{ => bit_ptr}/func2.fj | 18 +- programs/func_tests/{ => bit_ptr}/func3.fj | 8 +- programs/func_tests/{ => bit_ptr}/func4.fj | 8 +- programs/func_tests/{ => bit_ptr}/func5.fj | 8 +- programs/func_tests/hex_ptr/func1.fj | 19 ++ programs/func_tests/hex_ptr/func2.fj | 30 +++ programs/func_tests/hex_ptr/func3.fj | 26 +++ programs/func_tests/hex_ptr/func4.fj | 43 ++++ programs/func_tests/hex_ptr/func5.fj | 70 ++++++ stl/bit/pointers.fj | 102 +++------ stl/conf.json | 1 + stl/hex/pointers.fj | 207 ++++++++++++++++++ stl/ptrlib.fj | 61 +++++- stl/runlib.fj | 4 +- .../concept_checks/{ptr.out => bit_ptr.out} | 0 tests/inout/concept_checks/hex_ptr.out | 1 + .../inout/func_tests/{ => bit_ptr}/func1.out | 0 .../inout/func_tests/{ => bit_ptr}/func2.out | 0 .../inout/func_tests/{ => bit_ptr}/func3.out | 0 .../inout/func_tests/{ => bit_ptr}/func4.out | 0 .../inout/func_tests/{ => bit_ptr}/func5.out | 0 tests/inout/func_tests/hex_ptr/func1.out | 1 + tests/inout/func_tests/hex_ptr/func2.out | 1 + tests/inout/func_tests/hex_ptr/func3.out | 1 + tests/inout/func_tests/hex_ptr/func4.out | 1 + tests/inout/func_tests/hex_ptr/func5.out | 1 + tests/test_compile_medium.csv | 3 +- tests/test_compile_slow.csv | 16 +- tests/test_run_medium.csv | 3 +- tests/test_run_slow.csv | 16 +- 33 files changed, 621 insertions(+), 111 deletions(-) rename programs/concept_checks/{ptr.fj => bit_ptr.fj} (98%) create mode 100644 programs/concept_checks/hex_ptr.fj rename programs/func_tests/{ => bit_ptr}/func1.fj (67%) rename programs/func_tests/{ => bit_ptr}/func2.fj (60%) rename programs/func_tests/{ => bit_ptr}/func3.fj (77%) rename programs/func_tests/{ => bit_ptr}/func4.fj (89%) rename programs/func_tests/{ => bit_ptr}/func5.fj (94%) create mode 100644 programs/func_tests/hex_ptr/func1.fj create mode 100644 programs/func_tests/hex_ptr/func2.fj create mode 100644 programs/func_tests/hex_ptr/func3.fj create mode 100644 programs/func_tests/hex_ptr/func4.fj create mode 100644 programs/func_tests/hex_ptr/func5.fj create mode 100644 stl/hex/pointers.fj rename tests/inout/concept_checks/{ptr.out => bit_ptr.out} (100%) create mode 100644 tests/inout/concept_checks/hex_ptr.out rename tests/inout/func_tests/{ => bit_ptr}/func1.out (100%) rename tests/inout/func_tests/{ => bit_ptr}/func2.out (100%) rename tests/inout/func_tests/{ => bit_ptr}/func3.out (100%) rename tests/inout/func_tests/{ => bit_ptr}/func4.out (100%) rename tests/inout/func_tests/{ => bit_ptr}/func5.out (100%) create mode 100644 tests/inout/func_tests/hex_ptr/func1.out create mode 100644 tests/inout/func_tests/hex_ptr/func2.out create mode 100644 tests/inout/func_tests/hex_ptr/func3.out create mode 100644 tests/inout/func_tests/hex_ptr/func4.out create mode 100644 tests/inout/func_tests/hex_ptr/func5.out diff --git a/programs/concept_checks/ptr.fj b/programs/concept_checks/bit_ptr.fj similarity index 98% rename from programs/concept_checks/ptr.fj rename to programs/concept_checks/bit_ptr.fj index b5f3781..5bbeade 100644 --- a/programs/concept_checks/ptr.fj +++ b/programs/concept_checks/bit_ptr.fj @@ -46,7 +46,7 @@ test3: - bit.ptr_init + stl.ptr_init p0: bit.vec w, d0+dbit diff --git a/programs/concept_checks/hex_ptr.fj b/programs/concept_checks/hex_ptr.fj new file mode 100644 index 0000000..f6ed60e --- /dev/null +++ b/programs/concept_checks/hex_ptr.fj @@ -0,0 +1,73 @@ +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: + bit.zero d3_var + hex.xor_from_ptr d3_var, p3 + bit.if d3_var, d30, d31 + d30: + stl.output 'F' + stl.loop + d31: + stl.output 'T' + stl.loop + + + + stl.ptr_init + + p0: + bit.vec w, d0+dbit + d0: + bit.bit 0 // 0 => 1, 1 => 0 + + p1: + bit.vec w, d1 + d1: + ;jump_to7 // jump_to6 => 6, jump_to7 => 7 + + p2: + bit.vec w, d2+w + p2_jump: + bit.vec w, d2 + d2: + bit.bit 0 // 0 => N, 1 => Y + + p3: + bit.vec w, d3 + d3: + bit.bit 1 // 0 => F, 1 => T + d3_var: + bit.bit 0 diff --git a/programs/func_tests/func1.fj b/programs/func_tests/bit_ptr/func1.fj similarity index 67% rename from programs/func_tests/func1.fj rename to programs/func_tests/bit_ptr/func1.fj index 79f247a..7427645 100644 --- a/programs/func_tests/func1.fj +++ b/programs/func_tests/bit_ptr/func1.fj @@ -4,7 +4,7 @@ stl.startup // Prints "ABC" test1: stl.output 'A' - bit.call func1 + stl.call func1 stl.output 'C' stl.output '\n' @@ -12,8 +12,8 @@ test1: func1: stl.output 'B' - bit.return + stl.return -bit.ptr_init -bit.stack_init 10 +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/func2.fj b/programs/func_tests/bit_ptr/func2.fj similarity index 60% rename from programs/func_tests/func2.fj rename to programs/func_tests/bit_ptr/func2.fj index cf38f16..8c65dec 100644 --- a/programs/func_tests/func2.fj +++ b/programs/func_tests/bit_ptr/func2.fj @@ -4,8 +4,8 @@ stl.startup // Prints "AB~CD~EF" test2: stl.output 'A' - bit.call func2a - bit.call func2b + stl.call func2a + stl.call func2b stl.output 'F' stl.output '\n' @@ -13,18 +13,18 @@ test2: func2a: stl.output 'B' - bit.call func2c + stl.call func2c stl.output 'C' - bit.return + stl.return func2b: stl.output 'D' - bit.call func2c + stl.call func2c stl.output 'E' - bit.return + stl.return func2c: stl.output '~' - bit.return + stl.return -bit.ptr_init -bit.stack_init 10 +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/func3.fj b/programs/func_tests/bit_ptr/func3.fj similarity index 77% rename from programs/func_tests/func3.fj rename to programs/func_tests/bit_ptr/func3.fj index 5b00e8d..0e2197f 100644 --- a/programs/func_tests/func3.fj +++ b/programs/func_tests/bit_ptr/func3.fj @@ -6,7 +6,7 @@ test3: stl.output 'A' bit.push x3 stl.output 'B' - bit.call func3 + stl.call func3 stl.output 'D' bit.pop x3 stl.output 'E' @@ -16,11 +16,11 @@ test3: func3: stl.output 'C' - bit.return + stl.return x3: bit.bit 0 -bit.ptr_init -bit.stack_init 10 +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/func4.fj b/programs/func_tests/bit_ptr/func4.fj similarity index 89% rename from programs/func_tests/func4.fj rename to programs/func_tests/bit_ptr/func4.fj index b44810d..f04ae51 100644 --- a/programs/func_tests/func4.fj +++ b/programs/func_tests/bit_ptr/func4.fj @@ -7,7 +7,7 @@ test4: bit.push x4 stl.output 'B' - bit.call func4 + stl.call func4 stl.output 'G' bit.pop_res x4 @@ -27,7 +27,7 @@ func4: stl.output 'E' bit.ptr_flip_dbit __func4_arg_ptr stl.output 'F' - bit.return + stl.return __func4_arg_ptr: bit.vec w, 0 @@ -39,5 +39,5 @@ x4: ascii: bit.vec 8 -bit.ptr_init -bit.stack_init 10 +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/func5.fj b/programs/func_tests/bit_ptr/func5.fj similarity index 94% rename from programs/func_tests/func5.fj rename to programs/func_tests/bit_ptr/func5.fj index b6e71cd..b14afde 100644 --- a/programs/func_tests/func5.fj +++ b/programs/func_tests/bit_ptr/func5.fj @@ -11,7 +11,7 @@ test5: bit.push y5 stl.output ' ' - bit.call func5 + stl.call func5 stl.output ' ' stl.output 'A' @@ -49,7 +49,7 @@ func5: bit.xor_to_ptr __func5_arg_ptr, __func5_res stl.output 'g' - bit.return + stl.return __func5_res: bit.bit __func5_arg_ptr: @@ -66,5 +66,5 @@ res5: ascii: bit.vec 8 -bit.ptr_init -bit.stack_init 10 +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func1.fj b/programs/func_tests/hex_ptr/func1.fj new file mode 100644 index 0000000..7427645 --- /dev/null +++ b/programs/func_tests/hex_ptr/func1.fj @@ -0,0 +1,19 @@ +stl.startup + + +// Prints "ABC" +test1: + stl.output 'A' + stl.call func1 + stl.output 'C' + + stl.output '\n' + stl.loop + +func1: + stl.output 'B' + stl.return + + +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func2.fj b/programs/func_tests/hex_ptr/func2.fj new file mode 100644 index 0000000..8c65dec --- /dev/null +++ b/programs/func_tests/hex_ptr/func2.fj @@ -0,0 +1,30 @@ +stl.startup + + +// Prints "AB~CD~EF" +test2: + stl.output 'A' + stl.call func2a + stl.call func2b + stl.output 'F' + + stl.output '\n' + stl.loop + +func2a: + stl.output 'B' + stl.call func2c + stl.output 'C' + stl.return +func2b: + stl.output 'D' + stl.call func2c + stl.output 'E' + stl.return +func2c: + stl.output '~' + stl.return + + +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func3.fj b/programs/func_tests/hex_ptr/func3.fj new file mode 100644 index 0000000..0857dc5 --- /dev/null +++ b/programs/func_tests/hex_ptr/func3.fj @@ -0,0 +1,26 @@ +stl.startup + + +// Prints "ABCDE" +test3: + stl.output 'A' + hex.push x3 + stl.output 'B' + stl.call func3 + stl.output 'D' + hex.pop x3 + stl.output 'E' + + stl.output '\n' + stl.loop + +func3: + stl.output 'C' + stl.return + + +x3: + bit.bit 0 + +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func4.fj b/programs/func_tests/hex_ptr/func4.fj new file mode 100644 index 0000000..bc21485 --- /dev/null +++ b/programs/func_tests/hex_ptr/func4.fj @@ -0,0 +1,43 @@ +stl.startup + + +// Prints "ABCDEFGH-" and then 0/1, the invert of x4 +test4: + stl.output 'A' + hex.push x4 + stl.output 'B' + + stl.call func4 + + stl.output 'G' + hex.pop_res x4 + stl.output 'H' + bit.bin2ascii ascii, x4 + stl.output '-' + bit.print ascii + + stl.output '\n' + stl.loop + +func4: + stl.output 'C' + hex.get_sp __func4_arg_ptr + stl.output 'D' + hex.dec_ptr __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 + + + +x4: + bit.bit 0 + +ascii: + bit.vec 8 + +stl.ptr_init +stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func5.fj b/programs/func_tests/hex_ptr/func5.fj new file mode 100644 index 0000000..f2744f1 --- /dev/null +++ b/programs/func_tests/hex_ptr/func5.fj @@ -0,0 +1,70 @@ +stl.startup + + +// Prints "ABC abcdefg ABCD-", and then 0/1, the xor of x5,y5 +test5: + stl.output 'A' + hex.push res5 + stl.output 'B' + hex.push x5 + stl.output 'C' + hex.push y5 + + stl.output ' ' + stl.call func5 + stl.output ' ' + + stl.output 'A' + hex.pop y5 + stl.output 'B' + hex.pop x5 + stl.output 'C' + hex.pop_res res5 + stl.output 'D' + + bit.bin2ascii ascii, res5 + stl.output '-' + bit.print ascii + + stl.output '\n' + stl.loop + +// res = arg0 xor arg1 +func5: + bit.zero __func5_res + hex.get_sp __func5_arg_ptr + stl.output 'a' + + hex.dec_ptr __func5_arg_ptr + stl.output 'b' + hex.xor_from_ptr __func5_res, __func5_arg_ptr + stl.output 'c' + hex.dec_ptr __func5_arg_ptr + stl.output 'd' + hex.xor_from_ptr __func5_res, __func5_arg_ptr + stl.output 'e' + + hex.dec_ptr __func5_arg_ptr + stl.output 'f' + hex.xor_to_ptr __func5_arg_ptr, __func5_res + stl.output 'g' + + stl.return + __func5_res: + bit.bit + __func5_arg_ptr: + bit.vec w + + +x5: + bit.bit 1 +y5: + bit.bit 1 +res5: + bit.bit 0 + +ascii: + bit.vec 8 + +stl.ptr_init +stl.stack_init 10 diff --git a/stl/bit/pointers.fj b/stl/bit/pointers.fj index 26fe416..318b5ef 100644 --- a/stl/bit/pointers.fj +++ b/stl/bit/pointers.fj @@ -1,35 +1,3 @@ -// ---------- Init - - -ns bit { - // Comp - def ptr_init { - .pointers.ptr_init - } - - ns pointers { - // Space Complexity: 3w+2 - // Inits the - // @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 - } - } -} - - - // ---------- Jump: @@ -39,10 +7,10 @@ ns bit { // Jump to the address the pointer points to. // ( to_jump{_var} = ptr. ==> ;to_jump ) // ptr is a bit[:w] that holds an address. - def ptr_jump ptr < .pointers.to_jump, .pointers.to_jump_var { - .bit_var_xor w, .pointers.to_jump+w, .pointers.to_jump_var, .pointers.to_jump_var - .bit_var_xor w, .pointers.to_jump+w, .pointers.to_jump_var, ptr - ;.pointers.to_jump + def ptr_jump ptr < stl.pointers.to_jump, stl.pointers.to_jump_var { + .bit_var_xor w, stl.pointers.to_jump+w, stl.pointers.to_jump_var, stl.pointers.to_jump_var + .bit_var_xor w, stl.pointers.to_jump+w, stl.pointers.to_jump_var, ptr + ;stl.pointers.to_jump } } @@ -57,16 +25,16 @@ ns bit { // Flip the address the pointer points to. // ( to_flip{_var} = ptr. ==> ;to_flip ) // ptr is a bit[:w] that holds an address. - def ptr_flip ptr @ cleanup < .pointers.to_flip, .pointers.to_flip_var { - wflip .pointers.to_flip+w, cleanup + def ptr_flip ptr @ cleanup < stl.pointers.to_flip, stl.pointers.to_flip_var { + wflip stl.pointers.to_flip+w, cleanup - .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, .pointers.to_flip_var - .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, ptr - ;.pointers.to_flip + .bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, stl.pointers.to_flip_var + .bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, ptr + ;stl.pointers.to_flip pad 4 cleanup: - wflip .pointers.to_flip+w, cleanup + wflip stl.pointers.to_flip+w, cleanup } @@ -94,23 +62,23 @@ ns bit { // 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.to_flip, .pointers.to_flip_var { - .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, .pointers.to_flip_var - .bit_var_xor w, .pointers.to_flip, .pointers.to_flip_var, ptr + def ptr_wflip ptr, value < stl.pointers.to_flip, stl.pointers.to_flip_var { + .bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, stl.pointers.to_flip_var + .bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, 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 < .to_flip { + def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < stl.pointers.to_flip { stl.comp_if0 do_flip, advance - wflip .to_flip+w, cleanup, .to_flip + wflip stl.pointers.to_flip+w, cleanup, stl.pointers.to_flip cleanup: - wflip .to_flip+w, cleanup, advance + wflip stl.pointers.to_flip+w, cleanup, advance pad 4 advance: - rep(n, i) ..exact_not .to_flip+i + rep(n, i) bit.exact_not stl.pointers.to_flip+i } } @@ -165,7 +133,7 @@ ns bit { // Initializes a stack of size n (maximal capacity of n bits / return-addresses). // n is the size of the stack. def stack_init n { - .pointers.stack_init n + stl.pointers.stack_init n } ns pointers { @@ -184,10 +152,10 @@ ns bit { // Time Complexity: n(2@) // Space Complexity: n(2@+24) - // Unsafe if dst is .pointers.sp. + // Unsafe if dst is stl.pointers.sp. // dst[:n] = sp - def get_sp dst < .pointers.sp { - .mov w, dst, .pointers.sp + def get_sp dst < stl.pointers.sp { + .mov w, dst, stl.pointers.sp } @@ -211,9 +179,9 @@ ns bit { // 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 < .pointers.sp { - .inc_ptr .pointers.sp - .ptr_wflip_2nd_word .pointers.sp, return_address + def push_ret_address return_address < stl.pointers.sp { + .inc_ptr stl.pointers.sp + .ptr_wflip_2nd_word stl.pointers.sp, return_address } // Time Complexity: 4w@ (actually a bit smaller) @@ -221,9 +189,9 @@ ns bit { // 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 < .pointers.sp { - .ptr_wflip_2nd_word .pointers.sp, return_address - .dec_ptr .pointers.sp + def pop_ret_address return_address < stl.pointers.sp { + .ptr_wflip_2nd_word stl.pointers.sp, return_address + .dec_ptr stl.pointers.sp } @@ -231,18 +199,18 @@ ns bit { // Space Complexity: w(3.5@+13) // Like: stack[++sp] = bit // Pushes the given bit to the next cell in the stack (assumes it's zero). Increments sp. - def push bit < .pointers.sp { - .inc_ptr .pointers.sp - .xor_to_ptr .pointers.sp, bit + def push bit < stl.pointers.sp { + .inc_ptr stl.pointers.sp + .xor_to_ptr stl.pointers.sp, bit } // Time Complexity: 2w@ + 3@+2 // Space Complexity: w(3.5@+13) // Like: stack[sp--] = 0 // Pops the given bit from the current cell in the stack (assumes it has the value of bit). Decrements sp. - def pop bit < .pointers.sp { - .xor_to_ptr .pointers.sp, bit - .dec_ptr .pointers.sp + def pop bit < stl.pointers.sp { + .xor_to_ptr stl.pointers.sp, bit + .dec_ptr stl.pointers.sp } @@ -252,9 +220,9 @@ ns bit { // stack[sp--] = 0 // Pops the current stack cell into the the given bit. Decrements sp. // bit is only an output parameter - def pop_res bit < .pointers.sp { + def pop_res bit < stl.pointers.sp { .zero bit - .xor_from_ptr bit, .pointers.sp + .xor_from_ptr bit, stl.pointers.sp .pop bit } } diff --git a/stl/conf.json b/stl/conf.json index 98f1226..c8b8989 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -21,6 +21,7 @@ "hex/tables_init", "hex/input", "hex/output", + "hex/pointers", "casting", "ptrlib", diff --git a/stl/hex/pointers.fj b/stl/hex/pointers.fj new file mode 100644 index 0000000..600b5d3 --- /dev/null +++ b/stl/hex/pointers.fj @@ -0,0 +1,207 @@ +// ---------- Jump: + + +ns hex { + // Complexity: 2w@ + 2 + // like: ;*ptr + // Jump to the address the pointer points to. + // ( to_jump{_var} = ptr. ==> ;to_jump ) + // ptr is a bit[:w] that holds an address. + def ptr_jump ptr < stl.pointers.to_jump, stl.pointers.to_jump_var { + bit.bit_var_xor w, stl.pointers.to_jump+w, stl.pointers.to_jump_var, stl.pointers.to_jump_var + bit.bit_var_xor w, stl.pointers.to_jump+w, stl.pointers.to_jump_var, ptr + ;stl.pointers.to_jump + } +} + + + +// ---------- Flip: + + +ns hex { + // Complexity: 2w@ + @ + // like: *ptr; + // Flip the address the pointer points to. + // ( to_flip{_var} = ptr. ==> ;to_flip ) + // ptr is a bit[:w] that holds an address. + def ptr_flip ptr @ cleanup < stl.pointers.to_flip, stl.pointers.to_flip_var { + wflip stl.pointers.to_flip+w, cleanup + + bit.bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, stl.pointers.to_flip_var + bit.bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, ptr + ;stl.pointers.to_flip + + pad 4 + cleanup: + wflip stl.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 { + bit.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 < stl.pointers.to_flip, stl.pointers.to_flip_var { + bit.bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, stl.pointers.to_flip_var + bit.bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, 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 < stl.pointers.to_flip { + stl.comp_if0 do_flip, advance + wflip stl.pointers.to_flip+w, cleanup, stl.pointers.to_flip + cleanup: + wflip stl.pointers.to_flip+w, cleanup, advance + + pad 4 + advance: + rep(n, i) bit.exact_not stl.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 { + bit.not ptr + dw*(#w-1) + bit.ptr_wflip ptr, value + bit.not ptr + dw*(#w-1) + } +} + + + +// ---------- Xor + + +ns hex { + // 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 hex { + // Time Complexity: n(2@) + // Space Complexity: n(2@+24) + // Unsafe if dst is stl.pointers.sp. + // dst[:n] = sp + def get_sp dst < stl.pointers.sp { + bit.mov w, dst, stl.pointers.sp + } + + + // Time Complexity: 1.067@ // (16/15 * @) + // Space Complexity: w(1.5@+13) // actually (w-#w)(1.5@+13) + // ptr[:n] += 2w + def inc_ptr ptr { + bit.inc w-#w, ptr+#w*dw + } + + // Time Complexity: 1.067@ // (16/15 * @) + // Space Complexity: w(1.5@+13) // actually (w-#w)(1.5@+13) + // ptr[:n] -= 2w + def dec_ptr ptr { + bit.dec w-#w, ptr+#w*dw + } + + + // Time Complexity: 4w@ (actually a bit smaller) + // Space Complexity: 5w@ (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 < stl.pointers.sp { + .inc_ptr stl.pointers.sp + .ptr_wflip_2nd_word stl.pointers.sp, return_address + } + + // Time Complexity: 4w@ (actually a bit smaller) + // Space Complexity: 5w@ (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 < stl.pointers.sp { + .ptr_wflip_2nd_word stl.pointers.sp, return_address + .dec_ptr stl.pointers.sp + } + + + // Time Complexity: 2w@ + 3@+2 + // Space Complexity: w(3.5@+13) + // Like: stack[++sp] = bit + // Pushes the given bit to the next cell in the stack (assumes it's zero). Increments sp. + def push bit < stl.pointers.sp { + .inc_ptr stl.pointers.sp + .xor_to_ptr stl.pointers.sp, bit + } + + // Time Complexity: 2w@ + 3@+2 + // Space Complexity: w(3.5@+13) + // Like: stack[sp--] = 0 + // Pops the given bit from the current cell in the stack (assumes it has the value of bit). Decrements sp. + def pop bit < stl.pointers.sp { + .xor_to_ptr stl.pointers.sp, bit + .dec_ptr stl.pointers.sp + } + + + // Time Complexity: w(10@+10) (actually a bit smaller, 8w@ + 10w+9 + 2(@-2)^2) + // Space Complexity: w(11@+20) (actually a bit smaller, w(9.5@+19) + 2(@-2)^2 + @-1) + // Like: bit = stack[sp] + // stack[sp--] = 0 + // Pops the current stack cell into the the given bit. Decrements sp. + // bit is only an output parameter + def pop_res bit < stl.pointers.sp { + bit.zero bit + .xor_from_ptr bit, stl.pointers.sp + .pop bit + } +} diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index f176cb6..1378c9f 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -1,26 +1,79 @@ // TODO read 4-bit values (good for bit/hex/dec) values from pointers. +// ---------- Init + + +ns stl { + // Comp + def ptr_init { + .pointers.ptr_init + } + + // Space Complexity: n+w + // 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 { + .pointers.stack_init n + } + + ns pointers { + // Space Complexity: 3w+2 + // Inits the global opcodes and pointer-copies required for the bit.pointers, hex.pointers, and ptrlib macros. + // @note: The + // + // @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 + } + + // Space Complexity: n+w + // Initializes a stack of size n (maximal capacity of n bits / 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 > sp, stack { + sp: + bit.vec w, .stack-dw + stack: + bit.vec n, 0 + } + } +} + + + // ---------- Functions -ns bit { +ns stl { // Complexity: w(5phi+21) // the pop_ret_address is counted for the future return def call address @ return_label { - .push_ret_address return_label + bit.push_ret_address return_label ;address pad 2 return_label: - .pop_ret_address return_label + bit.pop_ret_address return_label } // Complexity: w(7phi+29) // the last-call's pop_ret_address is counted for this return def return < .pointers.sp { - .ptr_jump .pointers.sp + bit.ptr_jump .pointers.sp } } diff --git a/stl/runlib.fj b/stl/runlib.fj index 7934926..e29f71e 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -30,8 +30,8 @@ ns stl { ;0 // 2w;3w : sets the io_handler to address 0 (good for a future wflip) hex.init - bit.ptr_init - bit.stack_init stack_bit_size + stl.ptr_init + stl.stack_init stack_bit_size code_start: } 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..c3e6cd3 --- /dev/null +++ b/tests/inout/concept_checks/hex_ptr.out @@ -0,0 +1 @@ +17NT \ No newline at end of file diff --git a/tests/inout/func_tests/func1.out b/tests/inout/func_tests/bit_ptr/func1.out similarity index 100% rename from tests/inout/func_tests/func1.out rename to tests/inout/func_tests/bit_ptr/func1.out diff --git a/tests/inout/func_tests/func2.out b/tests/inout/func_tests/bit_ptr/func2.out similarity index 100% rename from tests/inout/func_tests/func2.out rename to tests/inout/func_tests/bit_ptr/func2.out diff --git a/tests/inout/func_tests/func3.out b/tests/inout/func_tests/bit_ptr/func3.out similarity index 100% rename from tests/inout/func_tests/func3.out rename to tests/inout/func_tests/bit_ptr/func3.out diff --git a/tests/inout/func_tests/func4.out b/tests/inout/func_tests/bit_ptr/func4.out similarity index 100% rename from tests/inout/func_tests/func4.out rename to tests/inout/func_tests/bit_ptr/func4.out diff --git a/tests/inout/func_tests/func5.out b/tests/inout/func_tests/bit_ptr/func5.out similarity index 100% rename from tests/inout/func_tests/func5.out rename to tests/inout/func_tests/bit_ptr/func5.out diff --git a/tests/inout/func_tests/hex_ptr/func1.out b/tests/inout/func_tests/hex_ptr/func1.out new file mode 100644 index 0000000..5da849b --- /dev/null +++ b/tests/inout/func_tests/hex_ptr/func1.out @@ -0,0 +1 @@ +ABC diff --git a/tests/inout/func_tests/hex_ptr/func2.out b/tests/inout/func_tests/hex_ptr/func2.out new file mode 100644 index 0000000..286717f --- /dev/null +++ b/tests/inout/func_tests/hex_ptr/func2.out @@ -0,0 +1 @@ +AB~CD~EF diff --git a/tests/inout/func_tests/hex_ptr/func3.out b/tests/inout/func_tests/hex_ptr/func3.out new file mode 100644 index 0000000..9812a4b --- /dev/null +++ b/tests/inout/func_tests/hex_ptr/func3.out @@ -0,0 +1 @@ +ABCDE diff --git a/tests/inout/func_tests/hex_ptr/func4.out b/tests/inout/func_tests/hex_ptr/func4.out new file mode 100644 index 0000000..39415c2 --- /dev/null +++ b/tests/inout/func_tests/hex_ptr/func4.out @@ -0,0 +1 @@ +ABCDEFGH-1 diff --git a/tests/inout/func_tests/hex_ptr/func5.out b/tests/inout/func_tests/hex_ptr/func5.out new file mode 100644 index 0000000..2030f01 --- /dev/null +++ b/tests/inout/func_tests/hex_ptr/func5.out @@ -0,0 +1 @@ +ABC abcdefg ABCD-0 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..2611f1a 100644 --- a/tests/test_compile_slow.csv +++ b/tests/test_compile_slow.csv @@ -1,10 +1,16 @@ 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 +bit_func1, programs/func_tests/bit_ptr/func1.fj,tests/compiled/func_tests/bit_ptr/func1.fjm, 64,3,0, True,True +bit_func2, programs/func_tests/bit_ptr/func2.fj,tests/compiled/func_tests/bit_ptr/func2.fjm, 64,3,0, True,True +bit_func3, programs/func_tests/bit_ptr/func3.fj,tests/compiled/func_tests/bit_ptr/func3.fjm, 64,3,0, True,True +bit_func4, programs/func_tests/bit_ptr/func4.fj,tests/compiled/func_tests/bit_ptr/func4.fjm, 64,3,0, True,True +bit_func5, programs/func_tests/bit_ptr/func5.fj,tests/compiled/func_tests/bit_ptr/func5.fjm, 64,3,0, True,True + +hex_func1, programs/func_tests/hex_ptr/func1.fj,tests/compiled/func_tests/hex_ptr/func1.fjm, 64,3,0, True,True +hex_func2, programs/func_tests/hex_ptr/func2.fj,tests/compiled/func_tests/hex_ptr/func2.fjm, 64,3,0, True,True +hex_func3, programs/func_tests/hex_ptr/func3.fj,tests/compiled/func_tests/hex_ptr/func3.fjm, 64,3,0, True,True +hex_func4, programs/func_tests/hex_ptr/func4.fj,tests/compiled/func_tests/hex_ptr/func4.fjm, 64,3,0, True,True +hex_func5, programs/func_tests/hex_ptr/func5.fj,tests/compiled/func_tests/hex_ptr/func5.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_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..e6e5695 100644 --- a/tests/test_run_slow.csv +++ b/tests/test_run_slow.csv @@ -11,11 +11,17 @@ 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 +bit_func1, tests/compiled/func_tests/bit_ptr/func1.fjm, ,tests/inout/func_tests/bit_ptr/func1.out, False,False +bit_func2, tests/compiled/func_tests/bit_ptr/func2.fjm, ,tests/inout/func_tests/bit_ptr/func2.out, False,False +bit_func3, tests/compiled/func_tests/bit_ptr/func3.fjm, ,tests/inout/func_tests/bit_ptr/func3.out, False,False +bit_func4, tests/compiled/func_tests/bit_ptr/func4.fjm, ,tests/inout/func_tests/bit_ptr/func4.out, False,False +bit_func5, tests/compiled/func_tests/bit_ptr/func5.fjm, ,tests/inout/func_tests/bit_ptr/func5.out, False,False + +hex_func1, tests/compiled/func_tests/hex_ptr/func1.fjm, ,tests/inout/func_tests/hex_ptr/func1.out, False,False +hex_func2, tests/compiled/func_tests/hex_ptr/func2.fjm, ,tests/inout/func_tests/hex_ptr/func2.out, False,False +hex_func3, tests/compiled/func_tests/hex_ptr/func3.fjm, ,tests/inout/func_tests/hex_ptr/func3.out, False,False +hex_func4, tests/compiled/func_tests/hex_ptr/func4.fjm, ,tests/inout/func_tests/hex_ptr/func4.out, False,False +hex_func5, tests/compiled/func_tests/hex_ptr/func5.fjm, ,tests/inout/func_tests/hex_ptr/func5.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 From 591cc249a63c44ceeeda91f9d3edd007ac96c365 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Wed, 26 Apr 2023 17:49:03 +0300 Subject: [PATCH 39/62] separate hex/bit.pointers inits and inner-structure --- stl/bit/logics.fj | 8 ++--- stl/bit/pointers.fj | 74 ++++++++++++++++++++++++++++++++++----------- stl/hex/logics.fj | 9 ++++++ stl/hex/pointers.fj | 69 +++++++++++++++++++++++++++++++----------- stl/ptrlib.fj | 3 +- 5 files changed, 124 insertions(+), 39 deletions(-) diff --git a/stl/bit/logics.fj b/stl/bit/logics.fj index 02981a7..975190d 100644 --- a/stl/bit/logics.fj +++ b/stl/bit/logics.fj @@ -47,11 +47,11 @@ ns bit { } // Complexity: n@ - // bit(bit_address) ^= src + // address(bit_address) ^= src // var ^= src - // dst,var,src are bit[:n]. - def bit_var_xor n, bit, var, src { - rep(n, i) .double_exact_xor bit+i, var+dbit+i*dw, src+i*dw + // 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: @ diff --git a/stl/bit/pointers.fj b/stl/bit/pointers.fj index 318b5ef..72f6de3 100644 --- a/stl/bit/pointers.fj +++ b/stl/bit/pointers.fj @@ -1,16 +1,58 @@ // ---------- Jump: +ns bit { + ns pointers { + // Space Complexity: 3w+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. // ( to_jump{_var} = ptr. ==> ;to_jump ) // ptr is a bit[:w] that holds an address. - def ptr_jump ptr < stl.pointers.to_jump, stl.pointers.to_jump_var { - .bit_var_xor w, stl.pointers.to_jump+w, stl.pointers.to_jump_var, stl.pointers.to_jump_var - .bit_var_xor w, stl.pointers.to_jump+w, stl.pointers.to_jump_var, ptr - ;stl.pointers.to_jump + def ptr_jump ptr < bit.pointers.to_jump { + .pointers.set_jump_pointer ptr + ;bit.pointers.to_jump } } @@ -25,16 +67,15 @@ ns bit { // Flip the address the pointer points to. // ( to_flip{_var} = ptr. ==> ;to_flip ) // ptr is a bit[:w] that holds an address. - def ptr_flip ptr @ cleanup < stl.pointers.to_flip, stl.pointers.to_flip_var { - wflip stl.pointers.to_flip+w, cleanup + def ptr_flip ptr @ cleanup < bit.pointers.to_flip { + wflip bit.pointers.to_flip+w, cleanup - .bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, stl.pointers.to_flip_var - .bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, ptr - ;stl.pointers.to_flip + .pointers.set_flip_pointer ptr + ;bit.pointers.to_flip pad 4 cleanup: - wflip stl.pointers.to_flip+w, cleanup + wflip bit.pointers.to_flip+w, cleanup } @@ -62,23 +103,22 @@ ns bit { // 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 < stl.pointers.to_flip, stl.pointers.to_flip_var { - .bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, stl.pointers.to_flip_var - .bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, ptr + 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 < stl.pointers.to_flip { + def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < bit.pointers.to_flip { stl.comp_if0 do_flip, advance - wflip stl.pointers.to_flip+w, cleanup, stl.pointers.to_flip + wflip bit.pointers.to_flip+w, cleanup, bit.pointers.to_flip cleanup: - wflip stl.pointers.to_flip+w, cleanup, advance + wflip bit.pointers.to_flip+w, cleanup, advance pad 4 advance: - rep(n, i) bit.exact_not stl.pointers.to_flip+i + rep(n, i) bit.exact_not bit.pointers.to_flip+i } } diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj index 1e3eeb2..acf380f 100644 --- a/stl/hex/logics.fj +++ b/stl/hex/logics.fj @@ -77,6 +77,15 @@ ns hex { .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 + } + // Time Complexity: @+4 // Space Complexity: @+28 // {t3,t2,t1,t0} ^= src diff --git a/stl/hex/pointers.fj b/stl/hex/pointers.fj index 600b5d3..17f55c2 100644 --- a/stl/hex/pointers.fj +++ b/stl/hex/pointers.fj @@ -1,16 +1,51 @@ // ---------- Jump: + +ns hex { + ns pointers { + // Space Complexity: 3w+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: + bit.vec w, 0 //TODO hex.vec + to_jump_var: + bit.vec w, 0 //TODO hex.vec + } + + // Time Complexity: n(2@+8) + // Space Complexity: n(2@+56) + // 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 + } + } +} + + ns hex { // Complexity: 2w@ + 2 // like: ;*ptr // Jump to the address the pointer points to. // ( to_jump{_var} = ptr. ==> ;to_jump ) // ptr is a bit[:w] that holds an address. - def ptr_jump ptr < stl.pointers.to_jump, stl.pointers.to_jump_var { - bit.bit_var_xor w, stl.pointers.to_jump+w, stl.pointers.to_jump_var, stl.pointers.to_jump_var - bit.bit_var_xor w, stl.pointers.to_jump+w, stl.pointers.to_jump_var, ptr - ;stl.pointers.to_jump + def ptr_jump ptr < hex.pointers.to_jump, hex.pointers.to_jump_var { + bit.address_and_variable_xor w, hex.pointers.to_jump+w, hex.pointers.to_jump_var, hex.pointers.to_jump_var + bit.address_and_variable_xor w, hex.pointers.to_jump+w, hex.pointers.to_jump_var, ptr + ;hex.pointers.to_jump } } @@ -25,16 +60,16 @@ ns hex { // Flip the address the pointer points to. // ( to_flip{_var} = ptr. ==> ;to_flip ) // ptr is a bit[:w] that holds an address. - def ptr_flip ptr @ cleanup < stl.pointers.to_flip, stl.pointers.to_flip_var { - wflip stl.pointers.to_flip+w, cleanup + def ptr_flip ptr @ cleanup < hex.pointers.to_flip, hex.pointers.to_flip_var { + wflip hex.pointers.to_flip+w, cleanup - bit.bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, stl.pointers.to_flip_var - bit.bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, ptr - ;stl.pointers.to_flip + bit.address_and_variable_xor w, hex.pointers.to_flip, hex.pointers.to_flip_var, hex.pointers.to_flip_var + bit.address_and_variable_xor w, hex.pointers.to_flip, hex.pointers.to_flip_var, ptr + ;hex.pointers.to_flip pad 4 cleanup: - wflip stl.pointers.to_flip+w, cleanup + wflip hex.pointers.to_flip+w, cleanup } @@ -62,23 +97,23 @@ ns hex { // 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 < stl.pointers.to_flip, stl.pointers.to_flip_var { - bit.bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, stl.pointers.to_flip_var - bit.bit_var_xor w, stl.pointers.to_flip, stl.pointers.to_flip_var, ptr + def ptr_wflip ptr, value < hex.pointers.to_flip, hex.pointers.to_flip_var { + bit.address_and_variable_xor w, hex.pointers.to_flip, hex.pointers.to_flip_var, hex.pointers.to_flip_var + bit.address_and_variable_xor w, hex.pointers.to_flip, hex.pointers.to_flip_var, 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 < stl.pointers.to_flip { + def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < hex.pointers.to_flip { stl.comp_if0 do_flip, advance - wflip stl.pointers.to_flip+w, cleanup, stl.pointers.to_flip + wflip hex.pointers.to_flip+w, cleanup, hex.pointers.to_flip cleanup: - wflip stl.pointers.to_flip+w, cleanup, advance + wflip hex.pointers.to_flip+w, cleanup, advance pad 4 advance: - rep(n, i) bit.exact_not stl.pointers.to_flip+i + rep(n, i) bit.exact_not hex.pointers.to_flip+i } } diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index 1378c9f..532d65a 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -7,7 +7,8 @@ ns stl { // Comp def ptr_init { - .pointers.ptr_init + bit.pointers.ptr_init + hex.pointers.ptr_init } // Space Complexity: n+w From 06998fa2283635050834144e5874bb6485b564f3 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 28 Apr 2023 20:03:13 +0300 Subject: [PATCH 40/62] poc: always print last 10 ops addresses --- src/defs.py | 23 ++++++---- src/exceptions.py | 4 ++ src/fjm.py | 7 ++- src/fjm_run.py | 84 +++++++++++++++++++++--------------- src/io_devices/FixedIO.py | 4 +- src/io_devices/StandardIO.py | 4 +- tests/test_fj.py | 8 +++- 7 files changed, 83 insertions(+), 51 deletions(-) diff --git a/src/defs.py b/src/defs.py index b02fd69..7872b5a 100644 --- a/src/defs.py +++ b/src/defs.py @@ -3,10 +3,11 @@ import dataclasses 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 typing import List, Dict, Deque from ops import CodePosition, Op @@ -22,14 +23,16 @@ 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 = "---" @@ -115,13 +118,14 @@ 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, *, number_of_saved_last_ops_addresses=10): self._op_size = 2 * w self._after_null_flip = 2 * w self.op_counter = 0 self.flip_counter = 0 self.jump_counter = 0 + self.last_ops_addresses: Deque[int] = deque(maxlen=number_of_saved_last_ops_addresses) self._start_time = time() self.pause_timer = self.PauseTimer() @@ -129,6 +133,9 @@ def __init__(self, w: int): def get_run_time(self) -> float: return time() - self._start_time - self.pause_timer.paused_time + def register_op_address(self, ip: int): + 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/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..91ba187 100644 --- a/src/fjm_run.py +++ b/src/fjm_run.py @@ -1,10 +1,12 @@ from pathlib import Path -from typing import Optional +from typing import Optional, Deque +from collections import 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,18 +24,26 @@ 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): flips_percentage = self.flip_counter / self.op_counter * 100 jumps_percentage = self.jump_counter / self.op_counter * 100 + + last_ops_str = '' + if True or TerminationCause.RuntimeMemoryError == self.termination_cause: # TODO remove the "if True" part. + last_ops_str = f'\nLast {len(self.last_ops_addresses)} ops were at:\n ' + \ + '\n '.join([hex(address) for address in self.last_ops_addresses]) + 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').' + f').' \ + f'{last_ops_str}' def handle_input(io_device: IODevice, ip: int, mem: fjm.Reader, statistics: RunStatistics) -> None: @@ -89,35 +99,41 @@ def run(fjm_path: Path, *, statistics = RunStatistics(w) - 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) - - # 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)) - - # 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) - - # JUMP! - ip = jump_address + 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) + + # 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) + + # 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) + + # 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 + + 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/tests/test_fj.py b/tests/test_fj.py index 8005a25..4e4570c 100644 --- a/tests/test_fj.py +++ b/tests/test_fj.py @@ -3,6 +3,7 @@ from threading import Lock from pathlib import Path +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 @@ -78,7 +79,8 @@ 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) 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=Path(f'{compile_args.fjm_out_path}.fj_debugging_info')) class RunTestArgs: @@ -154,6 +156,10 @@ def test_run(run_args: RunTestArgs) -> None: print(f'Running test {run_args.test_name}:') io_device = FixedIO(run_args.get_defined_input()) + + label_to_address = load_labels_dictionary(Path(f'{run_args.fjm_path}.fj_debugging_info'), True) + breakpoint_handler = BreakpointHandler({}, {label_to_address[label]: label for label in label_to_address}) + termination_statistics = fjm_run.run(run_args.fjm_path, io_device=io_device, time_verbose=True) From b24468e3adf4c14166954fed405f11b26dcec7be Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 29 Apr 2023 00:37:26 +0300 Subject: [PATCH 41/62] add tests' debug-flag, now shows last 10 ops' addresses/labels --- src/breakpoints.py | 13 ++++++++----- src/fj.py | 2 +- src/fjm_run.py | 41 ++++++++++++++++++++++++++++------------- tests/conftest.py | 28 +++++++++++++++++++--------- tests/test_fj.py | 32 ++++++++++++++++++++++++-------- 5 files changed, 80 insertions(+), 36 deletions(-) diff --git a/src/breakpoints.py b/src/breakpoints.py index 4b38a6f..bec311c 100644 --- a/src/breakpoints.py +++ b/src/breakpoints.py @@ -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) diff --git a/src/fj.py b/src/fj.py index 8d68228..dcd77b6 100644 --- a/src/fj.py +++ b/src/fj.py @@ -119,7 +119,7 @@ def run(in_fjm_path: Path, debug_file: Path, args: argparse.Namespace, error_fun breakpoint_handler=breakpoint_handler ) if not args.silent: - print(termination_statistics) + termination_statistics.print(labels_handler=breakpoint_handler) except FJReadFjmException as e: print() print(e) diff --git a/src/fjm_run.py b/src/fjm_run.py index 91ba187..baea45c 100644 --- a/src/fjm_run.py +++ b/src/fjm_run.py @@ -1,6 +1,5 @@ from pathlib import Path from typing import Optional, Deque -from collections import deque import fjm @@ -28,22 +27,38 @@ def __init__(self, run_statistics: RunStatistics, termination_cause: Termination 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): + """ + 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). + """ + flips_percentage = self.flip_counter / self.op_counter * 100 jumps_percentage = self.jump_counter / self.op_counter * 100 last_ops_str = '' - if True or TerminationCause.RuntimeMemoryError == self.termination_cause: # TODO remove the "if True" part. - last_ops_str = f'\nLast {len(self.last_ops_addresses)} ops were at:\n ' + \ - '\n '.join([hex(address) for address in self.last_ops_addresses]) - - 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').' \ - f'{last_ops_str}' + if TerminationCause.Looping != self.termination_cause: + last_ops_str = f'\n\nLast {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]) + + print(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: diff --git a/tests/conftest.py b/tests/conftest.py index bca8656..76dddef 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -40,6 +40,7 @@ RUN_ORDER_INDEX = 2 +NO_DEBUG_INFO_FLAG = 'nodebuginfo' ALL_FLAG = 'all' REGULAR_FLAG = 'regular' COMPILE_FLAG = 'compile' @@ -77,31 +78,33 @@ def argument_line_iterator(csv_file_path: Path, num_of_args: int) -> Iterable[Li yield 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, save_debug_info: bool) -> List: """ read the compile-tests from the csv @param csv_file_path: read tests from this csv + @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) + for line in argument_line_iterator(csv_file_path, CompileTestArgs.num_of_csv_line_args): + args = CompileTestArgs(*line, save_debug_info) params.append(pytest.param(args, marks=pytest.mark.run(order=COMPILE_ORDER_INDEX))) 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, use_debug_info: bool) -> List: """ read the run-tests from the csv @param csv_file_path: read tests from this csv + @param use_debug_info: should use the debugging info file @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) + for line in argument_line_iterator(csv_file_path, RunTestArgs.num_of_csv_line_args): + args = RunTestArgs(*line, use_debug_info) params.append(pytest.param(args, marks=pytest.mark.run(order=RUN_ORDER_INDEX))) return params @@ -115,10 +118,15 @@ def pytest_addoption(parser) -> None: colliding_keywords = set(TEST_TYPES) & SAVED_KEYWORDS assert not colliding_keywords + parser.addoption(f"--{NO_DEBUG_INFO_FLAG}", action="store_true", + help="don't show the last executed opcodes on tests that failed during their run" + "(thus the tests are ~15% faster, and takes ~half the size)." + "Anyway 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 +303,14 @@ 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) + use_debug_info = not is_parallel_active() and not get_option(NO_DEBUG_INFO_FLAG) + 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], use_debug_info)) compile_tests = filter_by_test_name(compile_tests, get_option) run_tests = [] @@ -308,7 +318,7 @@ 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], use_debug_info)) run_tests = filter_by_test_name(run_tests, get_option) return compile_tests, run_tests diff --git a/tests/test_fj.py b/tests/test_fj.py index 4e4570c..f4e18b0 100644 --- a/tests/test_fj.py +++ b/tests/test_fj.py @@ -14,6 +14,9 @@ CSV_BOOLEAN = (CSV_TRUE, CSV_FALSE) +DEBUGGING_FILE_SUFFIX = '.fj_debugging_info' + + ROOT_PATH = Path(__file__).parent.parent @@ -26,11 +29,12 @@ 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, word_size__str: str, version__str: str, flags__str: str, - use_stl__str: str, warning_as_errors__str: str): + use_stl__str: str, warning_as_errors__str: str, + save_debug_info: bool): """ handling a line.split() from a csv file """ @@ -39,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 [] @@ -78,9 +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, - debugging_file_path=Path(f'{compile_args.fjm_out_path}.fj_debugging_info')) + debugging_file_path=debugging_file_path) class RunTestArgs: @@ -88,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, 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, + use_debug_info: bool): """ @note handling a line.split() (each is stripped) from a csv file """ @@ -101,6 +113,8 @@ 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.use_debug_info = use_debug_info + self.test_name = test_name self.fjm_path = ROOT_PATH / fjm_path @@ -157,14 +171,16 @@ def test_run(run_args: RunTestArgs) -> None: io_device = FixedIO(run_args.get_defined_input()) - label_to_address = load_labels_dictionary(Path(f'{run_args.fjm_path}.fj_debugging_info'), True) - breakpoint_handler = BreakpointHandler({}, {label_to_address[label]: label for label in label_to_address}) + breakpoint_handler = None + if run_args.use_debug_info: + 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 label_to_address}) termination_statistics = fjm_run.run(run_args.fjm_path, io_device=io_device, time_verbose=True) - print(termination_statistics) + termination_statistics.print(labels_handler=breakpoint_handler) expected_termination_cause = TerminationCause.Looping assert termination_statistics.termination_cause == expected_termination_cause From b15816611c19d853e7d564262e5cf9cf4beb005e Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 29 Apr 2023 00:54:26 +0300 Subject: [PATCH 42/62] merge from dev (debuggable tests) --- src/breakpoints.py | 13 ++-- src/defs.py | 23 +++++--- src/exceptions.py | 4 ++ src/fj.py | 2 +- src/fjm.py | 7 +-- src/fjm_run.py | 111 ++++++++++++++++++++++------------- src/io_devices/FixedIO.py | 4 +- src/io_devices/StandardIO.py | 4 +- tests/conftest.py | 28 ++++++--- tests/test_fj.py | 35 ++++++++--- 10 files changed, 153 insertions(+), 78 deletions(-) diff --git a/src/breakpoints.py b/src/breakpoints.py index 4b38a6f..bec311c 100644 --- a/src/breakpoints.py +++ b/src/breakpoints.py @@ -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) diff --git a/src/defs.py b/src/defs.py index b02fd69..7872b5a 100644 --- a/src/defs.py +++ b/src/defs.py @@ -3,10 +3,11 @@ import dataclasses 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 typing import List, Dict, Deque from ops import CodePosition, Op @@ -22,14 +23,16 @@ 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 = "---" @@ -115,13 +118,14 @@ 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, *, number_of_saved_last_ops_addresses=10): self._op_size = 2 * w self._after_null_flip = 2 * w self.op_counter = 0 self.flip_counter = 0 self.jump_counter = 0 + self.last_ops_addresses: Deque[int] = deque(maxlen=number_of_saved_last_ops_addresses) self._start_time = time() self.pause_timer = self.PauseTimer() @@ -129,6 +133,9 @@ def __init__(self, w: int): def get_run_time(self) -> float: return time() - self._start_time - self.pause_timer.paused_time + def register_op_address(self, ip: int): + 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/fj.py b/src/fj.py index 8d68228..dcd77b6 100644 --- a/src/fj.py +++ b/src/fj.py @@ -119,7 +119,7 @@ def run(in_fjm_path: Path, debug_file: Path, args: argparse.Namespace, error_fun breakpoint_handler=breakpoint_handler ) if not args.silent: - print(termination_statistics) + termination_statistics.print(labels_handler=breakpoint_handler) except FJReadFjmException as e: print() print(e) 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 c33ec3a..3d393b4 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,18 +23,42 @@ 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): + """ + 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). + """ + 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 = '' + if TerminationCause.Looping != self.termination_cause: + last_ops_str = f'\n\nLast {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]) + + print(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: @@ -89,35 +114,41 @@ def run(fjm_path: Path, *, statistics = RunStatistics(w) - 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) - - # 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)) - - # 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) - - # JUMP! - ip = jump_address + 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) + + # 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) + + # 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) + + # 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 + + 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/tests/conftest.py b/tests/conftest.py index 70230fe..33ecdf1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -40,6 +40,7 @@ RUN_ORDER_INDEX = 2 +NO_DEBUG_INFO_FLAG = 'nodebuginfo' ALL_FLAG = 'all' REGULAR_FLAG = 'regular' COMPILE_FLAG = 'compile' @@ -77,17 +78,19 @@ def argument_line_iterator(csv_file_path: Path, num_of_args: int) -> Iterable[Li yield list(map(str.strip, line)) -def get_compile_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str]) -> 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) + 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()) @@ -96,17 +99,18 @@ def get_compile_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str] return params -def get_run_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str]) -> List: +def get_run_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str], use_debug_info: bool) -> 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 use_debug_info: should use the debugging info file @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) + for line in argument_line_iterator(csv_file_path, RunTestArgs.num_of_csv_line_args): + args = RunTestArgs(use_debug_info, *line) test_marks = [pytest.mark.run(order=RUN_ORDER_INDEX)] if args.test_name in xfail_list: test_marks.append(pytest.mark.xfail()) @@ -123,10 +127,15 @@ def pytest_addoption(parser) -> None: colliding_keywords = set(TEST_TYPES) & SAVED_KEYWORDS assert not colliding_keywords + parser.addoption(f"--{NO_DEBUG_INFO_FLAG}", action="store_true", + help="don't show the last executed opcodes on tests that failed during their run" + "(thus the tests are ~15% faster, and takes ~half the size)." + "Anyway 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') @@ -305,13 +314,14 @@ def get_tests_from_csvs(get_option: Callable[[str], Any]) -> Tuple[List, List]: 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)] + use_debug_info = not is_parallel_active() and not get_option(NO_DEBUG_INFO_FLAG) 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_xfail_list)) + compile_tests.extend(get_compile_tests_params_from_csv(compiles_csvs[test_type], compile_xfail_list, use_debug_info)) compile_tests = filter_by_test_name(compile_tests, get_option) run_tests = [] @@ -319,7 +329,7 @@ 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_xfail_list)) + run_tests.extend(get_run_tests_params_from_csv(run_csvs[test_type], run_xfail_list, use_debug_info)) run_tests = filter_by_test_name(run_tests, get_option) return compile_tests, run_tests diff --git a/tests/test_fj.py b/tests/test_fj.py index 8005a25..277069c 100644 --- a/tests/test_fj.py +++ b/tests/test_fj.py @@ -3,6 +3,7 @@ from threading import Lock from pathlib import Path +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 @@ -13,6 +14,9 @@ CSV_BOOLEAN = (CSV_TRUE, CSV_FALSE) +DEBUGGING_FILE_SUFFIX = '.fj_debugging_info' + + ROOT_PATH = Path(__file__).parent.parent @@ -25,9 +29,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 +42,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 +83,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 +98,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, use_debug_info: bool, 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 +112,8 @@ 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.use_debug_info = use_debug_info + self.test_name = test_name self.fjm_path = ROOT_PATH / fjm_path @@ -154,11 +169,17 @@ 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.use_debug_info: + 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 label_to_address}) + termination_statistics = fjm_run.run(run_args.fjm_path, io_device=io_device, time_verbose=True) - print(termination_statistics) + termination_statistics.print(labels_handler=breakpoint_handler) expected_termination_cause = TerminationCause.Looping assert termination_statistics.termination_cause == expected_termination_cause From b2ce340fa28de1cba6348b1a97d0f331e81e96dc Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 29 Apr 2023 13:57:42 +0300 Subject: [PATCH 43/62] add labels for each wflip, for better debugging --- src/assembler.py | 14 ++++++++++++-- tests/conftest.py | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/assembler.py b/src/assembler.py index 5c43279..d7841f4 100644 --- a/src/assembler.py +++ b/src/assembler.py @@ -58,12 +58,17 @@ class WFlipSpot: class BinaryData: - def __init__(self, w: int, first_segment: NewSegment): + _WFLIP_LABEL_PREFIX = '::wflips::' + + 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 +92,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'{self._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 +125,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,7 +173,7 @@ 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): diff --git a/tests/conftest.py b/tests/conftest.py index 33ecdf1..97c5e44 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -129,8 +129,8 @@ def pytest_addoption(parser) -> None: parser.addoption(f"--{NO_DEBUG_INFO_FLAG}", action="store_true", help="don't show the last executed opcodes on tests that failed during their run" - "(thus the tests are ~15% faster, and takes ~half the size)." - "Anyway doesn't show last executed opcodes on parallel tests.") + "(thus the tests are ~20% faster, and takes ~30% of their size)." + "Anyway this 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") From 28bb1357b38d7b59ccf34d9f983b9a4a358c77d6 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 29 Apr 2023 14:32:14 +0300 Subject: [PATCH 44/62] ctrl+shift+click script support for iterative clicks still needs to re-press the ctrl+shift again --- ide-extensions/pycharm/fj-pycharm-def-finder.ahk | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ide-extensions/pycharm/fj-pycharm-def-finder.ahk b/ide-extensions/pycharm/fj-pycharm-def-finder.ahk index c3c0101..f024d15 100644 --- a/ide-extensions/pycharm/fj-pycharm-def-finder.ahk +++ b/ide-extensions/pycharm/fj-pycharm-def-finder.ahk @@ -1,4 +1,4 @@ -; Double-click the script (with AutoHotKey v1 installed) to run now. Copy to "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup" to still take effect after reboot. +; 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). @@ -22,9 +22,14 @@ ; Open the "Find in files" window (shortcut in Pycharm) Send ^+f - Sleep 10 - + Sleep 100 + ; Search for "def COPIED_WORD" + Send {Home} + Send +{End} Send def{Space} Send ^v + Send {Space} + + return } \ No newline at end of file From fe135458361a92fad027cf37fdc2f01be9292940 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 29 Apr 2023 22:08:11 +0300 Subject: [PATCH 45/62] show more last-opcodes in debugging --- src/defs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defs.py b/src/defs.py index 7872b5a..27e19bf 100644 --- a/src/defs.py +++ b/src/defs.py @@ -118,7 +118,7 @@ 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, *, number_of_saved_last_ops_addresses=10): + def __init__(self, w: int, *, number_of_saved_last_ops_addresses=20): self._op_size = 2 * w self._after_null_flip = 2 * w From f279b7b07937a3956f377a137731cfa9100b63f4 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 29 Apr 2023 23:37:50 +0300 Subject: [PATCH 46/62] add starting label at the start of macros --- src/assembler.py | 6 ++---- src/breakpoints.py | 10 +++++----- src/defs.py | 4 +++- src/macro_usage_graph.py | 6 +++--- src/preprocessor.py | 11 +++++++---- tests/test_fj.py | 3 ++- 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/assembler.py b/src/assembler.py index d7841f4..37a588c 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,8 +58,6 @@ class WFlipSpot: class BinaryData: - _WFLIP_LABEL_PREFIX = '::wflips::' - def __init__(self, w: int, first_segment: NewSegment, labels: Dict[str, int]): self.w = w @@ -93,7 +91,7 @@ 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'{self._WFLIP_LABEL_PREFIX}{self.wflips_so_far}'] = address + 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: diff --git a/src/breakpoints.py b/src/breakpoints.py index bec311c..4ab5e22 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)) @@ -155,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 @@ -202,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 diff --git a/src/defs.py b/src/defs.py index 27e19bf..b310f5a 100644 --- a/src/defs.py +++ b/src/defs.py @@ -35,7 +35,9 @@ def __str__(self) -> str: return ['looping', 'EOF', 'ip<2w', 'unaligned-word', 'unaligned-op', 'runtime-memory-error'][self.value] -macro_separator_string = "---" +MACRO_SEPARATOR_STRING = "---" +STARTING_LABEL_IN_MACROS_STRING = ':start:' +WFLIP_LABEL_PREFIX = ':wflips:' io_bytes_encoding = 'raw_unicode_escape' 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/preprocessor.py b/src/preprocessor.py index 1dc9e02..6e17fbe 100644 --- a/src/preprocessor.py +++ b/src/preprocessor.py @@ -4,7 +4,7 @@ from typing import Dict, Tuple, Iterable, Union, Deque from expr import Expr -from defs import CodePosition, Macro, macro_separator_string +from defs import CodePosition, Macro, 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, \ @@ -172,7 +172,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 +195,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_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 +216,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,7 +227,7 @@ 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): diff --git a/tests/test_fj.py b/tests/test_fj.py index 277069c..212af2d 100644 --- a/tests/test_fj.py +++ b/tests/test_fj.py @@ -173,7 +173,8 @@ def test_run(run_args: RunTestArgs) -> None: breakpoint_handler = None if run_args.use_debug_info: 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 label_to_address}) + 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, From 6f4f1a6fa4930f2f531a80b1a85f3360923a4139 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sun, 30 Apr 2023 23:30:16 +0300 Subject: [PATCH 47/62] print outputs in tests debug, fix macro-start label overlaps labels --- src/defs.py | 4 +++- src/fj.py | 3 ++- src/fjm_run.py | 10 ++++++++-- src/preprocessor.py | 28 +++++++++++++++++++++++----- tests/test_fj.py | 3 ++- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/defs.py b/src/defs.py index b310f5a..925b842 100644 --- a/src/defs.py +++ b/src/defs.py @@ -39,6 +39,8 @@ def __str__(self) -> str: STARTING_LABEL_IN_MACROS_STRING = ':start:' WFLIP_LABEL_PREFIX = ':wflips:' +NUMBER_OF_SAVED_LAST_OPS_ADDRESSES = 50 + io_bytes_encoding = 'raw_unicode_escape' @@ -120,7 +122,7 @@ 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, *, number_of_saved_last_ops_addresses=20): + def __init__(self, w: int, *, number_of_saved_last_ops_addresses=NUMBER_OF_SAVED_LAST_OPS_ADDRESSES): self._op_size = 2 * w self._after_null_flip = 2 * w diff --git a/src/fj.py b/src/fj.py index dcd77b6..9dd4eac 100644 --- a/src/fj.py +++ b/src/fj.py @@ -119,7 +119,8 @@ def run(in_fjm_path: Path, debug_file: Path, args: argparse.Namespace, error_fun breakpoint_handler=breakpoint_handler ) if not args.silent: - termination_statistics.print(labels_handler=breakpoint_handler) + 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) diff --git a/src/fjm_run.py b/src/fjm_run.py index 3d393b4..75abd22 100644 --- a/src/fjm_run.py +++ b/src/fjm_run.py @@ -34,24 +34,30 @@ def beautify_address(address: int, breakpoint_handler: Optional[BreakpointHandle return breakpoint_handler.get_address_str(address) - def print(self, *, labels_handler: Optional[BreakpointHandler] = None): + 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 last_ops_str = '' + output_str = '' if TerminationCause.Looping != self.termination_cause: last_ops_str = f'\n\nLast {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'Finished by {str(self.termination_cause)} after {self.run_time:.3f}s ' + 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, ' diff --git a/src/preprocessor.py b/src/preprocessor.py index 6e17fbe..03de893 100644 --- a/src/preprocessor.py +++ b/src/preprocessor.py @@ -1,7 +1,7 @@ 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, STARTING_LABEL_IN_MACROS_STRING @@ -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: @@ -195,8 +213,8 @@ 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_label(f'{labels_prefix}{MACRO_SEPARATOR_STRING}{STARTING_LABEL_IN_MACROS_STRING}', - current_macro.code_position) + 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: diff --git a/tests/test_fj.py b/tests/test_fj.py index 212af2d..79e9b9d 100644 --- a/tests/test_fj.py +++ b/tests/test_fj.py @@ -180,7 +180,8 @@ def test_run(run_args: RunTestArgs) -> None: io_device=io_device, time_verbose=True) - termination_statistics.print(labels_handler=breakpoint_handler) + 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 From 89b8af6b91bef45b68794bc1df9b5de69173fdf9 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 5 May 2023 14:49:27 +0300 Subject: [PATCH 48/62] ctrl-shift-click script now restores clipboard --- ide-extensions/pycharm/fj-pycharm-def-finder.ahk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ide-extensions/pycharm/fj-pycharm-def-finder.ahk b/ide-extensions/pycharm/fj-pycharm-def-finder.ahk index f024d15..3a368aa 100644 --- a/ide-extensions/pycharm/fj-pycharm-def-finder.ahk +++ b/ide-extensions/pycharm/fj-pycharm-def-finder.ahk @@ -7,6 +7,8 @@ ^+Lbutton:: { + old_clipboard := clipboard + ; Click Send {Lbutton} @@ -31,5 +33,6 @@ Send ^v Send {Space} + clipboard := old_clipboard return } \ No newline at end of file From 3d339477bfe04da89460997f03449a107640643d Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Thu, 11 May 2023 06:22:22 +0300 Subject: [PATCH 49/62] update --debuginfo, --debug-ops-list, document debug flags in READMEs --- README.md | 9 +++++++++ src/breakpoints.py | 8 ++++---- src/defs.py | 27 ++++++++++++++++++++++----- src/fj.py | 11 +++++++++-- src/fjm_run.py | 18 ++++++++++++------ tests/README.md | 32 +++++++++++++++++++++++++++++++- tests/conftest.py | 46 +++++++++++++++++++++++++++++++++------------- tests/test_fj.py | 13 ++++++++----- 8 files changed, 128 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 9a97f7c..627809a 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,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): diff --git a/src/breakpoints.py b/src/breakpoints.py index 4ab5e22..f088fff 100644 --- a/src/breakpoints.py +++ b/src/breakpoints.py @@ -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 @@ -190,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) @@ -205,4 +205,4 @@ def get_breakpoint_handler(debugging_file: Path, breakpoint_addresses: Set[int], 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 925b842..4dc4c4e 100644 --- a/src/defs.py +++ b/src/defs.py @@ -1,5 +1,6 @@ from __future__ import annotations +import argparse import dataclasses import json import lzma @@ -7,7 +8,7 @@ from enum import IntEnum # IntEnum equality works between files. from pathlib import Path from time import time -from typing import List, Dict, Deque +from typing import List, Dict, Deque, Optional from ops import CodePosition, Op @@ -39,7 +40,7 @@ def __str__(self) -> str: STARTING_LABEL_IN_MACROS_STRING = ':start:' WFLIP_LABEL_PREFIX = ':wflips:' -NUMBER_OF_SAVED_LAST_OPS_ADDRESSES = 50 +LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH = 10 io_bytes_encoding = 'raw_unicode_escape' @@ -49,6 +50,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 @@ -122,14 +130,22 @@ 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, *, number_of_saved_last_ops_addresses=NUMBER_OF_SAVED_LAST_OPS_ADDRESSES): + 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 self.op_counter = 0 self.flip_counter = 0 self.jump_counter = 0 - self.last_ops_addresses: Deque[int] = deque(maxlen=number_of_saved_last_ops_addresses) + + 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() @@ -138,7 +154,8 @@ def get_run_time(self) -> float: return time() - self._start_time - self.pause_timer.paused_time def register_op_address(self, ip: int): - self.last_ops_addresses.append(ip) + 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 diff --git a/src/fj.py b/src/fj.py index 9dd4eac..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,7 +116,8 @@ 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: termination_statistics.print(labels_handler=breakpoint_handler, @@ -216,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/fjm_run.py b/src/fjm_run.py index 75abd22..fba2fde 100644 --- a/src/fjm_run.py +++ b/src/fjm_run.py @@ -48,10 +48,14 @@ def print(self, *, labels_handler: Optional[BreakpointHandler] = None, output_to last_ops_str = '' output_str = '' if TerminationCause.Looping != self.termination_cause: - last_ops_str = f'\n\nLast {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 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" @@ -98,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) @@ -107,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): @@ -118,7 +124,7 @@ def run(fjm_path: Path, *, ip = 0 w = mem.w - statistics = RunStatistics(w) + statistics = RunStatistics(w, last_ops_debugging_list_length) try: while True: diff --git a/tests/README.md b/tests/README.md index 743ee2a..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. diff --git a/tests/conftest.py b/tests/conftest.py index 97c5e44..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,7 +42,7 @@ RUN_ORDER_INDEX = 2 -NO_DEBUG_INFO_FLAG = 'nodebuginfo' +DEBUG_INFO_FLAG = 'debuginfo' ALL_FLAG = 'all' REGULAR_FLAG = 'regular' COMPILE_FLAG = 'compile' @@ -99,18 +101,20 @@ def get_compile_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str] return params -def get_run_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str], use_debug_info: bool) -> 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 use_debug_info: should use the debugging info file + @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_csv_line_args): - args = RunTestArgs(use_debug_info, *line) + 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()) @@ -119,7 +123,7 @@ def get_run_tests_params_from_csv(csv_file_path: Path, xfail_list: List[str], us return params -def pytest_addoption(parser) -> None: +def pytest_addoption(parser: pytest.Parser) -> None: """ add the costume flags to pytest @param parser: the parser @@ -127,10 +131,21 @@ def pytest_addoption(parser) -> None: colliding_keywords = set(TEST_TYPES) & SAVED_KEYWORDS assert not colliding_keywords - parser.addoption(f"--{NO_DEBUG_INFO_FLAG}", action="store_true", - help="don't show the last executed opcodes on tests that failed during their run" - "(thus the tests are ~20% faster, and takes ~30% of their size)." - "Anyway this is irrelevant (doesn't show last executed opcodes) on parallel tests.") + 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") @@ -314,14 +329,18 @@ def get_tests_from_csvs(get_option: Callable[[str], Any]) -> Tuple[List, List]: 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)] - use_debug_info = not is_parallel_active() and not get_option(NO_DEBUG_INFO_FLAG) + + 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_xfail_list, use_debug_info)) + 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 = [] @@ -329,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_xfail_list, use_debug_info)) + 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/test_fj.py b/tests/test_fj.py index 79e9b9d..66e3ecb 100644 --- a/tests/test_fj.py +++ b/tests/test_fj.py @@ -2,11 +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' @@ -100,7 +101,7 @@ class RunTestArgs: num_of_csv_line_args = 6 - def __init__(self, use_debug_info: bool, 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 ): @@ -112,7 +113,8 @@ def __init__(self, use_debug_info: bool, 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.use_debug_info = use_debug_info + 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 @@ -171,14 +173,15 @@ def test_run(run_args: RunTestArgs) -> None: io_device = FixedIO(run_args.get_defined_input()) breakpoint_handler = None - if run_args.use_debug_info: + 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) termination_statistics.print(labels_handler=breakpoint_handler, output_to_print=io_device.get_output(allow_incomplete_output=True)) From 48d28209167288162c712b5f3c0c706ff755a823 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 20 May 2023 13:58:39 +0300 Subject: [PATCH 50/62] hex-pointers, tested (removed bit-pointers), ptr-bugfixes - hex.{add,sub,inc,dec}_shifted - function macros are in stl, using hex. - bugfix in address_and_variable_xor - bugfix in ptr_flip_dbit --- programs/concept_checks/bit_ptr.fj | 5 +- programs/concept_checks/hex_ptr.fj | 10 +- programs/func_tests/bit_ptr/func2.fj | 30 ----- programs/func_tests/bit_ptr/func3.fj | 26 ---- programs/func_tests/bit_ptr/func4.fj | 43 ------ programs/func_tests/bit_ptr/func5.fj | 70 ---------- programs/func_tests/{bit_ptr => }/func1.fj | 6 +- programs/func_tests/{hex_ptr => }/func2.fj | 6 +- programs/func_tests/{hex_ptr => }/func3.fj | 5 +- programs/func_tests/{hex_ptr => }/func4.fj | 9 +- programs/func_tests/{hex_ptr => }/func5.fj | 9 +- programs/func_tests/hex_ptr/func1.fj | 19 --- programs/hexlib_tests/2params/add_shifted.fj | 48 +++++++ programs/hexlib_tests/2params/sub_shifted.fj | 48 +++++++ programs/sanity_checks/startup_init_all.fj | 2 + src/assembler.py | 4 +- stl/bit/math.fj | 5 +- stl/bit/pointers.fj | 99 +------------- stl/hex/logics.fj | 2 +- stl/hex/math.fj | 26 ++++ stl/hex/math_basic.fj | 29 +++- stl/hex/pointers.fj | 124 ++++++++++-------- stl/ptrlib.fj | 53 ++------ .../inout/func_tests/{bit_ptr => }/func1.out | 0 .../inout/func_tests/{bit_ptr => }/func2.out | 0 .../inout/func_tests/{bit_ptr => }/func3.out | 0 .../inout/func_tests/{bit_ptr => }/func4.out | 0 .../inout/func_tests/{bit_ptr => }/func5.out | 0 tests/inout/func_tests/hex_ptr/func1.out | 1 - tests/inout/func_tests/hex_ptr/func2.out | 1 - tests/inout/func_tests/hex_ptr/func3.out | 1 - tests/inout/func_tests/hex_ptr/func4.out | 1 - tests/inout/func_tests/hex_ptr/func5.out | 1 - .../inout/hexlib_tests/2params/108equals.out | 108 +++++++++++++++ tests/test_compile_hexlib.csv | 2 + tests/test_compile_slow.csv | 16 +-- tests/test_run_hexlib.csv | 2 + tests/test_run_slow.csv | 16 +-- 38 files changed, 383 insertions(+), 444 deletions(-) delete mode 100644 programs/func_tests/bit_ptr/func2.fj delete mode 100644 programs/func_tests/bit_ptr/func3.fj delete mode 100644 programs/func_tests/bit_ptr/func4.fj delete mode 100644 programs/func_tests/bit_ptr/func5.fj rename programs/func_tests/{bit_ptr => }/func1.fj (77%) rename programs/func_tests/{hex_ptr => }/func2.fj (88%) rename programs/func_tests/{hex_ptr => }/func3.fj (84%) rename programs/func_tests/{hex_ptr => }/func4.fj (85%) rename programs/func_tests/{hex_ptr => }/func5.fj (92%) delete mode 100644 programs/func_tests/hex_ptr/func1.fj create mode 100644 programs/hexlib_tests/2params/add_shifted.fj create mode 100644 programs/hexlib_tests/2params/sub_shifted.fj rename tests/inout/func_tests/{bit_ptr => }/func1.out (100%) rename tests/inout/func_tests/{bit_ptr => }/func2.out (100%) rename tests/inout/func_tests/{bit_ptr => }/func3.out (100%) rename tests/inout/func_tests/{bit_ptr => }/func4.out (100%) rename tests/inout/func_tests/{bit_ptr => }/func5.out (100%) delete mode 100644 tests/inout/func_tests/hex_ptr/func1.out delete mode 100644 tests/inout/func_tests/hex_ptr/func2.out delete mode 100644 tests/inout/func_tests/hex_ptr/func3.out delete mode 100644 tests/inout/func_tests/hex_ptr/func4.out delete mode 100644 tests/inout/func_tests/hex_ptr/func5.out create mode 100644 tests/inout/hexlib_tests/2params/108equals.out diff --git a/programs/concept_checks/bit_ptr.fj b/programs/concept_checks/bit_ptr.fj index 5bbeade..0b01101 100644 --- a/programs/concept_checks/bit_ptr.fj +++ b/programs/concept_checks/bit_ptr.fj @@ -46,8 +46,6 @@ test3: - stl.ptr_init - p0: bit.vec w, d0+dbit d0: @@ -71,3 +69,6 @@ test3: bit.bit 1 // 0 => F, 1 => T d3_var: bit.bit 0 + + +bit.pointers.ptr_init diff --git a/programs/concept_checks/hex_ptr.fj b/programs/concept_checks/hex_ptr.fj index f6ed60e..032ada4 100644 --- a/programs/concept_checks/hex_ptr.fj +++ b/programs/concept_checks/hex_ptr.fj @@ -49,24 +49,24 @@ test3: stl.ptr_init p0: - bit.vec w, d0+dbit + hex.vec w/4, d0+dbit d0: bit.bit 0 // 0 => 1, 1 => 0 p1: - bit.vec w, d1 + hex.vec w/4, d1 d1: ;jump_to7 // jump_to6 => 6, jump_to7 => 7 p2: - bit.vec w, d2+w + hex.vec w/4, d2+w p2_jump: - bit.vec w, d2 + hex.vec w/4, d2 d2: bit.bit 0 // 0 => N, 1 => Y p3: - bit.vec w, d3 + hex.vec w/4, d3 d3: bit.bit 1 // 0 => F, 1 => T d3_var: diff --git a/programs/func_tests/bit_ptr/func2.fj b/programs/func_tests/bit_ptr/func2.fj deleted file mode 100644 index 8c65dec..0000000 --- a/programs/func_tests/bit_ptr/func2.fj +++ /dev/null @@ -1,30 +0,0 @@ -stl.startup - - -// Prints "AB~CD~EF" -test2: - stl.output 'A' - stl.call func2a - stl.call func2b - stl.output 'F' - - stl.output '\n' - stl.loop - -func2a: - stl.output 'B' - stl.call func2c - stl.output 'C' - stl.return -func2b: - stl.output 'D' - stl.call func2c - stl.output 'E' - stl.return -func2c: - stl.output '~' - stl.return - - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/bit_ptr/func3.fj b/programs/func_tests/bit_ptr/func3.fj deleted file mode 100644 index 0e2197f..0000000 --- a/programs/func_tests/bit_ptr/func3.fj +++ /dev/null @@ -1,26 +0,0 @@ -stl.startup - - -// Prints "ABCDE" -test3: - stl.output 'A' - bit.push x3 - stl.output 'B' - stl.call func3 - stl.output 'D' - bit.pop x3 - stl.output 'E' - - stl.output '\n' - stl.loop - -func3: - stl.output 'C' - stl.return - - -x3: - bit.bit 0 - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/bit_ptr/func4.fj b/programs/func_tests/bit_ptr/func4.fj deleted file mode 100644 index f04ae51..0000000 --- a/programs/func_tests/bit_ptr/func4.fj +++ /dev/null @@ -1,43 +0,0 @@ -stl.startup - - -// Prints "ABCDEFGH-" and then 0/1, the invert of x4 -test4: - stl.output 'A' - bit.push x4 - stl.output 'B' - - stl.call func4 - - stl.output 'G' - bit.pop_res x4 - stl.output 'H' - bit.bin2ascii ascii, x4 - stl.output '-' - bit.print ascii - - stl.output '\n' - stl.loop - -func4: - stl.output 'C' - bit.get_sp __func4_arg_ptr - stl.output 'D' - bit.dec_ptr __func4_arg_ptr - stl.output 'E' - bit.ptr_flip_dbit __func4_arg_ptr - stl.output 'F' - stl.return - __func4_arg_ptr: - bit.vec w, 0 - - - -x4: - bit.bit 0 - -ascii: - bit.vec 8 - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/bit_ptr/func5.fj b/programs/func_tests/bit_ptr/func5.fj deleted file mode 100644 index b14afde..0000000 --- a/programs/func_tests/bit_ptr/func5.fj +++ /dev/null @@ -1,70 +0,0 @@ -stl.startup - - -// Prints "ABC abcdefg ABCD-", and then 0/1, the xor of x5,y5 -test5: - stl.output 'A' - bit.push res5 - stl.output 'B' - bit.push x5 - stl.output 'C' - bit.push y5 - - stl.output ' ' - stl.call func5 - stl.output ' ' - - stl.output 'A' - bit.pop y5 - stl.output 'B' - bit.pop x5 - stl.output 'C' - bit.pop_res res5 - stl.output 'D' - - bit.bin2ascii ascii, res5 - stl.output '-' - bit.print ascii - - stl.output '\n' - stl.loop - -// res = arg0 xor arg1 -func5: - bit.zero __func5_res - bit.get_sp __func5_arg_ptr - stl.output 'a' - - bit.dec_ptr __func5_arg_ptr - stl.output 'b' - bit.xor_from_ptr __func5_res, __func5_arg_ptr - stl.output 'c' - bit.dec_ptr __func5_arg_ptr - stl.output 'd' - bit.xor_from_ptr __func5_res, __func5_arg_ptr - stl.output 'e' - - bit.dec_ptr __func5_arg_ptr - stl.output 'f' - bit.xor_to_ptr __func5_arg_ptr, __func5_res - stl.output 'g' - - stl.return - __func5_res: - bit.bit - __func5_arg_ptr: - bit.vec w - - -x5: - bit.bit 1 -y5: - bit.bit 1 -res5: - bit.bit 0 - -ascii: - bit.vec 8 - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/bit_ptr/func1.fj b/programs/func_tests/func1.fj similarity index 77% rename from programs/func_tests/bit_ptr/func1.fj rename to programs/func_tests/func1.fj index 7427645..bf65d13 100644 --- a/programs/func_tests/bit_ptr/func1.fj +++ b/programs/func_tests/func1.fj @@ -1,4 +1,4 @@ -stl.startup +stl.startup_and_init_all 10 // Prints "ABC" @@ -13,7 +13,3 @@ test1: func1: stl.output 'B' stl.return - - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func2.fj b/programs/func_tests/func2.fj similarity index 88% rename from programs/func_tests/hex_ptr/func2.fj rename to programs/func_tests/func2.fj index 8c65dec..b8da578 100644 --- a/programs/func_tests/hex_ptr/func2.fj +++ b/programs/func_tests/func2.fj @@ -1,4 +1,4 @@ -stl.startup +stl.startup_and_init_all 10 // Prints "AB~CD~EF" @@ -24,7 +24,3 @@ func2b: func2c: stl.output '~' stl.return - - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func3.fj b/programs/func_tests/func3.fj similarity index 84% rename from programs/func_tests/hex_ptr/func3.fj rename to programs/func_tests/func3.fj index 0857dc5..a991275 100644 --- a/programs/func_tests/hex_ptr/func3.fj +++ b/programs/func_tests/func3.fj @@ -1,4 +1,4 @@ -stl.startup +stl.startup_and_init_all 10 // Prints "ABCDE" @@ -21,6 +21,3 @@ func3: x3: bit.bit 0 - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func4.fj b/programs/func_tests/func4.fj similarity index 85% rename from programs/func_tests/hex_ptr/func4.fj rename to programs/func_tests/func4.fj index bc21485..6f732da 100644 --- a/programs/func_tests/hex_ptr/func4.fj +++ b/programs/func_tests/func4.fj @@ -1,4 +1,4 @@ -stl.startup +stl.startup_and_init_all 10 // Prints "ABCDEFGH-" and then 0/1, the invert of x4 @@ -21,7 +21,7 @@ test4: func4: stl.output 'C' - hex.get_sp __func4_arg_ptr + stl.get_sp __func4_arg_ptr stl.output 'D' hex.dec_ptr __func4_arg_ptr stl.output 'E' @@ -29,7 +29,7 @@ func4: stl.output 'F' stl.return __func4_arg_ptr: - bit.vec w, 0 + hex.vec w/4, 0 @@ -38,6 +38,3 @@ x4: ascii: bit.vec 8 - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func5.fj b/programs/func_tests/func5.fj similarity index 92% rename from programs/func_tests/hex_ptr/func5.fj rename to programs/func_tests/func5.fj index f2744f1..71b68e8 100644 --- a/programs/func_tests/hex_ptr/func5.fj +++ b/programs/func_tests/func5.fj @@ -1,4 +1,4 @@ -stl.startup +stl.startup_and_init_all 10 // Prints "ABC abcdefg ABCD-", and then 0/1, the xor of x5,y5 @@ -32,7 +32,7 @@ test5: // res = arg0 xor arg1 func5: bit.zero __func5_res - hex.get_sp __func5_arg_ptr + stl.get_sp __func5_arg_ptr stl.output 'a' hex.dec_ptr __func5_arg_ptr @@ -53,7 +53,7 @@ func5: __func5_res: bit.bit __func5_arg_ptr: - bit.vec w + hex.vec w/4 x5: @@ -65,6 +65,3 @@ res5: ascii: bit.vec 8 - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/func_tests/hex_ptr/func1.fj b/programs/func_tests/hex_ptr/func1.fj deleted file mode 100644 index 7427645..0000000 --- a/programs/func_tests/hex_ptr/func1.fj +++ /dev/null @@ -1,19 +0,0 @@ -stl.startup - - -// Prints "ABC" -test1: - stl.output 'A' - stl.call func1 - stl.output 'C' - - stl.output '\n' - stl.loop - -func1: - stl.output 'B' - stl.return - - -stl.ptr_init -stl.stack_init 10 diff --git a/programs/hexlib_tests/2params/add_shifted.fj b/programs/hexlib_tests/2params/add_shifted.fj new file mode 100644 index 0000000..b07466a --- /dev/null +++ b/programs/hexlib_tests/2params/add_shifted.fj @@ -0,0 +1,48 @@ +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/sub_shifted.fj b/programs/hexlib_tests/2params/sub_shifted.fj new file mode 100644 index 0000000..8e4bdfe --- /dev/null +++ b/programs/hexlib_tests/2params/sub_shifted.fj @@ -0,0 +1,48 @@ +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/sanity_checks/startup_init_all.fj b/programs/sanity_checks/startup_init_all.fj index e0ea271..4019391 100644 --- a/programs/sanity_checks/startup_init_all.fj +++ b/programs/sanity_checks/startup_init_all.fj @@ -31,3 +31,5 @@ def flip_and_print @ d0, d1, end < p, d { ;end end: } + + diff --git a/src/assembler.py b/src/assembler.py index 37a588c..96a03c2 100644 --- a/src/assembler.py +++ b/src/assembler.py @@ -178,14 +178,14 @@ def labels_resolve(ops: Deque[LastPhaseOp], labels: Dict[str, int], 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/stl/bit/math.fj b/stl/bit/math.fj index 4281986..0160165 100644 --- a/stl/bit/math.fj +++ b/stl/bit/math.fj @@ -18,12 +18,13 @@ ns bit { // Complexity: n(2@+6) // x[:n]++ // x is a bit[:n] - def inc n, x @ carry { + def inc n, x @ carry, end { .one carry rep(n, i) .inc1 x+i*dw, carry - stl.skip + ;end carry: .bit + end: } // Complexity: n(2@+8) diff --git a/stl/bit/pointers.fj b/stl/bit/pointers.fj index 72f6de3..931d76b 100644 --- a/stl/bit/pointers.fj +++ b/stl/bit/pointers.fj @@ -48,7 +48,6 @@ ns bit { // Complexity: 2w@ + 2 // like: ;*ptr // Jump to the address the pointer points to. - // ( to_jump{_var} = ptr. ==> ;to_jump ) // ptr is a bit[:w] that holds an address. def ptr_jump ptr < bit.pointers.to_jump { .pointers.set_jump_pointer ptr @@ -65,7 +64,6 @@ ns bit { // Complexity: 2w@ + @ // like: *ptr; // Flip the address the pointer points to. - // ( to_flip{_var} = ptr. ==> ;to_flip ) // 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 @@ -126,9 +124,9 @@ ns bit { // 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) + .not ptr + dw*((#w)-1) .ptr_wflip ptr, value - .not ptr + dw*(#w-1) + .not ptr + dw*((#w)-1) } } @@ -169,100 +167,15 @@ ns bit { ns bit { - // Space Complexity: n+w - // Initializes a stack of size n (maximal capacity of n bits / return-addresses). - // n is the size of the stack. - def stack_init n { - stl.pointers.stack_init n - } - - ns pointers { - // Space Complexity: n+w - // Initializes a stack of size n (maximal capacity of n bits / 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 > sp, stack { - sp: - bit.vec w, .stack-dw - stack: - bit.vec n, 0 - } - } - - // Time Complexity: n(2@) - // Space Complexity: n(2@+24) - // Unsafe if dst is stl.pointers.sp. - // dst[:n] = sp - def get_sp dst < stl.pointers.sp { - .mov w, dst, stl.pointers.sp - } - - - // Time Complexity: 1.067@ // (16/15 * @) - // Space Complexity: w(1.5@+13) // actually (w-#w)(1.5@+13) + // Complexity: w(2@+6) // actually (w-#w)(2@+6) // ptr[:n] += 2w def inc_ptr ptr { - .inc w-#w, ptr+#w*dw + .inc w-#w, ptr+(#w)*dw //TODO check if need #dw or #w } - // Time Complexity: 1.067@ // (16/15 * @) - // Space Complexity: w(1.5@+13) // actually (w-#w)(1.5@+13) + // Complexity: w(2@+8) // actually (w-#w)(2@+8) // ptr[:n] -= 2w def dec_ptr ptr { - .dec w-#w, ptr+#w*dw - } - - - // Time Complexity: 4w@ (actually a bit smaller) - // Space Complexity: 5w@ (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 < stl.pointers.sp { - .inc_ptr stl.pointers.sp - .ptr_wflip_2nd_word stl.pointers.sp, return_address - } - - // Time Complexity: 4w@ (actually a bit smaller) - // Space Complexity: 5w@ (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 < stl.pointers.sp { - .ptr_wflip_2nd_word stl.pointers.sp, return_address - .dec_ptr stl.pointers.sp - } - - - // Time Complexity: 2w@ + 3@+2 - // Space Complexity: w(3.5@+13) - // Like: stack[++sp] = bit - // Pushes the given bit to the next cell in the stack (assumes it's zero). Increments sp. - def push bit < stl.pointers.sp { - .inc_ptr stl.pointers.sp - .xor_to_ptr stl.pointers.sp, bit - } - - // Time Complexity: 2w@ + 3@+2 - // Space Complexity: w(3.5@+13) - // Like: stack[sp--] = 0 - // Pops the given bit from the current cell in the stack (assumes it has the value of bit). Decrements sp. - def pop bit < stl.pointers.sp { - .xor_to_ptr stl.pointers.sp, bit - .dec_ptr stl.pointers.sp - } - - - // Time Complexity: w(10@+10) (actually a bit smaller, 8w@ + 10w+9 + 2(@-2)^2) - // Space Complexity: w(11@+20) (actually a bit smaller, w(9.5@+19) + 2(@-2)^2 + @-1) - // Like: bit = stack[sp] - // stack[sp--] = 0 - // Pops the current stack cell into the the given bit. Decrements sp. - // bit is only an output parameter - def pop_res bit < stl.pointers.sp { - .zero bit - .xor_from_ptr bit, stl.pointers.sp - .pop bit + .dec w-#w, ptr+(#w)*dw //TODO check if need #dw or #w } } diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj index acf380f..9e8b0ef 100644 --- a/stl/hex/logics.fj +++ b/stl/hex/logics.fj @@ -83,7 +83,7 @@ ns hex { // 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 + 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 diff --git a/stl/hex/math.fj b/stl/hex/math.fj index 302049d..a687010 100644 --- a/stl/hex/math.fj +++ b/stl/hex/math.fj @@ -23,6 +23,19 @@ ns hex { .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: + } + ns add { // Time Complexity: 2@ // Space Complexity: 2@+12 @@ -115,6 +128,19 @@ ns hex { .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 sub.add.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: + } + ns sub { // Time Complexity: 2@+5 // Space Complexity: 2@+20 diff --git a/stl/hex/math_basic.fj b/stl/hex/math_basic.fj index 84abdf4..afd8607 100644 --- a/stl/hex/math_basic.fj +++ b/stl/hex/math_basic.fj @@ -122,7 +122,7 @@ ns hex { wflip hex+w, switch, carry0 } - // Time Complexity: 1.067@ // (16/15 * @) + // 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 { @@ -169,7 +169,7 @@ ns hex { wflip hex+w, switch, borrow0 } - // Time Complexity: 1.067@ // (16/15 * @) + // 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 { @@ -184,6 +184,31 @@ ns hex { } + // Time Complexity: 10@+17 + // Space Complexity: (n+6-shift)(1.5@+13) // exact: (n-shift)(1.5@+13) + 7.5@+84 + // hex[:n] += 1< sp, stack { + sp: + hex.vec w/4, .stack-dw + + pad w + stack: + bit.vec n, 0 + } } } @@ -40,11 +64,9 @@ ns hex { // Complexity: 2w@ + 2 // like: ;*ptr // Jump to the address the pointer points to. - // ( to_jump{_var} = ptr. ==> ;to_jump ) - // ptr is a bit[:w] that holds an address. - def ptr_jump ptr < hex.pointers.to_jump, hex.pointers.to_jump_var { - bit.address_and_variable_xor w, hex.pointers.to_jump+w, hex.pointers.to_jump_var, hex.pointers.to_jump_var - bit.address_and_variable_xor w, hex.pointers.to_jump+w, hex.pointers.to_jump_var, ptr + // 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 } } @@ -58,13 +80,11 @@ ns hex { // Complexity: 2w@ + @ // like: *ptr; // Flip the address the pointer points to. - // ( to_flip{_var} = ptr. ==> ;to_flip ) - // ptr is a bit[:w] that holds an address. - def ptr_flip ptr @ cleanup < hex.pointers.to_flip, hex.pointers.to_flip_var { + // 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 - bit.address_and_variable_xor w, hex.pointers.to_flip, hex.pointers.to_flip_var, hex.pointers.to_flip_var - bit.address_and_variable_xor w, hex.pointers.to_flip, hex.pointers.to_flip_var, ptr + .pointers.set_flip_pointer ptr ;hex.pointers.to_flip pad 4 @@ -77,16 +97,16 @@ ns hex { // 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. + // ptr is a hex[:w/4] 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 + rep(#dbit, i) stl.comp_flip_if ptr+dbit+(i/4)*dw+i%4, (dbit>>i)&1 .ptr_flip ptr - rep(#dbit, i) stl.comp_flip_if ptr+dbit+i*dw, (dbit>>i)&1 + rep(#dbit, i) stl.comp_flip_if ptr+dbit+(i/4)*dw+i%4, (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. + // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def xor_to_ptr ptr, bit @ end { bit.if0 bit, end .ptr_flip_dbit ptr @@ -96,10 +116,9 @@ ns hex { // 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 < hex.pointers.to_flip, hex.pointers.to_flip_var { - bit.address_and_variable_xor w, hex.pointers.to_flip, hex.pointers.to_flip_var, hex.pointers.to_flip_var - bit.address_and_variable_xor w, hex.pointers.to_flip, hex.pointers.to_flip_var, ptr + // 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 { @@ -119,11 +138,11 @@ ns hex { // 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. + // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def ptr_wflip_2nd_word ptr, value { - bit.not ptr + dw*(#w-1) - bit.ptr_wflip ptr, value - bit.not ptr + dw*(#w-1) + ptr+dbit + ((#w-1)/4)*dw + (#w-1)%4; + hex.ptr_wflip ptr, value + ptr+dbit + ((#w-1)/4)*dw + (#w-1)%4; } } @@ -135,14 +154,14 @@ ns hex { ns hex { // 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. + // dst is a bit. 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, 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. + // dst is a bit-address. ptr is a hex[:w/4] 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 @@ -164,27 +183,18 @@ ns hex { ns hex { - // Time Complexity: n(2@) - // Space Complexity: n(2@+24) - // Unsafe if dst is stl.pointers.sp. - // dst[:n] = sp - def get_sp dst < stl.pointers.sp { - bit.mov w, dst, stl.pointers.sp - } - - - // Time Complexity: 1.067@ // (16/15 * @) - // Space Complexity: w(1.5@+13) // actually (w-#w)(1.5@+13) - // ptr[:n] += 2w + // Time Complexity: 10@+17 + // Space Complexity: w(0.375@ + 3.25) + 6@+71 (for log(w) in 16,32,64,128) + // ptr[:w/4] += 2w def inc_ptr ptr { - bit.inc w-#w, ptr+#w*dw + hex.inc_shifted w/4, ptr, #w } - // Time Complexity: 1.067@ // (16/15 * @) - // Space Complexity: w(1.5@+13) // actually (w-#w)(1.5@+13) - // ptr[:n] -= 2w + // Time Complexity: 10@+26 + // Space Complexity: w(0.375@ + 3.25) + 6@+83 (for log(w) in 16,32,64,128) + // ptr[:w/4] -= 2w def dec_ptr ptr { - bit.dec w-#w, ptr+#w*dw + hex.dec_shifted w/4, ptr, #w } @@ -193,9 +203,9 @@ ns hex { // 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 < stl.pointers.sp { - .inc_ptr stl.pointers.sp - .ptr_wflip_2nd_word stl.pointers.sp, return_address + def push_ret_address return_address < hex.pointers.sp { + .inc_ptr hex.pointers.sp + .ptr_wflip_2nd_word hex.pointers.sp, return_address } // Time Complexity: 4w@ (actually a bit smaller) @@ -203,9 +213,9 @@ ns hex { // 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 < stl.pointers.sp { - .ptr_wflip_2nd_word stl.pointers.sp, return_address - .dec_ptr stl.pointers.sp + def pop_ret_address return_address < hex.pointers.sp { + .ptr_wflip_2nd_word hex.pointers.sp, return_address + .dec_ptr hex.pointers.sp } @@ -213,18 +223,18 @@ ns hex { // Space Complexity: w(3.5@+13) // Like: stack[++sp] = bit // Pushes the given bit to the next cell in the stack (assumes it's zero). Increments sp. - def push bit < stl.pointers.sp { - .inc_ptr stl.pointers.sp - .xor_to_ptr stl.pointers.sp, bit + def push bit < hex.pointers.sp { + .inc_ptr hex.pointers.sp + .xor_to_ptr hex.pointers.sp, bit } // Time Complexity: 2w@ + 3@+2 // Space Complexity: w(3.5@+13) // Like: stack[sp--] = 0 // Pops the given bit from the current cell in the stack (assumes it has the value of bit). Decrements sp. - def pop bit < stl.pointers.sp { - .xor_to_ptr stl.pointers.sp, bit - .dec_ptr stl.pointers.sp + def pop bit < hex.pointers.sp { + .xor_to_ptr hex.pointers.sp, bit + .dec_ptr hex.pointers.sp } @@ -234,9 +244,9 @@ ns hex { // stack[sp--] = 0 // Pops the current stack cell into the the given bit. Decrements sp. // bit is only an output parameter - def pop_res bit < stl.pointers.sp { + def pop_res bit < hex.pointers.sp { bit.zero bit - .xor_from_ptr bit, stl.pointers.sp + .xor_from_ptr bit, hex.pointers.sp .pop bit } } diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index 532d65a..379cd99 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -15,41 +15,7 @@ ns stl { // 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 { - .pointers.stack_init n - } - - ns pointers { - // Space Complexity: 3w+2 - // Inits the global opcodes and pointer-copies required for the bit.pointers, hex.pointers, and ptrlib macros. - // @note: The - // - // @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 - } - - // Space Complexity: n+w - // Initializes a stack of size n (maximal capacity of n bits / 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 > sp, stack { - sp: - bit.vec w, .stack-dw - stack: - bit.vec n, 0 - } + hex.pointers.stack_init n } } @@ -62,19 +28,28 @@ ns stl { // Complexity: w(5phi+21) // the pop_ret_address is counted for the future return def call address @ return_label { - bit.push_ret_address return_label + hex.push_ret_address return_label ;address pad 2 return_label: - bit.pop_ret_address return_label + hex.pop_ret_address return_label } // Complexity: w(7phi+29) // the last-call's pop_ret_address is counted for this return - def return < .pointers.sp { - bit.ptr_jump .pointers.sp + def return < hex.pointers.sp { + hex.ptr_jump hex.pointers.sp + } + + + // 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 } } diff --git a/tests/inout/func_tests/bit_ptr/func1.out b/tests/inout/func_tests/func1.out similarity index 100% rename from tests/inout/func_tests/bit_ptr/func1.out rename to tests/inout/func_tests/func1.out diff --git a/tests/inout/func_tests/bit_ptr/func2.out b/tests/inout/func_tests/func2.out similarity index 100% rename from tests/inout/func_tests/bit_ptr/func2.out rename to tests/inout/func_tests/func2.out diff --git a/tests/inout/func_tests/bit_ptr/func3.out b/tests/inout/func_tests/func3.out similarity index 100% rename from tests/inout/func_tests/bit_ptr/func3.out rename to tests/inout/func_tests/func3.out diff --git a/tests/inout/func_tests/bit_ptr/func4.out b/tests/inout/func_tests/func4.out similarity index 100% rename from tests/inout/func_tests/bit_ptr/func4.out rename to tests/inout/func_tests/func4.out diff --git a/tests/inout/func_tests/bit_ptr/func5.out b/tests/inout/func_tests/func5.out similarity index 100% rename from tests/inout/func_tests/bit_ptr/func5.out rename to tests/inout/func_tests/func5.out diff --git a/tests/inout/func_tests/hex_ptr/func1.out b/tests/inout/func_tests/hex_ptr/func1.out deleted file mode 100644 index 5da849b..0000000 --- a/tests/inout/func_tests/hex_ptr/func1.out +++ /dev/null @@ -1 +0,0 @@ -ABC diff --git a/tests/inout/func_tests/hex_ptr/func2.out b/tests/inout/func_tests/hex_ptr/func2.out deleted file mode 100644 index 286717f..0000000 --- a/tests/inout/func_tests/hex_ptr/func2.out +++ /dev/null @@ -1 +0,0 @@ -AB~CD~EF diff --git a/tests/inout/func_tests/hex_ptr/func3.out b/tests/inout/func_tests/hex_ptr/func3.out deleted file mode 100644 index 9812a4b..0000000 --- a/tests/inout/func_tests/hex_ptr/func3.out +++ /dev/null @@ -1 +0,0 @@ -ABCDE diff --git a/tests/inout/func_tests/hex_ptr/func4.out b/tests/inout/func_tests/hex_ptr/func4.out deleted file mode 100644 index 39415c2..0000000 --- a/tests/inout/func_tests/hex_ptr/func4.out +++ /dev/null @@ -1 +0,0 @@ -ABCDEFGH-1 diff --git a/tests/inout/func_tests/hex_ptr/func5.out b/tests/inout/func_tests/hex_ptr/func5.out deleted file mode 100644 index 2030f01..0000000 --- a/tests/inout/func_tests/hex_ptr/func5.out +++ /dev/null @@ -1 +0,0 @@ -ABC abcdefg ABCD-0 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/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_slow.csv b/tests/test_compile_slow.csv index 2611f1a..4cb4acd 100644 --- a/tests/test_compile_slow.csv +++ b/tests/test_compile_slow.csv @@ -1,16 +1,10 @@ calc, programs/calc.fj,tests/compiled/calc.fjm, 64,3,0, True,True -bit_func1, programs/func_tests/bit_ptr/func1.fj,tests/compiled/func_tests/bit_ptr/func1.fjm, 64,3,0, True,True -bit_func2, programs/func_tests/bit_ptr/func2.fj,tests/compiled/func_tests/bit_ptr/func2.fjm, 64,3,0, True,True -bit_func3, programs/func_tests/bit_ptr/func3.fj,tests/compiled/func_tests/bit_ptr/func3.fjm, 64,3,0, True,True -bit_func4, programs/func_tests/bit_ptr/func4.fj,tests/compiled/func_tests/bit_ptr/func4.fjm, 64,3,0, True,True -bit_func5, programs/func_tests/bit_ptr/func5.fj,tests/compiled/func_tests/bit_ptr/func5.fjm, 64,3,0, True,True - -hex_func1, programs/func_tests/hex_ptr/func1.fj,tests/compiled/func_tests/hex_ptr/func1.fjm, 64,3,0, True,True -hex_func2, programs/func_tests/hex_ptr/func2.fj,tests/compiled/func_tests/hex_ptr/func2.fjm, 64,3,0, True,True -hex_func3, programs/func_tests/hex_ptr/func3.fj,tests/compiled/func_tests/hex_ptr/func3.fjm, 64,3,0, True,True -hex_func4, programs/func_tests/hex_ptr/func4.fj,tests/compiled/func_tests/hex_ptr/func4.fjm, 64,3,0, True,True -hex_func5, programs/func_tests/hex_ptr/func5.fj,tests/compiled/func_tests/hex_ptr/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 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_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_slow.csv b/tests/test_run_slow.csv index e6e5695..84ee402 100644 --- a/tests/test_run_slow.csv +++ b/tests/test_run_slow.csv @@ -11,17 +11,11 @@ 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 -bit_func1, tests/compiled/func_tests/bit_ptr/func1.fjm, ,tests/inout/func_tests/bit_ptr/func1.out, False,False -bit_func2, tests/compiled/func_tests/bit_ptr/func2.fjm, ,tests/inout/func_tests/bit_ptr/func2.out, False,False -bit_func3, tests/compiled/func_tests/bit_ptr/func3.fjm, ,tests/inout/func_tests/bit_ptr/func3.out, False,False -bit_func4, tests/compiled/func_tests/bit_ptr/func4.fjm, ,tests/inout/func_tests/bit_ptr/func4.out, False,False -bit_func5, tests/compiled/func_tests/bit_ptr/func5.fjm, ,tests/inout/func_tests/bit_ptr/func5.out, False,False - -hex_func1, tests/compiled/func_tests/hex_ptr/func1.fjm, ,tests/inout/func_tests/hex_ptr/func1.out, False,False -hex_func2, tests/compiled/func_tests/hex_ptr/func2.fjm, ,tests/inout/func_tests/hex_ptr/func2.out, False,False -hex_func3, tests/compiled/func_tests/hex_ptr/func3.fjm, ,tests/inout/func_tests/hex_ptr/func3.out, False,False -hex_func4, tests/compiled/func_tests/hex_ptr/func4.fjm, ,tests/inout/func_tests/hex_ptr/func4.out, False,False -hex_func5, tests/compiled/func_tests/hex_ptr/func5.fjm, ,tests/inout/func_tests/hex_ptr/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 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 From adcb5fbe37bec4776ddb1d219147492d427be802 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 20 May 2023 15:20:24 +0300 Subject: [PATCH 51/62] document remaining hex-pointers complexities --- stl/bit/pointers.fj | 6 ++--- stl/hex/pointers.fj | 60 ++++++++++++++++++++++++++---------------- stl/hex/tables_init.fj | 15 ++++++----- stl/ptrlib.fj | 17 ++++++------ stl/runlib.fj | 3 +++ 5 files changed, 60 insertions(+), 41 deletions(-) diff --git a/stl/bit/pointers.fj b/stl/bit/pointers.fj index 931d76b..a6c7ef9 100644 --- a/stl/bit/pointers.fj +++ b/stl/bit/pointers.fj @@ -3,7 +3,7 @@ ns bit { ns pointers { - // Space Complexity: 3w+2 + // 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. @@ -170,12 +170,12 @@ ns bit { // Complexity: w(2@+6) // actually (w-#w)(2@+6) // ptr[:n] += 2w def inc_ptr ptr { - .inc w-#w, ptr+(#w)*dw //TODO check if need #dw or #w + .inc w-#w, ptr+(#w)*dw } // Complexity: w(2@+8) // actually (w-#w)(2@+8) // ptr[:n] -= 2w def dec_ptr ptr { - .dec w-#w, ptr+(#w)*dw //TODO check if need #dw or #w + .dec w-#w, ptr+(#w)*dw } } diff --git a/stl/hex/pointers.fj b/stl/hex/pointers.fj index 793abb7..fc00d7f 100644 --- a/stl/hex/pointers.fj +++ b/stl/hex/pointers.fj @@ -4,7 +4,7 @@ ns hex { ns pointers { - // Space Complexity: 3w+2 + // 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. @@ -23,8 +23,8 @@ ns hex { hex.vec w/4, 0 } - // Time Complexity: n(2@+8) - // Space Complexity: n(2@+56) + // 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. @@ -33,8 +33,8 @@ ns hex { ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, ptr } - // Time Complexity: n(2@+8) - // Space Complexity: n(2@+56) + // 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. @@ -43,7 +43,7 @@ ns hex { ..address_and_variable_xor w/4, .to_flip, .to_flip_var, ptr } - // Space Complexity: n+w + // 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. // @output-param sp: the stack pointer. sp always points to the last pushed value (at start - to stack[-1]) @@ -61,8 +61,9 @@ ns hex { ns hex { - // Complexity: 2w@ + 2 - // like: ;*ptr + // 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 { @@ -77,7 +78,8 @@ ns hex { ns hex { - // Complexity: 2w@ + @ + // 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. @@ -93,7 +95,8 @@ ns hex { } - // Complexity 2w@ + 2@ + // Time Complexity: w(0.5@+2) + 2@ + // Space Complexity: w(0.5@+14) + 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. @@ -104,7 +107,8 @@ ns hex { rep(#dbit, i) stl.comp_flip_if ptr+dbit+(i/4)*dw+i%4, (dbit>>i)&1 } - // Complexity 2w@ + 2@+2 + // Time Complexity: w(0.5@+2) + 3@+2 + // Space Complexity: w(0.5@+14) + 3@+2 // like: bit.xor *ptr, bit // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def xor_to_ptr ptr, bit @ end { @@ -152,14 +156,15 @@ ns hex { ns hex { - // Complexity 7w@ (actually a bit smaller, 6w@+6w+8 + 2(@-2)^2) + // Complexity 5.5w@ // like: bit.xor dst, *ptr // dst is a bit. 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, ptr } - // Complexity 7w@ (actually a bit smaller, 6w@+6w+8 + 2(@-2)^2) + // Time Complexity: 5.5w@ (exact: 4.5w@+8w+8 + 2(@-2)^2) + // Space Complexity: 5.5w@ (exact: 4.5w@+8w+20 + 2(@-2)^2) // like: bit.exact_xor dst, *ptr // dst is a bit-address. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def exact_xor_from_ptr dst, ptr @ base_jump_label, cleanup { @@ -179,7 +184,7 @@ ns hex { -// ---------- Stack +// ---------- Ptr ++/-- ns hex { @@ -196,10 +201,16 @@ ns hex { def dec_ptr ptr { hex.dec_shifted w/4, ptr, #w } +} + + + +// ---------- Stack +ns hex { // Time Complexity: 4w@ (actually a bit smaller) - // Space Complexity: 5w@ (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. @@ -209,7 +220,7 @@ ns hex { } // Time Complexity: 4w@ (actually a bit smaller) - // Space Complexity: 5w@ (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. @@ -219,8 +230,13 @@ ns hex { } - // Time Complexity: 2w@ + 3@+2 - // Space Complexity: w(3.5@+13) + + // TODO read/write 4-bit values (good for bit/hex/dec) with hex.{push/pop/pop_res} + + + + // Time Complexity: w(0.5@+2) + 13@+19 + // Space Complexity: w(0.875@+5.25) + 9@+73 // Like: stack[++sp] = bit // Pushes the given bit to the next cell in the stack (assumes it's zero). Increments sp. def push bit < hex.pointers.sp { @@ -228,8 +244,8 @@ ns hex { .xor_to_ptr hex.pointers.sp, bit } - // Time Complexity: 2w@ + 3@+2 - // Space Complexity: w(3.5@+13) + // Time Complexity: w(0.5@+2) + 13@+28 + // Space Complexity: w(0.875@+17.25) + 9@+85 // Like: stack[sp--] = 0 // Pops the given bit from the current cell in the stack (assumes it has the value of bit). Decrements sp. def pop bit < hex.pointers.sp { @@ -238,8 +254,8 @@ ns hex { } - // Time Complexity: w(10@+10) (actually a bit smaller, 8w@ + 10w+9 + 2(@-2)^2) - // Space Complexity: w(11@+20) (actually a bit smaller, w(9.5@+19) + 2(@-2)^2 + @-1) + // Time Complexity: w(6@+10) (for w=64. exact: w(5@+10) + 14@+36 + 2(@-2)^2) + // Space Complexity: w(6.5@+20) (for w=64. exact: w(5.375@+25.25) + 10@+117 + 2(@-2)^2) // Like: bit = stack[sp] // stack[sp--] = 0 // Pops the current stack cell into the the given bit. Decrements sp. diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj index 5fd3736..18f0a89 100644 --- a/stl/hex/tables_init.fj +++ b/stl/hex/tables_init.fj @@ -2,18 +2,19 @@ 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 _ { - // 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. + // 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 diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index 379cd99..b835a1b 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -1,17 +1,14 @@ -// TODO read 4-bit values (good for bit/hex/dec) values from pointers. - - // ---------- Init ns stl { - // Comp + // Complexity: 2.5w+4 def ptr_init { bit.pointers.ptr_init hex.pointers.ptr_init } - // Space Complexity: n+w + // 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 { @@ -25,8 +22,9 @@ ns stl { ns stl { - // Complexity: w(5phi+21) - // the pop_ret_address is counted for the future return + // 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 @@ -37,8 +35,9 @@ ns stl { } - // Complexity: w(7phi+29) - // the last-call's pop_ret_address is counted for this return + // 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 } diff --git a/stl/runlib.fj b/stl/runlib.fj index e29f71e..bfbd0c0 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -4,6 +4,7 @@ dbit = w + #w // the bit-distance from the variable's start, to the bit value 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 { @@ -15,12 +16,14 @@ ns stl { // 4w;5w : start of code } + // Complexity: ~6700 (6765 for w=64, 6633 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: 6464 + 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 From 6a4c24e249099abbd76e65aa27955b9567006ccb Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 20 May 2023 21:01:43 +0300 Subject: [PATCH 52/62] support \ line-continuation, prettify existing fj files with it --- programs/calc.fj | 8 +++-- programs/hexlib_tests/2params/add_shifted.fj | 11 ++++-- programs/hexlib_tests/2params/sub_shifted.fj | 11 ++++-- programs/hexlib_tests/basics2/count_bits.fj | 10 +++++- programs/hexlib_tests/div/hexlib_div.fj | 3 +- programs/hexlib_tests/mul/add_mul_test.fj | 8 +++-- programs/hexlib_tests/mul/mul_test.fj | 4 ++- src/fj_parser.py | 1 + stl/bit/casting.fj | 9 +++-- stl/bit/output.fj | 10 ++++-- stl/hex/cond_jumps.fj | 9 +++-- stl/hex/logics.fj | 20 ++++++++--- stl/hex/math.fj | 16 ++++++--- stl/hex/math_basic.fj | 3 +- stl/hex/output.fj | 3 +- stl/hex/pointers.fj | 2 +- stl/hex/tables_init.fj | 4 ++- stl/mathlib.fj | 37 ++++++++++++++------ 18 files changed, 126 insertions(+), 43 deletions(-) diff --git a/programs/calc.fj b/programs/calc.fj index 4f088e6..351e74b 100644 --- a/programs/calc.fj +++ b/programs/calc.fj @@ -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 @@ -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: diff --git a/programs/hexlib_tests/2params/add_shifted.fj b/programs/hexlib_tests/2params/add_shifted.fj index b07466a..f7a4c2d 100644 --- a/programs/hexlib_tests/2params/add_shifted.fj +++ b/programs/hexlib_tests/2params/add_shifted.fj @@ -4,7 +4,9 @@ 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 +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 @@ -13,11 +15,14 @@ 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 + 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 + 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 { diff --git a/programs/hexlib_tests/2params/sub_shifted.fj b/programs/hexlib_tests/2params/sub_shifted.fj index 8e4bdfe..f3c7a1f 100644 --- a/programs/hexlib_tests/2params/sub_shifted.fj +++ b/programs/hexlib_tests/2params/sub_shifted.fj @@ -4,7 +4,9 @@ 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 +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 @@ -13,11 +15,14 @@ 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 + 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 + 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 { diff --git a/programs/hexlib_tests/basics2/count_bits.fj b/programs/hexlib_tests/basics2/count_bits.fj index 9380881..10ceb2d 100644 --- a/programs/hexlib_tests/basics2/count_bits.fj +++ b/programs/hexlib_tests/basics2/count_bits.fj @@ -23,7 +23,15 @@ count_bits_64: 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) + 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 diff --git a/programs/hexlib_tests/div/hexlib_div.fj b/programs/hexlib_tests/div/hexlib_div.fj index 6578509..20c5a04 100644 --- a/programs/hexlib_tests/div/hexlib_div.fj +++ b/programs/hexlib_tests/div/hexlib_div.fj @@ -52,7 +52,8 @@ neq_mod_print: 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 stl.fcall div_label, ret diff --git a/programs/hexlib_tests/mul/add_mul_test.fj b/programs/hexlib_tests/mul/add_mul_test.fj index 8063024..d5e06ce 100644 --- a/programs/hexlib_tests/mul/add_mul_test.fj +++ b/programs/hexlib_tests/mul/add_mul_test.fj @@ -3,7 +3,10 @@ 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 stl.loop @@ -61,7 +64,8 @@ add_mul: hex.add_mul HexSize, res, ah, bh 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 { +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 diff --git a/programs/hexlib_tests/mul/mul_test.fj b/programs/hexlib_tests/mul/mul_test.fj index caf1452..39d4112 100644 --- a/programs/hexlib_tests/mul/mul_test.fj +++ b/programs/hexlib_tests/mul/mul_test.fj @@ -3,7 +3,9 @@ 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 stl.loop diff --git a/src/fj_parser.py b/src/fj_parser.py index de6ff6c..9f0f9f0 100644 --- a/src/fj_parser.py +++ b/src/fj_parser.py @@ -95,6 +95,7 @@ class FJLexer(sly.Lexer): "@", ","} ignore_ending_comment = r'//.*' + ignore_line_continuation = r'\\[ \t]*\n' # Tokens DOT_ID = dot_id_re diff --git a/stl/bit/casting.fj b/stl/bit/casting.fj index e486e2d..1581a30 100644 --- a/stl/bit/casting.fj +++ b/stl/bit/casting.fj @@ -117,16 +117,19 @@ ns bit { // 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 { + 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 + .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 + .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 diff --git a/stl/bit/output.fj b/stl/bit/output.fj index 2a7efb5..9e5c472 100644 --- a/stl/bit/output.fj +++ b/stl/bit/output.fj @@ -134,7 +134,8 @@ ns bit { // // 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 { + 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 @@ -143,9 +144,12 @@ ns bit { .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 + 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 + 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 diff --git a/stl/hex/cond_jumps.fj b/stl/hex/cond_jumps.fj index e8a7492..8ec4a07 100644 --- a/stl/hex/cond_jumps.fj +++ b/stl/hex/cond_jumps.fj @@ -78,7 +78,9 @@ ns hex { // @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 { + 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 @@ -145,7 +147,10 @@ ns hex { // 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 + 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 diff --git a/stl/hex/logics.fj b/stl/hex/logics.fj index 9e8b0ef..a70b6ba 100644 --- a/stl/hex/logics.fj +++ b/stl/hex/logics.fj @@ -74,7 +74,10 @@ ns hex { // // 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 + .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) @@ -83,7 +86,10 @@ ns hex { // 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 + 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 @@ -186,7 +192,10 @@ ns hex { // 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 + 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 @@ -232,7 +241,10 @@ ns hex { // 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 + 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 diff --git a/stl/hex/math.fj b/stl/hex/math.fj index a687010..e3b3bf1 100644 --- a/stl/hex/math.fj +++ b/stl/hex/math.fj @@ -91,10 +91,14 @@ ns hex { // 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)) + 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)) + 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. @@ -195,10 +199,14 @@ ns hex { // 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)) + 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)) + 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. diff --git a/stl/hex/math_basic.fj b/stl/hex/math_basic.fj index afd8607..5f701ca 100644 --- a/stl/hex/math_basic.fj +++ b/stl/hex/math_basic.fj @@ -7,7 +7,8 @@ ns hex { // (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 { + 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 diff --git a/stl/hex/output.fj b/stl/hex/output.fj index 5794062..b4840f1 100644 --- a/stl/hex/output.fj +++ b/stl/hex/output.fj @@ -82,7 +82,8 @@ ns hex { // 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 { + 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: diff --git a/stl/hex/pointers.fj b/stl/hex/pointers.fj index fc00d7f..ab3283f 100644 --- a/stl/hex/pointers.fj +++ b/stl/hex/pointers.fj @@ -231,7 +231,7 @@ ns hex { - // TODO read/write 4-bit values (good for bit/hex/dec) with hex.{push/pop/pop_res} + // TODO hex.xor_{from/to}_ptr 4-bit values (good for bit/hex/dec). also affects hex.{push/pop/pop_res}. diff --git a/stl/hex/tables_init.fj b/stl/hex/tables_init.fj index 18f0a89..5df5f68 100644 --- a/stl/hex/tables_init.fj +++ b/stl/hex/tables_init.fj @@ -37,7 +37,9 @@ ns hex { // n is a size-constant, dst/ret are hexes. def clean_table_entry__table n, dst, ret @ clean { clean: - rep(n, d) stl.fj d==0?0: (dst+dbit+(#d)-1), (d==((1<<(#d))>>1)) ? ret : clean+(d^((1<<(#d))>>1))*dw + rep(n, d) stl.fj \ + d==0?0: (dst+dbit+(#d)-1), \ + (d==((1<<(#d))>>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 diff --git a/stl/mathlib.fj b/stl/mathlib.fj index 7dd2143..34721ca 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -217,7 +217,9 @@ ns hex { // @output-param ret: ... TODO document the output params // @output-param dst: ... // @output-param add_carry_dst: ... - 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 { + 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) @@ -245,13 +247,21 @@ ns hex { pad 16 // not really needed switch_small_table: - 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 + 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) 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 + 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) 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 + 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) stl.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 @@ -267,11 +277,17 @@ ns hex { // needs to be 1024-padded add_carry: - rep(256, d) stl.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) 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 + 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) 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 + 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: @@ -328,7 +344,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 @@ -434,7 +450,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 From e3619952564852528f90a7b16dc48f464d3cc793 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 20 May 2023 23:38:03 +0300 Subject: [PATCH 53/62] xor hex from pointer --- programs/concept_checks/hex_ptr.fj | 20 ++++---- stl/hex/pointers.fj | 64 ++++++++++++++++---------- tests/inout/concept_checks/hex_ptr.out | 2 +- 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/programs/concept_checks/hex_ptr.fj b/programs/concept_checks/hex_ptr.fj index 032ada4..f76bc4c 100644 --- a/programs/concept_checks/hex_ptr.fj +++ b/programs/concept_checks/hex_ptr.fj @@ -34,19 +34,14 @@ test2: ;test3 test3: - bit.zero d3_var + hex.set d3, 6 + hex.set d3_var, 0xD hex.xor_from_ptr d3_var, p3 - bit.if d3_var, d30, d31 - d30: - stl.output 'F' - stl.loop - d31: - stl.output 'T' - stl.loop + hex.print_as_digit d3_var, 1 + stl.loop - stl.ptr_init p0: hex.vec w/4, d0+dbit @@ -68,6 +63,9 @@ test3: p3: hex.vec w/4, d3 d3: - bit.bit 1 // 0 => F, 1 => T + hex.hex d3_var: - bit.bit 0 + hex.hex + + +stl.ptr_init diff --git a/stl/hex/pointers.fj b/stl/hex/pointers.fj index ab3283f..21bb4a8 100644 --- a/stl/hex/pointers.fj +++ b/stl/hex/pointers.fj @@ -157,28 +157,41 @@ ns hex { ns hex { // Complexity 5.5w@ - // like: bit.xor dst, *ptr - // dst is a bit. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. + // 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, 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+8 + 2(@-2)^2) - // Space Complexity: 5.5w@ (exact: 4.5w@+8w+20 + 2(@-2)^2) - // like: bit.exact_xor dst, *ptr - // dst is a bit-address. ptr is a hex[:w/4] 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 - + // 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 2 - base_jump_label: - ;cleanup - dst; - cleanup: - .ptr_wflip_2nd_word ptr, base_jump_label + 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 } } @@ -231,7 +244,10 @@ ns hex { - // TODO hex.xor_{from/to}_ptr 4-bit values (good for bit/hex/dec). also affects hex.{push/pop/pop_res}. + // TODO hex.xor_to_ptr 4-bit values (good for bit/hex/dec). also affects hex.{push/pop/pop_res}. + // also test both xor_{from/to}_ptr in func6, such that it will test a function that actually does something to the inputs (like add, sub).. + + // TODO also add xor full hex-address from address (ptr1 = *ptr2) (by zero ptr1; ptr1 ^= ptr2). @@ -256,13 +272,13 @@ ns hex { // Time Complexity: w(6@+10) (for w=64. exact: w(5@+10) + 14@+36 + 2(@-2)^2) // Space Complexity: w(6.5@+20) (for w=64. exact: w(5.375@+25.25) + 10@+117 + 2(@-2)^2) - // Like: bit = stack[sp] + // Like: hex = stack[sp] // stack[sp--] = 0 - // Pops the current stack cell into the the given bit. Decrements sp. - // bit is only an output parameter - def pop_res bit < hex.pointers.sp { - bit.zero bit - .xor_from_ptr bit, hex.pointers.sp - .pop bit + // Pops the current stack cell into the the given hex. Decrements sp. + // hex is only an output parameter + def pop_res hex < hex.pointers.sp { + hex.zero hex + .xor_from_ptr hex, hex.pointers.sp + .pop hex } } diff --git a/tests/inout/concept_checks/hex_ptr.out b/tests/inout/concept_checks/hex_ptr.out index c3e6cd3..7dcccfa 100644 --- a/tests/inout/concept_checks/hex_ptr.out +++ b/tests/inout/concept_checks/hex_ptr.out @@ -1 +1 @@ -17NT \ No newline at end of file +17NB \ No newline at end of file From b94b533729783b8c5960b4a5019a413548741f71 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Mon, 22 May 2023 00:55:22 +0300 Subject: [PATCH 54/62] *ptr is hex. pop/push n, hex[:n]. --- programs/func_tests/func3.fj | 2 +- programs/func_tests/func4.fj | 2 +- programs/func_tests/func5.fj | 6 +- stl/hex/pointers.fj | 126 +++++++++++++++++++++++++---------- 4 files changed, 97 insertions(+), 39 deletions(-) diff --git a/programs/func_tests/func3.fj b/programs/func_tests/func3.fj index a991275..e8d74c0 100644 --- a/programs/func_tests/func3.fj +++ b/programs/func_tests/func3.fj @@ -8,7 +8,7 @@ test3: stl.output 'B' stl.call func3 stl.output 'D' - hex.pop x3 + hex.pop_unchanged_parameter x3 stl.output 'E' stl.output '\n' diff --git a/programs/func_tests/func4.fj b/programs/func_tests/func4.fj index 6f732da..6cd0d22 100644 --- a/programs/func_tests/func4.fj +++ b/programs/func_tests/func4.fj @@ -10,7 +10,7 @@ test4: stl.call func4 stl.output 'G' - hex.pop_res x4 + hex.pop x4 stl.output 'H' bit.bin2ascii ascii, x4 stl.output '-' diff --git a/programs/func_tests/func5.fj b/programs/func_tests/func5.fj index 71b68e8..245c0ba 100644 --- a/programs/func_tests/func5.fj +++ b/programs/func_tests/func5.fj @@ -15,11 +15,11 @@ test5: stl.output ' ' stl.output 'A' - hex.pop y5 + hex.pop_unchanged_parameter y5 stl.output 'B' - hex.pop x5 + hex.pop_unchanged_parameter x5 stl.output 'C' - hex.pop_res res5 + hex.pop res5 stl.output 'D' bit.bin2ascii ascii, res5 diff --git a/stl/hex/pointers.fj b/stl/hex/pointers.fj index 21bb4a8..7cba7a3 100644 --- a/stl/hex/pointers.fj +++ b/stl/hex/pointers.fj @@ -44,7 +44,7 @@ ns hex { } // Space Complexity: n+w/4 - // Initializes a stack of size n (maximal capacity of n bits / hexs / return-addresses). + // 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. @@ -54,7 +54,7 @@ ns hex { pad w stack: - bit.vec n, 0 + hex.vec n, 0 } } } @@ -95,28 +95,56 @@ ns hex { } - // Time Complexity: w(0.5@+2) + 2@ - // Space Complexity: w(0.5@+14) + 2@ + // 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 { - rep(#dbit, i) stl.comp_flip_if ptr+dbit+(i/4)*dw+i%4, (dbit>>i)&1 + def ptr_flip_dbit ptr < .pointers.to_flip { + wflip .pointers.to_flip, dbit .ptr_flip ptr - rep(#dbit, i) stl.comp_flip_if ptr+dbit+(i/4)*dw+i%4, (dbit>>i)&1 + wflip .pointers.to_flip, dbit } - // Time Complexity: w(0.5@+2) + 3@+2 - // Space Complexity: w(0.5@+14) + 3@+2 - // like: bit.xor *ptr, bit - // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. - def xor_to_ptr ptr, bit @ end { - bit.if0 bit, end - .ptr_flip_dbit ptr - end: - } + // 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 @ handle_flip_bit0, handle_flip_bit1, handle_flip_bit2, handle_flip_bit3, \ + flip_bit0, flip_bit1, flip_bit2, flip_bit3, cleanup < hex.pointers.to_flip { + .pointers.set_flip_pointer ptr + wflip hex.pointers.to_flip, dbit + wflip hex.pointers.to_flip+w, flip_bit0, flip_bit0 + + handle_flip_bit0: + wflip hex.pointers.to_flip, (dbit+0)^(dbit+1) + hex.if_flags hex, 0xAAAA, flip_bit1, hex.pointers.to_flip + handle_flip_bit1: + wflip hex.pointers.to_flip, (dbit+1)^(dbit+3) + hex.if_flags hex, 0xCCCC, flip_bit3, hex.pointers.to_flip + handle_flip_bit2: + hex.if_flags hex, 0xF0F0, cleanup , hex.pointers.to_flip + handle_flip_bit3: + wflip hex.pointers.to_flip, (dbit+3)^(dbit+2) + hex.if_flags hex, 0xFF00, flip_bit2, hex.pointers.to_flip + + pad 8 + flip_bit0: + hex.pointers.to_flip+dbit+0;handle_flip_bit0 + flip_bit1: + hex.pointers.to_flip+dbit+1;handle_flip_bit1 + flip_bit2: + hex.pointers.to_flip+dbit+2;handle_flip_bit2 + flip_bit3: + hex.pointers.to_flip+dbit+0;handle_flip_bit3 + ; + ; + cleanup: + wflip hex.pointers.to_flip, dbit+2 + wflip hex.pointers.to_flip+w, cleanup + } // Complexity 3w@ (actually a bit smaller, 2w@+3w + (@-2)^2) // like: wflip *ptr, value @@ -244,41 +272,71 @@ ns hex { - // TODO hex.xor_to_ptr 4-bit values (good for bit/hex/dec). also affects hex.{push/pop/pop_res}. - // also test both xor_{from/to}_ptr in func6, such that it will test a function that actually does something to the inputs (like add, sub).. + // TODO test both xor_{from/to}_ptr and hex.{push/pop_unchanged_parameter/pop} in func6, + // such that it will test a function that actually does something to the inputs (like add, sub).. // TODO also add xor full hex-address from address (ptr1 = *ptr2) (by zero ptr1; ptr1 ^= ptr2). + // TODO test hex.{push/pop_unchanged_parameter/pop} n, vec + - // Time Complexity: w(0.5@+2) + 13@+19 - // Space Complexity: w(0.875@+5.25) + 9@+73 - // Like: stack[++sp] = bit - // Pushes the given bit to the next cell in the stack (assumes it's zero). Increments sp. - def push bit < hex.pointers.sp { + // Time Complexity: w(0.5@+2) + 15@+29 + // Space Complexity: w(0.875@+5.25) + 11@+147 + // 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 { .inc_ptr hex.pointers.sp - .xor_to_ptr hex.pointers.sp, bit + .xor_to_ptr hex.pointers.sp, hex } - // Time Complexity: w(0.5@+2) + 13@+28 - // Space Complexity: w(0.875@+17.25) + 9@+85 - // Like: stack[sp--] = 0 - // Pops the given bit from the current cell in the stack (assumes it has the value of bit). Decrements sp. - def pop bit < hex.pointers.sp { - .xor_to_ptr hex.pointers.sp, bit + // Time Complexity: n(w(0.5@+2) + 15@+29) + // Space Complexity: n(w(0.875@+5.25) + 11@+147) + // 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) + 15@+38 + // Space Complexity: w(0.875@+17.25) + 11@+159 + // 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 .dec_ptr hex.pointers.sp } + // Time Complexity: n(w(0.5@+2) + 15@+38) + // Space Complexity: n(w(0.875@+17.25) + 11@+159) + // 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) + 14@+36 + 2(@-2)^2) - // Space Complexity: w(6.5@+20) (for w=64. exact: w(5.375@+25.25) + 10@+117 + 2(@-2)^2) + // Time Complexity: w(6@+10) (for w=64. exact: w(5@+10) + 16@+46 + 2(@-2)^2) + // Space Complexity: w(6.5@+20) (for w=64. exact: w(5.375@+25.25) + 12@+189 + 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_res hex < hex.pointers.sp { + def pop hex < hex.pointers.sp { hex.zero hex .xor_from_ptr hex, hex.pointers.sp - .pop hex + .pop_unchanged_parameter hex + } + + // Time Complexity: nw(6@+10) (for w=64. exact/n is: w(5@+10) + 16@+46 + 2(@-2)^2) + // Space Complexity: nw(6.5@+20) (for w=64. exact/n is: w(5.375@+25.25) + 12@+189 + 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+i*dw } } From f59bbd0784a12ad87fc679f8060c5e5ccc420ccd Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 27 May 2023 17:35:03 +0300 Subject: [PATCH 55/62] better __repr__ for compiler objects --- src/defs.py | 15 --------------- src/expr.py | 6 +++++- src/fj_parser.py | 3 +-- src/ops.py | 23 +++++++++++++++++++++++ src/preprocessor.py | 4 ++-- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/defs.py b/src/defs.py index 4dc4c4e..1583c12 100644 --- a/src/defs.py +++ b/src/defs.py @@ -1,7 +1,6 @@ from __future__ import annotations import argparse -import dataclasses import json import lzma from collections import deque @@ -10,8 +9,6 @@ from time import time from typing import List, Dict, Deque, Optional -from ops import CodePosition, Op - def get_stl_paths() -> List[Path]: """ @@ -104,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. 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_parser.py b/src/fj_parser.py index 9f0f9f0..b1be4f0 100644 --- a/src/fj_parser.py +++ b/src/fj_parser.py @@ -6,11 +6,10 @@ 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, all_errors, curr_namespace diff --git a/src/ops.py b/src/ops.py index 97d8a6c..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('') @@ -298,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 03de893..2d46a01 100644 --- a/src/preprocessor.py +++ b/src/preprocessor.py @@ -4,10 +4,10 @@ from typing import Dict, Tuple, Iterable, Union, Deque, Set, List, Optional from expr import Expr -from defs import CodePosition, Macro, MACRO_SEPARATOR_STRING, STARTING_LABEL_IN_MACROS_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 From d97cce32051ca92b06666ea765fe91ffc424410c Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 27 May 2023 18:00:25 +0300 Subject: [PATCH 56/62] bugfix hex.xor_to_ptr, {add/sub}_constant, ptr/sp arithmetics - hex_func{6/7} tests. - add error printed if returning on an empty stack. - updated complexities. - add documentations to the hex_func{i} tests --- programs/func_tests/func1.fj | 3 + programs/func_tests/func2.fj | 3 + programs/func_tests/func3.fj | 3 + programs/func_tests/func4.fj | 5 +- programs/func_tests/func5.fj | 9 +- programs/func_tests/func6.fj | 43 +++++++ programs/func_tests/func7.fj | 207 +++++++++++++++++++++++++++++++ stl/bit/pointers.fj | 4 +- stl/hex/math.fj | 60 ++++++++- stl/hex/math_basic.fj | 37 ++---- stl/hex/pointers.fj | 168 ++++++++++++++++--------- stl/ptrlib.fj | 14 +++ stl/runlib.fj | 4 +- tests/conf.json | 4 +- tests/inout/func_tests/func6.out | 1 + tests/inout/func_tests/func7.out | 15 +++ tests/test_compile_slow.csv | 3 + tests/test_run_slow.csv | 3 + 18 files changed, 488 insertions(+), 98 deletions(-) create mode 100644 programs/func_tests/func6.fj create mode 100644 programs/func_tests/func7.fj create mode 100644 tests/inout/func_tests/func6.out create mode 100644 tests/inout/func_tests/func7.out diff --git a/programs/func_tests/func1.fj b/programs/func_tests/func1.fj index bf65d13..0126cd7 100644 --- a/programs/func_tests/func1.fj +++ b/programs/func_tests/func1.fj @@ -1,3 +1,6 @@ +// Tests a parameterless function call + + stl.startup_and_init_all 10 diff --git a/programs/func_tests/func2.fj b/programs/func_tests/func2.fj index b8da578..f68f886 100644 --- a/programs/func_tests/func2.fj +++ b/programs/func_tests/func2.fj @@ -1,3 +1,6 @@ +// Tests a diamond call-stack. (main->a->c ==> main->b->c) + + stl.startup_and_init_all 10 diff --git a/programs/func_tests/func3.fj b/programs/func_tests/func3.fj index e8d74c0..7877e54 100644 --- a/programs/func_tests/func3.fj +++ b/programs/func_tests/func3.fj @@ -1,3 +1,6 @@ +// Tests push/pop_unchanged_parameter with an empty function call + + stl.startup_and_init_all 10 diff --git a/programs/func_tests/func4.fj b/programs/func_tests/func4.fj index 6cd0d22..e362b6c 100644 --- a/programs/func_tests/func4.fj +++ b/programs/func_tests/func4.fj @@ -1,3 +1,6 @@ +// Tests the ptr_flip_dbit and function calls + + stl.startup_and_init_all 10 @@ -23,7 +26,7 @@ func4: stl.output 'C' stl.get_sp __func4_arg_ptr stl.output 'D' - hex.dec_ptr __func4_arg_ptr + hex.ptr_dec __func4_arg_ptr stl.output 'E' hex.ptr_flip_dbit __func4_arg_ptr stl.output 'F' diff --git a/programs/func_tests/func5.fj b/programs/func_tests/func5.fj index 245c0ba..50bb053 100644 --- a/programs/func_tests/func5.fj +++ b/programs/func_tests/func5.fj @@ -1,3 +1,6 @@ +// Tests the xor_from_ptr, xor_to_ptr and function calls + + stl.startup_and_init_all 10 @@ -35,16 +38,16 @@ func5: stl.get_sp __func5_arg_ptr stl.output 'a' - hex.dec_ptr __func5_arg_ptr + hex.ptr_dec __func5_arg_ptr stl.output 'b' hex.xor_from_ptr __func5_res, __func5_arg_ptr stl.output 'c' - hex.dec_ptr __func5_arg_ptr + hex.ptr_dec __func5_arg_ptr stl.output 'd' hex.xor_from_ptr __func5_res, __func5_arg_ptr stl.output 'e' - hex.dec_ptr __func5_arg_ptr + hex.ptr_dec __func5_arg_ptr stl.output 'f' hex.xor_to_ptr __func5_arg_ptr, __func5_res stl.output 'g' 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/stl/bit/pointers.fj b/stl/bit/pointers.fj index a6c7ef9..2c8f82e 100644 --- a/stl/bit/pointers.fj +++ b/stl/bit/pointers.fj @@ -169,13 +169,13 @@ ns bit { ns bit { // Complexity: w(2@+6) // actually (w-#w)(2@+6) // ptr[:n] += 2w - def inc_ptr ptr { + def ptr_inc ptr { .inc w-#w, ptr+(#w)*dw } // Complexity: w(2@+8) // actually (w-#w)(2@+8) // ptr[:n] -= 2w - def dec_ptr ptr { + def ptr_dec ptr { .dec w-#w, ptr+(#w)*dw } } diff --git a/stl/hex/math.fj b/stl/hex/math.fj index e3b3bf1..003818d 100644 --- a/stl/hex/math.fj +++ b/stl/hex/math.fj @@ -36,6 +36,35 @@ ns hex { 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 @@ -135,7 +164,7 @@ ns hex { // 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 sub.add.init (or hex.init) + // @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 @@ -145,6 +174,35 @@ ns hex { 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 diff --git a/stl/hex/math_basic.fj b/stl/hex/math_basic.fj index 5f701ca..d4fdcc7 100644 --- a/stl/hex/math_basic.fj +++ b/stl/hex/math_basic.fj @@ -185,31 +185,6 @@ ns hex { } - // Time Complexity: 10@+17 - // Space Complexity: (n+6-shift)(1.5@+13) // exact: (n-shift)(1.5@+13) + 7.5@+84 - // hex[:n] += 1< sp, stack { + def stack_init n @ stack_error_handler > sp, stack { sp: - hex.vec w/4, .stack-dw + 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). } } } @@ -112,38 +117,36 @@ ns hex { // 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 @ handle_flip_bit0, handle_flip_bit1, handle_flip_bit2, handle_flip_bit3, \ - flip_bit0, flip_bit1, flip_bit2, flip_bit3, cleanup < hex.pointers.to_flip { + 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, dbit - wflip hex.pointers.to_flip+w, flip_bit0, flip_bit0 + wflip hex.pointers.to_flip+w, after_flip_bit0, prepare_flip_bit0 - handle_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, 0xAAAA, flip_bit1, hex.pointers.to_flip - handle_flip_bit1: + 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, 0xCCCC, flip_bit3, hex.pointers.to_flip - handle_flip_bit2: - hex.if_flags hex, 0xF0F0, cleanup , hex.pointers.to_flip - handle_flip_bit3: + 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, 0xFF00, flip_bit2, hex.pointers.to_flip - - pad 8 - flip_bit0: - hex.pointers.to_flip+dbit+0;handle_flip_bit0 - flip_bit1: - hex.pointers.to_flip+dbit+1;handle_flip_bit1 - flip_bit2: - hex.pointers.to_flip+dbit+2;handle_flip_bit2 - flip_bit3: - hex.pointers.to_flip+dbit+0;handle_flip_bit3 - ; - ; + 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, dbit+2 - wflip hex.pointers.to_flip+w, cleanup + wflip hex.pointers.to_flip+w, after_flip_bit2 } // Complexity 3w@ (actually a bit smaller, 2w@+3w + (@-2)^2) @@ -225,22 +228,42 @@ ns hex { -// ---------- Ptr ++/-- +// ---------- Ptr ++/--/+=/-= ns hex { - // Time Complexity: 10@+17 - // Space Complexity: w(0.375@ + 3.25) + 6@+71 (for log(w) in 16,32,64,128) + // 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 - def inc_ptr ptr { - hex.inc_shifted w/4, ptr, #w + // @requires hex.add.init (or hex.init) + def ptr_inc ptr { + hex.add_constant w/4, ptr, dw } - // Time Complexity: 10@+26 - // Space Complexity: w(0.375@ + 3.25) + 6@+83 (for log(w) in 16,32,64,128) + // 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 - def dec_ptr ptr { - hex.dec_shifted w/4, ptr, #w + // @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 } } @@ -250,13 +273,41 @@ ns hex { 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 { - .inc_ptr hex.pointers.sp + .sp_inc .ptr_wflip_2nd_word hex.pointers.sp, return_address } @@ -267,31 +318,24 @@ ns hex { // 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 - .dec_ptr hex.pointers.sp + .sp_dec } - - // TODO test both xor_{from/to}_ptr and hex.{push/pop_unchanged_parameter/pop} in func6, - // such that it will test a function that actually does something to the inputs (like add, sub).. - // TODO also add xor full hex-address from address (ptr1 = *ptr2) (by zero ptr1; ptr1 ^= ptr2). - // TODO test hex.{push/pop_unchanged_parameter/pop} n, vec - - - // Time Complexity: w(0.5@+2) + 15@+29 - // Space Complexity: w(0.875@+5.25) + 11@+147 + // 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 { - .inc_ptr hex.pointers.sp + .sp_inc .xor_to_ptr hex.pointers.sp, hex } - // Time Complexity: n(w(0.5@+2) + 15@+29) - // Space Complexity: n(w(0.875@+5.25) + 11@+147) + // 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 { @@ -299,17 +343,17 @@ ns hex { } - // Time Complexity: w(0.5@+2) + 15@+38 - // Space Complexity: w(0.875@+17.25) + 11@+159 + // 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 - .dec_ptr hex.pointers.sp + .sp_dec } - // Time Complexity: n(w(0.5@+2) + 15@+38) - // Space Complexity: n(w(0.875@+17.25) + 11@+159) + // 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 { @@ -317,8 +361,8 @@ ns hex { } - // Time Complexity: w(6@+10) (for w=64. exact: w(5@+10) + 16@+46 + 2(@-2)^2) - // Space Complexity: w(6.5@+20) (for w=64. exact: w(5.375@+25.25) + 12@+189 + 2(@-2)^2) + // 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. @@ -329,14 +373,14 @@ ns hex { .pop_unchanged_parameter hex } - // Time Complexity: nw(6@+10) (for w=64. exact/n is: w(5@+10) + 16@+46 + 2(@-2)^2) - // Space Complexity: nw(6.5@+20) (for w=64. exact/n is: w(5.375@+25.25) + 12@+189 + 2(@-2)^2) + // 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+i*dw + rep(n, i) .pop hex+(n-1-i)*dw } } diff --git a/stl/ptrlib.fj b/stl/ptrlib.fj index b835a1b..b10446a 100644 --- a/stl/ptrlib.fj +++ b/stl/ptrlib.fj @@ -34,6 +34,20 @@ ns stl { 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 + + pad 2 + return_label: + hex.pop_ret_address return_label + hex.sp_sub params_hex_length + } + // Time Complexity: w(7phi+29) // Space Complexity: 2w@ diff --git a/stl/runlib.fj b/stl/runlib.fj index bfbd0c0..5f6f5e7 100644 --- a/stl/runlib.fj +++ b/stl/runlib.fj @@ -16,14 +16,14 @@ ns stl { // 4w;5w : start of code } - // Complexity: ~6700 (6765 for w=64, 6633 for w=16) + // 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: 6464 + 2.75w+@ + n + // 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 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/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/test_compile_slow.csv b/tests/test_compile_slow.csv index 4cb4acd..3227dff 100644 --- a/tests/test_compile_slow.csv +++ b/tests/test_compile_slow.csv @@ -1,3 +1,5 @@ +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 hex_func1, programs/func_tests/func1.fj,tests/compiled/func_tests/func1.fjm, 64,3,0, True,True @@ -5,6 +7,7 @@ hex_func2, programs/func_tests/func2.fj,tests/compiled/func_tests/func2.fjm, 64, 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_run_slow.csv b/tests/test_run_slow.csv index 84ee402..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 @@ -16,6 +18,7 @@ hex_func2, tests/compiled/func_tests/func2.fjm, ,tests/inout/func_tests/func2.ou 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 From 8e1ec4dc414ba71705860b325a8b3abf39719201 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 27 May 2023 18:03:36 +0300 Subject: [PATCH 57/62] add mathlib.fj refactor TODO --- stl/mathlib.fj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stl/mathlib.fj b/stl/mathlib.fj index 34721ca..1c534cf 100644 --- a/stl/mathlib.fj +++ b/stl/mathlib.fj @@ -1,3 +1,6 @@ +// 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 From 52ab47bb699f087b5e0ab65f42309b6aada353c4 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 27 May 2023 18:07:17 +0300 Subject: [PATCH 58/62] split hex.pointers --- stl/conf.json | 1 + stl/hex/advanced_pointers.fj | 156 ++++++++++++++++++++++++++++++++++ stl/hex/pointers.fj | 159 ----------------------------------- 3 files changed, 157 insertions(+), 159 deletions(-) create mode 100644 stl/hex/advanced_pointers.fj diff --git a/stl/conf.json b/stl/conf.json index c8b8989..eee05e9 100644 --- a/stl/conf.json +++ b/stl/conf.json @@ -22,6 +22,7 @@ "hex/input", "hex/output", "hex/pointers", + "hex/advanced_pointers", "casting", "ptrlib", diff --git a/stl/hex/advanced_pointers.fj b/stl/hex/advanced_pointers.fj new file mode 100644 index 0000000..8bd3ed3 --- /dev/null +++ b/stl/hex/advanced_pointers.fj @@ -0,0 +1,156 @@ +// ---------- 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 + } + + + // TODO also add xor full hex-address from address (ptr1 = *ptr2) (by zero ptr1; ptr1 ^= ptr2). + + + // 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/pointers.fj b/stl/hex/pointers.fj index c51edf6..9b51b30 100644 --- a/stl/hex/pointers.fj +++ b/stl/hex/pointers.fj @@ -225,162 +225,3 @@ ns hex { .ptr_wflip_2nd_word ptr, switch } } - - - -// ---------- 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 - } - - - // TODO also add xor full hex-address from address (ptr1 = *ptr2) (by zero ptr1; ptr1 ^= ptr2). - - - // 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 - } -} From b1b53003834ab3252896b1819143ec400962b0f0 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 27 May 2023 20:26:29 +0300 Subject: [PATCH 59/62] give up on ptr1 = *ptr2 TODO. --- stl/hex/advanced_pointers.fj | 3 --- 1 file changed, 3 deletions(-) diff --git a/stl/hex/advanced_pointers.fj b/stl/hex/advanced_pointers.fj index 8bd3ed3..c4e4c61 100644 --- a/stl/hex/advanced_pointers.fj +++ b/stl/hex/advanced_pointers.fj @@ -92,9 +92,6 @@ ns hex { } - // TODO also add xor full hex-address from address (ptr1 = *ptr2) (by zero ptr1; ptr1 ^= ptr2). - - // 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). From 349ac1e74cddca37d38032f3499d277451c006bc Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Mon, 29 May 2023 00:57:48 +0300 Subject: [PATCH 60/62] update stl/README.md with the refactored stl files --- stl/README.md | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/stl/README.md b/stl/README.md index 4eebb77..1544d34 100644 --- a/stl/README.md +++ b/stl/README.md @@ -21,21 +21,41 @@ Offers outputting constant chars/strings. ### [bit/](bit/) Defines the `bit` data-structure (for binary variables). -Offers macros for manipulating binary variables and vectors (i.e. numbers). +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 -You can find conditional jumps, memory manipulations, inputs, outputs, and logical and arithmetical macros. +### [hex/](hex/) +Defines the `hex` data-structure (for hexadecimal variables). -### [mathlib.fj](mathlib.fj) -Offers multiplication and division macros for bit/hex variables. +**They are smaller and faster than 4 `bit`s.** -**@note**: The hex.div fails test as for now. You can use the bit version and castings. +Offers macros for manipulating hexadecimal variables and vectors (i.e. numbers): -### [hex/](hex/) -Defines the `hex` data-structure (for hexadecimal variables), which is smaller and faster than using 4 `bit`s. +- [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 -Offers macros for manipulating hexadecimal variables and vectors (i.e. numbers). +### [mathlib.fj](mathlib.fj) +Offers multiplication and division macros for bit/hex variables. -You can find conditional jumps, memory manipulations, input, output, and logical and arithmetical macros. +**@note**: The hex.div fails test as for now. You can use the bit version and castings. ### [casting.fj](casting.fj) Offers casting between bits and hexes. @@ -113,4 +133,4 @@ The generic stl macro should look like `macro_name n dst src` for an n-bit/hex v 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 [bit/logics.fj](stl/bit/logics.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. From 19636dd30c9f83514cbee0a177ebc2fbed52e3f2 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Mon, 29 May 2023 01:33:13 +0300 Subject: [PATCH 61/62] add shileds.io badges --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 627809a..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**. From 682480eff30bf746a5a920b2d39a235941973b51 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Mon, 29 May 2023 01:33:58 +0300 Subject: [PATCH 62/62] update LICENCE year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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