From 28d360dc4afb19ece29fdd716cdf440bac2af346 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Thu, 5 Oct 2023 12:52:28 +0300 Subject: [PATCH 01/12] 4xors + startup macros, prepare for new xor_ptr macros, assembler fixes - split xor_to_flip_ptr from xor_to_ptr (for future read/write byte commands). - sketch the new xor_def_byte_from_ptr as comments in exact_xor_from_ptr. - macros address_and_variable_double_xor, quadrupled_exact_xor. - startup macros now have a version that jumps to a given address. - fix \\ line separation didn't count for newlines in parser errors - fix python's RecursionError raised instead of our recursion error, when ours is set to > 1000. still no tested: - read_ptr_byte_table, address_and_variable_double_xor, quadrupled_exact_xor. - update complexities for all changes --- flipjump/assembler/fj_parser.py | 4 + flipjump/assembler/preprocessor.py | 5 +- flipjump/stl/bit/pointers.fj | 10 +-- flipjump/stl/hex/advanced_pointers.fj | 12 +-- flipjump/stl/hex/logics.fj | 103 ++++++++++++++++++++++++++ flipjump/stl/hex/pointers.fj | 72 +++++++++++++++--- flipjump/stl/ptrlib.fj | 7 +- flipjump/stl/runlib.fj | 95 +++++++++++++----------- flipjump/utils/constants.py | 3 +- programs/concept_checks/hex_ptr.fj | 6 +- programs/simple_math_checks/ncmp.fj | 1 - 11 files changed, 241 insertions(+), 77 deletions(-) diff --git a/flipjump/assembler/fj_parser.py b/flipjump/assembler/fj_parser.py index 63c7510..bcac0eb 100644 --- a/flipjump/assembler/fj_parser.py +++ b/flipjump/assembler/fj_parser.py @@ -170,6 +170,10 @@ def NL(self, t: Token) -> Token: self.lineno += 1 return t + def ignore_line_continuation(self, t: Token) -> Token: + self.lineno += 1 + return t + def error(self, t: Token) -> None: global error_occurred, all_errors error_occurred = True diff --git a/flipjump/assembler/preprocessor.py b/flipjump/assembler/preprocessor.py index 4bee62f..4d16570 100644 --- a/flipjump/assembler/preprocessor.py +++ b/flipjump/assembler/preprocessor.py @@ -1,11 +1,12 @@ from __future__ import annotations import collections +import sys from typing import Dict, Tuple, Iterable, Union, Deque, Set, List, Optional from flipjump.interpretter.debugging.macro_usage_graph import show_macro_usage_pie_graph from flipjump.utils.constants import MACRO_SEPARATOR_STRING, STARTING_LABEL_IN_MACROS_STRING, \ - DEFAULT_MAX_MACRO_RECURSION_DEPTH + DEFAULT_MAX_MACRO_RECURSION_DEPTH, GAP_BETWEEN_PYTHONS_AND_PREPROCESSOR_MACRO_RECURSION_DEPTH from flipjump.utils.exceptions import FlipJumpPreprocessorException, FlipJumpExprException from flipjump.assembler.inner_classes.expr import Expr from flipjump.assembler.inner_classes.ops import FlipJump, WordFlip, Label, Segment, Reserve, MacroCall, RepCall, \ @@ -105,6 +106,8 @@ def __init__(self, self.result_ops.append(first_segment) self.max_recursion_depth = max_recursion_depth + if max_recursion_depth + GAP_BETWEEN_PYTHONS_AND_PREPROCESSOR_MACRO_RECURSION_DEPTH < sys.getrecursionlimit(): + sys.setrecursionlimit(max_recursion_depth + GAP_BETWEEN_PYTHONS_AND_PREPROCESSOR_MACRO_RECURSION_DEPTH) def patch_last_wflip_address(self) -> None: self.last_new_segment.wflip_start_address = self.curr_address diff --git a/flipjump/stl/bit/pointers.fj b/flipjump/stl/bit/pointers.fj index d23219a..29332bf 100644 --- a/flipjump/stl/bit/pointers.fj +++ b/flipjump/stl/bit/pointers.fj @@ -32,7 +32,7 @@ ns bit { } - // Complexity: 2n@ + // Complexity: 2w@ // 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. @@ -98,7 +98,7 @@ ns bit { } - // Complexity 3w@ (actually a bit smaller, 2w@+3w + (@-2)^2) + // Complexity 3w@ (actually a bit smaller, 3w@+3w) // like: wflip *ptr, value // ptr is a bit[:w] that holds an address, which we assume is w-aligned. def ptr_wflip ptr, value { @@ -120,7 +120,7 @@ ns bit { } } - // Complexity 3w@ (actually a bit smaller, 2w@+3w+2 + (@-2)^2) + // Complexity 3w@ // 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 { @@ -136,14 +136,14 @@ ns bit { ns bit { - // Complexity 7w@ (actually a bit smaller, 6w@+6w+8 + 2(@-2)^2) + // Complexity 8w@ // 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) + // Complexity 8w@ // 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 { diff --git a/flipjump/stl/hex/advanced_pointers.fj b/flipjump/stl/hex/advanced_pointers.fj index c4e4c61..73af9e0 100644 --- a/flipjump/stl/hex/advanced_pointers.fj +++ b/flipjump/stl/hex/advanced_pointers.fj @@ -71,8 +71,8 @@ ns hex { .ptr_sub hex.pointers.sp, value } - // Time Complexity: 4w@ (actually a bit smaller) - // Space Complexity: 4w@ (actually a bit smaller) + // Time Complexity: w(1.5@+5) + 9@+14 + // Space Complexity: w(1.875@+20) + 5@+55 // 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. @@ -81,8 +81,8 @@ ns hex { .ptr_wflip_2nd_word hex.pointers.sp, return_address } - // Time Complexity: 4w@ (actually a bit smaller) - // Space Complexity: 4w@ (actually a bit smaller) + // Time Complexity: w(1.5@+5) + 9@+23 + // Space Complexity: w(1.875@+20) + 5@+67 // 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. @@ -128,8 +128,8 @@ ns hex { } - // 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) + // Time Complexity: w(4@+14) + 14@+35 + // Space Complexity: w(4.375@+65) + 10@+143 // Like: hex = stack[sp] // stack[sp--] = 0 // Pops the current stack cell into the the given hex. Decrements sp. diff --git a/flipjump/stl/hex/logics.fj b/flipjump/stl/hex/logics.fj index 1640e81..f1200cc 100644 --- a/flipjump/stl/hex/logics.fj +++ b/flipjump/stl/hex/logics.fj @@ -139,6 +139,109 @@ ns hex { wflip src+w, first_flip } + // Time Complexity: n(@+4) + // Space Complexity: n(@+28) + // address1(bit_address) ^= src + // var1 ^= src + // address2(bit_address) ^= src + // var2 ^= src + // var1,var2,src are hex[:n], address1,address2 are addresses. + def address_and_variable_double_xor n, address1, var1, address2, var2, src { + rep(n, i) .quadrupled_exact_xor \ + address1+4*i+3, address1+4*i+2, address1+4*i+1, address1+4*i+0, \ + var1+dbit+i*dw+3, var1+dbit+i*dw+2, var1+dbit+i*dw+1, var1+dbit+i*dw+0, \ + address2+4*i+3, address2+4*i+2, address2+4*i+1, address2+4*i+0, \ + var2+dbit+i*dw+3, var2+dbit+i*dw+2, var2+dbit+i*dw+1, var2+dbit+i*dw+0, \ + src+i*dw + } + + // Time Complexity: @+12 + // Space Complexity: @+60 + // {q3,q2,q1,q0} ^= src + // {r3,r2,r1,r0} ^= src + // {t3,t2,t1,t0} ^= src + // {d3,d2,d1,d0} ^= src + // + // r3,r2,r1,r0,q3,q2,q1,q0,t3,t2,t1,t0,d3,d2,d1,d0 are bit-addresses; src is hex. + def quadrupled_exact_xor r3, r2, r1, r0, q3, q2, q1, q0, \ + t3, t2, t1, t0, d3, d2, d1, d0, src @ first_flip, second_flip, third_flip, fourth_flip, end { + wflip src+w, first_flip, src + pad 16 + first_flip: + ;end // 0 + r0;second_flip+ 1*dw // 1 + r1;second_flip+ 2*dw // 2 + r1;second_flip+ 3*dw // 3 + r2;second_flip+ 4*dw // 4 + r2;second_flip+ 5*dw // 5 + r2;second_flip+ 6*dw // 6 + r2;second_flip+ 7*dw // 7 + r3;second_flip+ 8*dw // 8 + r3;second_flip+ 9*dw // 9 + r3;second_flip+10*dw // 10 + r3;second_flip+11*dw // 11 + r3;second_flip+12*dw // 12 + r3;second_flip+13*dw // 13 + r3;second_flip+14*dw // 14 + r3;second_flip+15*dw // 15 + + second_flip: + ;end // 0 + q0;third_flip+ 1*dw // 1 + q1;third_flip+ 2*dw // 2 + q1;third_flip+ 3*dw // 3 + q2;third_flip+ 4*dw // 4 + q2;third_flip+ 5*dw // 5 + q2;third_flip+ 6*dw // 6 + q2;third_flip+ 7*dw // 7 + q3;third_flip+ 8*dw // 8 + q3;third_flip+ 9*dw // 9 + q3;third_flip+10*dw // 10 + q3;third_flip+11*dw // 11 + q3;third_flip+12*dw // 12 + q3;third_flip+13*dw // 13 + q3;third_flip+14*dw // 14 + q3;third_flip+15*dw // 15 + + third_flip: + ;end // 0 + t0;fourth_flip+ 1*dw // 1 + t1;fourth_flip+ 2*dw // 2 + t1;fourth_flip+ 3*dw // 3 + t2;fourth_flip+ 4*dw // 4 + t2;fourth_flip+ 5*dw // 5 + t2;fourth_flip+ 6*dw // 6 + t2;fourth_flip+ 7*dw // 7 + t3;fourth_flip+ 8*dw // 8 + t3;fourth_flip+ 9*dw // 9 + t3;fourth_flip+10*dw // 10 + t3;fourth_flip+11*dw // 11 + t3;fourth_flip+12*dw // 12 + t3;fourth_flip+13*dw // 13 + t3;fourth_flip+14*dw // 14 + t3;fourth_flip+15*dw // 15 + + fourth_flip: + ;end // 0 + d0;end // 1 + d1;end // 2 + d1;first_flip+1*dw // 3 + d2;end // 4 + d2;first_flip+1*dw // 5 + d2;first_flip+2*dw // 6 + d2;first_flip+3*dw // 7 + d3;end // 8 + d3;first_flip+1*dw // 9 + d3;first_flip+2*dw // 10 + d3;first_flip+3*dw // 11 + d3;first_flip+4*dw // 12 + d3;first_flip+5*dw // 13 + d3;first_flip+6*dw // 14 + d3;first_flip+7*dw // 15 + end: + wflip src+w, first_flip + } + // Complexity: 4 // hex = !hex (15-hex) diff --git a/flipjump/stl/hex/pointers.fj b/flipjump/stl/hex/pointers.fj index daa168b..6956a9c 100644 --- a/flipjump/stl/hex/pointers.fj +++ b/flipjump/stl/hex/pointers.fj @@ -4,14 +4,35 @@ ns hex { ns pointers { - // Space Complexity: w/2+2 + // NOTE: must be placed just after the startup, so that the read_ptr_byte_table will be in address 256. + // + // Space Complexity: w/2+261 // Initializes the global opcodes and pointer-copies required for the pointers macros. + // Initializes the read-byte-handling table and the result/return variables to the read-byte table. + // + // @output-param read_byte: hex[:2] variable. You want to zero it before jumping into ptr_jump. + // After jumping into ptr_jump, it's xored with the read byte. + // @output_param ret_after_read_byte: The return address. Jumps to it after finishing reading a byte. // // @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 { + def ptr_init @ read_ptr_byte_table > to_flip, to_jump, to_flip_var, to_jump_var, \ + read_byte, ret_after_read_byte { + pad 256 + // Time Complexity: 4/8 (when jumping to hex.pointers.to_jump, until finished) + // (4 is for reading from an hex memory, 8 is for byte memory). + read_ptr_byte_table: + rep(256, d) stl.fj \ + d==0?0: (.read_byte+dbit+(#d)-1), \ + (d==((1<<(#d))>>1)) ? .ret_after_read_byte : read_ptr_byte_table+(d^((1<<(#d))>>1))*dw + + read_byte: + hex.vec 2 + ret_after_read_byte: + ;0 + to_flip: 0;0 to_jump: @@ -44,7 +65,7 @@ ns hex { } // Space Complexity: n+w/4 + 330 - // Initializes a stack of size n (maximal capacity of n hexs / return-addresses). + // Initializes a stack of size n (maximal capacity of n hexes / 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. @@ -117,9 +138,19 @@ 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 @ 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 { + def xor_to_ptr ptr, hex { .pointers.set_flip_pointer ptr + .xor_to_flip_ptr hex + } + + + // Time Complexity: 5@+12 + // Space Complexity: 5@+76 + // xors (the parameter hex) the hex pointed by the memory-word hex.pointers.to_flip. + // like: hex.xor *to_flip, hex + // It assumes that the value in the memory-word to_flip is a dw-aligned address to an hex-variable. + def xor_to_flip_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 { wflip hex.pointers.to_flip+w, after_flip_bit0, prepare_flip_bit0 prepare_flip_bit0: @@ -149,7 +180,8 @@ ns hex { wflip hex.pointers.to_flip+w, after_flip_bit2 } - // Complexity 3w@ (actually a bit smaller, 2w@+3w + (@-2)^2) + // Time Complexity: w(1.5@+5) + // Space Complexity: w(1.5@+17) // like: wflip *ptr, value // ptr is a hex[:w/4] that holds an address, which we assume is w-aligned. def ptr_wflip ptr, value { @@ -171,7 +203,8 @@ ns hex { } } - // Complexity 3w@ (actually a bit smaller, 2w@+3w+2 + (@-2)^2) + // Time Complexity: w(1.5@+5) + // Space Complexity: w(1.5@+17) // like: wflip (*ptr)+w, value // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def ptr_wflip_2nd_word ptr, value { @@ -187,18 +220,33 @@ ns hex { ns hex { - // Complexity 5.5w@ + // Time Complexity: w(3.5@+12) + // Space Complexity: w(3.5@+48) // like: dst ^= *ptr // dst is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def xor_from_ptr dst, ptr { .exact_xor_from_ptr dst+dbit+3, dst+dbit+2, dst+dbit+1, dst+dbit+0, ptr } - // Time Complexity: 5.5w@ (exact: 4.5w@+8w+11 + 2(@-2)^2) - // Space Complexity: 5.5w@ (exact: 4.5w@+8w+34 + 2(@-2)^2) + // Time Complexity: w(3.5@+12) + // Space Complexity: w(3.5@+48) // 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 { + def exact_xor_from_ptr d3,d2,d1,d0, ptr @ switch, end { +// def xor_def_byte_from_ptr ptr @ switch, end { +// .pointers.set_flip_pointer ptr +// .pointers.set_jump_pointer ptr // TODO save 0.25w@ by using address_and_variable_double_xor +// +// wflip hex.pointers.to_flip+w, cleanup +// wflip hex.pointers.to_flip, dbit+8, hex.pointers.to_flip +// ;hex.pointers.to_flip +// pad 4 +// cleanup: +// // now flip_ptr -> ptr+dbit+8 +// // now *(ptr+w) == 256 +// wflip hex.pointers.to_flip+w, cleanup^end +// + .ptr_wflip_2nd_word ptr, switch .ptr_jump ptr @@ -222,6 +270,8 @@ ns hex { d3;switch+7*dw // 15 end: +// wflip hex.pointers.to_flip, dbit+8 +// wflip hex.pointers.to_flip+w, end .ptr_wflip_2nd_word ptr, switch } } diff --git a/flipjump/stl/ptrlib.fj b/flipjump/stl/ptrlib.fj index b10446a..340e4b9 100644 --- a/flipjump/stl/ptrlib.fj +++ b/flipjump/stl/ptrlib.fj @@ -2,14 +2,15 @@ ns stl { - // Complexity: 2.5w+4 + // NOTE: must be placed just after the startup, so that the read_ptr_byte_table will be in address 256. + // Complexity: 2.5w+263 def ptr_init { - bit.pointers.ptr_init hex.pointers.ptr_init + bit.pointers.ptr_init } // 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 hexes / return-addresses). // n is the size of the stack. def stack_init n { hex.pointers.stack_init n diff --git a/flipjump/stl/runlib.fj b/flipjump/stl/runlib.fj index 5f6f5e7..7cc734e 100644 --- a/flipjump/stl/runlib.fj +++ b/flipjump/stl/runlib.fj @@ -1,42 +1,73 @@ // w = ?? // memory and operands width. Is defined at compile time. dw = 2 * w // double word size -dbit = w + #w // the bit-distance from the variable's start, to the bit value (w + w_width) +dbit = w + #w // the bit-distance from the variable's start, to the bit/hex value (w + dw-width) + + +// More info about the FlipJump input / output in: https://esolangs.org/wiki/FlipJump#Input_/_Output ns stl { // Complexity: 2 - // startup Macro - should be the first piece of code in your program. + // startup Macro - Should be the first piece of code in your program. + // Inits the IO variable, and jumps to the next instruction. + def startup @ code_start { + stl.startup code_start + code_start: + } + + // Complexity: 2 + // startup Macro - Should be the first piece of code in your program. + // Inits the IO variable, and jumps to the given code start. // @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 + 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) + ;0 // 2w;3w : sets the io_handler to address 0 (good for a future wflip) + } + // Complexity: 2.5w+265 + // startup Macro - Should be the first piece of code in your program. + // Inits the IO variable, and the pointers globals. + // Jumps to the next instruction. + def startup_and_init_pointers @ code_start { + stl.startup_and_init_pointers code_start code_start: - // 4w;5w : start of code } - // 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 + // Complexity: 2.5w+265 + // startup Macro - Should be the first piece of code in your program. + // Inits the IO variable, and the pointers globals. + // Jumps to the given code_start. + def startup_and_init_pointers code_start { + stl.startup code_start + // NOTE: must be placed just after the startup, so that the read_ptr_byte_table will be in address 256. + stl.ptr_init + } + + // Complexity: ~7000 (7026 for w=64, 6894 for w=16) + // startup Macro - Should be the first piece of code in your program. + // Initialize anything needed for the standard library. def startup_and_init_all { .startup_and_init_all 100 } - // Complexity: 6793 + 2.75w+@ + n - // startup Macro, that initialize anything needed for the standard library - should be the first piece of code in your program. + // Complexity: 6725 + 2.75w+@ + n + // startup Macro - Should be the first piece of code in your program. + // Initialize anything needed for the standard library. // 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) + def startup_and_init_all stack_bit_size @ code_start { + .startup_and_init_all code_start, stack_bit_size + code_start: + } + // Complexity: 6725 + 2.75w+@ + n + // startup Macro - Should be the first piece of code in your program. + // Initialize anything needed for the standard library. + // stack_bit_size is the size of the global-stack (will hold this number of hexes / return-addresses). + def startup_and_init_all code_start, stack_bit_size { + stl.startup_and_init_pointers code_start hex.init - stl.ptr_init stl.stack_init stack_bit_size - - code_start: } @@ -114,32 +145,6 @@ ns stl { - // ---------- 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 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: diff --git a/flipjump/utils/constants.py b/flipjump/utils/constants.py index 11e2efa..91c77a4 100644 --- a/flipjump/utils/constants.py +++ b/flipjump/utils/constants.py @@ -10,7 +10,8 @@ WFLIP_LABEL_PREFIX = ':wflips:' LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH = 10 -DEFAULT_MAX_MACRO_RECURSION_DEPTH = 1000 +DEFAULT_MAX_MACRO_RECURSION_DEPTH = 900 +GAP_BETWEEN_PYTHONS_AND_PREPROCESSOR_MACRO_RECURSION_DEPTH = 100 IO_BYTES_ENCODING = 'raw_unicode_escape' diff --git a/programs/concept_checks/hex_ptr.fj b/programs/concept_checks/hex_ptr.fj index f76bc4c..995c162 100644 --- a/programs/concept_checks/hex_ptr.fj +++ b/programs/concept_checks/hex_ptr.fj @@ -1,4 +1,5 @@ -stl.startup +stl.startup_and_init_pointers + test0: hex.ptr_flip p0 @@ -66,6 +67,3 @@ test3: hex.hex d3_var: hex.hex - - -stl.ptr_init diff --git a/programs/simple_math_checks/ncmp.fj b/programs/simple_math_checks/ncmp.fj index e5da42d..9cd583f 100644 --- a/programs/simple_math_checks/ncmp.fj +++ b/programs/simple_math_checks/ncmp.fj @@ -1,5 +1,4 @@ stl.startup -stl.default_input 0, 0 n=4 From afd6d3bbbfaea1e8a40009e5b27200ef5e5e2639 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Thu, 5 Oct 2023 16:26:31 +0300 Subject: [PATCH 02/12] faster xor_from_ptr works! - it worked on my first run! - update related complexities, and better-documented the stl/ptrlib.fj file. --- flipjump/stl/hex/advanced_pointers.fj | 12 ++-- flipjump/stl/hex/logics.fj | 4 +- flipjump/stl/hex/pointers.fj | 99 ++++++++++++++------------- flipjump/stl/ptrlib.fj | 30 +++++--- 4 files changed, 80 insertions(+), 65 deletions(-) diff --git a/flipjump/stl/hex/advanced_pointers.fj b/flipjump/stl/hex/advanced_pointers.fj index 73af9e0..77824dc 100644 --- a/flipjump/stl/hex/advanced_pointers.fj +++ b/flipjump/stl/hex/advanced_pointers.fj @@ -71,7 +71,7 @@ ns hex { .ptr_sub hex.pointers.sp, value } - // Time Complexity: w(1.5@+5) + 9@+14 + // Time Complexity: w(1.5@+5) + 9@+14 // Space Complexity: w(1.875@+20) + 5@+55 // Like: stack[++sp] = return_address // Pushes the given return_address to the next cell in the stack (assumes it's zero). Increments sp. @@ -81,7 +81,7 @@ ns hex { .ptr_wflip_2nd_word hex.pointers.sp, return_address } - // Time Complexity: w(1.5@+5) + 9@+23 + // Time Complexity: w(1.5@+5) + 9@+23 // Space Complexity: w(1.875@+20) + 5@+67 // 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. @@ -128,8 +128,8 @@ ns hex { } - // Time Complexity: w(4@+14) + 14@+35 - // Space Complexity: w(4.375@+65) + 10@+143 + // Time Complexity: w(1.25@+7) + 21@+48 + // Space Complexity: w(1.625@+46) + 17@+191 // Like: hex = stack[sp] // stack[sp--] = 0 // Pops the current stack cell into the the given hex. Decrements sp. @@ -140,8 +140,8 @@ ns hex { .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) + // Time Complexity: n(w(1.25@+7) + 21@+48) + // Space Complexity: n(w(1.625@+46) + 17@+191) // Like: sp -= n // hex[:n] = stack[sp+1][:n] // stack[sp+1:][:n] = 0 diff --git a/flipjump/stl/hex/logics.fj b/flipjump/stl/hex/logics.fj index f1200cc..2a92efa 100644 --- a/flipjump/stl/hex/logics.fj +++ b/flipjump/stl/hex/logics.fj @@ -139,8 +139,8 @@ ns hex { wflip src+w, first_flip } - // Time Complexity: n(@+4) - // Space Complexity: n(@+28) + // Time Complexity: n(@+12) + // Space Complexity: n(@+60) // address1(bit_address) ^= src // var1 ^= src // address2(bit_address) ^= src diff --git a/flipjump/stl/hex/pointers.fj b/flipjump/stl/hex/pointers.fj index 6956a9c..1339c55 100644 --- a/flipjump/stl/hex/pointers.fj +++ b/flipjump/stl/hex/pointers.fj @@ -64,6 +64,18 @@ ns hex { ..address_and_variable_xor w/4, .to_flip, .to_flip_var, ptr } + // Time Complexity: w(0.75@+5) + // Space Complexity: w(0.75@+29) + // Sets both to_flip and to_flip_var, and to_jump and to_jump_var to point to the given pointer. + // ( to_flip{_var} = ptr ) + // ( to_jump{_var} = ptr ) + // ptr is a hex[:w/4] that holds an address. + def set_flip_and_jump_pointers ptr < .to_flip, .to_flip_var, .to_jump, .to_jump_var { + ..address_and_variable_xor w/4, .to_flip, .to_flip_var, .to_flip_var + ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, .to_jump_var + ..address_and_variable_double_xor w/4, .to_flip, .to_flip_var, .to_jump+w, .to_jump_var, ptr + } + // Space Complexity: n+w/4 + 330 // Initializes a stack of size n (maximal capacity of n hexes / return-addresses). // n is the size of the stack. @@ -220,58 +232,47 @@ ns hex { ns hex { - // Time Complexity: w(3.5@+12) - // Space Complexity: w(3.5@+48) + // Time Complexity: w(0.75@+ 5) + 6@+13 + // Space Complexity: w(0.75@+29) + 6@+36 // like: dst ^= *ptr // dst is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. - def xor_from_ptr dst, ptr { - .exact_xor_from_ptr dst+dbit+3, dst+dbit+2, dst+dbit+1, dst+dbit+0, ptr + def xor_from_ptr dst, ptr < hex.pointers.read_byte { + .read_def_byte_from_ptr ptr + .xor dst, hex.pointers.read_byte } - // Time Complexity: w(3.5@+12) - // Space Complexity: w(3.5@+48) - // 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 { -// def xor_def_byte_from_ptr ptr @ switch, end { -// .pointers.set_flip_pointer ptr -// .pointers.set_jump_pointer ptr // TODO save 0.25w@ by using address_and_variable_double_xor -// -// wflip hex.pointers.to_flip+w, cleanup -// wflip hex.pointers.to_flip, dbit+8, hex.pointers.to_flip -// ;hex.pointers.to_flip -// pad 4 -// cleanup: -// // now flip_ptr -> ptr+dbit+8 -// // now *(ptr+w) == 256 -// wflip hex.pointers.to_flip+w, cleanup^end -// - - .ptr_wflip_2nd_word ptr, switch - .ptr_jump ptr - - pad 16 - switch: - ;end // 0 - d0;end // 1 - d1;end // 2 - d1;switch+1*dw // 3 - d2;end // 4 - d2;switch+1*dw // 5 - d2;switch+2*dw // 6 - d2;switch+3*dw // 7 - d3;end // 8 - d3;switch+1*dw // 9 - d3;switch+2*dw // 10 - d3;switch+3*dw // 11 - d3;switch+4*dw // 12 - d3;switch+5*dw // 13 - d3;switch+6*dw // 14 - d3;switch+7*dw // 15 - - end: -// wflip hex.pointers.to_flip, dbit+8 -// wflip hex.pointers.to_flip+w, end - .ptr_wflip_2nd_word ptr, switch + // Time Complexity: w(0.75@+ 5) + 5@+13 + // Space Complexity: w(0.75@+29) + 5@+24 + // like: hex.pointers.read_byte = *ptr + // + // it also: set_flip_and_jump_pointers ptr + // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. + def read_def_byte_from_ptr ptr @ read_ptr_and_flip_back, cleanup \ + < hex.pointers.ret_after_read_byte, hex.pointers.read_byte, hex.pointers.to_jump, hex.pointers.to_flip { + // 1. setup: + // zero read_byte. + // to_flip = ptr + dbit+8. + // to_jump+w = ptr. + hex.zero 2, hex.pointers.read_byte + .pointers.set_flip_and_jump_pointers ptr + wflip hex.pointers.to_flip, dbit+8 + + // 2. *(ptr+w)^=256, so that now *(ptr+w) == 256 + original_value. + wflip hex.pointers.to_flip+w, read_ptr_and_flip_back, hex.pointers.to_flip + + pad 4 + read_ptr_and_flip_back: + // 3. Jump to *(ptr+w). It will xor the pointed original_value byte into hex.pointers.read_byte. + // 4. Then jump to hex.pointers.to_flip to make *(ptr+w)==original_value back again. + // 5. Then return to cleanup. + wflip hex.pointers.to_flip+w, read_ptr_and_flip_back^cleanup + wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip, hex.pointers.to_jump + + cleanup: + // 6. to_flip = ptr, clean jump-back addresses. + wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip + wflip hex.pointers.to_flip, dbit+8 + wflip hex.pointers.to_flip+w, cleanup } + } diff --git a/flipjump/stl/ptrlib.fj b/flipjump/stl/ptrlib.fj index 340e4b9..55b9d1e 100644 --- a/flipjump/stl/ptrlib.fj +++ b/flipjump/stl/ptrlib.fj @@ -22,10 +22,15 @@ ns stl { // ---------- Functions +// @requires the stack_init. ns stl { - // Time Complexity: 4w@ (actually a bit smaller) - // Space Complexity: 8w@ (actually a bit smaller) + // Time Complexity: ~1.5@ (exact: w(1.5@+5) + 9@+15) + // Space Complexity: <2@ (exact: w(1.875@+20) + 5@+55) + // Saves the return address to the stack and jumps to the given "address". + // When returned, it removes the return-address from the stack. + // // note: the pop_ret_address is for the future return (counts as space, but not time, complexity). + // @requires the stack_init. def call address @ return_label { hex.push_ret_address return_label ;address @@ -35,10 +40,13 @@ ns stl { hex.pop_ret_address return_label } - // Time Complexity: 4w@ (actually a bit smaller) - // Space Complexity: 8.5w@ (actually a bit smaller) + // Time Complexity: <2@ (exact: w(1.5@+5) + 22@+20) + // Space Complexity: <2@ (exact: w(1.875@+20) + 28@+75) + // Saves the return address to the stack and jumps to the given "address". + // When returned, it removes the value from the stack, and pops "params_hex_length" variables from the stack. // // note: the pop_ret_address is for the future return (counts as space, but not time, complexity). + // @requires the stack_init. def call address, params_hex_length @ return_label { hex.push_ret_address return_label ;address @@ -50,9 +58,12 @@ ns stl { } - // 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). + // Time Complexity: w(2@+7) + 9@+23 + // Space Complexity: w(2.375@+34) + 5@+67 + // Returns to the calling function (gets the return-address from the top of the stack). + // + // note: jumps to the last-call's pop_ret_address (which this macro counts as time, but not space, complexity). + // @requires the stack_init. def return < hex.pointers.sp { hex.ptr_jump hex.pointers.sp } @@ -60,8 +71,9 @@ ns stl { // Time Complexity: n(2@) // Space Complexity: n(2@+24) - // (Unsafe if dst is hex.pointers.sp). + // (Unsafe if dst overlaps with hex.pointers.sp). // dst[:w/4] = sp + // @requires the stack_init. def get_sp dst < hex.pointers.sp { hex.mov w/4, dst, hex.pointers.sp } @@ -74,6 +86,7 @@ ns stl { ns stl { // Complexity: @-1 + // Jumps to label, and saves the return address in the given "ret_reg" variable. def fcall label, ret_reg @ ret { wflip ret_reg+w, ret, label pad 2 @@ -82,6 +95,7 @@ ns stl { } // Complexity: 1 + // Return into the address written in the "ret_reg" variable. def fret ret_reg { ;ret_reg } From cd5c5591a0b6c7f62f170dd6bf0566d3576cf1ad Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 7 Oct 2023 01:24:07 +0300 Subject: [PATCH 03/12] Debugger feature: Read Memory. hex.pointers read/write functions. - deleted 'Skip 1000' from the debugger. - now if they are 2+ labels for the same address, the one that'll survive is the shortest one. - macro-usage-graph now shows more options (lower thresholds), but won't show reps. - the xor_hex_to_flip_ptr + read_byte_from_inners_ptrs are now hex.pointers. inner functions, that don't use ptr parameter at all. - new read/write_hex/byte functions, and zero_ptr. --- flipjump/flipjump_cli.py | 30 ++- .../interpretter/debugging/breakpoints.py | 148 ++++++++++++-- .../debugging/macro_usage_graph.py | 4 +- .../interpretter/debugging/message_boxes.py | 53 +++++ flipjump/stl/README.md | 2 +- flipjump/stl/conf.json | 2 +- flipjump/stl/hex/pointers.fj | 182 +++++++++++------- ...advanced_pointers.fj => stack_pointers.fj} | 21 +- programs/concept_checks/hex_ptr.fj | 2 +- programs/func_tests/func3.fj | 2 +- programs/func_tests/func4.fj | 4 +- programs/func_tests/func5.fj | 16 +- programs/func_tests/func7.fj | 2 - programs/prime_sieve.fj | 10 +- 14 files changed, 343 insertions(+), 135 deletions(-) create mode 100644 flipjump/interpretter/debugging/message_boxes.py rename flipjump/stl/hex/{advanced_pointers.fj => stack_pointers.fj} (90%) diff --git a/flipjump/flipjump_cli.py b/flipjump/flipjump_cli.py index d9fe5ed..275e3d1 100644 --- a/flipjump/flipjump_cli.py +++ b/flipjump/flipjump_cli.py @@ -9,7 +9,6 @@ from flipjump.assembler import assembler from flipjump.fjm.fjm_consts import FJMVersion, SUPPORTED_VERSIONS_NAMES from flipjump.fjm.fjm_writer import Writer -from flipjump.utils.exceptions import FlipJumpException from flipjump.interpretter.io_devices.StandardIO import StandardIO from flipjump.utils.constants import LAST_OPS_DEBUGGING_LIST_DEFAULT_LENGTH, DEFAULT_MAX_MACRO_RECURSION_DEPTH from flipjump.utils.functions import get_file_tuples, get_temp_directory_suffix @@ -78,23 +77,18 @@ def run(in_fjm_path: Path, debug_file: Optional[Path], args: argparse.Namespace, if debug_file: verify_file_exists(error_func, debug_file) - try: - flipjump_quickstart.debug( - in_fjm_path, - debug_file, - breakpoints_addresses=set(), - breakpoints=set(args.breakpoint), - breakpoints_contains=set(args.breakpoint_contains), - io_device=StandardIO(not args.no_output), - show_trace=args.trace, - print_time=not args.silent, - print_termination=not args.silent, - last_ops_debugging_list_length=args.debug_ops_list, - ) - except FlipJumpException as e: - print() - print(e) - exit(1) + flipjump_quickstart.debug( + in_fjm_path, + debug_file, + breakpoints_addresses=set(), + breakpoints=set(args.breakpoint), + breakpoints_contains=set(args.breakpoint_contains), + io_device=StandardIO(not args.no_output), + show_trace=args.trace, + print_time=not args.silent, + print_termination=not args.silent, + last_ops_debugging_list_length=args.debug_ops_list, + ) def get_version(version: Optional[int], is_outfile_specified: bool) -> FJMVersion: diff --git a/flipjump/interpretter/debugging/breakpoints.py b/flipjump/interpretter/debugging/breakpoints.py index b095941..67a9a07 100644 --- a/flipjump/interpretter/debugging/breakpoints.py +++ b/flipjump/interpretter/debugging/breakpoints.py @@ -1,30 +1,77 @@ +import re from pathlib import Path -from typing import Optional, List, Dict, Set +from typing import Optional, Dict, Set, Tuple from flipjump.fjm import fjm_reader +from flipjump.interpretter.debugging.message_boxes import (display_message_box, + display_message_box_and_get_text_answer, + display_message_box_with_choices_and_get_answer) from flipjump.utils.constants import MACRO_SEPARATOR_STRING from flipjump.utils.functions import load_debugging_labels from flipjump.utils.classes import RunStatistics -from flipjump.utils.exceptions import FlipJumpMissingImportException +from flipjump.utils.exceptions import FlipJumpException class BreakpointHandlerUnnecessary(Exception): pass -def display_message_box_and_get_answer(body_message: str, title_message: str, choices: List[str]) -> str: +def show_memory_address(variable_prefix: Optional[Tuple[str, int]], user_query: str, + address: int, mem: fjm_reader.Reader, label_name: Optional[str]) -> None: """ - Displays the message box query, and return the answer. If easygui isn't installed correctly, raise an exception. + Shows the value of the requested memory address / variable. + The function also support reading flipjump variables (saved in label+dbit+i*dw). + Also shows the label-name of the address if the user entered an integer-address. + + @param variable_prefix: if not None: the user asked for a flipjump variable: + tuple (variable_type - 'b'/'h'/'B' for bit/hex/byte, variable_length - number of memory-ops). + @param user_query: the string the user entered. + @param address: the address resolved from user_query string. + @param mem: the fjm_reader.Reader for the current running fj. Used for reading the actual memory values + of the given address (or addresses if the user asked for a variable). + @param label_name: if not None - the user asked for an integer address, and this its label-name, + or the closest label to it. """ - try: - import easygui - except ImportError: - raise FlipJumpMissingImportException("This debug feature requires the easygui python library.\n" - "Try `pip install easygui`, and also install tkinter on your system.") - - # might generate an 'import from collections is deprecated' warning if using easygui-version <= 0.98.3. - return easygui.buttonbox(body_message, title_message, choices) + if address % mem.memory_width != 0 or address < 0 or address >= (1 << mem.memory_width): + display_message_box( + body_message=f"Failed while trying to read {user_query}:\n" + f" The requested memory address ({address}) must be aligned" + f" (must be divisible by {mem.memory_width}),\n" + f" Can't be negative, and must be smaller than {hex(1 << mem.memory_width)}.", + title_message='Bad memory address') + else: + label_name = '' if label_name is None else f'\n\nThis address also goes by this label name:\n\n{label_name}' + + try: + if not variable_prefix: + memory_word_value = mem.get_word(address) + display_message_box( + body_message=f'Reading {user_query}:\n' + f'memory[{hex(address)}] = {memory_word_value} (or {hex(memory_word_value)}).' + f'{label_name}', + title_message='Read Memory') + else: + variable_type, variable_length = variable_prefix + variable_memory_words = [mem.get_word(address + (2*i+1) * mem.memory_width) + for i in range(variable_length)] + bits_per_word = {'b': 1, 'h': 4, 'B': 8}[variable_type] + value = 0 + for word in variable_memory_words[::-1]: + data_bits = (word >> mem.memory_width.bit_length()) & ((1 << bits_per_word) - 1) + value = (value << bits_per_word) | data_bits + display_message_box( + body_message=f'Reading the variable {user_query}:\n' + f'memory[{hex(address)}, {hex(address + 2 * variable_length * mem.memory_width)})' + f' = {value} (or {hex(value)}).' + f'{label_name}', + title_message='Reading FlipJump Variable') + except FlipJumpException as fje: + display_message_box( + body_message=f"Failed while trying to read {user_query}:\n" + f"Failed to read address {address}, with the error: {fje}.\n" + f"Maybe this memory region isn't initialized in the currently running .fjm?", + title_message='Read Memory Failure') def get_nice_label_repr(label: str, pad: int = 0) -> str: @@ -39,9 +86,10 @@ class BreakpointHandler: """ Handle breakpoints (know when breakpoints happen, query user for action). """ - def __init__(self, breakpoints: Dict[int, str], address_to_label: Dict[int, str]): + def __init__(self, breakpoints: Dict[int, str], address_to_label: Dict[int, str], label_to_address: Dict[str, int]): self.breakpoints = breakpoints self.address_to_label = address_to_label + self.label_to_address = label_to_address if self.address_to_label and 0 not in self.address_to_label: self.address_to_label[0] = ':memory-start:' @@ -81,6 +129,58 @@ def get_message_box_body(self, ip: int, mem: fjm_reader.Reader, op_counter: int) jump = self.get_address_str(mem.get_word(ip + mem.memory_width)) return f'Address {address}.\n\n{op_counter} ops executed.\n\nflip {flip}.\n\njump {jump}.' + def handle_read_memory(self, mem: fjm_reader.Reader) -> None: + """ + This function queries the user for reading a memory-word (by its address or a label). + It then shows the value of the requested word, and more useful information about it. + The function also support reading flipjump variables (saved in label+dbit+i*dw) with the ':' prefix + (for example ':b32:integer_label'). + + @param mem: the fjm_reader.Reader for the current running fj. Used for reading the actual memory values + of the given address (or addresses if the user asked for a variable). + """ + result = display_message_box_and_get_text_answer( + body_message="What memory-word would you like to read?\n" + "Use any of these options:\n" + "- Decimal number\n" + "- Hexadecimal number with the '0x' prefix\n" + "- A full label name\n" + "You can also read flipjump variables (like bit.vec, hex.vec, ..),\n" + " with the following prefixes to the address:\n" + '- :bN: read bit variable (like ":b32:integer_label")\n' + '- :hN: read hex variable (like ":h8:integer_label")\n' + '- :BN: read byte variable (holds 8 bits after the dbit)' + ' (like ":B4:integer_label")\n', + title_message='Debug: read memory address') + if result is None: + return + + variable_prefix = None + query = result + match = re.match(':([bhB])(\\d+):(.*)', result) + if match: + variable_type, variable_length, result = match.groups() + variable_prefix = (variable_type, int(variable_length)) + + if result in self.label_to_address: + show_memory_address(variable_prefix, query, self.label_to_address[result], mem, None) + return + + try: + address = int(result) + show_memory_address(variable_prefix, query, address, mem, self.get_address_str(address)) + except ValueError: + try: + address = int(result, 16) + show_memory_address(variable_prefix, query, address, mem, self.get_address_str(address)) + except ValueError: + display_message_box( + body_message=f"Failed, can't resolve the address/label \"{query}\".\n" + f"You entered an invalid memory-address, " + f"or the label you entered wasn't in its full form " + f"(remember the '---' parts. for more info read the flipjump/README.md in github).", + title_message='Invalid memory address.') + def query_user_for_debug_action(self, ip: int, mem: fjm_reader.Reader, op_counter: int) -> str: """ query the user for the next debug-action to make, while debugging (single-step, continue, ...) @@ -88,11 +188,13 @@ def query_user_for_debug_action(self, ip: int, mem: fjm_reader.Reader, op_counte """ title = "Breakpoint" if ip in self.breakpoints else "Debug Step" body = self.get_message_box_body(ip, mem, op_counter) - actions = ['Single Step', 'Skip 10', 'Skip 100', 'Skip 1000', 'Continue', 'Continue All'] + actions = ['Read Memory', 'Single Step', 'Skip 10', 'Skip 100', 'Continue', 'Continue All'] + + action = display_message_box_with_choices_and_get_answer(body, title, actions, 'Continue All') + while action == 'Read Memory': + self.handle_read_memory(mem) + action = display_message_box_with_choices_and_get_answer(body, title, actions, 'Continue All') - action = display_message_box_and_get_answer(body, title, actions) - if action is None: - action = 'Continue All' return action def apply_debug_action(self, action: str, op_counter: int) -> None: @@ -105,8 +207,6 @@ def apply_debug_action(self, action: str, op_counter: int) -> None: self.next_break = op_counter + 10 elif action == 'Skip 100': self.next_break = op_counter + 100 - elif action == 'Skip 1000': - self.next_break = op_counter + 1000 elif action == 'Continue': self.next_break = None elif action == 'Continue All': @@ -229,7 +329,13 @@ def get_breakpoint_handler(debugging_file: Optional[Path], breakpoint_addresses: 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 tuple(label_to_address)[::-1]} + address_to_label = {} + for label, address in label_to_address.items(): + if address in address_to_label: + if len(label) >= len(address_to_label[address]): + continue + address_to_label[address] = label + breakpoints = get_breakpoints(breakpoint_addresses, breakpoint_labels, breakpoint_contains_labels, label_to_address) - return BreakpointHandler(breakpoints, address_to_label) + return BreakpointHandler(breakpoints, address_to_label, label_to_address) diff --git a/flipjump/interpretter/debugging/macro_usage_graph.py b/flipjump/interpretter/debugging/macro_usage_graph.py index 99c5051..64c028a 100644 --- a/flipjump/interpretter/debugging/macro_usage_graph.py +++ b/flipjump/interpretter/debugging/macro_usage_graph.py @@ -24,6 +24,8 @@ def _prepare_first_and_second_level_significant_macros( parent, name = k_split if float(v) / macro_code_size[parent] < child_significance_min_thresh: continue + if len(name.split(':')) == 4: # if it's a rep + continue second_level[parent][name] = v return first_level, second_level @@ -74,7 +76,7 @@ def _show_macro_usage_graph(chosen_macros: List[Tuple[str, int]]) -> None: def show_macro_usage_pie_graph(macro_code_size: Dict[str, int], total_code_size: int, *, - min_main_thresh: float = 0.05, min_secondary_thresh: float = 0.01, + min_main_thresh: float = 0.01, min_secondary_thresh: float = 0.001, child_significance_min_thresh: float = 0.1) -> None: """ choose and present in a pie graph the macros with the most code-usage diff --git a/flipjump/interpretter/debugging/message_boxes.py b/flipjump/interpretter/debugging/message_boxes.py new file mode 100644 index 0000000..a02e8d4 --- /dev/null +++ b/flipjump/interpretter/debugging/message_boxes.py @@ -0,0 +1,53 @@ +from typing import List, Optional + +from flipjump.utils.exceptions import FlipJumpMissingImportException + + +EASYGUI_NOT_INSTALLED_MESSAGE = "This debug feature requires the easygui python library.\n"\ + "Try `pip install easygui`, and also install tkinter on your system." + + +def display_message_box_with_choices_and_get_answer(body_message: str, title_message: str, + choices: List[str], default_cancel_answer: str) -> str: + """ + Displays the message box query (with fixed choices), and return the answer. + If easygui isn't installed correctly, raises an exception. + """ + try: + # might generate an 'import from collections is deprecated' warning if using easygui-version <= 0.98.3. + import easygui + except ImportError: + raise FlipJumpMissingImportException(EASYGUI_NOT_INSTALLED_MESSAGE) + + answer = easygui.buttonbox(body_message, title_message, choices) + if answer is None: + return default_cancel_answer + return answer + + +def display_message_box(body_message: str, title_message: str) -> None: + """ + Displays the message box to the user. + If easygui isn't installed correctly, raises an exception. + """ + try: + # might generate an 'import from collections is deprecated' warning if using easygui-version <= 0.98.3. + import easygui + except ImportError: + raise FlipJumpMissingImportException(EASYGUI_NOT_INSTALLED_MESSAGE) + + easygui.msgbox(msg=body_message, title=title_message) + + +def display_message_box_and_get_text_answer(body_message: str, title_message: str) -> Optional[str]: + """ + Displays the message box query, and return the textual answer. + If easygui isn't installed correctly, raises an exception. + """ + try: + # might generate an 'import from collections is deprecated' warning if using easygui-version <= 0.98.3. + import easygui + except ImportError: + raise FlipJumpMissingImportException(EASYGUI_NOT_INSTALLED_MESSAGE) + + return easygui.enterbox(msg=body_message, title=title_message) diff --git a/flipjump/stl/README.md b/flipjump/stl/README.md index 14ebfda..9df3006 100644 --- a/flipjump/stl/README.md +++ b/flipjump/stl/README.md @@ -49,7 +49,7 @@ Offers macros for manipulating hexadecimal variables and vectors (i.e. numbers): - [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 +- [stack_pointers.fj](hex/stack_pointers.fj) - hex-vec pointers / stack operations: ptr/sp - inc/dec/add/sub, all push/pop - [tables_init.fj](hex/tables_init.fj) - initializes the "results-tables" for the next hex macros: or,and, add,sub, cmp, mul ### [mathlib.fj](mathlib.fj) diff --git a/flipjump/stl/conf.json b/flipjump/stl/conf.json index eee05e9..40cb222 100644 --- a/flipjump/stl/conf.json +++ b/flipjump/stl/conf.json @@ -22,7 +22,7 @@ "hex/input", "hex/output", "hex/pointers", - "hex/advanced_pointers", + "hex/stack_pointers", "casting", "ptrlib", diff --git a/flipjump/stl/hex/pointers.fj b/flipjump/stl/hex/pointers.fj index 1339c55..fe30ce7 100644 --- a/flipjump/stl/hex/pointers.fj +++ b/flipjump/stl/hex/pointers.fj @@ -150,46 +150,48 @@ 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 { + def xor_hex_to_ptr ptr, hex { .pointers.set_flip_pointer ptr - .xor_to_flip_ptr hex + .pointers.xor_hex_to_flip_ptr hex } + ns pointers { + // Time Complexity: 5@+12 + // Space Complexity: 5@+76 + // xors (the parameter hex) the hex pointed by the memory-word hex.pointers.to_flip. + // use after: .pointers.set_flip_pointer ptr + // does: .xor *ptr, hex (as it uses the address in to_flip) + // It assumes that the value in the memory-word to_flip is a dw-aligned address to an hex-variable. + def xor_hex_to_flip_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 { + wflip hex.pointers.to_flip+w, after_flip_bit0, prepare_flip_bit0 + + prepare_flip_bit0: + wflip hex.pointers.to_flip, dbit+0 + hex.if_flags hex, 0xAAAA, after_flip_bit0, hex.pointers.to_flip + prepare_flip_bit1: + wflip hex.pointers.to_flip, (dbit+0)^(dbit+1) + hex.if_flags hex, 0xCCCC, after_flip_bit1, hex.pointers.to_flip + prepare_flip_bit3: + wflip hex.pointers.to_flip, (dbit+1)^(dbit+3) + hex.if_flags hex, 0xFF00, after_flip_bit3, hex.pointers.to_flip + prepare_flip_bit2: + wflip hex.pointers.to_flip, (dbit+3)^(dbit+2) + hex.if_flags hex, 0xF0F0, after_flip_bit2, hex.pointers.to_flip - // Time Complexity: 5@+12 - // Space Complexity: 5@+76 - // xors (the parameter hex) the hex pointed by the memory-word hex.pointers.to_flip. - // like: hex.xor *to_flip, hex - // It assumes that the value in the memory-word to_flip is a dw-aligned address to an hex-variable. - def xor_to_flip_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 { - wflip hex.pointers.to_flip+w, after_flip_bit0, prepare_flip_bit0 - - prepare_flip_bit0: - wflip hex.pointers.to_flip, dbit+0 - hex.if_flags hex, 0xAAAA, after_flip_bit0, hex.pointers.to_flip - prepare_flip_bit1: - wflip hex.pointers.to_flip, (dbit+0)^(dbit+1) - hex.if_flags hex, 0xCCCC, after_flip_bit1, hex.pointers.to_flip - prepare_flip_bit3: - wflip hex.pointers.to_flip, (dbit+1)^(dbit+3) - hex.if_flags hex, 0xFF00, after_flip_bit3, hex.pointers.to_flip - prepare_flip_bit2: - wflip hex.pointers.to_flip, (dbit+3)^(dbit+2) - hex.if_flags hex, 0xF0F0, after_flip_bit2, hex.pointers.to_flip - - pad 4 - after_flip_bit0: - hex.pointers.to_flip+dbit+0;prepare_flip_bit1 - after_flip_bit1: - hex.pointers.to_flip+dbit+1;prepare_flip_bit3 - after_flip_bit2: - wflip hex.pointers.to_flip, dbit+2, cleanup - after_flip_bit3: - hex.pointers.to_flip+dbit+0;prepare_flip_bit2 + pad 4 + after_flip_bit0: + hex.pointers.to_flip+dbit+0;prepare_flip_bit1 + after_flip_bit1: + hex.pointers.to_flip+dbit+1;prepare_flip_bit3 + after_flip_bit2: + wflip hex.pointers.to_flip, dbit+2, cleanup + after_flip_bit3: + hex.pointers.to_flip+dbit+0;prepare_flip_bit2 - cleanup: - wflip hex.pointers.to_flip+w, after_flip_bit2 + cleanup: + wflip hex.pointers.to_flip+w, after_flip_bit2 + } } // Time Complexity: w(1.5@+5) @@ -236,43 +238,93 @@ ns hex { // Space Complexity: w(0.75@+29) + 6@+36 // 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 < hex.pointers.read_byte { - .read_def_byte_from_ptr ptr + def xor_hex_from_ptr dst, ptr < hex.pointers.read_byte { + .pointers.set_flip_and_jump_pointers ptr + .pointers.read_byte_from_inners_ptrs .xor dst, hex.pointers.read_byte } - // Time Complexity: w(0.75@+ 5) + 5@+13 - // Space Complexity: w(0.75@+29) + 5@+24 - // like: hex.pointers.read_byte = *ptr - // - // it also: set_flip_and_jump_pointers ptr - // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. - def read_def_byte_from_ptr ptr @ read_ptr_and_flip_back, cleanup \ - < hex.pointers.ret_after_read_byte, hex.pointers.read_byte, hex.pointers.to_jump, hex.pointers.to_flip { - // 1. setup: - // zero read_byte. - // to_flip = ptr + dbit+8. - // to_jump+w = ptr. - hex.zero 2, hex.pointers.read_byte + // Time Complexity: w(0.75@+ 5) + 7@+13 + // Space Complexity: w(0.75@+29) + 7@+48 + // like: dst[:2] ^= *ptr + // dst is a hex[2:]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. + def xor_byte_from_ptr dst, ptr < hex.pointers.read_byte { .pointers.set_flip_and_jump_pointers ptr - wflip hex.pointers.to_flip, dbit+8 + .pointers.read_byte_from_inners_ptrs + .xor 2, dst, hex.pointers.read_byte + } - // 2. *(ptr+w)^=256, so that now *(ptr+w) == 256 + original_value. - wflip hex.pointers.to_flip+w, read_ptr_and_flip_back, hex.pointers.to_flip + ns pointers { + // Time Complexity: 5@+13 + // Space Complexity: 5@+24 + // use after: hex.pointers.set_flip_and_jump_pointers ptr + // does: hex.pointers.read_byte[:2] = *ptr + // + // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. + def read_byte_from_inners_ptrs @ read_ptr_and_flip_back, cleanup \ + < hex.pointers.ret_after_read_byte, hex.pointers.read_byte, hex.pointers.to_jump, hex.pointers.to_flip { + // 1. setup: + // zero read_byte. + // to_flip = ptr + dbit+8. + // to_jump+w = ptr. + hex.zero 2, hex.pointers.read_byte + wflip hex.pointers.to_flip, dbit+8 + + // 2. *(ptr+w)^=256, so that now *(ptr+w) == 256 + original_value. + wflip hex.pointers.to_flip+w, read_ptr_and_flip_back, hex.pointers.to_flip - pad 4 - read_ptr_and_flip_back: - // 3. Jump to *(ptr+w). It will xor the pointed original_value byte into hex.pointers.read_byte. - // 4. Then jump to hex.pointers.to_flip to make *(ptr+w)==original_value back again. - // 5. Then return to cleanup. - wflip hex.pointers.to_flip+w, read_ptr_and_flip_back^cleanup - wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip, hex.pointers.to_jump + pad 4 + read_ptr_and_flip_back: + // 3. Jump to *(ptr+w). It will xor the pointed original_value byte into hex.pointers.read_byte. + // 4. Then jump to hex.pointers.to_flip to make *(ptr+w)==original_value back again. + // 5. Then return to cleanup. + wflip hex.pointers.to_flip+w, read_ptr_and_flip_back^cleanup + wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip, hex.pointers.to_jump - cleanup: - // 6. to_flip = ptr, clean jump-back addresses. - wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip - wflip hex.pointers.to_flip, dbit+8 - wflip hex.pointers.to_flip+w, cleanup + cleanup: + // 6. to_flip = ptr, clean jump-back addresses. + wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip + wflip hex.pointers.to_flip, dbit+8 + wflip hex.pointers.to_flip+w, cleanup + } + } +} + + + +// Read & Write memory. + +ns hex { + // like: dst = *ptr + def read_hex dst, ptr { + .zero dst + .xor_hex_from_ptr dst, ptr + } + + // like: *ptr = src + def write_hex ptr, src < hex.pointers.read_byte { + .pointers.set_flip_and_jump_pointers ptr + .pointers.read_byte_from_inners_ptrs + .xor hex.pointers.read_byte, src + .pointers.xor_hex_to_flip_ptr hex.pointers.read_byte + } + + // like: dst[:2] = *ptr + def read_byte dst, ptr { + .zero 2, dst + .xor_byte_from_ptr dst, ptr + } + + // like: *ptr = 0 + def zero_ptr ptr < hex.pointers.read_byte { + .pointers.set_flip_and_jump_pointers ptr + .pointers.read_byte_from_inners_ptrs + .pointers.xor_hex_to_flip_ptr hex.pointers.read_byte // TODO make xor_byte_to_flip_ptr } +// // like: *ptr = src[:2] +// def write_byte ptr, src { +// .zero 2, dst +// .xor_byte_from_ptr dst, ptr +// } } diff --git a/flipjump/stl/hex/advanced_pointers.fj b/flipjump/stl/hex/stack_pointers.fj similarity index 90% rename from flipjump/stl/hex/advanced_pointers.fj rename to flipjump/stl/hex/stack_pointers.fj index 77824dc..8f7e422 100644 --- a/flipjump/stl/hex/advanced_pointers.fj +++ b/flipjump/stl/hex/stack_pointers.fj @@ -78,6 +78,7 @@ ns hex { // return_address is a fj-op address, so we assume is dw-aligned. def push_ret_address return_address < hex.pointers.sp { .sp_inc + .zero_ptr hex.pointers.sp .ptr_wflip_2nd_word hex.pointers.sp, return_address } @@ -96,9 +97,10 @@ ns hex { // 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 { + def push_hex hex < hex.pointers.sp { .sp_inc - .xor_to_ptr hex.pointers.sp, hex + .write_hex hex.pointers.sp, hex +// .xor_hex_to_ptr hex.pointers.sp, hex } // Time Complexity: n(w(0.5@+2) + 14@+26) @@ -106,7 +108,7 @@ ns hex { // 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 + rep(n, i) .push_hex hex+i*dw } @@ -115,7 +117,7 @@ ns hex { // 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 + .xor_hex_to_ptr hex.pointers.sp, unchanged_hex .sp_dec } @@ -132,12 +134,13 @@ ns hex { // Space Complexity: w(1.625@+46) + 17@+191 // Like: hex = stack[sp] // stack[sp--] = 0 - // Pops the current stack cell into the the given hex. Decrements sp. + // Pops the current stack cell (only the least-significant-hex of it) into the the given hex. Decrements sp. // hex is only an output parameter - def pop hex < hex.pointers.sp { + def pop_hex hex < hex.pointers.sp { hex.zero hex - .xor_from_ptr hex, hex.pointers.sp - .pop_unchanged_parameter hex + .xor_hex_from_ptr hex, hex.pointers.sp +// .pop_unchanged_parameter hex + .sp_dec } // Time Complexity: n(w(1.25@+7) + 21@+48) @@ -148,6 +151,6 @@ ns hex { // 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 + rep(n, i) .pop_hex hex+(n-1-i)*dw } } diff --git a/programs/concept_checks/hex_ptr.fj b/programs/concept_checks/hex_ptr.fj index 995c162..82d2c4d 100644 --- a/programs/concept_checks/hex_ptr.fj +++ b/programs/concept_checks/hex_ptr.fj @@ -37,7 +37,7 @@ test2: test3: hex.set d3, 6 hex.set d3_var, 0xD - hex.xor_from_ptr d3_var, p3 + hex.xor_hex_from_ptr d3_var, p3 hex.print_as_digit d3_var, 1 stl.loop diff --git a/programs/func_tests/func3.fj b/programs/func_tests/func3.fj index 7877e54..0eacd21 100644 --- a/programs/func_tests/func3.fj +++ b/programs/func_tests/func3.fj @@ -7,7 +7,7 @@ stl.startup_and_init_all 10 // Prints "ABCDE" test3: stl.output 'A' - hex.push x3 + hex.push_hex x3 stl.output 'B' stl.call func3 stl.output 'D' diff --git a/programs/func_tests/func4.fj b/programs/func_tests/func4.fj index e362b6c..c60c5dc 100644 --- a/programs/func_tests/func4.fj +++ b/programs/func_tests/func4.fj @@ -7,13 +7,13 @@ stl.startup_and_init_all 10 // Prints "ABCDEFGH-" and then 0/1, the invert of x4 test4: stl.output 'A' - hex.push x4 + hex.push_hex x4 stl.output 'B' stl.call func4 stl.output 'G' - hex.pop x4 + hex.pop_hex 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 50bb053..9bcb879 100644 --- a/programs/func_tests/func5.fj +++ b/programs/func_tests/func5.fj @@ -1,4 +1,4 @@ -// Tests the xor_from_ptr, xor_to_ptr and function calls +// Tests the xor_hex_from_ptr, xor_hex_to_ptr and function calls stl.startup_and_init_all 10 @@ -7,11 +7,11 @@ stl.startup_and_init_all 10 // Prints "ABC abcdefg ABCD-", and then 0/1, the xor of x5,y5 test5: stl.output 'A' - hex.push res5 + hex.push_hex res5 stl.output 'B' - hex.push x5 + hex.push_hex x5 stl.output 'C' - hex.push y5 + hex.push_hex y5 stl.output ' ' stl.call func5 @@ -22,7 +22,7 @@ test5: stl.output 'B' hex.pop_unchanged_parameter x5 stl.output 'C' - hex.pop res5 + hex.pop_hex res5 stl.output 'D' bit.bin2ascii ascii, res5 @@ -40,16 +40,16 @@ func5: hex.ptr_dec __func5_arg_ptr stl.output 'b' - hex.xor_from_ptr __func5_res, __func5_arg_ptr + hex.xor_hex_from_ptr __func5_res, __func5_arg_ptr stl.output 'c' hex.ptr_dec __func5_arg_ptr stl.output 'd' - hex.xor_from_ptr __func5_res, __func5_arg_ptr + hex.xor_hex_from_ptr __func5_res, __func5_arg_ptr stl.output 'e' hex.ptr_dec __func5_arg_ptr stl.output 'f' - hex.xor_to_ptr __func5_arg_ptr, __func5_res + hex.xor_hex_to_ptr __func5_arg_ptr, __func5_res stl.output 'g' stl.return diff --git a/programs/func_tests/func7.fj b/programs/func_tests/func7.fj index faf1ca4..f50d1b1 100644 --- a/programs/func_tests/func7.fj +++ b/programs/func_tests/func7.fj @@ -89,7 +89,6 @@ ns add_2N { hex.push 2*N, .res hex.sp_add 2*N+1 stl.output "3-" - stl.return res: hex.vec 2*N @@ -175,7 +174,6 @@ ns square_distance { stl.call ..square_sub hex.pop 2*N, .res1 stl.output 'E' - // (y1-y2)**2 hex.push N, .y1 hex.push N, .y2 diff --git a/programs/prime_sieve.fj b/programs/prime_sieve.fj index d2c5dba..3a17399 100644 --- a/programs/prime_sieve.fj +++ b/programs/prime_sieve.fj @@ -78,7 +78,7 @@ def mark_primes mark_primes_ptr, primes_ptr_n, p_is_add_4, p_2dw_offset, p_4dw_o hex.cmp hw, curr_prime_ptr, primes_ptr_n, mark_loop, mark_loop, end mark_loop: if1_ptr curr_prime_ptr, next_prime - hex.xor_to_ptr curr_prime_ptr, ONE + hex.xor_hex_to_ptr curr_prime_ptr, ONE next_prime: advance_ptr_by_p_Xdw curr_prime_ptr, p_2dw_offset, p_4dw_offset, is_add_4 is_add_4+dbit; mark_loop_if @@ -92,10 +92,10 @@ def mark_primes mark_primes_ptr, primes_ptr_n, p_is_add_4, p_2dw_offset, p_4dw_o // if n < 2, print nothing and exit. if n == 2 print 2 and exit. else, print 2,3 and continue. -def handle_small_n n @ less_then_2, equals_2, print_2_3_then_start, TWO, continue_address { - hex.cmp hw, n, TWO, less_then_2, equals_2, print_2_3_then_start +def handle_small_n n @ less_than_2, equals_2, print_2_3_then_start, TWO, continue_address { + hex.cmp hw, n, TWO, less_than_2, equals_2, print_2_3_then_start - less_then_2: + less_than_2: stl.output NUMBER_OF_PRIMES_MESSAGE stl.output "0\n" stl.loop @@ -209,7 +209,7 @@ def if1_ptr hex_ptr, l1 @ l0 { // if *hex_ptr == 0 goto l0, else goto l1. def if_ptr hex_ptr, l0, l1 @ ptr_value { hex.zero ptr_value - hex.xor_from_ptr ptr_value, hex_ptr + hex.xor_hex_from_ptr ptr_value, hex_ptr hex.if ptr_value, l0, l1 ptr_value: hex.hex From c5a5b5fc441812c23a81e980a2a810b39357d363 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 7 Oct 2023 20:48:21 +0300 Subject: [PATCH 04/12] hex_bubble_sort tests, push/pop use the new {read/write}_{hex/byte} n / xor_hex_to n macros All new macros are tested but the following (the byte macros): - read_byte_and_inc / read_byte / read_byte n - write_byte_and_inc / write_byte / write_byte n --- flipjump/stl/hex/input.fj | 8 ++ flipjump/stl/hex/pointers.fj | 21 ++++ flipjump/stl/hex/stack_pointers.fj | 49 +++++++- programs/sorts/hex_bubble_sort.fj | 113 ++++++++++++++++++ .../utils/_swap_adjacent_using_writes.fj | 12 ++ .../sorts/utils/_swap_adjacent_using_xors.fj | 13 ++ tests/inout/sorts/hex_bubble_sort_1.in | 1 + tests/inout/sorts/hex_bubble_sort_1.out | 1 + tests/inout/sorts/hex_bubble_sort_2.in | 1 + tests/inout/sorts/hex_bubble_sort_2.out | 1 + tests/test_compile_slow.csv | 3 + tests/test_run_slow.csv | 3 + 12 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 programs/sorts/hex_bubble_sort.fj create mode 100644 programs/sorts/utils/_swap_adjacent_using_writes.fj create mode 100644 programs/sorts/utils/_swap_adjacent_using_xors.fj create mode 100644 tests/inout/sorts/hex_bubble_sort_1.in create mode 100644 tests/inout/sorts/hex_bubble_sort_1.out create mode 100644 tests/inout/sorts/hex_bubble_sort_2.in create mode 100644 tests/inout/sorts/hex_bubble_sort_2.out diff --git a/flipjump/stl/hex/input.fj b/flipjump/stl/hex/input.fj index b895756..fd4d268 100644 --- a/flipjump/stl/hex/input.fj +++ b/flipjump/stl/hex/input.fj @@ -84,4 +84,12 @@ ns hex { upper: .hex end: } + + // Time Complexity: n(7@+11) + // Space Complexity: n(8.5@+92) + // hex[:n] = hex_from_ascii(input(n-bytes)) + // *supports 0-9,a-f,A-F. if can't cast, jumps to error. + def input_as_hex n, hex, error { + rep(n, i) .input_as_hex hex + (n-1-i)*dw, error + } } diff --git a/flipjump/stl/hex/pointers.fj b/flipjump/stl/hex/pointers.fj index fe30ce7..5571fbf 100644 --- a/flipjump/stl/hex/pointers.fj +++ b/flipjump/stl/hex/pointers.fj @@ -155,7 +155,26 @@ ns hex { .pointers.xor_hex_to_flip_ptr hex } + // Time Complexity: w(0.5@+2) + 5@+12 + // Space Complexity: w(0.5@+14) + 5@+76 + // like: hex.xor *ptr[:n], hex[:n] + // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. + def xor_hex_to_ptr n, ptr, hex { + rep(n, i) .pointers.xor_hex_to_ptr_and_inc ptr, hex + i*dw + .ptr_sub ptr, n + } + ns pointers { + // Time Complexity: w(0.5@+2) + 5@+12 + // Space Complexity: w(0.5@+14) + 5@+76 + // like: hex.xor *ptr, hex + // ptr += dw + // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. + def xor_hex_to_ptr_and_inc ptr, hex { + ..xor_hex_to_ptr ptr, hex + ..ptr_inc ptr + } + // Time Complexity: 5@+12 // Space Complexity: 5@+76 // xors (the parameter hex) the hex pointed by the memory-word hex.pointers.to_flip. @@ -293,6 +312,8 @@ ns hex { // Read & Write memory. +// TODO document + ns hex { // like: dst = *ptr diff --git a/flipjump/stl/hex/stack_pointers.fj b/flipjump/stl/hex/stack_pointers.fj index 8f7e422..ac8fe15 100644 --- a/flipjump/stl/hex/stack_pointers.fj +++ b/flipjump/stl/hex/stack_pointers.fj @@ -100,7 +100,6 @@ ns hex { def push_hex hex < hex.pointers.sp { .sp_inc .write_hex hex.pointers.sp, hex -// .xor_hex_to_ptr hex.pointers.sp, hex } // Time Complexity: n(w(0.5@+2) + 14@+26) @@ -154,3 +153,51 @@ ns hex { rep(n, i) .pop_hex hex+(n-1-i)*dw } } + + + +// ---------- Read Write Pointers +// TODO document +// TODO add all changes (including new pointers, new debugs. look at commits to not miss anything) to READMEs and esolangs. + +ns hex { + def read_hex_and_inc dst, ptr { + .read_hex dst, ptr + .ptr_inc ptr + } + + def read_hex n, dst, ptr { + rep(n, i) .read_hex_and_inc dst + i*dw, ptr + .ptr_sub ptr, n + } + + def read_byte_and_inc dst, ptr { + .read_byte dst, ptr + .ptr_inc ptr + } + + def read_byte n, dst, ptr { + rep(n, i) .read_byte_and_inc dst + i*2*dw, ptr + .ptr_sub ptr, n + } + + def write_hex_and_inc ptr, src { + .write_hex ptr, src + .ptr_inc ptr + } + + def write_hex n, ptr, src { + rep(n, i) .write_hex_and_inc ptr, src + i*dw + .ptr_sub ptr, n + } + + def write_byte_and_inc ptr, src { + .write_byte ptr, src // TODO implement write_byte + .ptr_inc ptr + } + + def write_byte n, ptr, src { + rep(n, i) .write_byte_and_inc ptr, src + i*dw + .ptr_sub ptr, n + } +} diff --git a/programs/sorts/hex_bubble_sort.fj b/programs/sorts/hex_bubble_sort.fj new file mode 100644 index 0000000..6dcdb72 --- /dev/null +++ b/programs/sorts/hex_bubble_sort.fj @@ -0,0 +1,113 @@ +// This program inputs hexadecimal numbers (separated by spaces), sorts them, and prints them back sorted. +// The sorting algorithm is bubble-sort. + +// This program is expected to compile with another file that defines the next macro: +// swap_adjacent entry_length, array_ptr, small_index_num, big_index_num +// This macro can be found in the two "./utils/_swap_adjacent_using_*.fj files. +// +// This program tests the read_hex macro, and the write_hex / xor_hex_to_ptr macros (based on the swap_adjacent implementation). + + +ARRAY_LEN = 11 +HEX_LEN = 4 +hw = w/4 + + +// Code: + +stl.startup_and_init_all +input_array + +bubble_sort + +print_array +stl.loop + + +// Variables: + +array: hex.vec HEX_LEN * ARRAY_LEN + + +// Macros: + +// Sorts the array (ARRAY_LEN hex entries, each of size HEX_LEN) using the bubble sort algorithm. +def bubble_sort @ phase_loop, index_loop, finish_index_loop, swapped_flag, i, j, array_ptr, end < array { + hex.set hw, i, ARRAY_LEN - 1 + phase_loop: + hex.zero hw, j + hex.set hw, array_ptr, array + hex.zero swapped_flag + index_loop: + swap_if_needed array_ptr, swapped_flag + hex.inc hw, j + hex.ptr_add array_ptr, HEX_LEN + hex.cmp hw, j, i, index_loop, finish_index_loop, finish_index_loop + finish_index_loop: + + hex.dec hw, i + hex.if0 hw, i, end + hex.if swapped_flag, end, phase_loop + +swapped_flag: bit.bit +i: hex.vec hw +j: hex.vec hw +array_ptr: hex.vec hw + + end: +} + + +// swaps *ptr[:HEX_LEN] with *ptr[HEX_LEN:2*HEX_LEN] if the first is bigger than the latter. +def swap_if_needed array_ptr, swapped_flag @ small_index_num, big_index_num, swap, end { + hex.read_hex 2 * HEX_LEN, small_index_num, array_ptr + hex.cmp HEX_LEN, small_index_num, big_index_num, end, end, swap + + swap: + bit.one swapped_flag + swap_adjacent HEX_LEN, array_ptr, small_index_num, big_index_num + ;end + + small_index_num: + hex.vec HEX_LEN + big_index_num: + hex.vec HEX_LEN + + end: +} + + +// dst = hex(input(1-byte)). if it's not an hex digit - jump to error. +def input_one_variable dst, error @ garbage, end { + hex.input_as_hex HEX_LEN, dst, error + hex.input garbage + ;end + garbage: hex.vec 2 + end: +} + + +// array[:ARRAY_LEN] = hex(input(ARRAY_LEN-bytes)). If any char isn't an hex digit - print an error and exit. +def input_array @ error, end < array { + rep(ARRAY_LEN, i) input_one_variable array + i*HEX_LEN*dw, error + ;end + + error: + stl.output "Couldn't parse the input as hexadecimal numbers.\n" + stl.loop + + end: +} + + +// print the src[:HEX_LEN] in its hexadecimal form. +def print_one_variable src, is_end_of_line { + hex.print_as_digit HEX_LEN, src, 0 + stl.output is_end_of_line ? '\n' : ' ' +} + + +// print every hexadecimal number[:HEX_LEN] in the entire array. +def print_array < array { + rep(ARRAY_LEN, i) print_one_variable array + i*HEX_LEN*dw, i == ARRAY_LEN-1 +} diff --git a/programs/sorts/utils/_swap_adjacent_using_writes.fj b/programs/sorts/utils/_swap_adjacent_using_writes.fj new file mode 100644 index 0000000..52e1c41 --- /dev/null +++ b/programs/sorts/utils/_swap_adjacent_using_writes.fj @@ -0,0 +1,12 @@ +// Compile this file with the bubble_sort programs. +// This file implements the swap_adjacent macro +// (swaps *array_ptr[:entry_length] with *array_ptr[entry_length:2*entry_length]) +// Using the hex.write_hex function (it's a slower implementation than the one with hex.xor_hex_to_ptr). + + +def swap_adjacent entry_length, array_ptr, small_index_num, big_index_num { + hex.write_hex entry_length, array_ptr, big_index_num + hex.ptr_add array_ptr, entry_length + hex.write_hex entry_length, array_ptr, small_index_num + hex.ptr_sub array_ptr, entry_length +} diff --git a/programs/sorts/utils/_swap_adjacent_using_xors.fj b/programs/sorts/utils/_swap_adjacent_using_xors.fj new file mode 100644 index 0000000..69c08d3 --- /dev/null +++ b/programs/sorts/utils/_swap_adjacent_using_xors.fj @@ -0,0 +1,13 @@ +// Compile this file with the bubble_sort programs. +// This file implements the swap_adjacent macro +// (swaps *array_ptr[:entry_length] with *array_ptr[entry_length:2*entry_length]) +// Using the hex.xor_hex_to_ptr function (it's a faster implementation than the one with hex.write_hex). + + +def swap_adjacent entry_length, array_ptr, small_index_num, big_index_num { + hex.xor entry_length, small_index_num, big_index_num + hex.xor_hex_to_ptr entry_length, array_ptr, small_index_num + hex.ptr_add array_ptr, entry_length + hex.xor_hex_to_ptr entry_length, array_ptr, small_index_num + hex.ptr_sub array_ptr, entry_length +} diff --git a/tests/inout/sorts/hex_bubble_sort_1.in b/tests/inout/sorts/hex_bubble_sort_1.in new file mode 100644 index 0000000..b07910f --- /dev/null +++ b/tests/inout/sorts/hex_bubble_sort_1.in @@ -0,0 +1 @@ +f5fe cf62 aed8 b2fd 7bbc aae5 121c 9e00 9e00 7f17 0cdf diff --git a/tests/inout/sorts/hex_bubble_sort_1.out b/tests/inout/sorts/hex_bubble_sort_1.out new file mode 100644 index 0000000..dba3450 --- /dev/null +++ b/tests/inout/sorts/hex_bubble_sort_1.out @@ -0,0 +1 @@ +0cdf 121c 7bbc 7f17 9e00 9e00 aae5 aed8 b2fd cf62 f5fe diff --git a/tests/inout/sorts/hex_bubble_sort_2.in b/tests/inout/sorts/hex_bubble_sort_2.in new file mode 100644 index 0000000..3c1caf5 --- /dev/null +++ b/tests/inout/sorts/hex_bubble_sort_2.in @@ -0,0 +1 @@ +85ec 27bd 8925 e26c 56a6 9929 d2fd b137 bd93 5343 f83d diff --git a/tests/inout/sorts/hex_bubble_sort_2.out b/tests/inout/sorts/hex_bubble_sort_2.out new file mode 100644 index 0000000..7f79b81 --- /dev/null +++ b/tests/inout/sorts/hex_bubble_sort_2.out @@ -0,0 +1 @@ +27bd 5343 56a6 85ec 8925 9929 b137 bd93 d2fd e26c f83d diff --git a/tests/test_compile_slow.csv b/tests/test_compile_slow.csv index 808f3fc..469350b 100644 --- a/tests/test_compile_slow.csv +++ b/tests/test_compile_slow.csv @@ -16,3 +16,6 @@ pair_ns3, programs/concept_checks/pair_ns.fj | programs/pair_ns_tests/test3.fj,t series_sum, programs/simple_math_checks/series_sum.fj,tests/compiled/simple_math_checks/series_sum.fjm, 64,3,0, True,True prime_sieve, programs/prime_sieve.fj,tests/compiled/prime_sieve.fjm, 64,3,0, True,True + +bubble_sort__write_hex, programs/sorts/hex_bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_writes.fj,tests/compiled/sorts/bubble_sort__write_hex.fjm, 64,3,0, True,True +bubble_sort__xor_hex , programs/sorts/hex_bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_xors.fj ,tests/compiled/sorts/bubble_sort__xor_hex.fjm , 64,3,0, True,True diff --git a/tests/test_run_slow.csv b/tests/test_run_slow.csv index 594108e..cfd6a17 100644 --- a/tests/test_run_slow.csv +++ b/tests/test_run_slow.csv @@ -48,3 +48,6 @@ prime_sieve_err_abc, tests/compiled/prime_sieve.fjm, tests/inout/prime_sieve_tes prime_sieve_err_empty, tests/compiled/prime_sieve.fjm, tests/inout/prime_sieve_tests/primes_err_empty.in,tests/inout/prime_sieve_tests/primes_err_bad_number.out, False,False prime_sieve_err_minus5, tests/compiled/prime_sieve.fjm, tests/inout/prime_sieve_tests/primes_err_minus5.in,tests/inout/prime_sieve_tests/primes_err_bad_number.out, False,False +bubble_sort__write_hex_1, tests/compiled/sorts/bubble_sort__write_hex.fjm, tests/inout/sorts/hex_bubble_sort_1.in,tests/inout/sorts/hex_bubble_sort_1.out, False,False +bubble_sort__xor_hex_1, tests/compiled/sorts/bubble_sort__xor_hex.fjm, tests/inout/sorts/hex_bubble_sort_1.in,tests/inout/sorts/hex_bubble_sort_1.out, False,False +bubble_sort__xor_hex_2, tests/compiled/sorts/bubble_sort__xor_hex.fjm, tests/inout/sorts/hex_bubble_sort_2.in,tests/inout/sorts/hex_bubble_sort_2.out, False,False From 1d7414fd2a30623939c99d6f56d80b646ea3efe6 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 17 Nov 2023 17:32:27 +0200 Subject: [PATCH 05/12] split hex.pointers into stl/hex/pointers directory - fix write_byte macro - documented here and in esolangs --- README.md | 1 + flipjump/README.md | 8 +- flipjump/stl/README.md | 4 +- flipjump/stl/conf.json | 10 +- flipjump/stl/hex/pointers.fj | 351 ------------------ flipjump/stl/hex/pointers/basic_pointers.fj | 111 ++++++ .../stl/hex/pointers/pointer_arithmetics.fj | 38 ++ flipjump/stl/hex/pointers/read_pointers.fj | 47 +++ .../{stack_pointers.fj => pointers/stack.fj} | 89 ----- flipjump/stl/hex/pointers/write_pointers.fj | 58 +++ flipjump/stl/hex/pointers/xor_from_pointer.fj | 56 +++ flipjump/stl/hex/pointers/xor_to_pointer.fj | 181 +++++++++ programs/sorts/hex_bubble_sort.fj | 2 + programs/sorts/utils/_byte_memory_access.fj | 22 ++ programs/sorts/utils/_hex_memory_access.fj | 22 ++ tests/README.md | 2 + tests/test_compile_slow.csv | 4 +- 17 files changed, 558 insertions(+), 448 deletions(-) delete mode 100644 flipjump/stl/hex/pointers.fj create mode 100644 flipjump/stl/hex/pointers/basic_pointers.fj create mode 100644 flipjump/stl/hex/pointers/pointer_arithmetics.fj create mode 100644 flipjump/stl/hex/pointers/read_pointers.fj rename flipjump/stl/hex/{stack_pointers.fj => pointers/stack.fj} (65%) create mode 100644 flipjump/stl/hex/pointers/write_pointers.fj create mode 100644 flipjump/stl/hex/pointers/xor_from_pointer.fj create mode 100644 flipjump/stl/hex/pointers/xor_to_pointer.fj create mode 100644 programs/sorts/utils/_byte_memory_access.fj create mode 100644 programs/sorts/utils/_hex_memory_access.fj diff --git a/README.md b/README.md index b7e09ca..0d1780f 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,7 @@ Programs won't work on their first run. They just can't. That's why we support t - `-b NAME [NAME ...]`: Places breakpoints at every specified label NAMEs (note that label names are long: [more information about labels](flipjump/README.md#generated-label-names)). (requires `-b`) - `-B NAME [NAME ...]`: Places breakpoints at every label that contains one of the given NAMEs. (requires `-b`) +The debugger can single-step, read-memory, read flipjump variables (bit/hex/byte, and their vectors), continue, or skip forward a fixed number of opcodes. # Get Started with FlipJump - Install flipjump: `pip install flipjump` diff --git a/flipjump/README.md b/flipjump/README.md index 7b8bbad..a559561 100644 --- a/flipjump/README.md +++ b/flipjump/README.md @@ -24,11 +24,15 @@ The whole interpretation is done within the [run()](interpretter/fjm_run.py) fun More about [how to run](../README.md#how-to-run). ![Running the compiled calculator](../res/calc__run.jpg) -The Interpreter has a built-in debugger, and it's activated by specifying breakpoints when called (via the [breakpoints.py](interpretter/debugging/breakpoints.py)'s `BreakpointHandler`). -The debugger can stop on the next breakpoint, or on a fixed number of executed ops after the current breakpoint. +### The Debugger + +The Interpreter has a built-in debugger, and it's activated by specifying breakpoints when called (via the [breakpoints.py](interpretter/debugging/breakpoints.py)'s `BreakpointHandler`). +The debugger can stop on the next breakpoint, read memory, read flipjump variables, or on a fixed number of executed ops after the current breakpoint. In order to call the debugger with the right labels, get familiar with the [generating label names](README.md#Generated-Label-Names) (and see the debugger-image there), and use the `-d`/`-b`/`-B` cli options. More about [how to debug](../README.md#how-to-debug). +### Macro Usage + The [macro_usage_graph.py](interpretter/debugging/macro_usage_graph.py) file exports a feature to present the macro-usage (which are the most used macros, and what % do they take from the overall flipjump ops) in a graph. In order to view it, run the assembler with `--stats` (requires plotly to be installed (installed automatically with `pip install flipjump[stats]`)). For example: diff --git a/flipjump/stl/README.md b/flipjump/stl/README.md index 9df3006..395355e 100644 --- a/flipjump/stl/README.md +++ b/flipjump/stl/README.md @@ -48,9 +48,9 @@ Offers macros for manipulating hexadecimal variables and vectors (i.e. numbers): - [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 -- [stack_pointers.fj](hex/stack_pointers.fj) - hex-vec pointers / stack operations: 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 +- [pointers/](hex/pointers/) - hex-vec pointers subdirectory: [flip](hex/pointers/xor_to_pointer.fj), [jump](hex/pointers/basic_pointers.fj), [xor_to](hex/pointers/xor_to_pointer.fj), [xor_from](hex/pointers/xor_from_pointer.fj); [stack](hex/pointers/stack.fj)/[pointers](hex/pointers/basic_pointers.fj) init. [pointer arithmetics](hex/pointers/pointer_arithmetics.fj), [stack arithmetics + push/pop](hex/pointers/stack.fj). + ### [mathlib.fj](mathlib.fj) Offers multiplication and division macros for bit/hex variables. diff --git a/flipjump/stl/conf.json b/flipjump/stl/conf.json index 40cb222..64d7754 100644 --- a/flipjump/stl/conf.json +++ b/flipjump/stl/conf.json @@ -21,8 +21,14 @@ "hex/tables_init", "hex/input", "hex/output", - "hex/pointers", - "hex/stack_pointers", + + "hex/pointers/basic_pointers", + "hex/pointers/xor_to_pointer", + "hex/pointers/xor_from_pointer", + "hex/pointers/read_pointers", + "hex/pointers/write_pointers", + "hex/pointers/stack", + "hex/pointers/pointer_arithmetics", "casting", "ptrlib", diff --git a/flipjump/stl/hex/pointers.fj b/flipjump/stl/hex/pointers.fj deleted file mode 100644 index 5571fbf..0000000 --- a/flipjump/stl/hex/pointers.fj +++ /dev/null @@ -1,351 +0,0 @@ -// ---------- Jump: - - - -ns hex { - ns pointers { - // NOTE: must be placed just after the startup, so that the read_ptr_byte_table will be in address 256. - // - // Space Complexity: w/2+261 - // Initializes the global opcodes and pointer-copies required for the pointers macros. - // Initializes the read-byte-handling table and the result/return variables to the read-byte table. - // - // @output-param read_byte: hex[:2] variable. You want to zero it before jumping into ptr_jump. - // After jumping into ptr_jump, it's xored with the read byte. - // @output_param ret_after_read_byte: The return address. Jumps to it after finishing reading a byte. - // - // @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 @ read_ptr_byte_table > to_flip, to_jump, to_flip_var, to_jump_var, \ - read_byte, ret_after_read_byte { - pad 256 - // Time Complexity: 4/8 (when jumping to hex.pointers.to_jump, until finished) - // (4 is for reading from an hex memory, 8 is for byte memory). - read_ptr_byte_table: - rep(256, d) stl.fj \ - d==0?0: (.read_byte+dbit+(#d)-1), \ - (d==((1<<(#d))>>1)) ? .ret_after_read_byte : read_ptr_byte_table+(d^((1<<(#d))>>1))*dw - - read_byte: - hex.vec 2 - ret_after_read_byte: - ;0 - - to_flip: - 0;0 - to_jump: - ;0 - - to_flip_var: - hex.vec w/4, 0 - to_jump_var: - hex.vec w/4, 0 - } - - // Time Complexity: w(0.5@+2) - // Space Complexity: w(0.5@+14) - // Sets both to_jump and to_jump_var to point to the given pointer. - // ( to_jump{_var} = ptr ) - // ptr is a hex[:w/4] that holds an address. - def set_jump_pointer ptr < .to_jump, .to_jump_var { - ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, .to_jump_var - ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, ptr - } - - // Time Complexity: w(0.5@+2) - // Space Complexity: w(0.5@+14) - // Sets both to_flip and to_flip_var to point to the given pointer. - // ( to_flip{_var} = ptr ) - // ptr is a hex[:w/4] that holds an address. - def set_flip_pointer ptr < .to_flip, .to_flip_var { - ..address_and_variable_xor w/4, .to_flip, .to_flip_var, .to_flip_var - ..address_and_variable_xor w/4, .to_flip, .to_flip_var, ptr - } - - // Time Complexity: w(0.75@+5) - // Space Complexity: w(0.75@+29) - // Sets both to_flip and to_flip_var, and to_jump and to_jump_var to point to the given pointer. - // ( to_flip{_var} = ptr ) - // ( to_jump{_var} = ptr ) - // ptr is a hex[:w/4] that holds an address. - def set_flip_and_jump_pointers ptr < .to_flip, .to_flip_var, .to_jump, .to_jump_var { - ..address_and_variable_xor w/4, .to_flip, .to_flip_var, .to_flip_var - ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, .to_jump_var - ..address_and_variable_double_xor w/4, .to_flip, .to_flip_var, .to_jump+w, .to_jump_var, ptr - } - - // Space Complexity: n+w/4 + 330 - // Initializes a stack of size n (maximal capacity of n hexes / return-addresses). - // n is the size of the stack. - // @output-param sp: the stack pointer. sp always points to the last pushed value (at start - to stack[-1]) - // @output-param stack: the global stack. - def stack_init n @ stack_error_handler > sp, stack { - sp: - hex.vec w/4, .stack - - pad w - stack: - hex.hex stack_error_handler - hex.vec n, 0 - - stack_error_handler: - stl.output "\n\nERROR: You returned on an empty stack.\n" - ;0 // (would fail, so the stack trace would be printed). - } - } -} - - -ns hex { - // Time Complexity: w(0.5@+2) - // Space Complexity: w(0.5@+14) - // like: ;*ptr - // Jump to the address the pointer points to. - // ptr is a hex[:w/4] that holds an address. - def ptr_jump ptr < hex.pointers.to_jump { - .pointers.set_jump_pointer ptr - ;hex.pointers.to_jump - } -} - - - -// ---------- Flip: - - -ns hex { - // Time Complexity: w(0.5@+2) + @ - // Space Complexity: w(0.5@+14) + @ - // like: *ptr; - // Flip the address the pointer points to. - // ptr is a hex[:w/4] that holds an address. - def ptr_flip ptr @ cleanup < hex.pointers.to_flip { - wflip hex.pointers.to_flip+w, cleanup - - .pointers.set_flip_pointer ptr - ;hex.pointers.to_flip - - pad 4 - cleanup: - wflip hex.pointers.to_flip+w, cleanup - } - - - // Time Complexity: w(0.5@+2) + @+6 - // Space Complexity: w(0.5@+14) + @+6 - // The stl.comp_flip_if executes in ~##w, which should be much less than @/2 operations. - // like: (*ptr)+dbit; - // Flip the address dbit-ahead of what the pointer points to. - // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. - def ptr_flip_dbit ptr < .pointers.to_flip { - wflip .pointers.to_flip, dbit - .ptr_flip ptr - wflip .pointers.to_flip, dbit - } - - - // Time Complexity: w(0.5@+2) + 5@+12 - // Space Complexity: w(0.5@+14) + 5@+76 - // like: hex.xor *ptr, hex - // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. - def xor_hex_to_ptr ptr, hex { - .pointers.set_flip_pointer ptr - .pointers.xor_hex_to_flip_ptr hex - } - - // Time Complexity: w(0.5@+2) + 5@+12 - // Space Complexity: w(0.5@+14) + 5@+76 - // like: hex.xor *ptr[:n], hex[:n] - // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. - def xor_hex_to_ptr n, ptr, hex { - rep(n, i) .pointers.xor_hex_to_ptr_and_inc ptr, hex + i*dw - .ptr_sub ptr, n - } - - ns pointers { - // Time Complexity: w(0.5@+2) + 5@+12 - // Space Complexity: w(0.5@+14) + 5@+76 - // like: hex.xor *ptr, hex - // ptr += dw - // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. - def xor_hex_to_ptr_and_inc ptr, hex { - ..xor_hex_to_ptr ptr, hex - ..ptr_inc ptr - } - - // Time Complexity: 5@+12 - // Space Complexity: 5@+76 - // xors (the parameter hex) the hex pointed by the memory-word hex.pointers.to_flip. - // use after: .pointers.set_flip_pointer ptr - // does: .xor *ptr, hex (as it uses the address in to_flip) - // It assumes that the value in the memory-word to_flip is a dw-aligned address to an hex-variable. - def xor_hex_to_flip_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 { - wflip hex.pointers.to_flip+w, after_flip_bit0, prepare_flip_bit0 - - prepare_flip_bit0: - wflip hex.pointers.to_flip, dbit+0 - hex.if_flags hex, 0xAAAA, after_flip_bit0, hex.pointers.to_flip - prepare_flip_bit1: - wflip hex.pointers.to_flip, (dbit+0)^(dbit+1) - hex.if_flags hex, 0xCCCC, after_flip_bit1, hex.pointers.to_flip - prepare_flip_bit3: - wflip hex.pointers.to_flip, (dbit+1)^(dbit+3) - hex.if_flags hex, 0xFF00, after_flip_bit3, hex.pointers.to_flip - prepare_flip_bit2: - wflip hex.pointers.to_flip, (dbit+3)^(dbit+2) - hex.if_flags hex, 0xF0F0, after_flip_bit2, hex.pointers.to_flip - - pad 4 - after_flip_bit0: - hex.pointers.to_flip+dbit+0;prepare_flip_bit1 - after_flip_bit1: - hex.pointers.to_flip+dbit+1;prepare_flip_bit3 - after_flip_bit2: - wflip hex.pointers.to_flip, dbit+2, cleanup - after_flip_bit3: - hex.pointers.to_flip+dbit+0;prepare_flip_bit2 - - cleanup: - wflip hex.pointers.to_flip+w, after_flip_bit2 - } - } - - // Time Complexity: w(1.5@+5) - // Space Complexity: w(1.5@+17) - // like: wflip *ptr, value - // ptr is a hex[:w/4] that holds an address, which we assume is w-aligned. - def ptr_wflip ptr, value { - .pointers.set_flip_pointer ptr - rep(w, i) .pointers.advance_by_one_and_flip__ptr_wflip (#(i^((i+1)%w))), (value>>i)&1 - } - ns pointers { - // Advances *to_flip by 1 (which takes n flips, from bit0 to bit1, bit2,...). - // If do_flip (value) isn't 0 - than make a flip, like: to_flip;advance. - def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < hex.pointers.to_flip { - stl.comp_if0 do_flip, advance - wflip hex.pointers.to_flip+w, cleanup, hex.pointers.to_flip - cleanup: - wflip hex.pointers.to_flip+w, cleanup, advance - - pad 4 - advance: - rep(n, i) bit.exact_not hex.pointers.to_flip+i - } - } - - // Time Complexity: w(1.5@+5) - // Space Complexity: w(1.5@+17) - // like: wflip (*ptr)+w, value - // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. - def ptr_wflip_2nd_word ptr, value { - ptr+dbit + ((#w-1)/4)*dw + (#w-1)%4; - hex.ptr_wflip ptr, value - ptr+dbit + ((#w-1)/4)*dw + (#w-1)%4; - } -} - - - -// ---------- Xor - - -ns hex { - // Time Complexity: w(0.75@+ 5) + 6@+13 - // Space Complexity: w(0.75@+29) + 6@+36 - // 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_hex_from_ptr dst, ptr < hex.pointers.read_byte { - .pointers.set_flip_and_jump_pointers ptr - .pointers.read_byte_from_inners_ptrs - .xor dst, hex.pointers.read_byte - } - - // Time Complexity: w(0.75@+ 5) + 7@+13 - // Space Complexity: w(0.75@+29) + 7@+48 - // like: dst[:2] ^= *ptr - // dst is a hex[2:]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. - def xor_byte_from_ptr dst, ptr < hex.pointers.read_byte { - .pointers.set_flip_and_jump_pointers ptr - .pointers.read_byte_from_inners_ptrs - .xor 2, dst, hex.pointers.read_byte - } - - ns pointers { - // Time Complexity: 5@+13 - // Space Complexity: 5@+24 - // use after: hex.pointers.set_flip_and_jump_pointers ptr - // does: hex.pointers.read_byte[:2] = *ptr - // - // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. - def read_byte_from_inners_ptrs @ read_ptr_and_flip_back, cleanup \ - < hex.pointers.ret_after_read_byte, hex.pointers.read_byte, hex.pointers.to_jump, hex.pointers.to_flip { - // 1. setup: - // zero read_byte. - // to_flip = ptr + dbit+8. - // to_jump+w = ptr. - hex.zero 2, hex.pointers.read_byte - wflip hex.pointers.to_flip, dbit+8 - - // 2. *(ptr+w)^=256, so that now *(ptr+w) == 256 + original_value. - wflip hex.pointers.to_flip+w, read_ptr_and_flip_back, hex.pointers.to_flip - - pad 4 - read_ptr_and_flip_back: - // 3. Jump to *(ptr+w). It will xor the pointed original_value byte into hex.pointers.read_byte. - // 4. Then jump to hex.pointers.to_flip to make *(ptr+w)==original_value back again. - // 5. Then return to cleanup. - wflip hex.pointers.to_flip+w, read_ptr_and_flip_back^cleanup - wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip, hex.pointers.to_jump - - cleanup: - // 6. to_flip = ptr, clean jump-back addresses. - wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip - wflip hex.pointers.to_flip, dbit+8 - wflip hex.pointers.to_flip+w, cleanup - } - } -} - - - -// Read & Write memory. -// TODO document - - -ns hex { - // like: dst = *ptr - def read_hex dst, ptr { - .zero dst - .xor_hex_from_ptr dst, ptr - } - - // like: *ptr = src - def write_hex ptr, src < hex.pointers.read_byte { - .pointers.set_flip_and_jump_pointers ptr - .pointers.read_byte_from_inners_ptrs - .xor hex.pointers.read_byte, src - .pointers.xor_hex_to_flip_ptr hex.pointers.read_byte - } - - // like: dst[:2] = *ptr - def read_byte dst, ptr { - .zero 2, dst - .xor_byte_from_ptr dst, ptr - } - - // like: *ptr = 0 - def zero_ptr ptr < hex.pointers.read_byte { - .pointers.set_flip_and_jump_pointers ptr - .pointers.read_byte_from_inners_ptrs - .pointers.xor_hex_to_flip_ptr hex.pointers.read_byte // TODO make xor_byte_to_flip_ptr - } - -// // like: *ptr = src[:2] -// def write_byte ptr, src { -// .zero 2, dst -// .xor_byte_from_ptr dst, ptr -// } -} diff --git a/flipjump/stl/hex/pointers/basic_pointers.fj b/flipjump/stl/hex/pointers/basic_pointers.fj new file mode 100644 index 0000000..953d9c9 --- /dev/null +++ b/flipjump/stl/hex/pointers/basic_pointers.fj @@ -0,0 +1,111 @@ +ns hex { + ns pointers { + // NOTE: must be placed just after the startup, so that the read_ptr_byte_table will be in address 256. + // + // Space Complexity: w/2+261 + // Initializes the global opcodes and pointer-copies required for the pointers macros. + // Initializes the read-byte-handling table and the result/return variables to the read-byte table. + // + // @output-param read_byte: hex[:2] variable. You want to zero it before jumping into ptr_jump. + // After jumping into ptr_jump, it's xored with the read byte. + // @output_param ret_after_read_byte: The return address. Jumps to it after finishing reading a byte. + // + // @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 @ read_ptr_byte_table > to_flip, to_jump, to_flip_var, to_jump_var, \ + read_byte, ret_after_read_byte { + pad 256 + // Time Complexity: 4/8 (when jumping to hex.pointers.to_jump, until finished) + // (4 is for reading from an hex memory, 8 is for byte memory). + read_ptr_byte_table: + rep(256, d) stl.fj \ + d==0?0: (.read_byte+dbit+(#d)-1), \ + (d==((1<<(#d))>>1)) ? .ret_after_read_byte : read_ptr_byte_table+(d^((1<<(#d))>>1))*dw + + read_byte: + hex.vec 2 + ret_after_read_byte: + ;0 + + to_flip: + 0;0 + to_jump: + ;0 + + to_flip_var: + hex.vec w/4, 0 + to_jump_var: + hex.vec w/4, 0 + } + + // Time Complexity: w(0.5@+2) + // Space Complexity: w(0.5@+14) + // Sets both to_jump and to_jump_var to point to the given pointer. + // ( to_jump{_var} = ptr ) + // ptr is a hex[:w/4] that holds an address. + def set_jump_pointer ptr < .to_jump, .to_jump_var { + ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, .to_jump_var + ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, ptr + } + + // Time Complexity: w(0.5@+2) + // Space Complexity: w(0.5@+14) + // Sets both to_flip and to_flip_var to point to the given pointer. + // ( to_flip{_var} = ptr ) + // ptr is a hex[:w/4] that holds an address. + def set_flip_pointer ptr < .to_flip, .to_flip_var { + ..address_and_variable_xor w/4, .to_flip, .to_flip_var, .to_flip_var + ..address_and_variable_xor w/4, .to_flip, .to_flip_var, ptr + } + + // Time Complexity: w(0.75@+5) + // Space Complexity: w(0.75@+29) + // Sets both to_flip and to_flip_var, and to_jump and to_jump_var to point to the given pointer. + // ( to_flip{_var} = ptr ) + // ( to_jump{_var} = ptr ) + // ptr is a hex[:w/4] that holds an address. + def set_flip_and_jump_pointers ptr < .to_flip, .to_flip_var, .to_jump, .to_jump_var { + ..address_and_variable_xor w/4, .to_flip, .to_flip_var, .to_flip_var + ..address_and_variable_xor w/4, .to_jump+w, .to_jump_var, .to_jump_var + ..address_and_variable_double_xor w/4, .to_flip, .to_flip_var, .to_jump+w, .to_jump_var, ptr + } + + // Space Complexity: n+w/4 + 330 + // Initializes a stack of size n (maximal capacity of n hexes / return-addresses). + // n is the size of the stack. + // @output-param sp: the stack pointer. sp always points to the last pushed value (at start - to stack[-1]) + // @output-param stack: the global stack. + def stack_init n @ stack_error_handler > sp, stack { + sp: + hex.vec w/4, .stack + + pad w + stack: + hex.hex stack_error_handler + hex.vec n, 0 + + stack_error_handler: + stl.output "\n\nERROR: You returned on an empty stack.\n" + ;0 // (would fail, so the stack trace would be printed). + } + } +} + + + +// ---------- Jump: + + +ns hex { + // Time Complexity: w(0.5@+2) + // Space Complexity: w(0.5@+14) + // like: ;*ptr + // Jump to the address the pointer points to. + // ptr is a hex[:w/4] that holds an address. + def ptr_jump ptr < hex.pointers.to_jump { + .pointers.set_jump_pointer ptr + ;hex.pointers.to_jump + } +} diff --git a/flipjump/stl/hex/pointers/pointer_arithmetics.fj b/flipjump/stl/hex/pointers/pointer_arithmetics.fj new file mode 100644 index 0000000..067d4ec --- /dev/null +++ b/flipjump/stl/hex/pointers/pointer_arithmetics.fj @@ -0,0 +1,38 @@ +// ---------- 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 + } +} diff --git a/flipjump/stl/hex/pointers/read_pointers.fj b/flipjump/stl/hex/pointers/read_pointers.fj new file mode 100644 index 0000000..ede0ad6 --- /dev/null +++ b/flipjump/stl/hex/pointers/read_pointers.fj @@ -0,0 +1,47 @@ +// TODO document The entire file + + + +// ---------- Read Pointers + + +ns hex { + // like: dst = *ptr + def read_hex dst, ptr { + .zero dst + .xor_hex_from_ptr dst, ptr + } + + // like: dst[:2] = *ptr + def read_byte dst, ptr { + .zero 2, dst + .xor_byte_from_ptr dst, ptr + } +} + + + +// ---------- Multi Read Pointers + + +ns hex { + def read_hex_and_inc dst, ptr { + .read_hex dst, ptr + .ptr_inc ptr + } + + def read_hex n, dst, ptr { + rep(n, i) .read_hex_and_inc dst + i*dw, ptr + .ptr_sub ptr, n + } + + def read_byte_and_inc dst, ptr { + .read_byte dst, ptr + .ptr_inc ptr + } + + def read_byte n, dst, ptr { + rep(n, i) .read_byte_and_inc dst + i*2*dw, ptr + .ptr_sub ptr, n + } +} diff --git a/flipjump/stl/hex/stack_pointers.fj b/flipjump/stl/hex/pointers/stack.fj similarity index 65% rename from flipjump/stl/hex/stack_pointers.fj rename to flipjump/stl/hex/pointers/stack.fj index ac8fe15..7a1de16 100644 --- a/flipjump/stl/hex/stack_pointers.fj +++ b/flipjump/stl/hex/pointers/stack.fj @@ -1,44 +1,3 @@ -// ---------- 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 @@ -153,51 +112,3 @@ ns hex { rep(n, i) .pop_hex hex+(n-1-i)*dw } } - - - -// ---------- Read Write Pointers -// TODO document -// TODO add all changes (including new pointers, new debugs. look at commits to not miss anything) to READMEs and esolangs. - -ns hex { - def read_hex_and_inc dst, ptr { - .read_hex dst, ptr - .ptr_inc ptr - } - - def read_hex n, dst, ptr { - rep(n, i) .read_hex_and_inc dst + i*dw, ptr - .ptr_sub ptr, n - } - - def read_byte_and_inc dst, ptr { - .read_byte dst, ptr - .ptr_inc ptr - } - - def read_byte n, dst, ptr { - rep(n, i) .read_byte_and_inc dst + i*2*dw, ptr - .ptr_sub ptr, n - } - - def write_hex_and_inc ptr, src { - .write_hex ptr, src - .ptr_inc ptr - } - - def write_hex n, ptr, src { - rep(n, i) .write_hex_and_inc ptr, src + i*dw - .ptr_sub ptr, n - } - - def write_byte_and_inc ptr, src { - .write_byte ptr, src // TODO implement write_byte - .ptr_inc ptr - } - - def write_byte n, ptr, src { - rep(n, i) .write_byte_and_inc ptr, src + i*dw - .ptr_sub ptr, n - } -} diff --git a/flipjump/stl/hex/pointers/write_pointers.fj b/flipjump/stl/hex/pointers/write_pointers.fj new file mode 100644 index 0000000..15639e0 --- /dev/null +++ b/flipjump/stl/hex/pointers/write_pointers.fj @@ -0,0 +1,58 @@ +// TODO document The entire file + + + +// ---------- Write Pointers + + +ns hex { + // like: *ptr = src + def write_hex ptr, src < hex.pointers.read_byte { + .pointers.set_flip_and_jump_pointers ptr + .pointers.read_byte_from_inners_ptrs + .xor hex.pointers.read_byte, src + .pointers.xor_hex_to_flip_ptr hex.pointers.read_byte + } + + // like: *ptr = 0 + def zero_ptr ptr < hex.pointers.read_byte { + .pointers.set_flip_and_jump_pointers ptr + .pointers.read_byte_from_inners_ptrs + .pointers.xor_byte_to_flip_ptr hex.pointers.read_byte + } + + // like: *ptr = src[:2] + def write_byte ptr, src < hex.pointers.read_byte { + .pointers.set_flip_and_jump_pointers ptr + .pointers.read_byte_from_inners_ptrs + .xor 2, hex.pointers.read_byte, src + .pointers.xor_byte_to_flip_ptr hex.pointers.read_byte + } +} + + + +// ---------- Multi Read Write Pointers + + +ns hex { + def write_hex_and_inc ptr, src { + .write_hex ptr, src + .ptr_inc ptr + } + + def write_hex n, ptr, src { + rep(n, i) .write_hex_and_inc ptr, src + i*dw + .ptr_sub ptr, n + } + + def write_byte_and_inc ptr, src { + .write_byte ptr, src + .ptr_inc ptr + } + + def write_byte n, ptr, src { + rep(n, i) .write_byte_and_inc ptr, src + i*dw + .ptr_sub ptr, n + } +} diff --git a/flipjump/stl/hex/pointers/xor_from_pointer.fj b/flipjump/stl/hex/pointers/xor_from_pointer.fj new file mode 100644 index 0000000..18dc916 --- /dev/null +++ b/flipjump/stl/hex/pointers/xor_from_pointer.fj @@ -0,0 +1,56 @@ +ns hex { + // Time Complexity: w(0.75@+ 5) + 6@+13 + // Space Complexity: w(0.75@+29) + 6@+36 + // 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_hex_from_ptr dst, ptr < hex.pointers.read_byte { + .pointers.set_flip_and_jump_pointers ptr + .pointers.read_byte_from_inners_ptrs + .xor dst, hex.pointers.read_byte + } + + // Time Complexity: w(0.75@+ 5) + 7@+13 + // Space Complexity: w(0.75@+29) + 7@+48 + // like: dst[:2] ^= *ptr + // dst is a hex[2:]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. + def xor_byte_from_ptr dst, ptr < hex.pointers.read_byte { + .pointers.set_flip_and_jump_pointers ptr + .pointers.read_byte_from_inners_ptrs + .xor 2, dst, hex.pointers.read_byte + } + + ns pointers { + // Time Complexity: 5@+13 + // Space Complexity: 5@+24 + // use after: hex.pointers.set_flip_and_jump_pointers ptr + // does: hex.pointers.read_byte[:2] = *ptr + // + // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. + def read_byte_from_inners_ptrs @ read_ptr_and_flip_back, cleanup \ + < hex.pointers.ret_after_read_byte, hex.pointers.read_byte, hex.pointers.to_jump, hex.pointers.to_flip { + // 1. setup: + // zero read_byte. + // to_flip = ptr + dbit+8. + // to_jump+w = ptr. + hex.zero 2, hex.pointers.read_byte + wflip hex.pointers.to_flip, dbit+8 + + // 2. *(ptr+w)^=256, so that now *(ptr+w) == 256 + original_value. + wflip hex.pointers.to_flip+w, read_ptr_and_flip_back, hex.pointers.to_flip + + pad 4 + read_ptr_and_flip_back: + // 3. Jump to *(ptr+w). It will xor the pointed original_value byte into hex.pointers.read_byte. + // 4. Then jump to hex.pointers.to_flip to make *(ptr+w)==original_value back again. + // 5. Then return to cleanup. + wflip hex.pointers.to_flip+w, read_ptr_and_flip_back^cleanup + wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip, hex.pointers.to_jump + + cleanup: + // 6. to_flip = ptr, clean jump-back addresses. + wflip hex.pointers.ret_after_read_byte+w, hex.pointers.to_flip + wflip hex.pointers.to_flip, dbit+8 + wflip hex.pointers.to_flip+w, cleanup + } + } +} diff --git a/flipjump/stl/hex/pointers/xor_to_pointer.fj b/flipjump/stl/hex/pointers/xor_to_pointer.fj new file mode 100644 index 0000000..48ca70c --- /dev/null +++ b/flipjump/stl/hex/pointers/xor_to_pointer.fj @@ -0,0 +1,181 @@ +ns hex { + // Time Complexity: w(0.5@+2) + @ + // Space Complexity: w(0.5@+14) + @ + // like: *ptr; + // Flip the address the pointer points to. + // ptr is a hex[:w/4] that holds an address. + def ptr_flip ptr @ cleanup < hex.pointers.to_flip { + wflip hex.pointers.to_flip+w, cleanup + + .pointers.set_flip_pointer ptr + ;hex.pointers.to_flip + + pad 4 + cleanup: + wflip hex.pointers.to_flip+w, cleanup + } + + + // Time Complexity: w(0.5@+2) + @+6 + // Space Complexity: w(0.5@+14) + @+6 + // The stl.comp_flip_if executes in ~##w, which should be much less than @/2 operations. + // like: (*ptr)+dbit; + // Flip the address dbit-ahead of what the pointer points to. + // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. + def ptr_flip_dbit ptr < .pointers.to_flip { + wflip .pointers.to_flip, dbit + .ptr_flip ptr + wflip .pointers.to_flip, dbit + } + + + // Time Complexity: w(0.5@+2) + 5@+12 + // Space Complexity: w(0.5@+14) + 5@+76 + // like: hex.xor *ptr, hex + // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. + def xor_hex_to_ptr ptr, hex { + .pointers.set_flip_pointer ptr + .pointers.xor_hex_to_flip_ptr hex + } + + // Time Complexity: w(0.5@+2) + 10@+24 + // Space Complexity: w(0.5@+14) + 10@+152 + // like: hex.xor *ptr, hex[:2] + // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. + def xor_byte_to_ptr ptr, hex { + .pointers.set_flip_pointer ptr + .pointers.xor_byte_to_flip_ptr hex + } + + // Time Complexity: n(w(0.5@+2) + 14@+26) + // Space Complexity: n(w(0.9@+17) + 10@+131) + // like: hex.xor *ptr[:n], hex[:n] + // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. + def xor_hex_to_ptr n, ptr, hex { + rep(n, i) .pointers.xor_hex_to_ptr_and_inc ptr, hex + i*dw + .ptr_sub ptr, n + } + + // Time Complexity: n(w(0.5@+2) + 19@+38) + // Space Complexity: n(w(0.9@+17) + 15@+207) + // like: hex.xor *ptr[:n], hex[:2n] + // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. + def xor_byte_to_ptr n, ptr, hex { + rep(n, i) .pointers.xor_byte_to_ptr_and_inc ptr, hex + i*2*dw + .ptr_sub ptr, n + } + + ns pointers { + // Time Complexity: w(0.5@+2) + 14@+26 + // Space Complexity: w(0.9@+17) + 10@+131 + // like: hex.xor *ptr, hex + // ptr += dw + // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. + def xor_hex_to_ptr_and_inc ptr, hex { + ..xor_hex_to_ptr ptr, hex + ..ptr_inc ptr + } + + // Time Complexity: w(0.5@+2) + 19@+38 + // Space Complexity: w(0.9@+17) + 15@+207 + // like: hex.xor *ptr, hex[:2] + // ptr += dw + // ptr is a hex[:w/4] that holds an address, which we assume is an hex-variable, which is dw-aligned. + def xor_byte_to_ptr_and_inc ptr, hex { + ..xor_byte_to_ptr ptr, hex + ..ptr_inc ptr + } + + + // Time Complexity: 5@+12 + // Space Complexity: 5@+76 + // xors (the parameter hex) to the hex pointed by the memory-word hex.pointers.to_flip. + // use after: .pointers.set_flip_pointer ptr + // does: .xor *ptr, hex (as it uses the address in to_flip) + // It assumes that the value in the memory-word to_flip is a dw-aligned address to an hex-variable. + def xor_hex_to_flip_ptr hex { + .xor_hex_to_flip_ptr hex, 0 + } + + // Time Complexity: 10@+24 + // Space Complexity: 10@+152 + // xors (the byte hex[2:]) to the byte pointed by the memory-word hex.pointers.to_flip. + // use after: .pointers.set_flip_pointer ptr + // does: .xor *ptr, hex[:2] (as it uses the address in to_flip) + // It assumes that the value in the memory-word to_flip is a dw-aligned address to an hex-variable. + def xor_byte_to_flip_ptr hex { + rep(2, i) .xor_hex_to_flip_ptr hex+i*dw, 4*i + } + + // Time Complexity: 5@+12 + // Space Complexity: 5@+76 + // xors (the parameter hex, shifted left by bit_shift) to the hex/byte pointed by the memory-word hex.pointers.to_flip. + // use after: .pointers.set_flip_pointer ptr + // does: .xor *ptr, hex<>i)&1 + } + ns pointers { + // Advances *to_flip by 1 (which takes n flips, from bit0 to bit1, bit2,...). + // If do_flip (value) isn't 0 - than make a flip, like: to_flip;advance. + def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < hex.pointers.to_flip { + stl.comp_if0 do_flip, advance + wflip hex.pointers.to_flip+w, cleanup, hex.pointers.to_flip + cleanup: + wflip hex.pointers.to_flip+w, cleanup, advance + + pad 4 + advance: + rep(n, i) bit.exact_not hex.pointers.to_flip+i + } + } + + // Time Complexity: w(1.5@+5) + // Space Complexity: w(1.5@+17) + // like: wflip (*ptr)+w, value + // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. + def ptr_wflip_2nd_word ptr, value { + ptr+dbit + ((#w-1)/4)*dw + (#w-1)%4; + hex.ptr_wflip ptr, value + ptr+dbit + ((#w-1)/4)*dw + (#w-1)%4; + } +} diff --git a/programs/sorts/hex_bubble_sort.fj b/programs/sorts/hex_bubble_sort.fj index 6dcdb72..d8dd7d6 100644 --- a/programs/sorts/hex_bubble_sort.fj +++ b/programs/sorts/hex_bubble_sort.fj @@ -10,6 +10,7 @@ ARRAY_LEN = 11 HEX_LEN = 4 +CELL_HEX_LEN = HEX_LEN / HEX_VARS_PER_MEMORY_CELL hw = w/4 @@ -26,6 +27,7 @@ stl.loop // Variables: +array_len: hex.vec hw // TODO as an input, not a constant array: hex.vec HEX_LEN * ARRAY_LEN diff --git a/programs/sorts/utils/_byte_memory_access.fj b/programs/sorts/utils/_byte_memory_access.fj new file mode 100644 index 0000000..2f0642a --- /dev/null +++ b/programs/sorts/utils/_byte_memory_access.fj @@ -0,0 +1,22 @@ +// Compile this file with (and before) the bubble_sort programs. +// This file implements the xor/write-to / read-from pointer macros. +// Using the byte-pointer-access macros (it's a faster implementation than the one with hex-access). + + +HEX_VARS_PER_MEMORY_CELL = 2 + + +// Xor: hex.xor *ptr[:hex_length/2], hex[:hex_length] +def xor_to_ptr hex_length, ptr, variable { + hex.xor_byte_to_ptr hex_length/2, ptr, variable +} + +// Write: *ptr[:hex_length/2] = variable[:hex_length] +def write_to_ptr hex_length, ptr, variable { + hex.write_byte hex_length/2, ptr, variable +} + +// Read: variable[:hex_length] = *ptr[:hex_length/2] +def read_from_ptr hex_length, variable, ptr { + hex.read_byte hex_length/2, variable, ptr +} diff --git a/programs/sorts/utils/_hex_memory_access.fj b/programs/sorts/utils/_hex_memory_access.fj new file mode 100644 index 0000000..88c847a --- /dev/null +++ b/programs/sorts/utils/_hex_memory_access.fj @@ -0,0 +1,22 @@ +// Compile this file with (and before) the bubble_sort programs. +// This file implements the xor/write-to / read-from pointer macros. +// Using the hex-pointer-access macros (it's a slower implementation than the one with bytes-access). + + +HEX_VARS_PER_MEMORY_CELL = 1 + + +// Xor: hex.xor *ptr[:hex_length], hex[:hex_length] +def xor_to_ptr hex_length, ptr, variable { + hex.xor_hex_to_ptr hex_length, ptr, variable +} + +// Write: *ptr[:hex_length] = variable[:hex_length] +def write_to_ptr hex_length, ptr, variable { + hex.write_hex hex_length, ptr, variable +} + +// Read: variable[:hex_length] = *ptr[:hex_length] +def read_from_ptr hex_length, variable, ptr { + hex.read_hex hex_length, variable, ptr +} diff --git a/tests/README.md b/tests/README.md index 531e2e3..c62044a 100644 --- a/tests/README.md +++ b/tests/README.md @@ -51,6 +51,8 @@ You can get the entire "macro-stack" of the last executed addresses to get a bet More information about the labels can be found [here](../flipjump/README.md#generated-label-names). +More information about debugging with flipjump in general: [how to debug](../README.md#how-to-debug). + ### Filter tests by their name You can filter the running tests. No filter means that all the tests in the chosen test type (--regular, --all, etc.) will run. diff --git a/tests/test_compile_slow.csv b/tests/test_compile_slow.csv index 469350b..53d9d5d 100644 --- a/tests/test_compile_slow.csv +++ b/tests/test_compile_slow.csv @@ -17,5 +17,5 @@ series_sum, programs/simple_math_checks/series_sum.fj,tests/compiled/simple_math prime_sieve, programs/prime_sieve.fj,tests/compiled/prime_sieve.fjm, 64,3,0, True,True -bubble_sort__write_hex, programs/sorts/hex_bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_writes.fj,tests/compiled/sorts/bubble_sort__write_hex.fjm, 64,3,0, True,True -bubble_sort__xor_hex , programs/sorts/hex_bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_xors.fj ,tests/compiled/sorts/bubble_sort__xor_hex.fjm , 64,3,0, True,True +bubble_sort__write_hex, programs/sorts/utils/_hex_memory_access.fj | programs/sorts/hex_bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_writes.fj ,tests/compiled/sorts/bubble_sort__write_hex.fjm, 64,3,0, True,True +bubble_sort__xor_hex , programs/sorts/utils/_hex_memory_access.fj | programs/sorts/hex_bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_xors.fj ,tests/compiled/sorts/bubble_sort__xor_hex.fjm , 64,3,0, True,True From 85e7efc6cb105ae34695c7fe1aaef224d4b7976f Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 17 Nov 2023 21:54:26 +0200 Subject: [PATCH 06/12] document read/write pointers, without complexities --- flipjump/stl/hex/pointers/read_pointers.fj | 30 ++++++++++++++++-- flipjump/stl/hex/pointers/write_pointers.fj | 35 ++++++++++++++++++--- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/flipjump/stl/hex/pointers/read_pointers.fj b/flipjump/stl/hex/pointers/read_pointers.fj index ede0ad6..a155850 100644 --- a/flipjump/stl/hex/pointers/read_pointers.fj +++ b/flipjump/stl/hex/pointers/read_pointers.fj @@ -1,4 +1,4 @@ -// TODO document The entire file +// TODO document complexities in the entire file @@ -6,13 +6,19 @@ ns hex { - // like: dst = *ptr + // Time Complexity: + // Space Complexity: + // like: dst = *ptr + // dst is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_hex dst, ptr { .zero dst .xor_hex_from_ptr dst, ptr } - // like: dst[:2] = *ptr + // Time Complexity: + // Space Complexity: + // like: dst[:2] = *ptr + // dst is a hex[:2]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_byte dst, ptr { .zero 2, dst .xor_byte_from_ptr dst, ptr @@ -25,21 +31,39 @@ ns hex { ns hex { + // Time Complexity: + // Space Complexity: + // like: dst = *ptr + // ptr++ + // dst is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_hex_and_inc dst, ptr { .read_hex dst, ptr .ptr_inc ptr } + // Time Complexity: + // Space Complexity: + // like: dst[:n] = *ptr[:n] + // dst is a hex[:n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_hex n, dst, ptr { rep(n, i) .read_hex_and_inc dst + i*dw, ptr .ptr_sub ptr, n } + // Time Complexity: + // Space Complexity: + // like: dst[:2] = *ptr + // ptr++ + // dst is a hex[:2]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_byte_and_inc dst, ptr { .read_byte dst, ptr .ptr_inc ptr } + // Time Complexity: + // Space Complexity: + // like: dst[:2n] = *ptr[:n] + // dst is a hex[:2n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_byte n, dst, ptr { rep(n, i) .read_byte_and_inc dst + i*2*dw, ptr .ptr_sub ptr, n diff --git a/flipjump/stl/hex/pointers/write_pointers.fj b/flipjump/stl/hex/pointers/write_pointers.fj index 15639e0..173d021 100644 --- a/flipjump/stl/hex/pointers/write_pointers.fj +++ b/flipjump/stl/hex/pointers/write_pointers.fj @@ -1,4 +1,4 @@ -// TODO document The entire file +// TODO document complexities in the entire file @@ -6,7 +6,10 @@ ns hex { - // like: *ptr = src + // Time Complexity: + // Space Complexity: + // like: *ptr = src + // src is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_hex ptr, src < hex.pointers.read_byte { .pointers.set_flip_and_jump_pointers ptr .pointers.read_byte_from_inners_ptrs @@ -14,14 +17,20 @@ ns hex { .pointers.xor_hex_to_flip_ptr hex.pointers.read_byte } - // like: *ptr = 0 + // Time Complexity: + // Space Complexity: + // like: *ptr = 0 + // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def zero_ptr ptr < hex.pointers.read_byte { .pointers.set_flip_and_jump_pointers ptr .pointers.read_byte_from_inners_ptrs .pointers.xor_byte_to_flip_ptr hex.pointers.read_byte } - // like: *ptr = src[:2] + // Time Complexity: + // Space Complexity: + // like: *ptr = src[:2] + // src is a hex[:2]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_byte ptr, src < hex.pointers.read_byte { .pointers.set_flip_and_jump_pointers ptr .pointers.read_byte_from_inners_ptrs @@ -36,21 +45,39 @@ ns hex { ns hex { + // Time Complexity: + // Space Complexity: + // like: *ptr = src + // ptr++ + // src is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_hex_and_inc ptr, src { .write_hex ptr, src .ptr_inc ptr } + // Time Complexity: + // Space Complexity: + // like: *ptr[:n] = src[:n] + // src is a hex[:n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_hex n, ptr, src { rep(n, i) .write_hex_and_inc ptr, src + i*dw .ptr_sub ptr, n } + // Time Complexity: + // Space Complexity: + // like: *ptr = src[:2] + // ptr++ + // src is a hex[:2]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_byte_and_inc ptr, src { .write_byte ptr, src .ptr_inc ptr } + // Time Complexity: + // Space Complexity: + // like: *ptr[:n] = src[:2n] + // src is a hex[:2n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_byte n, ptr, src { rep(n, i) .write_byte_and_inc ptr, src + i*dw .ptr_sub ptr, n From a11867a7087133781dd68e93f7eff8cb7148ef74 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Fri, 17 Nov 2023 23:17:13 +0200 Subject: [PATCH 07/12] bubble_sort array length is now an input - also swap expected&actual in python run test --- flipjump/flipjump_quickstart.py | 6 +-- programs/sorts/hex_bubble_sort.fj | 75 ++++++++++++++++++++------ tests/inout/sorts/hex_bubble_sort_1.in | 1 + tests/inout/sorts/hex_bubble_sort_2.in | 1 + 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/flipjump/flipjump_quickstart.py b/flipjump/flipjump_quickstart.py index 35f951a..3c41ecc 100644 --- a/flipjump/flipjump_quickstart.py +++ b/flipjump/flipjump_quickstart.py @@ -187,9 +187,9 @@ def run_test_output(fjm_path: Path, last_ops_debugging_list_length=last_ops_debugging_list_length) try: - assert expected_termination_cause == termination_statistics.termination_cause - assert expected_output.decode(IO_BYTES_ENCODING) == \ - io_device.get_output(allow_incomplete_output=True).decode(IO_BYTES_ENCODING) + assert termination_statistics.termination_cause == expected_termination_cause + assert io_device.get_output(allow_incomplete_output=True).decode(IO_BYTES_ENCODING) == \ + expected_output.decode(IO_BYTES_ENCODING) return True except AssertionError as assertion_error: if should_raise_assertion_error: diff --git a/programs/sorts/hex_bubble_sort.fj b/programs/sorts/hex_bubble_sort.fj index d8dd7d6..fb707ad 100644 --- a/programs/sorts/hex_bubble_sort.fj +++ b/programs/sorts/hex_bubble_sort.fj @@ -8,7 +8,7 @@ // This program tests the read_hex macro, and the write_hex / xor_hex_to_ptr macros (based on the swap_adjacent implementation). -ARRAY_LEN = 11 +MAX_ARRAY_SIZE = 2000 HEX_LEN = 4 CELL_HEX_LEN = HEX_LEN / HEX_VARS_PER_MEMORY_CELL hw = w/4 @@ -27,15 +27,16 @@ stl.loop // Variables: -array_len: hex.vec hw // TODO as an input, not a constant -array: hex.vec HEX_LEN * ARRAY_LEN +array_len: hex.vec hw, 0 // TODO as an input, not a constant +array: hex.vec HEX_LEN * MAX_ARRAY_SIZE // Macros: -// Sorts the array (ARRAY_LEN hex entries, each of size HEX_LEN) using the bubble sort algorithm. -def bubble_sort @ phase_loop, index_loop, finish_index_loop, swapped_flag, i, j, array_ptr, end < array { - hex.set hw, i, ARRAY_LEN - 1 +// Sorts the array (array_len hex entries, each of size HEX_LEN) using the bubble sort algorithm. +def bubble_sort @ phase_loop, index_loop, finish_index_loop, swapped_flag, i, j, array_ptr, end < array, array_len { + hex.mov hw, i, array_len + hex.dec hw, i phase_loop: hex.zero hw, j hex.set hw, array_ptr, array @@ -79,37 +80,79 @@ def swap_if_needed array_ptr, swapped_flag @ small_index_num, big_index_num, swa } -// dst = hex(input(1-byte)). if it's not an hex digit - jump to error. +// *array_ptr[:CELL_HEX_LEN] = hex(input(HEX_LEN byte)). if it's not an hex digit - jump to error. +def input_one_variable_ptr array_ptr, error @ input, end { + input_one_variable input, error + write_to_ptr HEX_LEN, array_ptr, input + ;end + + input: hex.vec HEX_LEN + end: +} + +// dst[:HEX_LEN] = hex(input(HEX_LEN bytes)). if it's not an hex digit - jump to error. def input_one_variable dst, error @ garbage, end { hex.input_as_hex HEX_LEN, dst, error hex.input garbage ;end + garbage: hex.vec 2 end: } -// array[:ARRAY_LEN] = hex(input(ARRAY_LEN-bytes)). If any char isn't an hex digit - print an error and exit. -def input_array @ error, end < array { - rep(ARRAY_LEN, i) input_one_variable array + i*HEX_LEN*dw, error - ;end +// array[:array_len] = hex(input(array_len bytes)). If any char isn't an hex digit - print an error and exit. +def input_array @ input_loop, i, array_ptr, error, end < array, array_len { + input_one_variable array_len, error + hex.set hw, array_ptr, array + hex.zero hw, i + + input_loop: + input_one_variable_ptr array_ptr, error + hex.ptr_add array_ptr, CELL_HEX_LEN + hex.inc hw, i + hex.cmp hw, i, array_len, input_loop, end, end error: stl.output "Couldn't parse the input as hexadecimal numbers.\n" stl.loop + i: hex.vec hw + array_ptr: hex.vec hw + end: } // print the src[:HEX_LEN] in its hexadecimal form. -def print_one_variable src, is_end_of_line { - hex.print_as_digit HEX_LEN, src, 0 - stl.output is_end_of_line ? '\n' : ' ' +def print_one_variable_ptr array_ptr @ output, end { + read_from_ptr HEX_LEN, output, array_ptr + hex.print_as_digit HEX_LEN, output, 0 + ;end + + output: hex.vec HEX_LEN + + end: } // print every hexadecimal number[:HEX_LEN] in the entire array. -def print_array < array { - rep(ARRAY_LEN, i) print_one_variable array + i*HEX_LEN*dw, i == ARRAY_LEN-1 +def print_array @ print_loop, print_space, i, array_ptr, end < array, array_len { + hex.set hw, array_ptr, array + hex.zero hw, i + + print_loop: + print_one_variable_ptr array_ptr + hex.ptr_add array_ptr, CELL_HEX_LEN + hex.inc hw, i + hex.cmp hw, i, array_len, print_space, end, end + print_space: + stl.output ' ' + ;print_loop + + i: hex.vec hw + array_ptr: hex.vec hw + + end: + stl.output '\n' } diff --git a/tests/inout/sorts/hex_bubble_sort_1.in b/tests/inout/sorts/hex_bubble_sort_1.in index b07910f..d18b014 100644 --- a/tests/inout/sorts/hex_bubble_sort_1.in +++ b/tests/inout/sorts/hex_bubble_sort_1.in @@ -1 +1,2 @@ +000b f5fe cf62 aed8 b2fd 7bbc aae5 121c 9e00 9e00 7f17 0cdf diff --git a/tests/inout/sorts/hex_bubble_sort_2.in b/tests/inout/sorts/hex_bubble_sort_2.in index 3c1caf5..dcdfd06 100644 --- a/tests/inout/sorts/hex_bubble_sort_2.in +++ b/tests/inout/sorts/hex_bubble_sort_2.in @@ -1 +1,2 @@ +000b 85ec 27bd 8925 e26c 56a6 9929 d2fd b137 bd93 5343 f83d From 916a2ef719c79bcee4ffa0332da1b2f2748ed78b Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 18 Nov 2023 17:12:50 +0200 Subject: [PATCH 08/12] breakpoints features: index, f/j --- .../interpretter/debugging/breakpoints.py | 149 ++++++++++++------ 1 file changed, 103 insertions(+), 46 deletions(-) diff --git a/flipjump/interpretter/debugging/breakpoints.py b/flipjump/interpretter/debugging/breakpoints.py index 67a9a07..38e3b85 100644 --- a/flipjump/interpretter/debugging/breakpoints.py +++ b/flipjump/interpretter/debugging/breakpoints.py @@ -6,26 +6,75 @@ from flipjump.interpretter.debugging.message_boxes import (display_message_box, display_message_box_and_get_text_answer, display_message_box_with_choices_and_get_answer) -from flipjump.utils.constants import MACRO_SEPARATOR_STRING -from flipjump.utils.functions import load_debugging_labels from flipjump.utils.classes import RunStatistics - +from flipjump.utils.constants import MACRO_SEPARATOR_STRING from flipjump.utils.exceptions import FlipJumpException +from flipjump.utils.functions import load_debugging_labels class BreakpointHandlerUnnecessary(Exception): pass -def show_memory_address(variable_prefix: Optional[Tuple[str, int]], user_query: str, +def calculate_variable_value(variable_prefix: Optional[Tuple[str, int, int]], address: int, mem: fjm_reader.Reader): + """ + Read the variable related memory words (using 'mem'), + and return the value of the word created by this bit/hex/Byte vector. + The memory words are pointed by the given 'address' and 'variable_prefix'. + """ + w = mem.memory_width + variable_type, variable_length, index = variable_prefix + index_offset_in_w = 2 * variable_length * index + + first_address = address + index_offset_in_w * w + last_address = first_address + 2 * w * variable_length + variable_memory_words = [mem.get_word(current_address) + for current_address in range(first_address + w, last_address, 2 * w)] + bits_per_word = {'b': 1, 'h': 4, 'B': 8}[variable_type] + + value = 0 + for word in variable_memory_words[::-1]: + data_bits = (word >> w.bit_length()) & ((1 << bits_per_word) - 1) + value = (value << bits_per_word) | data_bits + + return value, first_address, last_address + + +def handle_read_f_j(variable_prefix: Optional[Tuple[str, int, int]], address: int, label_name: Optional[str], w: int): + """ + If variable_type is f/j, modify the address accordingly, them set variable_prefix = None. + Anyway, also create a label_name string and return the new one. + """ + if variable_prefix and variable_prefix[0] in ('f', 'j'): + variable_type, variable_length, index = variable_prefix + + added_w = 2 * variable_length * index + if variable_type == 'j': + added_w += 1 + if label_name is not None and added_w != 0: + label_name += f' + {added_w}w' + + address += w * added_w + variable_prefix = None + + label_name = '' if label_name is None else f'\n\nThis address also goes by this label name:\n\n{label_name}' + + return variable_prefix, address, label_name + + +def show_memory_address(variable_prefix: Optional[Tuple[str, int, int]], user_query: str, address: int, mem: fjm_reader.Reader, label_name: Optional[str]) -> None: """ Shows the value of the requested memory address / variable. The function also support reading flipjump variables (saved in label+dbit+i*dw). Also shows the label-name of the address if the user entered an integer-address. - @param variable_prefix: if not None: the user asked for a flipjump variable: - tuple (variable_type - 'b'/'h'/'B' for bit/hex/byte, variable_length - number of memory-ops). + @param variable_prefix: if not None: the user asked for a flipjump variable: tuple + ( + variable_type - 'b'/'h'/'B' for bit/hex/byte, + variable_length - number of memory-ops, + index - the index of the variable, in an array starting from address, and of cells variable_type[:variable_length] + ). @param user_query: the string the user entered. @param address: the address resolved from user_query string. @param mem: the fjm_reader.Reader for the current running fj. Used for reading the actual memory values @@ -33,45 +82,43 @@ def show_memory_address(variable_prefix: Optional[Tuple[str, int]], user_query: @param label_name: if not None - the user asked for an integer address, and this its label-name, or the closest label to it. """ - if address % mem.memory_width != 0 or address < 0 or address >= (1 << mem.memory_width): + w = mem.memory_width + + if address % w != 0 or address < 0 or address >= (1 << w): display_message_box( body_message=f"Failed while trying to read {user_query}:\n" f" The requested memory address ({address}) must be aligned" - f" (must be divisible by {mem.memory_width}),\n" - f" Can't be negative, and must be smaller than {hex(1 << mem.memory_width)}.", + f" (must be divisible by {w}),\n" + f" Can't be negative, and must be smaller than {hex(1 << w)}.", title_message='Bad memory address') - else: - label_name = '' if label_name is None else f'\n\nThis address also goes by this label name:\n\n{label_name}' + return - try: - if not variable_prefix: - memory_word_value = mem.get_word(address) - display_message_box( - body_message=f'Reading {user_query}:\n' - f'memory[{hex(address)}] = {memory_word_value} (or {hex(memory_word_value)}).' - f'{label_name}', - title_message='Read Memory') - else: - variable_type, variable_length = variable_prefix - variable_memory_words = [mem.get_word(address + (2*i+1) * mem.memory_width) - for i in range(variable_length)] - bits_per_word = {'b': 1, 'h': 4, 'B': 8}[variable_type] - value = 0 - for word in variable_memory_words[::-1]: - data_bits = (word >> mem.memory_width.bit_length()) & ((1 << bits_per_word) - 1) - value = (value << bits_per_word) | data_bits - display_message_box( - body_message=f'Reading the variable {user_query}:\n' - f'memory[{hex(address)}, {hex(address + 2 * variable_length * mem.memory_width)})' - f' = {value} (or {hex(value)}).' - f'{label_name}', - title_message='Reading FlipJump Variable') - except FlipJumpException as fje: + try: + variable_prefix, address, label_name = handle_read_f_j(variable_prefix, address, label_name, w) + + if not variable_prefix: + memory_word_value = mem.get_word(address) display_message_box( - body_message=f"Failed while trying to read {user_query}:\n" - f"Failed to read address {address}, with the error: {fje}.\n" - f"Maybe this memory region isn't initialized in the currently running .fjm?", - title_message='Read Memory Failure') + body_message=f'Reading {user_query}:\n' + f'memory[{hex(address)}] = {memory_word_value} (or {hex(memory_word_value)}).' + f'{label_name}', + title_message='Read Memory') + return + + value, first_address, last_address = calculate_variable_value(variable_prefix, address, mem) + display_message_box( + body_message=f'Reading the variable {user_query}:\n' + f'memory[{hex(first_address)}, {hex(last_address)})' + f' = {value} (or {hex(value)}).' + f'{label_name}', + title_message='Reading FlipJump Variable') + + except FlipJumpException as fje: + display_message_box( + body_message=f"Failed while trying to read {user_query}:\n" + f"Failed to read address {address}, with the error: {fje}.\n" + f"Maybe this memory region isn't initialized in the currently running .fjm?", + title_message='Read Memory Failure') def get_nice_label_repr(label: str, pad: int = 0) -> str: @@ -79,13 +126,14 @@ def get_nice_label_repr(label: str, pad: int = 0) -> str: @return: a well-formed string that represents the label (padded with 'pad' spaces). """ parts = label.split(MACRO_SEPARATOR_STRING) - return ' ->\n'.join(f"{' '*(pad+i)}{part}" for i, part in enumerate(parts)) + return ' ->\n'.join(f"{' ' * (pad + i)}{part}" for i, part in enumerate(parts)) class BreakpointHandler: """ Handle breakpoints (know when breakpoints happen, query user for action). """ + def __init__(self, breakpoints: Dict[int, str], address_to_label: Dict[int, str], label_to_address: Dict[str, int]): self.breakpoints = breakpoints self.address_to_label = address_to_label @@ -144,23 +192,32 @@ def handle_read_memory(self, mem: fjm_reader.Reader) -> None: "Use any of these options:\n" "- Decimal number\n" "- Hexadecimal number with the '0x' prefix\n" - "- A full label name\n" + "- A full label name\n\n" + 'You can read the jump-words of a label by using the ":j:" prefix.\n\n' "You can also read flipjump variables (like bit.vec, hex.vec, ..),\n" " with the following prefixes to the address:\n" '- :bN: read bit variable (like ":b32:integer_label")\n' '- :hN: read hex variable (like ":h8:integer_label")\n' '- :BN: read byte variable (holds 8 bits after the dbit)' - ' (like ":B4:integer_label")\n', + ' (like ":B4:integer_label")\n\n' + "Also, you can index a variable in an array, by using the ':*:N:* prefix':\n" + '- (like ":B4:7:integer_array_label" - this will access the 7th integer\n' + ' in the array, so starting from byte 28 of the array\'s variables)\n' + '- (you can also use the ":f/j:N:label" to skip N ops forward,\n' + ' and also ":f/j:n:label:N" to skip n*N ops forward)\n', title_message='Debug: read memory address') if result is None: return variable_prefix = None query = result - match = re.match(':([bhB])(\\d+):(.*)', result) + match = re.match(r':([bhBfj])(\d*):(\d+:)?([^:]*)', result) if match: - variable_type, variable_length, result = match.groups() - variable_prefix = (variable_type, int(variable_length)) + variable_type, variable_length, index_string, result = match.groups() + if variable_length == '': + variable_length = '1' + index = int(index_string[:-1]) if index_string else 0 + variable_prefix = (variable_type, int(variable_length), index) if result in self.label_to_address: show_memory_address(variable_prefix, query, self.label_to_address[result], mem, None) @@ -240,7 +297,7 @@ def handle_breakpoint(breakpoint_handler: BreakpointHandler, ip: int, mem: fjm_r def get_breakpoints(breakpoint_addresses: Optional[Set[int]], breakpoint_labels: Optional[Set[str]], breakpoint_contains_labels: Optional[Set[str]], - label_to_address: Dict[str, int])\ + label_to_address: Dict[str, int]) \ -> Dict[int, str]: """ generate the breakpoints' dictionary From 5b1394d6314d6181041982d624d936b26f40bf0b Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 18 Nov 2023 17:17:52 +0200 Subject: [PATCH 09/12] bugfix pointers stl - hex.pointers.read_bytes was flipped as a 1-Byte variable, instead of a 2-hex variable. - "write_byte n" should advance the src variable by 2*dw each byte-write --- flipjump/stl/hex/pointers/basic_pointers.fj | 4 +++- flipjump/stl/hex/pointers/write_pointers.fj | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/flipjump/stl/hex/pointers/basic_pointers.fj b/flipjump/stl/hex/pointers/basic_pointers.fj index 953d9c9..d42cf6a 100644 --- a/flipjump/stl/hex/pointers/basic_pointers.fj +++ b/flipjump/stl/hex/pointers/basic_pointers.fj @@ -21,7 +21,9 @@ ns hex { // (4 is for reading from an hex memory, 8 is for byte memory). read_ptr_byte_table: rep(256, d) stl.fj \ - d==0?0: (.read_byte+dbit+(#d)-1), \ + d==0?0: (#d)<=4 \ + ? (.read_byte +dbit+(#d)-1) \ + : (.read_byte+dw+dbit+(#d)-5), \ (d==((1<<(#d))>>1)) ? .ret_after_read_byte : read_ptr_byte_table+(d^((1<<(#d))>>1))*dw read_byte: diff --git a/flipjump/stl/hex/pointers/write_pointers.fj b/flipjump/stl/hex/pointers/write_pointers.fj index 173d021..6597cbf 100644 --- a/flipjump/stl/hex/pointers/write_pointers.fj +++ b/flipjump/stl/hex/pointers/write_pointers.fj @@ -79,7 +79,7 @@ ns hex { // like: *ptr[:n] = src[:2n] // src is a hex[:2n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_byte n, ptr, src { - rep(n, i) .write_byte_and_inc ptr, src + i*dw + rep(n, i) .write_byte_and_inc ptr, src + i*2*dw .ptr_sub ptr, n } } From 2d115b94568a894a53b7ea2f41921019e891c5d0 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 18 Nov 2023 17:23:00 +0200 Subject: [PATCH 10/12] expand bubble_sort tests to test accessing bytes in memory - all read/write/xor hex/byte [n] macros are tested under these 6 tests, directly or indirectly --- .../{hex_bubble_sort.fj => bubble_sort.fj} | 24 ++++++++++++------- .../utils/_swap_adjacent_using_writes.fj | 14 +++++------ .../sorts/utils/_swap_adjacent_using_xors.fj | 14 +++++------ ...{hex_bubble_sort_1.in => bubble_sort_1.in} | 0 ...ex_bubble_sort_1.out => bubble_sort_1.out} | 0 ...{hex_bubble_sort_2.in => bubble_sort_2.in} | 0 ...ex_bubble_sort_2.out => bubble_sort_2.out} | 0 tests/test_compile_slow.csv | 6 +++-- tests/test_run_slow.csv | 9 ++++--- 9 files changed, 40 insertions(+), 27 deletions(-) rename programs/sorts/{hex_bubble_sort.fj => bubble_sort.fj} (77%) rename tests/inout/sorts/{hex_bubble_sort_1.in => bubble_sort_1.in} (100%) rename tests/inout/sorts/{hex_bubble_sort_1.out => bubble_sort_1.out} (100%) rename tests/inout/sorts/{hex_bubble_sort_2.in => bubble_sort_2.in} (100%) rename tests/inout/sorts/{hex_bubble_sort_2.out => bubble_sort_2.out} (100%) diff --git a/programs/sorts/hex_bubble_sort.fj b/programs/sorts/bubble_sort.fj similarity index 77% rename from programs/sorts/hex_bubble_sort.fj rename to programs/sorts/bubble_sort.fj index fb707ad..5ddeff0 100644 --- a/programs/sorts/hex_bubble_sort.fj +++ b/programs/sorts/bubble_sort.fj @@ -1,15 +1,23 @@ // This program inputs hexadecimal numbers (separated by spaces), sorts them, and prints them back sorted. +// It first inputs a 'length' variable, and then inputs 'length' more numbers. // The sorting algorithm is bubble-sort. -// This program is expected to compile with another file that defines the next macro: -// swap_adjacent entry_length, array_ptr, small_index_num, big_index_num -// This macro can be found in the two "./utils/_swap_adjacent_using_*.fj files. +// This program is expected to compile with the next files that define the next macros: +// - One of the two "./utils/_swap_adjacent_using_{writes/xors}.fj" files: +// * swap_adjacent entry_length, array_ptr, small_index_num, big_index_num +// - One of the two "./utils/_{hex/byte}_memory_access.fj" files: +// * The HEX_VARS_PER_MEMORY_CELL constant. +// * Macros: xor_to_ptr / write_to_ptr / read_from_ptr // -// This program tests the read_hex macro, and the write_hex / xor_hex_to_ptr macros (based on the swap_adjacent implementation). +// This program tests the read_hex macro, and the write_hex / xor_hex_to_ptr macros. +// It also tests the read_byte macro, and the write_byte / xor_byte_to_ptr macros. +// It also tests the vectored xor/read/write macros, . +// It's all based on the swap_adjacent implementation, and the memory-access implementation. MAX_ARRAY_SIZE = 2000 HEX_LEN = 4 + CELL_HEX_LEN = HEX_LEN / HEX_VARS_PER_MEMORY_CELL hw = w/4 @@ -27,7 +35,7 @@ stl.loop // Variables: -array_len: hex.vec hw, 0 // TODO as an input, not a constant +array_len: hex.vec hw, 0 array: hex.vec HEX_LEN * MAX_ARRAY_SIZE @@ -40,11 +48,11 @@ def bubble_sort @ phase_loop, index_loop, finish_index_loop, swapped_flag, i, j, phase_loop: hex.zero hw, j hex.set hw, array_ptr, array - hex.zero swapped_flag + bit.zero swapped_flag index_loop: swap_if_needed array_ptr, swapped_flag hex.inc hw, j - hex.ptr_add array_ptr, HEX_LEN + hex.ptr_add array_ptr, CELL_HEX_LEN hex.cmp hw, j, i, index_loop, finish_index_loop, finish_index_loop finish_index_loop: @@ -63,7 +71,7 @@ array_ptr: hex.vec hw // swaps *ptr[:HEX_LEN] with *ptr[HEX_LEN:2*HEX_LEN] if the first is bigger than the latter. def swap_if_needed array_ptr, swapped_flag @ small_index_num, big_index_num, swap, end { - hex.read_hex 2 * HEX_LEN, small_index_num, array_ptr + read_from_ptr 2 * HEX_LEN, small_index_num, array_ptr hex.cmp HEX_LEN, small_index_num, big_index_num, end, end, swap swap: diff --git a/programs/sorts/utils/_swap_adjacent_using_writes.fj b/programs/sorts/utils/_swap_adjacent_using_writes.fj index 52e1c41..448f05f 100644 --- a/programs/sorts/utils/_swap_adjacent_using_writes.fj +++ b/programs/sorts/utils/_swap_adjacent_using_writes.fj @@ -1,12 +1,12 @@ -// Compile this file with the bubble_sort programs. +// Compile this file with the bubble_sort programs (and with a _{hex/byte}_memory_access.fj util file). // This file implements the swap_adjacent macro -// (swaps *array_ptr[:entry_length] with *array_ptr[entry_length:2*entry_length]) -// Using the hex.write_hex function (it's a slower implementation than the one with hex.xor_hex_to_ptr). +// (swaps *array_ptr[:entry_length] with *array_ptr[entry_length:2*entry_length]. entry_length is the hex-length) +// Using the hex.write_{hex/byte} function (it's a slower implementation than the one with hex.xor_{hex/byte}_to_ptr). def swap_adjacent entry_length, array_ptr, small_index_num, big_index_num { - hex.write_hex entry_length, array_ptr, big_index_num - hex.ptr_add array_ptr, entry_length - hex.write_hex entry_length, array_ptr, small_index_num - hex.ptr_sub array_ptr, entry_length + write_to_ptr entry_length, array_ptr, big_index_num + hex.ptr_add array_ptr, entry_length / HEX_VARS_PER_MEMORY_CELL + write_to_ptr entry_length, array_ptr, small_index_num + hex.ptr_sub array_ptr, entry_length / HEX_VARS_PER_MEMORY_CELL } diff --git a/programs/sorts/utils/_swap_adjacent_using_xors.fj b/programs/sorts/utils/_swap_adjacent_using_xors.fj index 69c08d3..835ddab 100644 --- a/programs/sorts/utils/_swap_adjacent_using_xors.fj +++ b/programs/sorts/utils/_swap_adjacent_using_xors.fj @@ -1,13 +1,13 @@ -// Compile this file with the bubble_sort programs. +// Compile this file with the bubble_sort programs (and with a _{hex/byte}_memory_access.fj util file). // This file implements the swap_adjacent macro -// (swaps *array_ptr[:entry_length] with *array_ptr[entry_length:2*entry_length]) -// Using the hex.xor_hex_to_ptr function (it's a faster implementation than the one with hex.write_hex). +// (swaps *array_ptr[:entry_length] with *array_ptr[entry_length:2*entry_length]. entry_length is the hex-length) +// Using the hex.xor_{hex/byte}_to_ptr function (it's a faster implementation than the one with hex.write_{hex/byte}). def swap_adjacent entry_length, array_ptr, small_index_num, big_index_num { hex.xor entry_length, small_index_num, big_index_num - hex.xor_hex_to_ptr entry_length, array_ptr, small_index_num - hex.ptr_add array_ptr, entry_length - hex.xor_hex_to_ptr entry_length, array_ptr, small_index_num - hex.ptr_sub array_ptr, entry_length + xor_to_ptr entry_length, array_ptr, small_index_num + hex.ptr_add array_ptr, entry_length / HEX_VARS_PER_MEMORY_CELL + xor_to_ptr entry_length, array_ptr, small_index_num + hex.ptr_sub array_ptr, entry_length / HEX_VARS_PER_MEMORY_CELL } diff --git a/tests/inout/sorts/hex_bubble_sort_1.in b/tests/inout/sorts/bubble_sort_1.in similarity index 100% rename from tests/inout/sorts/hex_bubble_sort_1.in rename to tests/inout/sorts/bubble_sort_1.in diff --git a/tests/inout/sorts/hex_bubble_sort_1.out b/tests/inout/sorts/bubble_sort_1.out similarity index 100% rename from tests/inout/sorts/hex_bubble_sort_1.out rename to tests/inout/sorts/bubble_sort_1.out diff --git a/tests/inout/sorts/hex_bubble_sort_2.in b/tests/inout/sorts/bubble_sort_2.in similarity index 100% rename from tests/inout/sorts/hex_bubble_sort_2.in rename to tests/inout/sorts/bubble_sort_2.in diff --git a/tests/inout/sorts/hex_bubble_sort_2.out b/tests/inout/sorts/bubble_sort_2.out similarity index 100% rename from tests/inout/sorts/hex_bubble_sort_2.out rename to tests/inout/sorts/bubble_sort_2.out diff --git a/tests/test_compile_slow.csv b/tests/test_compile_slow.csv index 53d9d5d..7140f91 100644 --- a/tests/test_compile_slow.csv +++ b/tests/test_compile_slow.csv @@ -17,5 +17,7 @@ series_sum, programs/simple_math_checks/series_sum.fj,tests/compiled/simple_math prime_sieve, programs/prime_sieve.fj,tests/compiled/prime_sieve.fjm, 64,3,0, True,True -bubble_sort__write_hex, programs/sorts/utils/_hex_memory_access.fj | programs/sorts/hex_bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_writes.fj ,tests/compiled/sorts/bubble_sort__write_hex.fjm, 64,3,0, True,True -bubble_sort__xor_hex , programs/sorts/utils/_hex_memory_access.fj | programs/sorts/hex_bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_xors.fj ,tests/compiled/sorts/bubble_sort__xor_hex.fjm , 64,3,0, True,True +bubble_sort__write_hex , programs/sorts/utils/_hex_memory_access.fj | programs/sorts/bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_writes.fj ,tests/compiled/sorts/bubble_sort__write_hex.fjm , 64,3,0, True,True +bubble_sort__xor_hex , programs/sorts/utils/_hex_memory_access.fj | programs/sorts/bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_xors.fj ,tests/compiled/sorts/bubble_sort__xor_hex.fjm , 64,3,0, True,True +bubble_sort__write_byte, programs/sorts/utils/_byte_memory_access.fj | programs/sorts/bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_writes.fj ,tests/compiled/sorts/bubble_sort__write_byte.fjm, 64,3,0, True,True +bubble_sort__xor_byte , programs/sorts/utils/_byte_memory_access.fj | programs/sorts/bubble_sort.fj | programs/sorts/utils/_swap_adjacent_using_xors.fj ,tests/compiled/sorts/bubble_sort__xor_byte.fjm , 64,3,0, True,True diff --git a/tests/test_run_slow.csv b/tests/test_run_slow.csv index cfd6a17..188314f 100644 --- a/tests/test_run_slow.csv +++ b/tests/test_run_slow.csv @@ -48,6 +48,9 @@ prime_sieve_err_abc, tests/compiled/prime_sieve.fjm, tests/inout/prime_sieve_tes prime_sieve_err_empty, tests/compiled/prime_sieve.fjm, tests/inout/prime_sieve_tests/primes_err_empty.in,tests/inout/prime_sieve_tests/primes_err_bad_number.out, False,False prime_sieve_err_minus5, tests/compiled/prime_sieve.fjm, tests/inout/prime_sieve_tests/primes_err_minus5.in,tests/inout/prime_sieve_tests/primes_err_bad_number.out, False,False -bubble_sort__write_hex_1, tests/compiled/sorts/bubble_sort__write_hex.fjm, tests/inout/sorts/hex_bubble_sort_1.in,tests/inout/sorts/hex_bubble_sort_1.out, False,False -bubble_sort__xor_hex_1, tests/compiled/sorts/bubble_sort__xor_hex.fjm, tests/inout/sorts/hex_bubble_sort_1.in,tests/inout/sorts/hex_bubble_sort_1.out, False,False -bubble_sort__xor_hex_2, tests/compiled/sorts/bubble_sort__xor_hex.fjm, tests/inout/sorts/hex_bubble_sort_2.in,tests/inout/sorts/hex_bubble_sort_2.out, False,False +bubble_sort__write_hex_1, tests/compiled/sorts/bubble_sort__write_hex.fjm, tests/inout/sorts/bubble_sort_1.in,tests/inout/sorts/bubble_sort_1.out, False,False +bubble_sort__xor_hex_1, tests/compiled/sorts/bubble_sort__xor_hex.fjm, tests/inout/sorts/bubble_sort_1.in,tests/inout/sorts/bubble_sort_1.out, False,False +bubble_sort__xor_hex_2, tests/compiled/sorts/bubble_sort__xor_hex.fjm, tests/inout/sorts/bubble_sort_2.in,tests/inout/sorts/bubble_sort_2.out, False,False +bubble_sort__write_byte_1, tests/compiled/sorts/bubble_sort__write_byte.fjm, tests/inout/sorts/bubble_sort_1.in,tests/inout/sorts/bubble_sort_1.out, False,False +bubble_sort__xor_byte_1, tests/compiled/sorts/bubble_sort__xor_byte.fjm, tests/inout/sorts/bubble_sort_1.in,tests/inout/sorts/bubble_sort_1.out, False,False +bubble_sort__xor_byte_2, tests/compiled/sorts/bubble_sort__xor_byte.fjm, tests/inout/sorts/bubble_sort_2.in,tests/inout/sorts/bubble_sort_2.out, False,False From 93c9da852240564e0e6747e4cd4e563abf7b2197 Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 18 Nov 2023 18:10:40 +0200 Subject: [PATCH 11/12] document read/write hex/byte complexities --- flipjump/stl/hex/pointers/read_pointers.fj | 28 ++++++++---------- flipjump/stl/hex/pointers/write_pointers.fj | 32 +++++++++------------ 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/flipjump/stl/hex/pointers/read_pointers.fj b/flipjump/stl/hex/pointers/read_pointers.fj index a155850..bc9828e 100644 --- a/flipjump/stl/hex/pointers/read_pointers.fj +++ b/flipjump/stl/hex/pointers/read_pointers.fj @@ -1,13 +1,9 @@ -// TODO document complexities in the entire file - - - // ---------- Read Pointers ns hex { - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+ 5) + 7@+13 + // Space Complexity: w(0.75@+29) + 7@+48 // like: dst = *ptr // dst is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_hex dst, ptr { @@ -15,8 +11,8 @@ ns hex { .xor_hex_from_ptr dst, ptr } - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+ 5) + 9@+13 + // Space Complexity: w(0.75@+29) + 9@+72 // like: dst[:2] = *ptr // dst is a hex[:2]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_byte dst, ptr { @@ -31,8 +27,8 @@ ns hex { ns hex { - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+ 5) + 16@+27 + // Space Complexity: w(1.13@+32) + 12@+103 // like: dst = *ptr // ptr++ // dst is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. @@ -41,8 +37,8 @@ ns hex { .ptr_inc ptr } - // Time Complexity: - // Space Complexity: + // Time Complexity: n(w(0.75@+ 5) + 16@+27) + // Space Complexity: n(w(1.13@+32) + 12@+103) // like: dst[:n] = *ptr[:n] // dst is a hex[:n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_hex n, dst, ptr { @@ -50,8 +46,8 @@ ns hex { .ptr_sub ptr, n } - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+ 5) + 18@+27 + // Space Complexity: w(1.13@+32) + 14@+127 // like: dst[:2] = *ptr // ptr++ // dst is a hex[:2]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. @@ -60,8 +56,8 @@ ns hex { .ptr_inc ptr } - // Time Complexity: - // Space Complexity: + // Time Complexity: n(w(0.75@+ 5) + 18@+27) + // Space Complexity: n(w(1.13@+32) + 14@+127) // like: dst[:2n] = *ptr[:n] // dst is a hex[:2n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def read_byte n, dst, ptr { diff --git a/flipjump/stl/hex/pointers/write_pointers.fj b/flipjump/stl/hex/pointers/write_pointers.fj index 6597cbf..88716bb 100644 --- a/flipjump/stl/hex/pointers/write_pointers.fj +++ b/flipjump/stl/hex/pointers/write_pointers.fj @@ -1,13 +1,9 @@ -// TODO document complexities in the entire file - - - // ---------- Write Pointers ns hex { - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+5) + 11@+25 + // Space Complexity: w(0.75@+29) + 11@+112 // like: *ptr = src // src is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_hex ptr, src < hex.pointers.read_byte { @@ -17,8 +13,8 @@ ns hex { .pointers.xor_hex_to_flip_ptr hex.pointers.read_byte } - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+5) + 15@+37 + // Space Complexity: w(0.75@+29) + 15@+176 // like: *ptr = 0 // ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def zero_ptr ptr < hex.pointers.read_byte { @@ -27,8 +23,8 @@ ns hex { .pointers.xor_byte_to_flip_ptr hex.pointers.read_byte } - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+5) + 17@+37 + // Space Complexity: w(0.75@+29) + 17@+200 // like: *ptr = src[:2] // src is a hex[:2]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_byte ptr, src < hex.pointers.read_byte { @@ -45,8 +41,8 @@ ns hex { ns hex { - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+5) + 20@+39 + // Space Complexity: w(1.13@+32) + 16@+167 // like: *ptr = src // ptr++ // src is a hex. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. @@ -55,8 +51,8 @@ ns hex { .ptr_inc ptr } - // Time Complexity: - // Space Complexity: + // Time Complexity: n(w(0.75@+5) + 20@+39) + // Space Complexity: n(w(1.13@+32) + 16@+167) // like: *ptr[:n] = src[:n] // src is a hex[:n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_hex n, ptr, src { @@ -64,8 +60,8 @@ ns hex { .ptr_sub ptr, n } - // Time Complexity: - // Space Complexity: + // Time Complexity: w(0.75@+5) + 26@+51 + // Space Complexity: w(1.13@+32) + 22@+255 // like: *ptr = src[:2] // ptr++ // src is a hex[:2]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. @@ -74,8 +70,8 @@ ns hex { .ptr_inc ptr } - // Time Complexity: - // Space Complexity: + // Time Complexity: n(w(0.75@+5) + 26@+51) + // Space Complexity: n(w(1.13@+32) + 22@+255) // like: *ptr[:n] = src[:2n] // src is a hex[:2n]. ptr is a hex[:w/4] that holds an address, which we assume is dw-aligned. def write_byte n, ptr, src { From f3463b3ec95d4c4c5c737e13f82cc552b0a7207d Mon Sep 17 00:00:00 2001 From: Tom Herman Date: Sat, 18 Nov 2023 18:26:35 +0200 Subject: [PATCH 12/12] add issue number to each TODO --- flipjump/assembler/fj_parser.py | 3 ++- flipjump/interpretter/debugging/breakpoints.py | 2 +- flipjump/stl/mathlib.fj | 6 +++--- programs/prime_sieve.fj | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/flipjump/assembler/fj_parser.py b/flipjump/assembler/fj_parser.py index bcac0eb..94585bf 100644 --- a/flipjump/assembler/fj_parser.py +++ b/flipjump/assembler/fj_parser.py @@ -197,7 +197,8 @@ def _get_main_macro_code_position(first_file: Tuple[str, Path]) -> CodePosition: # noinspection PyUnusedLocal,PyUnresolvedReferences,PyPep8Naming class FJParser(sly.Parser): tokens = FJLexer.tokens - # TODO add Unary Minus (-), Unary Not (~). Maybe add logical or (||) and logical and (&&). Maybe handle power (**). + # TODO #249 - add Unary Minus (-), Unary Not (~). + # Maybe add logical or (||) and logical and (&&). Maybe handle power (**). precedence = ( ('right', '?', ':'), ('left', '|'), diff --git a/flipjump/interpretter/debugging/breakpoints.py b/flipjump/interpretter/debugging/breakpoints.py index 38e3b85..9728416 100644 --- a/flipjump/interpretter/debugging/breakpoints.py +++ b/flipjump/interpretter/debugging/breakpoints.py @@ -334,7 +334,7 @@ def update_breakpoints_from_breakpoint_contains_set(breakpoint_contains_labels: add breakpoints generated with breakpoint_contains_labels. param breakpoints[in,out] - adds breakpoints to it """ - # TODO improve the speed of this part with suffix trees + # TODO #248 - improve the speed of this part with suffix trees if breakpoint_contains_labels: for label in tuple(label_to_address)[::-1]: for bcl in breakpoint_contains_labels: diff --git a/flipjump/stl/mathlib.fj b/flipjump/stl/mathlib.fj index bbbfd08..564b8ba 100644 --- a/flipjump/stl/mathlib.fj +++ b/flipjump/stl/mathlib.fj @@ -1,4 +1,4 @@ -// TODO refactor this file into: bit/mul.fj, bit/div.fj, hex/mul.fj, hex/div.fj, and update complexities +// TODO #223 - 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! @@ -217,7 +217,7 @@ ns hex { } // Space Complexity: 1616+@ - // @output-param ret: ... TODO document the output params + // @output-param ret: ... TODO #223 - document the output params // @output-param dst: ... // @output-param add_carry_dst: ... // @requires hex.tables.init_shared (or hex.init) @@ -453,7 +453,7 @@ ns bit { ns hex { - // TODO - hex.div fails tests. for example, 0xc3 / 0xe fails. + // TODO #191 - 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 { .if0 nb, _b, div0 diff --git a/programs/prime_sieve.fj b/programs/prime_sieve.fj index 3a17399..f1b819a 100644 --- a/programs/prime_sieve.fj +++ b/programs/prime_sieve.fj @@ -35,7 +35,7 @@ def prime_sieve_main @ prime_loop_if, prime_loop, next_prime, end, \ prime_loop: if1_ptr primes_ptr, next_prime // if p is prime: - print_int hw, p // TODO save ton of times by declaring p "dec", with dec.vec, dec.set, dec.add and dec.print. + print_int hw, p // TODO #196 - save ton of times by declaring p "dec", with dec.vec, dec.set, dec.add and dec.print hex.inc hw, num_of_primes mark_primes mark_primes_ptr, primes_ptr_n, is_add_4, p_2dw_offset, p_4dw_offset next_prime: