diff --git a/flipjump/LICENSE b/flipjump/LICENSE new file mode 100644 index 0000000..f823fec --- /dev/null +++ b/flipjump/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2022, Tom Herman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/flipjump/README.txt b/flipjump/README.txt new file mode 100644 index 0000000..0fa5e74 --- /dev/null +++ b/flipjump/README.txt @@ -0,0 +1,4 @@ +FlipJump has only 1 opcode - f;j - flip the f'th bit, then jump to address j. + +Esolangs page - https://esolangs.org/wiki/FlipJump + Github Page - https://github.com/tomhea/flip-jump diff --git a/flipjump/impl/assembler.py b/flipjump/impl/assembler.py new file mode 100644 index 0000000..b8cdc04 --- /dev/null +++ b/flipjump/impl/assembler.py @@ -0,0 +1,180 @@ +import fjm +from preprocessor import resolve_macros +from tempfile import mkstemp +import os +from time import time +from defs import * +from fj_parser import parse_macro_tree +import pickle + + +def lsb_first_bin_array(int_value, bit_size): + return [int(c) for c in bin(int_value & ((1 << bit_size) - 1))[2:].zfill(bit_size)[-bit_size:]][::-1][:bit_size] + + +def write_flip_jump(bits, f, j, w): + bits += lsb_first_bin_array(f, w) + bits += lsb_first_bin_array(j, w) + + +def close_segment(w, segment_index, boundary_addresses, writer, first_address, last_address, bits, wflips): + if first_address == last_address: + return + assert_none_crossing_segments(segment_index, first_address, last_address, boundary_addresses) + + data_start, data_length = writer.add_data(bits + wflips) + segment_length = (last_address - first_address) // w + if segment_length < data_length: + raise FJAssemblerException(f'segment-length is smaller than data-length: {segment_length} < {data_length}') + writer.add_segment(first_address // w, segment_length, data_start, data_length) + + bits.clear() + wflips.clear() + + +def clean_segment_index(index, boundary_addresses): + clean_index = 0 + for entry in boundary_addresses[:index]: + if entry[0] == SegEntry.WflipAddress: + clean_index += 1 + return clean_index + + +def assert_none_crossing_segments(curr_segment_index, old_address, new_address, boundary_addresses): + min_i = None + min_seg_start = None + + last_start = None + last_start_i = None + for i, entry in enumerate(boundary_addresses): + if entry[0] == SegEntry.StartAddress: + last_start = entry[1] + last_start_i = i + if entry[0] == SegEntry.WflipAddress: + if entry[1] != last_start: + if old_address < last_start < new_address: + if min_i is None or min_seg_start > last_start: + min_i = last_start_i + min_seg_start = last_start + + if min_i is not None: + raise FJAssemblerException(f"Overlapping segments (address {hex(new_address)}): " + f"seg[{clean_segment_index(curr_segment_index, boundary_addresses)}]" + f"=({hex(boundary_addresses[curr_segment_index][1])}..) and " + f"seg[{clean_segment_index(min_i, boundary_addresses)}]=({hex(min_seg_start)}..)") + + +def get_next_wflip_entry_index(boundary_addresses, index): + length = len(boundary_addresses) + while boundary_addresses[index][0] != SegEntry.WflipAddress: + index += 1 + if index >= length: + raise FJAssemblerException(f'No WflipAddress entry found in boundary_addresses.') + return index + + +def labels_resolve(ops, labels, boundary_addresses, w, output_file, verbose=False, flags=0): # TODO handle verbose? + if max(e[1] for e in boundary_addresses) >= (1 << w): + raise FJAssemblerException(f"Not enough space with the {w}-width.") + + writer = fjm.Writer(w, flags=flags if flags else 0) + + bits = [] + wflips = [] + segment_index = 0 + last_start_seg_index = segment_index + first_address = boundary_addresses[last_start_seg_index][1] + wflip_address = boundary_addresses[get_next_wflip_entry_index(boundary_addresses, 0)][1] + + for op in ops: + ids = eval_all(op, labels) + if ids: + raise FJAssemblerException(f"Can't resolve the following names: {', '.join(ids)} (in op {op}).") + vals = [datum.val for datum in op.data] + + if op.type == OpType.FlipJump: + f, j = vals + bits += [f, j] + elif op.type == OpType.Segment: + segment_index += 2 + close_segment(w, last_start_seg_index, boundary_addresses, writer, first_address, wflip_address, bits, + wflips) + last_start_seg_index = segment_index + first_address = boundary_addresses[last_start_seg_index][1] + wflip_address = boundary_addresses[get_next_wflip_entry_index(boundary_addresses, segment_index)][1] + elif op.type == OpType.Reserve: + segment_index += 1 + last_address = boundary_addresses[segment_index][1] + close_segment(w, last_start_seg_index, boundary_addresses, writer, first_address, last_address, bits, []) + first_address = last_address + elif op.type == OpType.WordFlip: + to_address, by_address, return_address = vals + flip_bits = [i for i in range(w) if by_address & (1 << i)] + + if len(flip_bits) <= 1: + bits += [to_address + flip_bits[0] if flip_bits else 0, + return_address] + else: + bits += [to_address + flip_bits[0], + wflip_address] + next_op = wflip_address + for bit in flip_bits[1:-1]: + next_op += 2*w + wflips += [to_address+bit, + next_op] + wflips += [to_address + flip_bits[-1], + return_address] + wflip_address = next_op + 2 * w + + if wflip_address >= (1 << w): + raise FJAssemblerException(f"Not enough space with the {w}-width.") + else: + raise FJAssemblerException(f"Can't resolve/assemble the next opcode - {str(op)}") + + close_segment(w, last_start_seg_index, boundary_addresses, writer, first_address, wflip_address, bits, wflips) + writer.write_to_file(output_file) + + +def assemble(input_files, output_file, w, warning_as_errors, flags=None, + show_statistics=False, preprocessed_file=None, debugging_file=None, verbose=None): + if verbose is None: + verbose = set() + + if w not in (8, 16, 32, 64): + raise FJAssemblerException(f'The width ({w}) must be one of (8, 16, 32, 64).') + + temp_preprocessed_file, temp_fd = False, 0 + if preprocessed_file is None: + temp_fd, preprocessed_file = mkstemp() + temp_preprocessed_file = True + + print(' parsing: ', end='', flush=True) + start_time = time() + macros = parse_macro_tree(input_files, w, warning_as_errors, verbose=Verbose.Parse in verbose) + if Verbose.Time in verbose: + print(f'{time() - start_time:.3f}s') + + print(' macro resolve: ', end='', flush=True) + start_time = time() + ops, labels, boundary_addresses = resolve_macros(w, macros, output_file=preprocessed_file, + show_statistics=show_statistics, + verbose=Verbose.MacroSolve in verbose) + if Verbose.Time in verbose: + print(f'{time() - start_time:.3f}s') + + print(' labels resolve: ', end='', flush=True) + start_time = time() + labels_resolve(ops, labels, boundary_addresses, w, output_file, verbose=Verbose.LabelSolve in verbose, flags=flags) + if Verbose.Time in verbose: + print(f'{time() - start_time:.3f}s') + + if temp_preprocessed_file: + os.close(temp_fd) + + labels = {label: labels[label].val for label in labels} + + if debugging_file: + with open(debugging_file, 'wb') as f: + pickle.dump(labels, f, pickle.HIGHEST_PROTOCOL) + + return labels diff --git a/flipjump/impl/defs.py b/flipjump/impl/defs.py new file mode 100644 index 0000000..5c6b609 --- /dev/null +++ b/flipjump/impl/defs.py @@ -0,0 +1,255 @@ +from enum import Enum +from pathlib import Path +from operator import mul, add, sub, floordiv, lshift, rshift, mod, xor, or_, and_ + + +main_macro = ('', 0) + + +parsing_op2func = {'+': add, '-': sub, '*': mul, '/': floordiv, '%': mod, + '<<': lshift, '>>': rshift, '^': xor, '|': or_, '&': and_, + '#': lambda x: x.bit_length(), + '?:': lambda a, b, c: b if a else c, + '<': lambda a, b: 1 if a < b else 0, + '>': lambda a, b: 1 if a > b else 0, + '<=': lambda a, b: 1 if a <= b else 0, + '>=': lambda a, b: 1 if a >= b else 0, + '==': lambda a, b: 1 if a == b else 0, + '!=': lambda a, b: 1 if a != b else 0, + } + + +class FJException(Exception): + pass + + +class FJParsingException(FJException): + pass + + +class FJPreprocessorException(FJException): + pass + + +class FJExprException(FJException): + pass + + +class FJAssemblerException(FJException): + pass + + +class FJReadFjmException(FJException): + pass + + +class FJWriteFjmException(FJException): + pass + + +def smart_int16(num): + try: + return int(num, 16) + except ...: + raise FJException(f'{num} is not a number!') + + +def stl(): + path = Path(__file__).parent # relative address + + return [str(path / f'../stl/{lib}.fj') for lib in ('runlib', 'bitlib', 'iolib', 'ptrlib', 'mathlib', + 'hexlib', 'declib')] + + +id_re = r'[a-zA-Z_][a-zA-Z_0-9]*' +dot_id_re = fr'(({id_re})|\.*)?(\.({id_re}))+' + +bin_num = r'0[bB][01]+' +hex_num = r'0[xX][0-9a-fA-F]+' +dec_num = r'[0-9]+' + +char_escape_dict = {'0': 0x0, 'a': 0x7, 'b': 0x8, 'e': 0x1b, 'f': 0xc, 'n': 0xa, 'r': 0xd, 't': 0x9, 'v': 0xb, + '\\': 0x5c, "'": 0x27, '"': 0x22, '?': 0x3f} +escape_chars = ''.join(k for k in char_escape_dict) +char = fr'[ -~]|\\[{escape_chars}]|\\[xX][0-9a-fA-F]{{2}}' + +number_re = fr"({bin_num})|({hex_num})|('({char})')|({dec_num})" +string_re = fr'"({char})*"' + + +def handle_char(s): + if s[0] != '\\': + return ord(s[0]), 1 + if s[1] in char_escape_dict: + return char_escape_dict[s[1]], 2 + return int(s[2:4], 16), 4 + + +class Verbose(Enum): + Parse = 1 + MacroSolve = 2 + LabelDict = 3 + LabelSolve = 4 + Run = 5 + Time = 6 + PrintOutput = 7 + + +class RunFinish(Enum): + Looping = 'looping' + Input = 'input' + NullIP = 'ip<2w' + + +class SegEntry(Enum): + StartAddress = 0 + ReserveAddress = 1 + WflipAddress = 2 + + +class OpType(Enum): # op.data array content: + + FlipJump = 1 # expr, expr # Survives until (2) label resolve + WordFlip = 2 # expr, expr, expr # Survives until (2) label resolve + Segment = 3 # expr # Survives until (2) label resolve + Reserve = 4 # expr # Survives until (2) label resolve + Label = 5 # ID # Survives until (1) macro resolve + Macro = 6 # ID, expr [expr..] # Survives until (1) macro resolve + Rep = 7 # expr, ID, macro_call # Survives until (1) macro resolve + + +class Op: + def __init__(self, op_type, data, file, line): + self.type = op_type + self.data = data + self.file = file + self.line = line + + def __str__(self): + return f'{f"{self.type}:"[7:]:10} Data: {", ".join([str(d) for d in self.data])} ' \ + f'File: {self.file} (line {self.line})' + + def macro_trace_str(self): + assert self.type == OpType.Macro + macro_name, param_len = self.data[0] + return f'macro {macro_name}({param_len}) (File {self.file}, line {self.line})' + + def rep_trace_str(self, iter_value, iter_times): + assert self.type == OpType.Rep + _, iter_name, macro = self.data + macro_name, param_len = macro.data[0] + return f'rep({iter_name}={iter_value}, out of 0..{iter_times-1}) ' \ + f'macro {macro_name}({param_len}) (File {self.file}, line {self.line})' + + +class Expr: + def __init__(self, expr): + self.val = expr + + # replaces every string it can with its dictionary value, and evaluates anything it can. + # returns the list of unknown id's + def eval(self, id_dict, file, line): + if self.is_tuple(): + op, exps = self.val + res = [e.eval(id_dict, file, line) for e in exps] + if any(res): + return sum(res, start=[]) + else: + try: + self.val = parsing_op2func[op](*[e.val for e in exps]) + return [] + except BaseException as e: + raise FJExprException(f'{repr(e)}. bad math operation ({op}): {str(self)} in file {file} (line {line})') + elif self.is_str(): + if self.val in id_dict: + self.val = id_dict[self.val].val + return self.eval({}, file, line) + else: + return [self.val] + return [] + + def is_int(self): + return type(self.val) is int + + def is_str(self): + return type(self.val) is str + + def is_tuple(self): + return type(self.val) is tuple + + def __str__(self): + if self.is_tuple(): + op, exps = self.val + if len(exps) == 1: + e1 = exps[0] + return f'(#{str(e1)})' + elif len(exps) == 2: + e1, e2 = exps + return f'({str(e1)} {op} {str(e2)})' + else: + e1, e2, e3 = exps + return f'({str(e1)} ? {str(e2)} : {str(e3)})' + if self.is_str(): + return self.val + if self.is_int(): + return hex(self.val)[2:] + raise FJExprException(f'bad expression: {self.val} (of type {type(self.val)})') + + +def eval_all(op, id_dict=None): + if id_dict is None: + id_dict = {} + + ids = [] + for expr in op.data: + if type(expr) is Expr: + ids += expr.eval(id_dict, op.file, op.line) + if op.type == OpType.Rep: + macro_op = op.data[2] + ids += eval_all(macro_op, id_dict) + return ids + + +def all_used_labels(ops): + used_labels, declared_labels = set(), set() + for op in ops: + if op.type == OpType.Rep: + n, i, macro_call = op.data + used_labels.update(n.eval({}, op.file, op.line)) + new_labels = set() + new_labels.update(*[e.eval({}, op.file, op.line) for e in macro_call.data[1:]]) + used_labels.update(new_labels - {i}) + elif op.type == OpType.Label: + declared_labels.add(op.data[0]) + else: + for expr in op.data: + if type(expr) is Expr: + used_labels.update(expr.eval({}, op.file, op.line)) + return used_labels, declared_labels + + +def id_swap(op, id_dict): + new_data = [] + for datum in op.data: + if type(datum) is str and datum in id_dict: + swapped_label = id_dict[datum] + if not swapped_label.is_str(): + raise FJExprException(f'Bad label swap (from {datum} to {swapped_label}) in {op}.') + new_data.append(swapped_label.val) + else: + new_data.append(datum) + op.data = tuple(new_data) + + +def new_label(counter, name=''): + if name == '': + return Expr(f'_.label{next(counter)}') + else: + return Expr(f'_.label{next(counter)}_{name}') + + +wflip_start_label = '_.wflip_area_start_' + + +def next_address() -> Expr: + return Expr('$') diff --git a/flipjump/impl/fj.py b/flipjump/impl/fj.py new file mode 100644 index 0000000..39af9f1 --- /dev/null +++ b/flipjump/impl/fj.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 + +from assembler import assemble +from fjm_run import debug_and_run + +import os +import struct +from os.path import isfile, abspath +import difflib +from tempfile import mkstemp +import argparse +from defs import * + + +def main(): + parser = argparse.ArgumentParser(description='Assemble and Run FlipJump programs.') + parser.add_argument('file', help="the FlipJump files.", nargs='+') + parser.add_argument('-s', '--silent', help="don't show assemble & run times", action='store_true') + parser.add_argument('-o', '--outfile', help="output assembled file.") + parser.add_argument('--no-macros', help="output no-macros file.") + parser.add_argument('-d', '--debug', help="debug file (used for breakpoints).", nargs='?', const=True) + parser.add_argument('-f', '--flags', help="running flags", type=int, default=0) + parser.add_argument('-w', '--width', help="specify memory-width. 64 by default.", + type=int, default=64, choices=[8, 16, 32, 64]) + parser.add_argument('--Werror', help="make all warnings into errors.", action='store_true') + parser.add_argument('--no-stl', help="don't assemble/link the standard library files.", action='store_true') + parser.add_argument('--stats', help="show macro usage statistics.", action='store_true') + parser.add_argument('-t', '--test', help="expects paths to input/expected-output files " + "(s.t. the files are path.in, path.out)", nargs='+') + parser.add_argument('-b', '--breakpoint', help="pause when reaching this label", + default=[], action='append') + parser.add_argument('-B', '--any_breakpoint', help="pause when reaching any label containing this", + default=[], action='append') + + args = parser.parse_args() + + + + ##### - ASSEMBLE + + verbose_set = set() + if not args.silent: + verbose_set.add(Verbose.Time) + + if not args.no_stl: + args.file = stl() + args.file + for file in args.file: + file = abspath(file) + if not file.endswith('.fj'): + parser.error(f'file {file} is not a .fj file.') + if not isfile(abspath(file)): + parser.error(f'file {file} does not exist.') + + temp_assembled_file, temp_assembled_fd = False, 0 + if args.outfile is None: + temp_assembled_fd, args.outfile = mkstemp() + temp_assembled_file = True + else: + if not args.outfile.endswith('.fjm'): + parser.error(f'output file {args.outfile} is not a .fjm file.') + + temp_debug_file, temp_debug_fd = False, 0 + if args.debug is None and (len(args.breakpoint) > 0 or len(args.any_breakpoint) > 0): + print(f"Warning - breakpoints are used but the debugging flag (-d) is not specified. " + f"Debugging data will be saved.") + args.debug = True + if args.debug is True: + temp_debug_fd, args.debug = mkstemp() + temp_debug_file = True + + try: + assemble(args.file, args.outfile, args.width, args.Werror, flags=args.flags, + show_statistics=args.stats, + preprocessed_file=args.no_macros, debugging_file=args.debug, verbose=verbose_set) + except FJException as e: + print() + print(e) + exit(1) + + if temp_assembled_file: + os.close(temp_assembled_fd) + + + + ##### - RUN + + verbose_set = set() if args.test else {Verbose.PrintOutput} + if not args.silent: + verbose_set.add(Verbose.Time) + + if args.test: + failures = [] + total = 0 + for test in args.test: + total += 1 + infile = f'{test}.in' + outfile = f'{test}.out' + if not isfile(infile): + print(f'test "{test}" missing an infile ("{infile}").\n') + failures.append(test) + continue + if not isfile(outfile): + print(f'test "{test}" missing an outfile ("{outfile}").\n') + failures.append(test) + continue + + print(f'running {Path(test).name}:') + with open(infile, 'r', encoding='utf-8') as inf: + test_input = inf.read() + with open(outfile, 'r', encoding='utf-8') as outf: + expected_output = outf.read() + + try: + run_time, ops_executed, flips_executed, output, finish_cause = \ + debug_and_run(args.outfile, + defined_input=test_input, + verbose=verbose_set) + if output != expected_output: + print(f'test "{test}" failed. here\'s the diff:') + print(''.join(difflib.context_diff(output.splitlines(1), expected_output.splitlines(True), + fromfile='assembled file' if temp_assembled_file else args.outfile, + tofile=outfile))) + failures.append(test) + if not args.silent: + print(f'finished by {finish_cause.value} after {run_time:.3f}s ({ops_executed:,} ops executed, {flips_executed / ops_executed * 100:.2f}% flips)') + except FJReadFjmException as e: + print() + print(e) + failures.append(test) + + print() + + print() + if len(failures) == 0: + print(f'All tests passed! 100%') + else: + print(f'{total-len(failures)}/{total} tests passed ({(total-len(failures))/total*100:.2f}%).') + print(f'Failed tests:') + for test in failures: + print(f' {test}') + else: + + breakpoint_set = set(args.breakpoint) + breakpoint_any_set = set(args.any_breakpoint) + + try: + run_time, ops_executed, flips_executed, output, finish_cause = \ + debug_and_run(args.outfile, debugging_file=args.debug, + defined_input=None, + verbose=verbose_set, + breakpoint_labels=breakpoint_set, + breakpoint_any_labels=breakpoint_any_set) + if not args.silent: + print(f'finished by {finish_cause.value} after {run_time:.3f}s ({ops_executed:,} ops executed, {flips_executed / ops_executed * 100:.2f}% flips)') + print() + except FJReadFjmException as e: + print() + print(e) + exit(1) + + if temp_debug_file: + os.close(temp_debug_fd) + + +if __name__ == '__main__': + main() diff --git a/flipjump/impl/fj_parser.py b/flipjump/impl/fj_parser.py new file mode 100644 index 0000000..4b281e6 --- /dev/null +++ b/flipjump/impl/fj_parser.py @@ -0,0 +1,642 @@ +from sly import Lexer, Parser +from os import path +from defs import * + + +global curr_file, curr_text, error_occurred, curr_namespace, reserved_names + + +def syntax_error(line, msg=''): + global error_occurred + error_occurred = True + print() + if msg: + print(f"Syntax Error in file {curr_file} line {line}:") + print(f" {msg}") + else: + print(f"Syntax Error in file {curr_file} line {line}") + + +def syntax_warning(line, is_error, msg=''): + if is_error: + global error_occurred + error_occurred = True + print() + print(f"Syntax Warning in file {curr_file}", end="") + if line is not None: + print(f" line {line}", end="") + if msg: + print(f":") + print(f" {msg}") + else: + print() + + +class FJLexer(Lexer): + tokens = {NS, DEF, REP, + WFLIP, SEGMENT, RESERVE, + ID, DOT_ID, NUMBER, STRING, + LE, GE, EQ, NEQ, + SHL, SHR, + NL, SC} + + literals = {'=', '+', '-', '*', '/', '%', + '(', ')', + '$', + '^', '|', '&', + '?', ':', + '<', '>', + '"', + '#', + '{', '}', + "@", ","} + + ignore_ending_comment = r'//.*' + + # Tokens + DOT_ID = dot_id_re + ID = id_re + NUMBER = number_re + STRING = string_re + + ID[r'def'] = DEF + ID[r'rep'] = REP + ID[r'ns'] = NS + + ID[r'wflip'] = WFLIP + + ID[r'segment'] = SEGMENT + ID[r'reserve'] = RESERVE + + global reserved_names + reserved_names = {DEF, REP, NS, WFLIP, SEGMENT, RESERVE} + + LE = "<=" + GE = ">=" + + EQ = "==" + NEQ = "!=" + + SHL = r'<<' + SHR = r'>>' + + # Punctuations + NL = r'[\r\n]' + SC = r';' + + ignore = ' \t' + + def NUMBER(self, t): + n = t.value + if len(n) >= 2: + if n[0] == "'": + t.value = handle_char(n[1:-1])[0] + elif n[1] in 'xX': + t.value = int(n, 16) + elif n[1] in 'bB': + t.value = int(n, 2) + else: + t.value = int(n) + else: + t.value = int(t.value) + return t + + def STRING(self, t): + chars = [] + s = t.value[1:-1] + i = 0 + while i < len(s): + val, length = handle_char(s[i:]) + chars.append(val) + i += length + t.value = sum(val << (i*8) for i, val in enumerate(chars)) + return t + + def NL(self, t): + self.lineno += 1 + return t + + def error(self, t): + global error_occurred + error_occurred = True + print() + print(f"Lexing Error in file {curr_file} line {self.lineno}: {t.value[0]}") + self.index += 1 + + +class FJParser(Parser): + tokens = FJLexer.tokens + # TODO add Unary Minus (-), Unary Not (~). Maybe add logical or (||) and logical and (&&). Maybe handle power (**). + precedence = ( + ('right', '?', ':'), + ('left', '|'), + ('left', '^'), + ('nonassoc', '<', '>', LE, GE), + ('left', EQ, NEQ), + ('left', '&'), + ('left', SHL, SHR), + ('left', '+', '-'), + ('left', '*', '/', '%'), + ('right', '#'), + ) + # debugfile = 'src/parser.out' + + def __init__(self, w, warning_as_errors, verbose=False): + self.verbose = verbose + self.defs = {'w': Expr(w)} + self.warning_as_errors = warning_as_errors + + # [(params, quiet_params), statements, (curr_file, p.lineno, ns_name)] + self.macros = {main_macro: [([], []), [], (None, None, '')]} + + def check_macro_name(self, name, line): + global reserved_names + base_name = self.ns_to_base_name(name[0]) + if base_name in reserved_names: + syntax_error(line, f'macro name can\'t be {name[0]} ({base_name} is a reserved name)!') + if name in self.macros: + _, _, (other_file, other_line, _) = self.macros[name] + syntax_error(line, f'macro {name} is declared twice! ' + f'also declared in file {other_file} (line {other_line}).') + + def check_params(self, ids, macro_name, line): + for param_id in ids: + if param_id in self.defs: + syntax_error(line, f'parameter {param_id} in macro {macro_name[0]}({macro_name[1]}) ' + f'is also defined as a constant variable (with value {self.defs[param_id]})') + for i1 in range(len(ids)): + for i2 in range(i1): + if ids[i1] == ids[i2]: + syntax_error(line, f'parameter {ids[i1]} in macro {macro_name[0]}({macro_name[1]}) ' + f'is declared twice!') + + def check_label_usage(self, labels_used, labels_declared, params, externs, global_labels, line, macro_name): + if global_labels & externs: + syntax_error(line, f"In macro {macro_name[0]}({macro_name[1]}): " + f"extern labels can't be global labels: " + ', '.join(global_labels & externs)) + if global_labels & params: + syntax_error(line, f"In macro {macro_name[0]}({macro_name[1]}): " + f"extern labels can't be regular labels: " + ', '.join(global_labels & params)) + if externs & params: + syntax_error(line, f"In macro {macro_name[0]}({macro_name[1]}): " + f"global labels can't be regular labels: " + ', '.join(externs & params)) + + # params.update([self.ns_full_name(p) for p in params]) + # externs = set([self.ns_full_name(p) for p in externs]) + # globals.update([self.ns_full_name(p) for p in globals]) + + unused_labels = params - labels_used.union(self.ns_to_base_name(label) for label in labels_declared) + if unused_labels: + syntax_warning(line, self.warning_as_errors, + f"In macro {macro_name[0]}({macro_name[1]}): " + f"unused labels: {', '.join(unused_labels)}.") + + bad_declarations = labels_declared - set(self.ns_full_name(label) for label in externs.union(params)) + if bad_declarations: + syntax_warning(line, self.warning_as_errors, + f"In macro {macro_name[0]}({macro_name[1]}): " + f"Declared a not extern/parameter label: {', '.join(bad_declarations)}.") + + bad_uses = labels_used - global_labels - params - set(labels_declared) - {'$'} + if bad_uses: + # print('\nused:', labels_used, 'globals:', globals, 'params:', params) + syntax_warning(line, self.warning_as_errors, + f"In macro {macro_name[0]}({macro_name[1]}): " + f"Used a not global/parameter/declared-extern label: {', '.join(bad_uses)}.") + + @staticmethod + def ns_name(): + return '.'.join(curr_namespace) + + @staticmethod + def ns_full_name(base_name): + return '.'.join(curr_namespace + [base_name]) + + @staticmethod + def dot_id_to_ns_full_name(p): + base_name = p.DOT_ID + without_dots = base_name.lstrip('.') + if len(without_dots) == len(base_name): + return base_name + num_of_dots = len(base_name) - len(without_dots) + if num_of_dots - 1 > len(curr_namespace): + syntax_error(p.lineno, f'Used more leading dots than current namespace depth ' + f'({num_of_dots}-1 > {len(curr_namespace)})') + return '.'.join(curr_namespace[:len(curr_namespace)-(num_of_dots-1)] + [without_dots]) + + @staticmethod + def ns_to_base_name(name): + return name.split('.')[-1] + + def error(self, token): + global error_occurred + error_occurred = True + print() + print(f'Syntax Error in file {curr_file} line {token.lineno}, token=("{token.type}", {token.value})') + + @_('definable_line_statements') + def program(self, p): + ops = p.definable_line_statements + self.macros[main_macro][1] = ops + + # labels_used, labels_declared = all_used_labels(ops) + # bad_uses = labels_used - set(labels_declared) - {'$'} + # if bad_uses: + # syntax_warning(None, self.warning_as_errors, + # f"Outside of macros: " + # f"Used a not declared label: {', '.join(bad_uses)}.") + + @_('definable_line_statements NL definable_line_statement') + def definable_line_statements(self, p): + if p.definable_line_statement: + return p.definable_line_statements + p.definable_line_statement + return p.definable_line_statements + + @_('definable_line_statement') + def definable_line_statements(self, p): + if p.definable_line_statement: + return p.definable_line_statement + return [] + + @_('') + def empty(self, p): + return None + + @_('line_statement') + def definable_line_statement(self, p): + return p.line_statement + + @_('macro_def') + def definable_line_statement(self, p): + return [] + + @_('NS ID') + def namespace(self, p): + curr_namespace.append(p.ID) + + @_('namespace "{" NL definable_line_statements NL "}"') + def definable_line_statement(self, p): + curr_namespace.pop() + return p.definable_line_statements + + @_('DEF ID macro_params "{" NL line_statements NL "}"') + def macro_def(self, p): + params, local_params, global_params, extern_params = p.macro_params + name = (self.ns_full_name(p.ID), len(params)) + self.check_macro_name(name, p.lineno) + self.check_params(params + local_params, name, p.lineno) + ops = p.line_statements + self.check_label_usage(*all_used_labels(ops), set(params + local_params), set(extern_params), + set(global_params), p.lineno, name) + self.macros[name] = [(params, local_params), ops, (curr_file, p.lineno, self.ns_name())] + return None + + @_('empty') + def maybe_ids(self, p): + return [] + + @_('IDs') + def maybe_ids(self, p): + return p.IDs + + @_('empty') + def maybe_local_ids(self, p): + return [] + + @_('"@" IDs') + def maybe_local_ids(self, p): + return p.IDs + + @_('empty') + def maybe_extern_ids(self, p): + return [] + + @_('empty') + def maybe_global_ids(self, p): + return [] + + @_('"<" ids') + def maybe_global_ids(self, p): + return p.ids + + @_('">" IDs') + def maybe_extern_ids(self, p): + return p.IDs + + @_('maybe_ids maybe_local_ids maybe_global_ids maybe_extern_ids') + def macro_params(self, p): + return p.maybe_ids, p.maybe_local_ids, p.maybe_global_ids, p.maybe_extern_ids + + @_('IDs "," ID') + def IDs(self, p): + return p.IDs + [p.ID] + + @_('ID') + def IDs(self, p): + return [p.ID] + + @_('line_statements NL line_statement') + def line_statements(self, p): + return p.line_statements + p.line_statement + + @_('line_statement') + def line_statements(self, p): + return p.line_statement + + # @_('empty') + # def line_statements(self, p): + # return [] + + @_('empty') + def line_statement(self, p): + return [] + + @_('statement') + def line_statement(self, p): + if p.statement: + return [p.statement] + return [] + + @_('label statement') + def line_statement(self, p): + if p.statement: + return [p.label, p.statement] + return [p.label] + + @_('label') + def line_statement(self, p): + return [p.label] + + @_('ID ":"') + def label(self, p): + return Op(OpType.Label, (self.ns_full_name(p.ID),), curr_file, p.lineno) + + @_('expr SC') + def statement(self, p): + return Op(OpType.FlipJump, (p.expr, next_address()), curr_file, p.lineno) + + @_('expr SC expr') + def statement(self, p): + return Op(OpType.FlipJump, (p.expr0, p.expr1), curr_file, p.lineno) + + @_('SC expr') + def statement(self, p): + return Op(OpType.FlipJump, (Expr(0), p.expr), curr_file, p.lineno) + + @_('SC') + def statement(self, p): + return Op(OpType.FlipJump, (Expr(0), next_address()), curr_file, p.lineno) + + @_('ID') + def id(self, p): + return p.ID, p.lineno + + @_('DOT_ID') + def id(self, p): + return self.dot_id_to_ns_full_name(p), p.lineno + + @_('ids "," id') + def ids(self, p): + return p.ids + [p.id[0]] + + @_('id') + def ids(self, p): + return [p.id[0]] + + @_('id') + def statement(self, p): + macro_name, lineno = p.id + return Op(OpType.Macro, ((macro_name, 0), ), curr_file, lineno) + + @_('id expressions') + def statement(self, p): + macro_name, lineno = p.id + return Op(OpType.Macro, ((macro_name, len(p.expressions)), *p.expressions), curr_file, lineno) + + @_('WFLIP expr "," expr') + def statement(self, p): + return Op(OpType.WordFlip, (p.expr0, p.expr1, next_address()), curr_file, p.lineno) + + @_('WFLIP expr "," expr "," expr') + def statement(self, p): + return Op(OpType.WordFlip, (p.expr0, p.expr1, p.expr2), curr_file, p.lineno) + + @_('ID "=" expr') + def statement(self, p): + name = self.ns_full_name(p.ID) + if name in self.defs: + syntax_error(p.lineno, f'Can\'t redeclare the variable "{name}".') + if not p.expr.eval(self.defs, curr_file, p.lineno): + self.defs[name] = p.expr + return None + syntax_error(p.lineno, f'Can\'t evaluate expression: {str(p.expr)}.') + + @_('REP "(" expr "," ID ")" id') + def statement(self, p): + macro_name, lineno = p.id + return Op(OpType.Rep, + (p.expr, p.ID, Op(OpType.Macro, ((macro_name, 0), ), curr_file, lineno)), + curr_file, p.lineno) + + @_('REP "(" expr "," ID ")" id expressions') + def statement(self, p): + exps = p.expressions + macro_name, lineno = p.id + return Op(OpType.Rep, + (p.expr, p.ID, Op(OpType.Macro, ((macro_name, len(exps)), *exps), curr_file, lineno)), + curr_file, p.lineno) + + @_('SEGMENT expr') + def statement(self, p): + return Op(OpType.Segment, (p.expr,), curr_file, p.lineno) + + @_('RESERVE expr') + def statement(self, p): + return Op(OpType.Reserve, (p.expr,), curr_file, p.lineno) + + @_('expressions "," expr') + def expressions(self, p): + return p.expressions + [p.expr] + + @_('expr') + def expressions(self, p): + return [p.expr] + + @_('_expr') + def expr(self, p): + return p._expr[0] + + @_('_expr "+" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a + b), p.lineno + return Expr(('+', (a, b))), p.lineno + + @_('_expr "-" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a - b), p.lineno + return Expr(('-', (a, b))), p.lineno + + @_('_expr "*" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a * b), p.lineno + return Expr(('*', (a, b))), p.lineno + + @_('"#" _expr') + def _expr(self, p): + a = p._expr[0] + if a is int: + return Expr(a.bit_length()), p.lineno + return Expr(('#', (a,))), p.lineno + + @_('_expr "/" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a // b), p.lineno + return Expr(('/', (a, b))), p.lineno + + @_('_expr "%" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a % b), p.lineno + return Expr(('%', (a, b))), p.lineno + + @_('_expr SHL _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a << b), p.lineno + return Expr(('<<', (a, b))), p.lineno + + @_('_expr SHR _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a >> b), p.lineno + return Expr(('>>', (a, b))), p.lineno + + @_('_expr "^" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a ^ b), p.lineno + return Expr(('^', (a, b))), p.lineno + + @_('_expr "|" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a | b), p.lineno + return Expr(('|', (a, b))), p.lineno + + @_('_expr "&" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(a & b), p.lineno + return Expr(('&', (a, b))), p.lineno + + @_('_expr "?" _expr ":" _expr') + def _expr(self, p): + a, b, c = p._expr0[0], p._expr1[0], p._expr2[0] + if a is int and b is int and c is int: + return Expr(b if a else c), p.lineno + return Expr(('?:', (a, b, c))), p.lineno + + @_('_expr "<" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(1 if a < b else 0), p.lineno + return Expr(('<', (a, b))), p.lineno + + @_('_expr ">" _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(1 if a > b else 0), p.lineno + return Expr(('>', (a, b))), p.lineno + + @_('_expr LE _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(1 if a <= b else 0), p.lineno + return Expr(('<=', (a, b))), p.lineno + + @_('_expr GE _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(1 if a >= b else 0), p.lineno + return Expr(('>=', (a, b))), p.lineno + + @_('_expr EQ _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(1 if a == b else 0), p.lineno + return Expr(('==', (a, b))), p.lineno + + @_('_expr NEQ _expr') + def _expr(self, p): + a, b = p._expr0[0], p._expr1[0] + if a is int and b is int: + return Expr(1 if a != b else 0), p.lineno + return Expr(('!=', (a, b))), p.lineno + + @_('"(" _expr ")"') + def _expr(self, p): + return p._expr + + @_('NUMBER') + def _expr(self, p): + return Expr(p.NUMBER), p.lineno + + @_('STRING') + def _expr(self, p): + return Expr(p.STRING), p.lineno + + @_('"$"') + def _expr(self, p): + return next_address(), p.lineno + + @_('id') + def _expr(self, p): + id_str, lineno = p.id + if id_str in self.defs: + return self.defs[id_str], lineno + return Expr(id_str), lineno + + +def exit_if_errors(): + if error_occurred: + raise FJParsingException(f'Errors found in file {curr_file}. Assembly stopped.') + + +def parse_macro_tree(input_files, w, warning_as_errors, verbose=False): + global curr_file, curr_text, error_occurred, curr_namespace + error_occurred = False + + lexer = FJLexer() + parser = FJParser(w, warning_as_errors, verbose=verbose) + for curr_file in input_files: + if not path.isfile(curr_file): + raise FJParsingException(f"No such file {curr_file}.") + curr_text = open(curr_file, 'r').read() + curr_namespace = [] + + lex_res = lexer.tokenize(curr_text) + exit_if_errors() + + parser.parse(lex_res) + exit_if_errors() + + return parser.macros diff --git a/flipjump/impl/fja.py b/flipjump/impl/fja.py new file mode 100644 index 0000000..e0b92c4 --- /dev/null +++ b/flipjump/impl/fja.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +from assembler import assemble + +from os.path import isfile, abspath, isdir, join +from glob import glob +import traceback +import argparse +from defs import * + + +def main(): + parser = argparse.ArgumentParser(description='Assemble FlipJump programs.') + parser.add_argument('file', help="the FlipJump files.", nargs='+') + parser.add_argument('-s', '--silent', help="don't show assemble times", action='store_true') + parser.add_argument('-o', '--outfile', help="output assembled file.", default="a.fjm") + parser.add_argument('--no-macros', help="output no-macros file.") + parser.add_argument('-d', '--debug', help="output debug file (used for breakpoints).") + parser.add_argument('-f', '--flags', help="default running flags", type=int, default=0) + parser.add_argument('-w', '--width', help="specify memory-width. 64 by default.", + type=int, default=64, choices=[8, 16, 32, 64]) + parser.add_argument('--Werror', help="make all warnings into errors.", action='store_true') + parser.add_argument('--no-stl', help="don't assemble/link the standard library files.", action='store_true') + parser.add_argument('--tests', help="compile all .fj files in the given folder (instead of specifying a file).", + action='store_true') + parser.add_argument('--stats', help="show macro usage statistics.", action='store_true') + args = parser.parse_args() + + verbose_set = set() + if not args.silent: + verbose_set.add(Verbose.Time) + + if args.tests: + if len(args.file) != 1 or not isdir(args.file[0]): + parser.error('the "file" argument should contain a folder path.') + Path.mkdir(Path(args.file[0]) / 'compiled', exist_ok=True) + failures = [] + total = 0 + for file in glob(join(args.file[0], '*.fj')): + + # if file in (r'tests\calc.fj', r'tests\func.fj', r'tests\pair_ns.fj') or file.startswith(r'tests\hexlib-'): + # continue + + total += 1 + print(f'compiling {Path(file).name}:') + no_stl = args.no_stl or 'no-stl' in Path(file).stem + try: + assemble([file] if no_stl else stl() + [file], + (Path(args.file[0]) / 'compiled' / (Path(file).stem + '.fjm')), + args.width, args.Werror, flags=args.flags, verbose=verbose_set) + except FJException as e: + print() + print(e) + failures.append(file) + print() + + print() + if len(failures) == 0: + print(f'All tests compiled successfully! 100%') + else: + print(f'{total-len(failures)}/{total} tests compiled successfully ({(total-len(failures))/total*100:.2f}%).') + print(f'Failed compilations:') + for test in failures: + print(f' {test}') + + else: + if not args.no_stl: + args.file = stl() + args.file + for file in args.file: + file = abspath(file) + if not file.endswith('.fj'): + parser.error(f'file {file} is not a .fj file.') + if not isfile(abspath(file)): + parser.error(f'file {file} does not exist.') + try: + assemble(args.file, args.outfile, args.width, args.Werror, flags=args.flags, + show_statistics=args.stats, + preprocessed_file=args.no_macros, debugging_file=args.debug, verbose=verbose_set) + except FJException as e: + print() + print(e) + exit(1) + + +if __name__ == '__main__': + main() diff --git a/flipjump/impl/fji.py b/flipjump/impl/fji.py new file mode 100644 index 0000000..6ff1d71 --- /dev/null +++ b/flipjump/impl/fji.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +import struct + +from fjm_run import debug_and_run + +from os.path import isfile, abspath, isdir, join +from defs import * +from glob import glob +import argparse +import difflib + + +def main(): + parser = argparse.ArgumentParser(description='Run FlipJump programs.') + parser.add_argument('file', help="the FlipJump file.") + parser.add_argument('-s', '--silent', help="don't show run times", action='store_true') + parser.add_argument('-t', '--trace', help="trace the running opcodes.", action='store_true') + parser.add_argument('-f', '--flags', help="running flags", type=int, default=0) + parser.add_argument('-d', '--debug', help='debugging file') + parser.add_argument('-b', '--breakpoint', help="pause when reaching this label", + default=[], action='append') + parser.add_argument('-B', '--any_breakpoint', help="pause when reaching any label containing this", + default=[], action='append') + parser.add_argument('--tests', help="run all .fjm files in the given folder (instead of specifying a file). " + "Expects an input/expected-output directory. " + "Each *.fjm file will be tested with " + "dir/*.in as input, and its output will be compared to dir/*.out.") + args = parser.parse_args() + + verbose_set = set() if args.tests else {Verbose.PrintOutput} + if not args.silent: + verbose_set.add(Verbose.Time) + if args.trace: + verbose_set.add(Verbose.Run) + + if args.tests: + inout_dir = args.tests + failures = [] + total = 0 + folder = abspath(args.file) + if not isdir(folder): + print('Error: The "file" argument should contain a folder path.') + exit(1) + for file in glob(join(folder, '*.fjm')): + total += 1 + infile = abspath(str(Path(inout_dir) / f'{Path(file).stem}.in')) + outfile = abspath(str(Path(inout_dir) / f'{Path(file).stem}.out')) + if not isfile(infile): + print(f'test "{file}" missing an infile ("{infile}").\n') + failures.append(file) + continue + if not isfile(outfile): + print(f'test "{file}" missing an outfile ("{outfile}").\n') + failures.append(file) + continue + + print(f'running {Path(file).name}:') + with open(infile, 'r', encoding='utf-8') as inf: + test_input = inf.read() + with open(outfile, 'r', encoding='utf-8') as outf: + expected_output = outf.read() + + try: + run_time, ops_executed, flips_executed, output, finish_cause = \ + debug_and_run(file, defined_input=test_input, verbose=verbose_set) + + if not args.silent: + print(f'finished by {finish_cause.value} after {run_time:.3f}s ({ops_executed:,} ops executed, {flips_executed/ops_executed*100:.2f}% flips)') + + if output != expected_output: + print(f'test "{file}" failed. here\'s the diff:') + print(''.join(difflib.context_diff(output.splitlines(1), expected_output.splitlines(True), + fromfile=file, tofile=outfile))) + failures.append(file) + + if finish_cause != RunFinish.Looping: + print(f'test "{file}" finished unexpectedly, with {finish_cause.value}.') + failures.append(file) + except FJReadFjmException as e: + print() + print(e) + failures.append(file) + + print() + + print() + if len(failures) == 0: + print(f'All tests passed! 100%') + else: + print(f'{total-len(failures)}/{total} tests passed ({(total-len(failures))/total*100:.2f}%).') + print(f'Failed tests:') + for test in failures: + print(f' {test}') + else: + + file = abspath(args.file) + if not isfile(file): + parser.error(f'file {file} does not exist.') + if not file.endswith('.fjm'): + parser.error(f'file {file} is not a .fjm file.') + + if args.debug: + debug_file = abspath(args.debug) + if not isfile(debug_file): + parser.error(f'debug-file {debug_file} does not exist.') + + breakpoint_set = set(args.breakpoint) + breakpoint_any_set = set(args.any_breakpoint) + + try: + run_time, ops_executed, flips_executed, output, finish_cause = \ + debug_and_run(file, debugging_file=args.debug, + defined_input=None, + verbose=verbose_set, + breakpoint_labels=breakpoint_set, + breakpoint_any_labels=breakpoint_any_set) + + if not args.silent: + print(f'finished by {finish_cause.value} after {run_time:.3f}s ({ops_executed:,} ops executed, {flips_executed/ops_executed*100:.2f}% flips)') + print() + except FJReadFjmException as e: + print() + print(e) + exit(1) + + +if __name__ == '__main__': + main() diff --git a/flipjump/impl/fjm.py b/flipjump/impl/fjm.py new file mode 100644 index 0000000..9d1e37d --- /dev/null +++ b/flipjump/impl/fjm.py @@ -0,0 +1,150 @@ +import struct +from struct import pack, unpack +from random import randint +from time import sleep +from defs import FJReadFjmException, FJWriteFjmException + + +""" +struct { + u16 fj_magic; // 'F' + 'J'<<8 (0x4a46) + u16 word_size; // in bits + u64 flags; + u64 segment_num; + struct segment { + u64 segment_start; // in memory words (w-bits) + u64 segment_length; // in memory words (w-bits) + u64 data_start; // in the outer-struct.data words (w-bits) + u64 data_length; // in the outer-struct.data words (w-bits) + } *segments; // segments[segment_num] + u8* data; // the data +} fjm_file; // Flip-Jump Memory file +""" + +fj_magic = ord('F') + (ord('J') << 8) +reserved_dict_threshold = 1000 + +header_struct_format = ' data_length: + if segment_length - data_length < reserved_dict_threshold: + for i in range(data_length, segment_length): + self.mem[segment_start + i] = 0 + else: + self.zeros_boundaries.append((segment_start + data_length, segment_start + segment_length)) + except struct.error: + raise FJReadFjmException(f"Bad file {input_file}, can't unpack. Maybe it's not a .fjm file?") + + def __getitem__(self, address): + address &= ((1 << self.w) - 1) + if address not in self.mem: + for start, end in self.zeros_boundaries: + if start <= address < end: + self.mem[address] = 0 + return 0 + garbage_val = randint(0, (1 << self.w) - 1) + garbage_message = f'Reading garbage word at mem[{hex(address << self.w)[2:]}] = {hex(garbage_val)[2:]}' + if self.stop_after_garbage: + raise FJReadFjmException(garbage_message) + print(f'\nWarning: {garbage_message}') + if self.slow_garbage_read: + sleep(0.1) + self.mem[address] = garbage_val + return self.mem[address] + + def __setitem__(self, address, value): + address &= ((1 << self.w) - 1) + value &= ((1 << self.w) - 1) + self.mem[address] = value + + def bit_address_decompose(self, bit_address): + address = (bit_address >> (self.w.bit_length() - 1)) & ((1 << self.w) - 1) + bit = bit_address & (self.w - 1) + return address, bit + + def read_bit(self, bit_address): + address, bit = self.bit_address_decompose(bit_address) + return (self[address] >> bit) & 1 + + def write_bit(self, bit_address, value): + address, bit = self.bit_address_decompose(bit_address) + if value: + self[address] = self[address] | (1 << bit) + else: + self[address] = self[address] & ((1 << self.w) - 1 - (1 << bit)) + + def get_word(self, bit_address): + address, bit = self.bit_address_decompose(bit_address) + if bit == 0: + return self[address] + if address == ((1 << self.w) - 1): + raise FJReadFjmException(f'Accessed outside of memory (beyond the last bit).') + l, m = self[address], self[address+1] + return ((l >> bit) | (m << (self.w - bit))) & ((1 << self.w) - 1) + + +class Writer: + def __init__(self, w, flags=0): + self.word_size = w + if self.word_size not in (8, 16, 32, 64): + raise FJWriteFjmException(f"Word size {w} is not in {{8, 16, 32, 64}}.") + self.write_tag = '<' + {8: 'B', 16: 'H', 32: 'L', 64: 'Q'}[self.word_size] + self.flags = flags & ((1 << 64) - 1) + self.segments = [] + self.data = [] # words array + + def write_to_file(self, output_file): + write_tag = '<' + {8: 'B', 16: 'H', 32: 'L', 64: 'Q'}[self.word_size] + + with open(output_file, 'wb') as f: + f.write(pack(header_struct_format, fj_magic, self.word_size, self.flags, len(self.segments))) + + for segment in self.segments: + f.write(pack(segment_struct_format, *segment)) + + for datum in self.data: + f.write(pack(write_tag, datum)) + + def add_segment(self, segment_start, segment_length, data_start, data_length): + if segment_length < data_length: + raise FJWriteFjmException(f"segment-length must be at-least data-length") + self.segments.append((segment_start, segment_length, data_start, data_length)) + + def add_data(self, data): + start = len(self.data) + self.data += data + return start, len(data) + + def add_simple_segment_with_data(self, segment_start, data): + data_start, data_length = self.add_data(data) + self.add_segment(segment_start, data_length, data_start, data_length) diff --git a/flipjump/impl/fjm_run.py b/flipjump/impl/fjm_run.py new file mode 100644 index 0000000..d30c32c --- /dev/null +++ b/flipjump/impl/fjm_run.py @@ -0,0 +1,192 @@ +import fjm + +from os import path +from sys import stdin +from time import time +import pickle +import easygui + +from defs import * + + +def get_address_str(address, breakpoints, labels_dict): + if address in breakpoints: + return f'{hex(address)[2:]} ({breakpoints[address]})' + else: + if address in labels_dict: + return f'{hex(address)[2:]} ({labels_dict[address]})' + else: + address_before = max([a for a in labels_dict if a <= address]) + return f'{hex(address)[2:]} ({labels_dict[address_before]} + {hex(address - address_before)})' + + +def run(input_file, breakpoints=None, defined_input=None, verbose=False, time_verbose=False, output_verbose=False, + next_break=None, labels_dict=None): + if labels_dict is None: + labels_dict = {} + if breakpoints is None: + breakpoints = {} + + if time_verbose: + print(f' loading memory: ', end='', flush=True) + start_time = time() + mem = fjm.Reader(input_file) + if time_verbose: + print(f'{time() - start_time:.3f}s') + + ip = 0 + w = mem.w + out_addr = 2*w + in_addr = 3*w + w.bit_length() # 3w + dww + + input_char, input_size = 0, 0 + output_char, output_size = 0, 0 + output = '' + + if 0 not in labels_dict: + labels_dict[0] = 'memory_start_0x0000' + + output_anything_yet = False + ops_executed = 0 + flips_executed = 0 + + start_time = time() + pause_time = 0 + + while True: + if next_break == ops_executed or ip in breakpoints: + pause_time_start = time() + title = "Breakpoint" if ip in breakpoints else "Single Step" + address = get_address_str(ip, breakpoints, labels_dict) + flip = f'flip: {get_address_str(mem.get_word(ip), breakpoints, labels_dict)}' + jump = f'jump: {get_address_str(mem.get_word(ip + w), breakpoints, labels_dict)}' + button_body = f'Address {address} ({ops_executed} ops executed):\n {flip}.\n {jump}.' + print(' program break', end="") + action = easygui.buttonbox(button_body, title, ['Single Step', 'Skip 10', 'Skip 100', 'Skip 1000', + 'Continue', 'Continue All']) + if action is None: + action = 'Continue All' + print(f': {action}') + if action == 'Single Step': + next_break = ops_executed + 1 + elif action == 'Skip 10': + next_break = ops_executed + 10 + elif action == 'Skip 100': + next_break = ops_executed + 100 + elif action == 'Skip 1000': + next_break = ops_executed + 1000 + elif action == 'Continue': + next_break = None + elif action == 'Continue All': + next_break = None + breakpoints.clear() + pause_time += time() - pause_time_start + + f = mem.get_word(ip) + if verbose: + print(f'{hex(ip)[2:].rjust(7)}: {hex(f)[2:]}', end='; ', flush=True) + + ops_executed += 1 + if f >= 2*w: + flips_executed += 1 + + # handle output + if out_addr <= f <= out_addr+1: + output_char |= (f-out_addr) << output_size + output_size += 1 + if output_size == 8: + output += chr(output_char) + if output_verbose: + if verbose: + for _ in range(3): + print() + print(f'Outputted Char: {chr(output_char)}', end='', flush=True) + for _ in range(3): + print() + else: + print(chr(output_char), end='', flush=True) + output_anything_yet = True + output_char, output_size = 0, 0 + + # handle input + if ip <= in_addr < ip+2*w: + if input_size == 0: + if defined_input is None: + pause_time_start = time() + input_char = ord(stdin.read(1)) + pause_time += time() - pause_time_start + elif len(defined_input) > 0: + input_char = ord(defined_input[0]) + defined_input = defined_input[1:] + else: + if output_verbose and output_anything_yet: + print() + run_time = time() - start_time - pause_time + return run_time, ops_executed, flips_executed, output, RunFinish.Input # no more input + input_size = 8 + mem.write_bit(in_addr, input_char & 1) + input_char = input_char >> 1 + input_size -= 1 + + mem.write_bit(f, 1-mem.read_bit(f)) # Flip! + new_ip = mem.get_word(ip+w) + if verbose: + print(hex(new_ip)[2:]) + + if new_ip == ip and not ip <= f < ip+2*w: + if output_verbose and output_anything_yet: + print() + run_time = time()-start_time-pause_time + return run_time, ops_executed, flips_executed, output, RunFinish.Looping # infinite simple loop + if new_ip < 2*w: + if output_verbose and output_anything_yet: + print() + run_time = time() - start_time - pause_time + return run_time, ops_executed, flips_executed, output, RunFinish.NullIP # null ip + ip = new_ip # Jump! + + +def debug_and_run(input_file, debugging_file=None, + defined_input=None, verbose=None, + breakpoint_addresses=None, breakpoint_labels=None, breakpoint_any_labels=None): + if breakpoint_any_labels is None: + breakpoint_any_labels = set() + if breakpoint_labels is None: + breakpoint_labels = set() + if breakpoint_addresses is None: + breakpoint_addresses = set() + if verbose is None: + verbose = set() + + labels = [] + if debugging_file is not None: + if path.isfile(debugging_file): + with open(debugging_file, 'rb') as f: + labels = pickle.load(f) + else: + print(f"Warning: debugging file {debugging_file} can't be found!") + elif breakpoint_labels or breakpoint_addresses or breakpoint_any_labels: + print(f"Warning: debugging labels can't be found! no debugging file specified.") + + # Handle breakpoints + breakpoint_map = {ba: hex(ba) for ba in breakpoint_addresses} + for bl in breakpoint_labels: + if bl not in labels: + print(f"Warning: Breakpoint label {bl} can't be found!") + else: + breakpoint_map[labels[bl]] = bl + for bal in breakpoint_any_labels: + for label in labels: + if bal in label: + breakpoint_map[labels[label]] = f'{bal}@{label}' + + opposite_labels = {labels[label]: label for label in labels} + + run_time, ops_executed, flips_executed, output, finish_cause = run( + input_file, defined_input=defined_input, + verbose=Verbose.Run in verbose, + time_verbose=Verbose.Time in verbose, + output_verbose=Verbose.PrintOutput in verbose, + breakpoints=breakpoint_map, labels_dict=opposite_labels) + + return run_time, ops_executed, flips_executed, output, finish_cause diff --git a/flipjump/impl/preprocessor.py b/flipjump/impl/preprocessor.py new file mode 100644 index 0000000..1918ebb --- /dev/null +++ b/flipjump/impl/preprocessor.py @@ -0,0 +1,216 @@ +from itertools import count +from defs import * +from copy import deepcopy +import collections +import plotly.graph_objects as go +# import matplotlib.pyplot as plt + + +def macro_resolve_error(curr_tree, msg=''): + error_str = f"Macro Resolve Error" + (f':\n {msg}' if msg else '.') + f'\nmacro call trace:\n' + for i, trace_str in enumerate(curr_tree): + error_str += f' {i}) {trace_str}\n' + raise FJPreprocessorException(error_str) + + +def output_ops(ops, output_file): + with open(output_file, 'w') as f: + for op in ops: + eval_all(op) + if op.type == OpType.FlipJump: + f.write(f' {op.data[0]};{op.data[1]}\n') + elif op.type == OpType.WordFlip: + f.write(f' wflip {op.data[0]}, {op.data[1]}, {op.data[2]}\n') + elif op.type == OpType.Label: + f.write(f'{op.data[0]}:\n') + + +def dict_pie_graph(d, total, min_main_thresh=0.05, min_secondary_thresh=0.02): + main_thresh = min_main_thresh * total + secondary_thresh = min_secondary_thresh * total + first_level = {} + second_level = collections.defaultdict(lambda: dict()) + for k, v in d.items(): + if ' => ' not in k: + if v < main_thresh: + continue + first_level[k] = v + else: + if v < secondary_thresh: + continue + k_split = k.split(' => ') + if len(k_split) != 2: + continue + parent, name = k_split + second_level[parent][name] = v + + chosen = [] + for k, v in sorted(first_level.items(), key=lambda x: x[1], reverse=True): + if len(second_level[k]) == 0: + chosen.append((k, v)) + else: + for k2, v2 in sorted(second_level[k].items(), key=lambda x: x[1], reverse=True): + chosen.append((f"{k} => {k2}", v2)) + v -= v2 + if v >= secondary_thresh: + chosen.append((f"{k} others", v)) + + others = total - sum([value for label, value in chosen]) + chosen.append(('all others', others)) + + fig = go.Figure(data=[go.Pie(labels=[label for label, value in chosen], + values=[value for label, value in chosen], + textinfo='label+percent' + )]) + fig.show() + + # plt.pie(d.values(), labels=d.keys(), autopct='%1.2f%%') + # plt.savefig(output_file) + + +def resolve_macros(w, macros, output_file=None, show_statistics=False, verbose=False): + curr_address = [0] + rem_ops = [] + labels = {} + last_address_index = [0] + label_places = {} + boundary_addresses = [(SegEntry.StartAddress, 0)] # SegEntries + stat_dict = collections.defaultdict(lambda: 0) + + ops = resolve_macro_aux(w, '', [], macros, main_macro, [], {}, count(), stat_dict, + labels, rem_ops, boundary_addresses, curr_address, last_address_index, label_places, + verbose) + if output_file: + output_ops(ops, output_file) + + if show_statistics: + dict_pie_graph(dict(stat_dict), curr_address[0]) + + boundary_addresses.append((SegEntry.WflipAddress, curr_address[0])) + return rem_ops, labels, boundary_addresses + + +def try_int(op, expr): + if expr.is_int(): + return expr.val + raise FJPreprocessorException(f"Can't resolve the following name: {expr.eval({}, op.file, op.line)} (in op={op}).") + + +def resolve_macro_aux(w, parent_name, curr_tree, macros, macro_name, args, rep_dict, dollar_count, stat_dict, + labels, rem_ops, boundary_addresses, curr_address, last_address_index, label_places, + verbose=False, file=None, line=None): + commands = [] + init_curr_address = curr_address[0] + this_curr_address = 0 + if macro_name not in macros: + macro_name = f'{macro_name[0]}({macro_name[1]})' + if None in (file, line): + macro_resolve_error(curr_tree, f"macro {macro_name} isn't defined.") + else: + macro_resolve_error(curr_tree, f"macro {macro_name} isn't defined. Used in file {file} (line {line}).") + full_name = (f"{parent_name} => " if parent_name else "") + macro_name[0] + (f"({macro_name[1]})" if macro_name[0] + else "") + (params, dollar_params), ops, (_, _, ns_name) = macros[macro_name] + id_dict = dict(zip(params, args)) + for dp in dollar_params: + id_dict[dp] = new_label(dollar_count, dp) + for k in rep_dict: + id_dict[k] = rep_dict[k] + if ns_name: + for k in list(id_dict.keys()): + id_dict[f'{ns_name}.{k}'] = id_dict[k] + + for op in ops: + # macro-resolve + if type(op) is not Op: + macro_resolve_error(curr_tree, f"bad op (not of Op type)! type {type(op)}, str {str(op)}.") + if verbose: + print(op) + op = deepcopy(op) + eval_all(op, id_dict) + id_swap(op, id_dict) + if op.type == OpType.Macro: + commands += resolve_macro_aux(w, full_name, curr_tree+[op.macro_trace_str()], macros, op.data[0], + list(op.data[1:]), {}, dollar_count, stat_dict, + labels, rem_ops, boundary_addresses, curr_address, last_address_index, + label_places, verbose, file=op.file, line=op.line) + elif op.type == OpType.Rep: + eval_all(op, labels) + n, i_name, macro_call = op.data + if not n.is_int(): + macro_resolve_error(curr_tree, f'Rep used without a number "{str(n)}" ' + f'in file {op.file} line {op.line}.') + times = n.val + if times == 0: + continue + if i_name in rep_dict: + macro_resolve_error(curr_tree, f'Rep index {i_name} is declared twice; maybe an inner rep. ' + f'in file {op.file} line {op.line}.') + pseudo_macro_name = (new_label(dollar_count).val, 1) # just moved outside (before) the for loop + for i in range(times): + rep_dict[i_name] = Expr(i) # TODO - call the macro_name directly, and do deepcopy(op) beforehand. + macros[pseudo_macro_name] = (([], []), [macro_call], (op.file, op.line, ns_name)) + commands += resolve_macro_aux(w, full_name, curr_tree+[op.rep_trace_str(i, times)], macros, + pseudo_macro_name, [], rep_dict, dollar_count, stat_dict, + labels, rem_ops, boundary_addresses, curr_address, last_address_index, + label_places, verbose, file=op.file, line=op.line) + if i_name in rep_dict: + del rep_dict[i_name] + else: + macro_resolve_error(curr_tree, f'Rep is used but {i_name} index is gone; maybe also declared elsewhere.' + f' in file {op.file} line {op.line}.') + + # labels_resolve + elif op.type == OpType.Segment: + eval_all(op, labels) + value = try_int(op, op.data[0]) + if value % w != 0: + macro_resolve_error(curr_tree, f'segment ops must have a w-aligned address. In {op}.') + + boundary_addresses.append((SegEntry.WflipAddress, curr_address[0])) + labels[f'{wflip_start_label}{last_address_index[0]}'] = Expr(curr_address[0]) + last_address_index[0] += 1 + + this_curr_address += value - curr_address[0] + curr_address[0] = value + boundary_addresses.append((SegEntry.StartAddress, curr_address[0])) + rem_ops.append(op) + elif op.type == OpType.Reserve: + eval_all(op, labels) + value = try_int(op, op.data[0]) + if value % w != 0: + macro_resolve_error(curr_tree, f'reserve ops must have a w-aligned value. In {op}.') + + this_curr_address += value + curr_address[0] += value + boundary_addresses.append((SegEntry.ReserveAddress, curr_address[0])) + labels[f'{wflip_start_label}{last_address_index[0]}'] = Expr(curr_address[0]) + + last_address_index[0] += 1 + rem_ops.append(op) + elif op.type in {OpType.FlipJump, OpType.WordFlip}: + this_curr_address += 2*w + curr_address[0] += 2*w + eval_all(op, {'$': Expr(curr_address[0])}) + if verbose: + print(f'op added: {str(op)}') + rem_ops.append(op) + elif op.type == OpType.Label: + label = op.data[0] + if label in labels: + other_file, other_line = label_places[label] + macro_resolve_error(curr_tree, f'label declared twice - "{label}" on file {op.file} (line {op.line}) ' + f'and file {other_file} (line {other_line})') + if verbose: + print(f'label added: "{label}" in {op.file} line {op.line}') + labels[label] = Expr(curr_address[0]) + label_places[label] = (op.file, op.line) + else: + macro_resolve_error(curr_tree, f"Can't assemble this opcode - {str(op)}") + + # if len(curr_tree) == 1: + # stat_dict[macro_name[0]] += curr_address[0] - init_curr_address + # stat_dict[macro_name[0]] += this_curr_address + if 1 <= len(curr_tree) <= 2: + stat_dict[full_name] += curr_address[0] - init_curr_address + return commands diff --git a/flipjump/src/stl/bitlib.fj b/flipjump/src/stl/bitlib.fj new file mode 100644 index 0000000..5da5796 --- /dev/null +++ b/flipjump/src/stl/bitlib.fj @@ -0,0 +1,402 @@ +// Every line is (a bit) bananas! +// Implementation of binary-variables operations, and vectors of it + +// should be assembled with the runlib.fj file +// This file is independent of the bit-width, and uses the consts defined at runlib.fj + +// Everything after // is ignored, and every whitespace is ignored (besides new line) +// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next) + +// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op. +// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity + +// The complexities are not updated in this file (should be lower/faster). + + + +// ---------- Memory Variables: +// Size Complexity: 1 + + +def bit value { + ; value ? dw : 0 +} + +def bit { + bit 0 +} + + +// Size Complexity: n +ns bit { + def vec n, value { + rep(n, i) bit (value>>i)&1 + } + + def vec n { + rep(n, i) bit + } +} + + +// ---------- Memory Manipulation: + + +ns bit { + // Complexity: phi+2 + def zero x { + .xor x, x + } + + // Complexity: n(phi+2) + def zero n, x { + rep(n, i) .zero x+i*dw + } + + + // Complexity: phi+3 + def one x { + .zero x + .not x + } + + // Complexity: n(phi+3) + def one n, x { + rep(n, i) .one x+i*dw + } + + + ////Complexity: 2phi + 9 + //__if_mov dst src @ l0 l1 flip end { + // .if src l0 l1 + // l0: .if dst end flip + // l1: .if dst flip end + // flip: .not dst + // end: + //} + + + // safe even for dst==src ! + // Complexity: 2phi+5 + def mov dst, src @ do_mov, end { + comp_if1 dst==src, end + do_mov: + .zero dst + .xor dst, src + end: + } + + // Complexity: n(2phi+5) + def mov n, dst, src { + rep(n, i) .mov dst+i*dw, src+i*dw + } + + + //Complexity: 2phi+10 + def swap a, b @ a0, a1, notnot, end { + .if a, a0, a1 + a0: + .if b, end, notnot + a1: + .if b, notnot, end + notnot: + .not a + .not b + end: + } + + // Complexity: n(2phi+10) + def swap n, a, b { + rep(n, i) .swap a+i*dw, b+i*dw + } +} + + + +// ---------- Conditional Jump + + +ns bit { + // Complexity: phi+4 + def if x, l0, l1 @ label_ptr, base_jump_label { + .xor label_ptr, x + label_ptr: + ;base_jump_label + pad 2 + base_jump_label: + ;l0 + label_ptr + dbit;l1 + } + + // Complexity: n(phi+4) + def if n, x, l0, l1 { + rep(n-1, i) ._.if_next_l0 x+i*dw, l1 + .if x+(n-1)*dw, l0, l1 + } + ns _ { + def if_next_l0 x, l1 @ l0 { + ..if x, l0, l1 + l0: + } + } + + def if1 x, l1 @ end { + .if x, end, l1 + end: + } + + def if1 n, x, l1 @ end { + .if n, x, end, l1 + end: + } + + def if0 x, l0 @ end { + .if x, l0, end + end: + } + + def if0 n, x, l0 @ end { + .if n, x, l0, end + end: + } + + + // Complexity: 2phi+8 + def cmp a, b, lt, eq, gt @ a_is1_label { + .if1 a, a_is1_label + .if b, eq, lt + a_is1_label: + .if b, gt, eq + } + + // Complexity: n(2phi+8) + def cmp n, a, b, lt, eq, gt { + rep(n-1, i) ._.cmp_next_eq a+(n-1-i)*dw, b+(n-1-i)*dw, lt, gt + .cmp a, b, lt, eq, gt + } + ns _ { + def cmp_next_eq a, b, lt, gt @ eq { + ..cmp a, b, lt, eq, gt + eq: + } + } +} + + + +// ---------- Logical Macros: + + +ns bit { + // Complexity: phi+2 + def xor dst, src { + .exact_xor dst + dbit, src + } + + // Complexity: n(phi+2) + def xor n, dst, src { + rep(n, i) .xor dst+dw*i, src+dw*i + } + + def exact_xor dst, src @ base_jump_label, cleanup { + wflip src+w, base_jump_label, src + pad 2 + base_jump_label: + ;cleanup + dst; + cleanup: + wflip src+w, base_jump_label + } + + // Complexity: phi+3 + def double_exact_xor dst1, dst2, src @ base_jump_label, cleanup { + wflip src+w, base_jump_label, src + pad 2 + base_jump_label: + ;cleanup + dst1; + dst2; + cleanup: + wflip src+w, base_jump_label + } + + // Complexity: n(phi+3) + def bit_var_xor n, bit, var, src { + rep(n, i) .double_exact_xor bit+i, var+dbit+i*dw, src+i*dw + } + + def xor_zero dst, src { + .double_exact_xor dst+dbit, src+dbit, src + } + + // Complexity: n(phi+3) + def xor_zero n, dst, src { + rep(n, i) .xor_zero dst+dw*i, src+dw*i + } + + + // Complexity: 2phi+7 + def or dst, src @ end { + .if0 src, end + .one dst + end: + } + + // Complexity: n(2phi+7) + def or n, dst, src { + rep(n, i) .or dst+dw*i, src+dw*i + } + + + // Complexity: 2phi+6 + def and dst, src @ end { + .if1 src, end + .zero dst + end: + } + + // Complexity: n(2phi+6) + def and n, dst, src { + rep(n, i) .and dst+dw*i, src+dw*i + } + + + // Complexity: 1 + def not dst { + dst + dbit; + } + + // Complexity: n + def not n, dst { + rep(n, i) .not dst+dw*i + } + + def exact_not dst { + dst; + } +} + + + +// ---------- Logical Shifts + + +ns bit { + // Complexity: n(2phi+5) + def shr n, x { + .shr n, 1, x + } + + // Complexity: n(2phi+5) + def shr n, times, x { + rep(n-times, i) .mov x+i*dw, x+(i+times)*dw + .zero times, x+(n-times)*dw + } + + + // Complexity: n(2phi+5) + def shl n, x { + .shl n, 1, x + } + + // Complexity: n(2phi+5) + def shl n, times, x { + rep(n-times, i) .mov x+(n-1-i)*dw, x+(n-1-i-times)*dw + .zero times, x + } + + + // Complexity: n(2phi+5) + def ror n, x @ temp_bit { + .mov temp_bit, x + rep(n-1, i) .mov x+i*dw, x+(i+1)*dw + .mov x+(n-1)*dw, temp_bit + skip + temp_bit: + bit + } + + + // Complexity: n(2phi+5) + def rol n, x @ temp_bit { + .mov temp_bit, x+(n-1)*dw + rep(n-1, i) .mov x+(n-1-i)*dw, x+(n-1-i-1)*dw + .mov x, temp_bit + skip + temp_bit: + bit + } +} + + + +// ---------- Arithmetical Macros +// carry is both input and output + + +ns bit { + // Unsafe for dst==carry (but there is no reason in calling it that way) + // Complexity: 2phi+10 + def inc1 dst, carry @ end { + .if0 carry, end + .not dst + .if0 dst, end + .not carry + end: + } + + // Complexity: n(2phi+10) + def inc n, x @ carry { + .one carry + rep(n, i) .inc1 x+i*dw, carry + skip + carry: + bit + } + + // Complexity: n(2phi+12) + def dec n, x { + .not n, x + .inc n, x + .not n, x + } + + // Complexity: n(2phi+11) + def neg n, x { + .not n, x + .inc n, x + } + + + // Unsafe for dst==carry (but there is no reason in calling it that way) + // Complexity: 8phi+33 + def add1 dst, src, carry @ _src { + .mov _src, src + .inc1 dst, _src + .inc1 dst, carry + .or carry, _src + skip + _src: + bit + } + + // Complexity: n(8phi+33) + def add n, dst, src @ carry { + .zero carry + rep(n, i) .add1 dst+i*dw, src+i*dw, carry + skip + carry: + bit + } + + // Complexity: n(8phi+35) + def sub n, dst, src @ carry { + .not n, src + .one carry + rep(n, i) .add1 dst+i*dw, src+i*dw, carry + .not n, src + skip + carry: + bit + } +} diff --git a/flipjump/src/stl/declib.fj b/flipjump/src/stl/declib.fj new file mode 100644 index 0000000..d3c2e8f --- /dev/null +++ b/flipjump/src/stl/declib.fj @@ -0,0 +1,34 @@ +// Every line is (10) bananas! +// Implementation of decimal-variables operations, and vectors of it + +// should be assembled with the runlib.fj file +// This file is independent of the bit-width, and uses the consts defined at runlib.fj + +// Everything after // is ignored, and every whitespace is ignored (besides new line) +// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next) + +// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op. +// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity + + + +// ---------- Memory Variables: +// Size Complexity: 1 + + +def dec val { + ;(val > 9 ? 9 : (val < 0 ? 0 : val)) * dw +} + +def dec { + dec 0 +} + + + +// ---------- Logical Macros: + + +ns dec { + +} diff --git a/flipjump/src/stl/hexlib.fj b/flipjump/src/stl/hexlib.fj new file mode 100644 index 0000000..8e1411b --- /dev/null +++ b/flipjump/src/stl/hexlib.fj @@ -0,0 +1,1080 @@ +// Every line is (16) bananas! +// Implementation of hexadecimal-variables operations, and vectors of it + +// should be assembled with the runlib.fj file +// This file is independent of the bit-width, and uses the consts defined at runlib.fj + +// Everything after // is ignored, and every whitespace is ignored (besides new line) +// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next) + +// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op. +// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity + +// Space complexity might not be exact + + + +// ---------- Memory Variables: +// Size Complexity: 1 + + +def hex val { + ;(val > 0xf ? 0xf : (val < 0 ? 0 : val)) * dw +} + +def hex { + hex 0 +} + + +ns hex { + def vec n, value { + rep(n, i) hex (value>>(4*i))&0xf + } + + def vec n { + rep(n, i) hex + } +} + + +// ---------- Logical Macros: + + +ns hex { + + // Time Complexity: phi + // Space Complexity: phi+27 + def xor dst, src { + .exact_xor dst+dbit+3, dst+dbit+2, dst+dbit+1, dst+dbit+0, src + } + + // Time Complexity: n*phi + // Space Complexity: n*(phi+26) + def xor n, dst, src { + rep (n, i) .xor dst+i*dw, src+i*dw + } + + + // Time Complexity: phi + // Space Complexity: phi+27 + def exact_xor d3, d2, d1, d0, src @ switch, end { + wflip src+w, switch, src + pad 16 + switch: + ;end // 0 + d0;end // 1 + d1;end // 2 + d1;switch+1*dw // 3 + d2;end // 4 + d2;switch+1*dw // 5 + d2;switch+2*dw // 6 + d2;switch+3*dw // 7 + d3;end // 8 + d3;switch+1*dw // 9 + d3;switch+2*dw // 10 + d3;switch+3*dw // 11 + d3;switch+4*dw // 12 + d3;switch+5*dw // 13 + d3;switch+6*dw // 14 + d3;switch+7*dw // 15 + end: + wflip src+w, switch + } + + // Time Complexity: phi+4 + // Space Complexity: phi+42 + def xor_zero dst, src { + .double_xor dst, src, src + } + + // Time Complexity: n(phi+4) + // Space Complexity: n(phi+42) + def xor_zero n, dst, src { + rep (n, i) .xor_zero dst+i*dw, src+i*dw + } + + // Time Complexity: phi+4 + // Space Complexity: phi+42 + def double_xor dst1, dst2, src { + .double_exact_xor dst1+dbit+3, dst1+dbit+2, dst1+dbit+1, dst1+dbit+0, dst2+dbit+3, dst2+dbit+2, dst2+dbit+1, dst2+dbit+0, src + } + + // Time Complexity: phi+4 + // Space Complexity: phi+42 + def double_exact_xor t3, t2, t1, t0, d3, d2, d1, d0, src @ switch, second_flip, end { + wflip src+w, switch, src + pad 16 + switch: + ;end // 0 + d0;second_flip+ 0*dw // 1 + d1;second_flip+ 1*dw // 2 + d1;second_flip+ 2*dw // 3 + d2;second_flip+ 3*dw // 4 + d2;second_flip+ 4*dw // 5 + d2;second_flip+ 5*dw // 6 + d2;second_flip+ 6*dw // 7 + d3;second_flip+ 7*dw // 8 + d3;second_flip+ 8*dw // 9 + d3;second_flip+ 9*dw // 10 + d3;second_flip+10*dw // 11 + d3;second_flip+11*dw // 12 + d3;second_flip+12*dw // 13 + d3;second_flip+13*dw // 14 + d3;second_flip+14*dw // 15 + + second_flip: + t0;end // 1 + t1;end // 2 + t1;switch+1*dw // 3 + t2;end // 4 + t2;switch+1*dw // 5 + t2;switch+2*dw // 6 + t2;switch+3*dw // 7 + t3;end // 8 + t3;switch+1*dw // 9 + t3;switch+2*dw // 10 + t3;switch+3*dw // 11 + t3;switch+4*dw // 12 + t3;switch+5*dw // 13 + t3;switch+6*dw // 14 + t3;switch+7*dw // 15 + end: + wflip src+w, switch + } + + + // Complexity: 4 + def not hex { + hex+dbit+0; + hex+dbit+1; + hex+dbit+2; + hex+dbit+3; + } + + // Complexity: 4n + def not n, hex { + rep(n, i) .not hex+i*dw + } + + + // Time Complexity: 4phi+16 + // Space Complexity: 4phi+96 + def or dst, src < .or.dst { + ._.table_query dst, src, .or.dst + } + + // Time Complexity: n(4phi+17) + // Space Complexity: n(4phi+96) + def or n, dst, src { + rep(n, i) .or dst+i*dw, src+i*dw + } + + ns or { + // Space Complexity: 600 + def init @ switch, clean, end < .._.res, .._.ret > dst { + ;end + dst: ;.switch + + pad 256 + switch: + rep(256, d) wflip_macro .._.res+w, (((d&0xf)|(d>>4))^(d&0xf))*dw, clean+d*dw + + clean: + .._.clean_table .dst + end: + } + } + + + // Time Complexity: 4phi+16 + // Space Complexity: 4phi+96 + def and dst, src < .and.dst { + ._.table_query dst, src, .and.dst + } + + // Time Complexity: n(4phi+17) + // Space Complexity: n(4phi+96) + def and n, dst, src { + rep(n, i) .and dst+i*dw, src+i*dw + } + + ns and { + // Space Complexity: 600 + def init @ switch, clean, end < .._.res, .._.ret > dst { + ;end + dst: ;.switch + + pad 256 + switch: + rep(256, d) wflip_macro .._.res+w, (((d&0xf)&(d>>4))^(d&0xf))*dw, clean+d*dw + + clean: + .._.clean_table .dst + end: + } + } + + + // Time Complexity: 2.13phi+2 + // Space Complexity: n(1.5phi+23) + 2phi+121 (+padding) + // dst[n] += x.#on-bits + def add_count_bits n, dst, x @ count_switch, do_add, add_switch, add4_switch, xor_switch, after_add, is_carry, should_inc, do_inc, clean { + wflip x+w, count_switch, x + + pad 16 + count_switch: + ;clean // 0 + ;do_add + ;do_add + dst+dbit+4;do_add + ;do_add // 4 + dst+dbit+4;do_add + dst+dbit+4;do_add + dst+dbit+5;do_add + ;do_add // 8 + dst+dbit+4;do_add + dst+dbit+4;do_add + dst+dbit+5;do_add + dst+dbit+4;do_add // 12 + dst+dbit+5;do_add + dst+dbit+5;do_add + dst+dbit+5;count_switch+3*dw + + do_add: + wflip dst+w, add_switch, dst + + pad 64 + add_switch: + rep(16, d) fj 0, xor_switch+(d^(d+1))*dw + rep(16, d) fj dst+dbit+4, xor_switch+(d^(d+2))*dw + rep(16, d) fj dst+dbit+5, xor_switch+(d^(d+3))*dw + rep(16, d) fj dst+dbit+5, add4_switch+d*dw + add4_switch: + rep(16, d) fj dst+dbit+4, xor_switch+(d^(d+4))*dw + + pad 32 + xor_switch: + ._.clean_table 16, dst, after_add + rep(16, i) fj is_carry+dbit, xor_switch+i*dw + + after_add: + wflip dst+w, add_switch, is_carry + is_carry: ;should_inc + pad 2 + should_inc: + ;clean + is_carry+dbit;do_inc + do_inc: + .inc n-1, dst+dw + ;clean + + clean: + wflip x+w, count_switch + } + + // Time Complexity: n(2.13phi+2) + // Space Complexity: n(#n(0.4phi+6) + 2phi+121) + def count_bits n, dst, x { + .zero ((#(n*4))+3)/4, dst + rep(n, i) .add_count_bits ((#(n*4))+3)/4, dst, x+i*dw + } + + + // Time Complexity: phi+1 + // Space Complexity: phi+28 + def shl_bit_once dst, next @ switch, xor_by, end { + wflip dst+w, switch, dst + + pad 16 + switch: + rep(16, i) fj i&8 ? next+dbit+0 : 0, xor_by+(i^((i<<1)&0xf))*dw + xor_by: + ._.clean_table 16, dst, end + + end: + wflip dst+w, switch + } + + // Time Complexity: n(phi+1) + // Space Complexity: n(phi+28) + def shl_bit n, dst { + .shl_bit_once dst+(n-1)*dw, 0 + rep(n-1, i) .shl_bit_once dst+(n-2-i)*dw, dst+(n-1-i)*dw + } + + + // Time Complexity: phi+1 + // Space Complexity: phi+28 + def shr_bit_once dst, next @ switch, xor_by, end { + wflip dst+w, switch, dst + + pad 16 + switch: + rep(16, i) fj i&1 ? next+dbit+3 : 0, xor_by+(i^((i>>1)&0xf))*dw + xor_by: + ._.clean_table 16, dst, end + + end: + wflip dst+w, switch + } + + // Time Complexity: n(phi+1) + // Space Complexity: n(phi+28) + def shr_bit n, dst { + .shr_bit_once dst, 0 + rep(n-1, i) .shr_bit_once dst+(i+1)*dw, dst+i*dw + } + + + // Time Complexity: n(phi+4) + // Space Complexity: n(phi+42) + // shift left by 4bits (1hex) + def shl_hex n, dst { + .zero dst+(n-1)*dw + rep(n-1, i) .xor_zero dst+(n-1-i)*dw, dst+(n-2-i)*dw + } + + + // Time Complexity: n(phi+4) + // Space Complexity: n(phi+42) + // shift right by 4bits (1hex) + def shr_hex n, dst { + .zero dst + rep(n-1, i) .xor_zero dst+i*dw, dst+(i+1)*dw + } +} + + + +// ---------- Arithmetical Macros +// carry is both input and output, and is saved in the 8th bit in hex.{add/sub}.dst + + +ns hex { + // Time Complexity: phi + // Space Complexity: 1.5phi+28 + def inc1 hex, carry0, carry1 @ switch, end { + wflip hex+w, switch, hex + pad 16 + switch: + hex+dbit+0;end // 0 + hex+dbit+1;switch+0*dw // 1 + hex+dbit+0;end // 2 + hex+dbit+2;switch+1*dw // 3 + hex+dbit+0;end // 4 + hex+dbit+1;switch+0*dw // 5 + hex+dbit+0;end // 6 + hex+dbit+3;switch+3*dw // 7 + hex+dbit+0;end // 8 + hex+dbit+1;switch+0*dw // 9 + hex+dbit+0;end // 10 + hex+dbit+2;switch+1*dw // 11 + hex+dbit+0;end // 12 + hex+dbit+1;switch+0*dw // 13 + hex+dbit+0;end // 14 + hex+dbit+3; // 15 + hex+dbit+2; + hex+dbit+1; + hex+dbit+0; + wflip hex+w, switch, carry1 + end: + wflip hex+w, switch, carry0 + } + + // Time Complexity: 16/15*phi + // Space Complexity: n(1.5phi+23) + def inc n, hex @ end { + rep(n, i) .inc.step hex+i*dw, end + end: + } + ns inc { + def step hex, end @ next { + ..inc1 hex, end, next + next: + } + } + + + // Time Complexity: phi + // Space Complexity: 1.5phi+28 + def dec1 hex, borrow0, borrow1 @ switch, borrow, end { + wflip hex+w, switch, hex + pad 16 + switch: + hex+dbit+3;borrow // 0 + hex+dbit+0;end // 1 + hex+dbit+1;switch+1*dw // 2 + hex+dbit+0;end // 3 + hex+dbit+2;switch+2*dw // 4 + hex+dbit+0;end // 5 + hex+dbit+1;switch+1*dw // 6 + hex+dbit+0;end // 7 + hex+dbit+3;switch+4*dw // 8 + hex+dbit+0;end // 9 + hex+dbit+1;switch+1*dw // 10 + hex+dbit+0;end // 11 + hex+dbit+2;switch+2*dw // 12 + hex+dbit+0;end // 13 + hex+dbit+1;switch+1*dw // 14 + hex+dbit+0;end // 15 + borrow: + hex+dbit+2; + hex+dbit+1; + hex+dbit+0; + wflip hex+w, switch, borrow1 + end: + wflip hex+w, switch, borrow0 + } + + // Time Complexity: n*phi + // Space Complexity: n(1.5phi+23) + def dec n, hex @ end { + rep(n, i) .dec.step hex+i*dw, end + end: + } + ns dec { + def step hex, end @ next { + ..dec1 hex, end, next + next: + } + } + + + // Time Complexity: 4n + // Space Complexity: n(1.5phi+27) + def neg n, hex { + .not n, hex + .inc n, hex + } + + + // Time Complexity: 4phi+17 + // Space Complexity: 4phi+96 + def add dst, src < .add.dst { + ._.table_query dst, src, .add.dst + } + + // Time Complexity: n(4phi+17) + // Space Complexity: n(4phi+96) + def add n, dst, src { + .add.clear_carry + rep(n, i) .add dst+i*dw, src+i*dw + .add.clear_carry + } + + ns add { + // Time Complexity: 2phi+2 + // Space Complexity: 2phi+27 + def clear_carry @ ret < .._.ret, .dst, .._.res { + wflip .._.ret+w, ret, .dst + ret: + wflip .._.ret+w, ret + ..zero .._.res + } + + // Time Complexity: 2phi+3 + // Space Complexity: 2.5phi+26 + def clear_carry c0, c1 @ ret < .._.ret, .dst, .._.res { + wflip .._.ret+w, ret, .dst + ret: + wflip .._.ret+w, ret + ..if0 .._.res, c0 + .._.res+dbit; c1 + } + + // Complexity: 1 + def not_carry < .dst { + .dst+dbit+8; + } + + // Time Complexity: 2phi+3 + // Space Complexity: 2phi+28 + def set_carry { + .clear_carry + .not_carry + } + + // Space Complexity: 1800 + def init @ switch0, switch1, flip_carry, clean, end < .._.res, .._.ret > dst { + ;end + dst: ;.switch0 + + pad 512 + switch0: + rep(256, d) wflip_macro .._.res+w, ((((d&0xf)+(d>>4) )&0xf)^(d&0xf))*dw, (((d&0xf)+(d>>4) > 0xf) ? (flip_carry+d*dw) : (clean+d*dw)) + switch1: + rep(256, d) wflip_macro .._.res+w, ((((d&0xf)+(d>>4)+1)&0xf)^(d&0xf))*dw, (((d&0xf)+(d>>4)+1 > 0xf) ? (clean+d*dw) : (flip_carry+d*dw)) + + flip_carry: + rep(256, i) fj .dst+dbit+8, clean+i*dw + clean: + .._.clean_table .dst + end: + } + } + + + // Time Complexity: 4phi+17 + // Space Complexity: 4phi+96 + def sub dst, src < .sub.dst { + ._.table_query dst, src, .sub.dst + } + + // Time Complexity: n(4phi+17) + // Space Complexity: n(4phi+96) + def sub n, dst, src { + .sub.clear_carry + rep(n, i) .sub dst+i*dw, src+i*dw + .sub.clear_carry + } + + ns sub { + // Time Complexity: 2phi+14 + // Space Complexity: 2.5phi+30 + def clear_carry @ end { + .clear_carry end, end + end: + } + + // Time Complexity: 2phi+14 + // Space Complexity: 2.5phi+30 + def clear_carry c0, c1 @ ret < .._.ret, .dst, .._.res { + wflip .._.ret+w, ret, .dst + ret: + wflip .._.ret+w, ret + ..if0 .._.res, c0 + .not_carry + wflip .._.res+w, 0xf*dw, c1 + } + + // Complexity: 1 + def not_carry < .dst { + .dst+dbit+8; + } + + // Time Complexity: 2phi+15 + // Space Complexity: 2.5phi+31 + def set_carry { + .clear_carry + .not_carry + } + + // Space Complexity: 1600 + def init @ switch0, switch1, flip_carry, clean, end < .._.res, .._.ret > dst { + ;end + dst: ;.switch0 + + pad 512 + switch0: + rep(256, d) wflip_macro .._.res+w, ((((d&0xf)-(d>>4) )&0xf)^(d&0xf))*dw, (((d&0xf)-(d>>4) < 0) ? (flip_carry+d*dw) : (clean+d*dw)) + switch1: + rep(256, d) wflip_macro .._.res+w, ((((d&0xf)-(d>>4)-1)&0xf)^(d&0xf))*dw, (((d&0xf)-(d>>4)-1 < 0) ? (clean+d*dw) : (flip_carry+d*dw)) + + flip_carry: + rep(256, i) fj .dst+dbit+8, clean+i*dw + clean: + .._.clean_table .dst + end: + } + } +} + + + +// ---------- Memory Manipulation: + + +ns hex { + + // Time Complexity: phi + // Space Complexity: phi+27 + def zero x { + .xor x, x + } + + // Time Complexity: n*phi + // Space Complexity: n*(phi+26) + def zero n, x { + rep (n, i) .zero x+i*dw + } + + // Time Complexity: 2phi+1 + // Space Complexity: phi+54 + def mov dst, src @ end { + comp_if1 dst==src, end + .zero dst + .xor dst, src + end: + } + + // Time Complexity: n*(2phi+1) + // Space Complexity: n*(phi+52) + def mov n, dst, src { + rep(n, i) .mov dst+i*dw, src+i*dw + } + + // Complexity: 4 (avg. 2. #on-bits) + def xor_by hex, val { + wflip hex+w, (val > 0xf ? 0xf : (val < 0 ? 0 : val)) * dw + } + + // Complexity: 4n (#on-bits) + def xor_by n, hex, val { + rep(n, i) .xor_by hex+i*dw, (val>>(4*i))&0xf + } + + // Time Complexity: phi+4 + // Space Complexity: phi+31 + def set hex, val { + .zero hex + .xor_by hex, val + } + + def set n, hex, val { + rep(n, i) .set hex+i*dw, (val>>(4*i))&0xf + } + + // Time Complexity: 3phi + // Space Complexity: 3phi+79 + def swap hex1, hex2 @ end { + comp_if1 hex1==hex2, end + .xor hex1, hex2 + .xor hex2, hex1 + .xor hex1, hex2 + end: + } + + // Time Complexity: n*(3phi) + // Space Complexity: n*(3phi+78) + def swap n, hex1, hex2 { + rep(n, i) .swap hex1+i*dw, hex2+i*dw + } +} + + + +// ---------- Conditional Jump + + +ns hex { + // Time Complexity: phi-1 + // Space Complexity: phi+15 + def if_flags hex, flags, l0, l1 @ switch, clean, return, finish { + wflip hex+w, switch, hex + + pad 16 + switch: + rep(16, i) fj (flags>>i)&1 ? return+dbit+0 : 0, clean + + clean: + wflip hex+w, switch + return: ;finish + pad 2 + finish: + ; l0 + return+dbit+0; l1 + } + + // Time Complexity: phi-1 + // Space Complexity: phi+15 + def if hex, l0, l1 { + .if_flags hex, 0xfffe, l0, l1 + } + def if0 hex, l0 @ l1 { + .if hex, l0, l1 + l1: + } + def if1 hex, l1 @ l0 { + .if hex, l0, l1 + l0: + } + + // Time Complexity: n(phi-1) + // Space Complexity: n(phi+15) + def if n, hex, l0, l1 { + rep(n-1, i) .if1 hex+i*dw, l1 + .if hex+(n-1)*dw, l0, l1 + } + def if0 n, hex, l0 @ l1 { + .if n, hex, l0, l1 + l1: + } + def if1 n, hex, l1 @ l0 { + .if n, hex, l0, l1 + l0: + } + + + // Time Complexity: phi-1 + // Space Complexity: phi+15 + def sign n, x, neg, zpos { + .if_flags x+(n-1)*dw, 0xff00, zpos, neg + } + + + // Time Complexity: 3phi+12 + // Space Complexity: 3phi+51 + def cmp a, b, lt, eq, gt @ ret, _eq, _gt, real_ret, __lt, __eq, __gt, second_xor < .cmp.dst, ._.ret { + .xor .cmp.dst, a // 1 + ;second_xor + + + pad 4 + ret: // 4 + wflip ._.ret+w, ret, real_ret // 5 + ._.ret+dbit ;_eq + ._.ret+dbit+1;_gt + + _eq: real_ret+dbit ;ret // (4.5) + _gt: real_ret+dbit+1;ret + + real_ret: // 6 + ;__lt + + pad 4 + __lt: ;lt // 7 (and last) + __eq: real_ret+dbit ;eq + __gt: real_ret+dbit+1;gt + + + second_xor: + .xor .cmp.dst+4, b // 2 + wflip ._.ret+w, ret, .cmp.dst // 3 + } + + def cmp n, a, b, lt, eq, gt { + rep(n-1, i) .cmp.cmp_eq_next a+(n-1-i)*dw, b+(n-1-i)*dw, lt, gt + .cmp a, b, lt, eq, gt + } + + ns cmp { + def cmp_eq_next a, b, lt, gt @ eq { + ..cmp a, b, lt, eq, gt + eq: + } + + // Space Complexity: 500 + def init @ switch, clean, end < .._.ret > dst { + ;end + dst: ;.switch + + pad 256 + switch: + rep(256, d) fj ((d&0xf) > (d>>4)) ? .._.ret+dbit+1 : (((d&0xf) == (d>>4)) ? .._.ret+dbit : 0), clean+d*dw + + clean: + .._.clean_table .dst + end: + } + } +} + + +ns hex { + def init { + ._.init + } + + ns _ { + // Space Complexity: 6700 + def init @ end > ret, res { + ;end + ret: ;0 + res: hex + ..cmp.init // 1600 + ..add.init // 1800 + ..sub.init // 500 + ..or.init // 600 + ..and.init // 600 + ..mul.init // 1600 + end: + } + + // n must be a power of 2 + def clean_table n, dst, ret @ clean { + clean: + rep(n, d) fj d==0?0: (dst+dbit+(#d)-1), (d==((1<<(#d))>>1)) ? ret : clean+(d^((1<<(#d))>>1))*dw + } + + // Space Complexity: 256 + def clean_table dst, ret { + .clean_table 256, dst, ret + } + + // Space Complexity: 256 + def clean_table dst < .ret { + .clean_table dst, .ret + } + + def table_query dst, src, dst_switch @ return < .ret, .res { + ..xor dst_switch , dst + ..xor dst_switch+4, src + wflip .ret+w, return, dst_switch + return: + wflip .ret+w ,return + ..xor_zero dst, .res + } + } +} + + + +// ---------- IO + + +ns hex { + def output hex @ switch, print_0, print_2, print_4, print_6, print_8, print_a, print_c, print_e, end < IO { + wflip hex+w, switch, hex + pad 16 + switch: + IO+0;print_0 // 0 + IO+1;print_0 // 1 + IO+0;print_2 // 2 + IO+1;print_2 // 3 + IO+0;print_4 // 4 + IO+1;print_4 // 5 + IO+0;print_6 // 6 + IO+1;print_6 // 7 + IO+0;print_8 // 8 + IO+1;print_8 // 9 + IO+0;print_a // 4 + IO+1;print_a // 5 + IO+0;print_c // 6 + IO+1;print_c // 7 + IO+0;print_e // 8 + IO+1;print_e // 9 + + + print_0: + IO+0; + IO+0; + IO+0;end + print_2: + IO+1;print_0+1*dw + print_4: + IO+0; + IO+1;print_0+2*dw + print_6: + IO+1;print_4+1*dw + print_8: + IO+0; + IO+0; + IO+1;end + print_a: + IO+1;print_8+1*dw + print_c: + IO+0; + IO+1;print_8+2*dw + print_e: + IO+1;print_c+1*dw + + end: + wflip hex+w, switch + } + + + def print x { + .output x + .output x+dw + } + + def print n, x { + rep(n, i) .print x+2*i*dw + } + + + // Time Complexity: phi+4 + // Space Complexity: phi+51 phi-4+15+16+24 + def print_as_digit hex, big_flag @ switch, print_0, print_2, print_4, print_6, print_8, print_a, print_b, print_d, print_f, end < IO { + wflip hex+w, switch, hex + pad 16 + switch: + IO+0;print_0 // 0 + IO+1;print_0 // 1 + IO+0;print_2 // 2 + IO+1;print_2 // 3 + IO+0;print_4 // 4 + IO+1;print_4 // 5 + IO+0;print_6 // 6 + IO+1;print_6 // 7 + IO+0;print_8 // 8 + IO+1;print_8 // 9 + + IO+1;print_a // a + IO+0;print_b // b + IO+1;print_b // c + IO+0;print_d // d + IO+1;print_d // e + IO+0;print_f // f + + print_0: + IO+0; + IO+0; + IO+0; + IO+1; + IO+1; + IO+0; + IO+0;end + print_2: + IO+1;print_0+1*dw + print_4: + IO+0; + IO+1;print_0+2*dw + print_6: + IO+1;print_4+1*dw + print_8: + IO+0; + IO+0; + IO+1;print_0+3*dw + print_a: + IO+0; + IO+0; + IO+0; + IO+0; + IO+(big_flag ? 0 : 1); + IO+1;print_0+6*dw + print_b: + IO+1;print_a+1*dw + print_d: + IO+0; + IO+1;print_a+2*dw + print_f: + IO+1;print_d+1*dw + + end: + wflip hex+w, switch + } + + // Time Complexity: phi+4 + // Space Complexity: phi+42 + def print_as_digit n, x, big_flag { + rep (n, i) .print_as_digit x+(n-1-i)*dw, big_flag + } + + // Time Complexity: n(2phi+8) + // Space Complexity: n(3.5phi+72) + def print_uint n, x, x_prefix, big_flag @ after_prefix, printed_something, end { + bit.zero printed_something + comp_if0 x_prefix, after_prefix + output "0x" + + after_prefix: + rep(n, i) .print_uint.print_digit x+(n-1-i)*dw, printed_something, big_flag + bit.if1 printed_something, end + output '0' + ;end + + printed_something: bit + end: + } + ns print_uint { + // Time Complexity: 2phi+8 (once: 3phi+9) + // Space Complexity: 3.5phi+72 + def print_digit hex, printed_something, big_flag @ print, end { + bit.if1 printed_something, print + ..if0 hex, end + bit.not printed_something + print: + ..print_as_digit hex, big_flag + end: + } + } + + // Time Complexity: n(2phi+16) + // Space Complexity: n(6.5phi+126) + def print_int n, x, x_prefix, big_flag @ do_neg, print, neg, end { + bit.zero neg + .if_flags x+(n-1)*dw, 0xff00, print, do_neg + do_neg: + bit.not neg + .neg n, x + output '-' + print: + .print_uint n, x, x_prefix, big_flag + bit.if0 neg, end + .neg n, x + ;end + + neg: bit + end: + } + + // Time Complexity: 2phi+7 + // Space Complexity: 2phi+39 + def input_hex hex @ flip0, flip1, flip2, flip3, end < IO { + .zero hex + wflip IO+w, flip0, IO + + pad 8 + flip0: + IO+dbit+1;IO + hex+dbit+0;flip0 + flip1: + IO+dbit+2;IO + hex+dbit+1;flip1 + flip3: + wflip IO+w, flip3, end + hex+dbit+3;flip3 + flip2: + IO+dbit+1;IO + hex+dbit+2;flip2 + end: + } + + // Time Complexity: 4phi+14 + // Space Complexity: 4phi+70 + def input x { + .input_hex x + .input_hex x+dw + } + + // Time Complexity: n(4phi+14) + // Space Complexity: n(4phi+70) + def input n, x { + rep(n, i) .input x+2*i*dw + } + + + // Time Complexity: 6phi+14 + // Space Complexity: 9.5phi+168 + def input_as_hex hex, error @ try_dec, do_dec, do_hex, switch, finish_hex, upper, end { + .input_hex hex + .input_hex upper + .if_flags upper, (1<<4)|(1<<6), try_dec, do_hex + try_dec: + .if_flags upper, (1<<3), error, do_dec + + do_dec: + .if_flags hex, (1<<10)-1, error, end + + do_hex: + wflip hex+w, switch, hex + + finish_hex: + hex+dbit+3; + wflip hex+w, switch, end + + pad 16 + switch: + wflip hex+w, switch, error // 0 + hex+dbit+1;switch+2*dw // 1 + hex+dbit+0;finish_hex // 2 + hex+dbit+2;switch+1*dw // 3 + hex+dbit+0;finish_hex // 4 + hex+dbit+1;switch+2*dw // 5 + hex+dbit+0;finish_hex // 6 + ;switch // 7 + ;switch + ;switch + ;switch + ;switch + ;switch + ;switch + ;switch + ;switch + + upper: hex + end: + } +} diff --git a/flipjump/src/stl/iolib.fj b/flipjump/src/stl/iolib.fj new file mode 100644 index 0000000..d357916 --- /dev/null +++ b/flipjump/src/stl/iolib.fj @@ -0,0 +1,497 @@ +// Every line is (Input/Output of) bananas! +// Implementation of input/output and casting operations + +// should be assembled with both bitlib.fj and runlib.fj files +// This file is independent of the bit-width, and uses the consts defined at runlib.fj + +// Everything after // is ignored, and every whitespace is ignored (besides new line) +// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next) + +// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op. +// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity + +// The complexities are not updated in this file (should be lower/faster). + + + +// ---------- String: + + +ns bit { + def str str { + .vec (((#str)+15)>>3)<<3, str + } +} + + + +// ---------- Input: + + + +ns bit { + // Complexity: 2phi+4 + def input_bit dst < IO { + .zero dst + .xor dst, IO + } + + + // Complexity: 16phi+32 + def input dst { + rep(8, i) .input_bit dst+i*dw + } + + + // Complexity: n(16phi+32) + def input n, dst { + rep(n, i) .input dst+8*(n-1-i)*dw + } +} + + + +// ---------- Output: + + +def output_bit bit < IO { + IO + (bit ? 1 : 0); +} + +// Complexity: 8 +def output_char ascii { + rep(8, i) output_bit (ascii>>i)&1 +} + +def output str { + rep(((#str)+7)>>3, i) output_char (str>>(8*i))&0xff +} + + +ns bit { + // Complexity phi+5 + def output x @ label_ptr, base_jump_label, end < IO { + .xor label_ptr, x + label_ptr: + ;base_jump_label + pad 2 + base_jump_label: + IO+0;end + IO+1; + .not label_ptr + end: + } + + + // Complexity 8phi+40 + def print x { + rep(8, i) .output x+i*dw + } + + // Complexity n(8phi+40) + def print n, x { + rep(n, i) .print x+8*i*dw + } + + + + // print string of max size n. + // Complexity min(n, len+1)*(16phi+72) + def print_str n, x @ end { + rep(n, i) ._.print_str_one_char x+8*i*dw, end + end: + } + ns _ { + def print_str_one_char char, end { + ..if0 8, char, end + ..print char + } + } + + + def print_as_digit x { + .output x + rep(7, i) output_bit ('0'>>(i+1)) & 1 + } + + def print_as_digit n, x { + rep(n, i) .print_as_digit x+(n-1-i)*dw + } +} + + +// ---------- Casting to ascii: + + +ns bit { + // Complexity 9phi+20 + def bin2ascii ascii, bin { + .zero 8, ascii + .not 2, ascii + 4*dw // ascii = 0x30 + .xor ascii, bin + } + + + // Complexity 12phi+26 + def dec2ascii ascii, dec { + .zero 8, ascii + .not 2, ascii + 4*dw // ascii = 0x30 + .xor 4, ascii, dec + } + + + // Complexity 25phi+92 + def hex2ascii ascii, hex @ dec_label, hex_label, nine4, end { + .zero 8, ascii + .xor 3, ascii, hex + hex; + .cmp 4, hex, nine4, dec_label, dec_label, hex_label + dec_label: + .xor ascii+3*dw, hex+3*dw + .not 2, ascii + 4*dw // ascii = 0x30 + ;end + hex_label: + .dec 3, ascii // A-F is now 1-6 + .not ascii + 6*dw // ascii = 0x40 + ;end + nine4: + .vec 4, 9 + end: + } +} + + + +// ---------- Casting from ascii: + + +ns bit { +// Complexity: 17phi+63 + def ascii2bin error, bin, ascii @ half_bin, return_error, good, end { + .zero error + .zero bin + + .cmp 7, ascii+dw, half_bin, return_error, good, return_error + + return_error: + .not error + ;end + + good: + .xor bin, ascii + ;end + + half_bin: + .vec 7, 0x30>>1 + + end: + } + + + // Complexity: 25phi+83 + def ascii2dec error, dec, ascii @ half_dec, return_error, first_good, good, nine4, end { + .zero error + .zero 4, dec + + .cmp 4, ascii+4*dw, half_dec, return_error, first_good, return_error + first_good: + .cmp 4, ascii, nine4, good, good, return_error + + return_error: + .not error + ;end + + good: + .xor 4, dec, ascii + ;end + + half_dec: + .vec 4, 0x30>>4 + nine4: + .vec 4, 9 + end: + } + + + // Complexity: 48phi+184 + def ascii2hex error, hex, ascii @ half_dec, half_big_hex, half_small_hex, return_error, try_big_hex, try_small_hex, dec_first_good, hex_first_good, dec_good, hex_good, nine4, two3, end { + .zero error + .zero 4, hex + + .cmp 4, ascii+4*dw, half_dec, try_big_hex, dec_first_good, try_big_hex + + try_big_hex: + .cmp 5, ascii+3*dw, half_big_hex, try_small_hex, hex_first_good, try_small_hex + try_small_hex: + .cmp 5, ascii+3*dw, half_small_hex, return_error, hex_first_good, return_error + + dec_first_good: + .cmp 4, ascii, nine4, dec_good, dec_good, return_error + dec_good: + .xor 4, hex, ascii + ;end + + hex_first_good: + .inc 3, ascii + .cmp 3, ascii, two3, return_error, hex_good, hex_good + hex_good: + .xor 3, hex, ascii + .not hex+3*dw + ;end + + return_error: + .not error + ;end + + half_dec: + .vec 4, 0x30>>4 + half_big_hex: + .vec 5, 0x40>>3 + half_small_hex: + .vec 5, 0x60>>3 + nine4: + .vec 4, 9 + two3: + .vec 3, 2 + end: + } +} + + + +// ---------- Casting from bit + + +def bit2hex hex, bit { + hex.zero hex + bit.xor hex, bit +} + +def bit2hex n, hex, bit { + hex.zero (n+3)/4, hex + rep(n, i) bit.exact_xor hex+(i/4)*dw+dbit+(i%4), bit+i*dw +} + + + +// ---------- Casting from hex + + +def hex2bit bit, hex { + hex.exact_xor bit+3*dw+dbit, bit+2*dw+dbit, bit+dw+dbit, bit+dbit, hex +} + +def hex2bit n, bit, hex { + rep(n, i) hex2bit bit+4*i*dw, hex+i*dw +} + + + +// ---------- Print Hex Int + + +ns bit { + // Assumes n divides by 4. + // Complexity: n(10phi+39) + def print_hex_uint n, x, print_x @ after_print_x, printed_flag, end { + comp_if0 print_x, after_print_x + output '0' + output 'x' + after_print_x: + + .zero printed_flag + rep(n/4, i) ._.print_hex_uint_char x+(n/4-1-i)*4*dw, printed_flag + + .if1 printed_flag, end + output '0' + ;end + + printed_flag: + bit + end: + } + //Comp: 39phi+155 + ns _ { + def print_hex_uint_char hex, printed_flag @ continue, ascii, end { + ..if1 4, hex, continue + ..if1 printed_flag, continue + ;end + + continue: + ..one printed_flag + ..hex2ascii ascii, hex + ..print ascii + ;end + + ascii: + ..vec 8 + end: + } + } + + + + def print_hex_int n, x, print_x @ do_print { + .if0 x+(n-1)*dw, do_print + output '-' + .neg n, x + do_print: + .print_hex_uint n, x, print_x + } +} + + + +// ---------- Print Dec Int + + +ns bit { +//// Complexity: n^2(8phi+29) + nb(17phi+74) + //// Space Complexity: ~O(130n^2) + //def print_dec_uint n, x @ printed_flag, curr_ten, tens, val, r, end { + // .zero printed_flag + // + // .zero n+4, curr_ten + // .not curr_ten + // + // .zero n+7, val + // .xor n, val, x + // + // rep(n*28/93+2, i) ._.print_dec_uint_put_pow_ten n+4, tens+i*(n+4)*dw, curr_ten, val + // + // rep(n*28/93+2, i) ._.print_dec_uint_char n+4, val, tens+(n*28/93+2-1-i)*(n+4)*dw, printed_flag + // + // .if1 printed_flag, end + // output '0' + // ;end + // + // printed_flag: + // bit + // curr_ten: + // .vec n+4 + // tens: + // .vec (n*28/93+2)*(n+4) // 28/93 is very close from above to log10(2) + // val: + // .vec n+7 + // r: + // .vec n + // end: + //} + //ns _ { + // //Comp: n(18phi+60) + // def print_dec_uint_put_pow_ten n, dst, curr_ten, top @ put, end { + // .zero n, dst + // .cmp n, curr_ten, top, put, put, end + // put: + // .xor n, dst, curr_ten + // .mul10 n, curr_ten + // end: + // } + // //Comp: n(9phi+36) + 7b*(8phi+35) + // def print_dec_uint_char n, v, curr_ten, printed_flag @ do_print, dec, ascii, end { + // .if0 n, curr_ten, end + // .zero 4, dec + // rep(4, i) ._.print_dec_uint_sub_curr_ten n, v, curr_ten, dec, 3-i + // + // .if1 4, dec, do_print + // .if1 printed_flag, do_print + // ;end + // + // do_print: + // .one printed_flag + // dec2ascii ascii, dec + // print ascii + // ;end + // + // dec: + // .vec 4 + // ascii: + // .vec 8 + // end: + // } + // //Comp: worst: n(2phi+8) + 3.3b*(8phi+35), avg: n(2phi+8) + 1.7b*(8phi+35) + // def print_dec_uint_sub_curr_ten n, v, curr_ten, dec, index @ do_sub, end { + // .cmp n, v+index*dw, curr_ten, end, do_sub, do_sub + // do_sub: + // .sub n, v+index*dw, curr_ten + // .not dec+index*dw + // end: + // } + //} + // + // + // + //def print_dec_int n, x @ do_print { + // .if0 x+(n-1)*dw, do_print + // output '-' + // .neg n, x + // do_print: + // .print_dec_uint n, x + //} + + + // Time Complexity: n^2(2phi+8) + // Space Complexity: n(14phi+51) + def print_dec_uint n, x @ start_printing, xor, end_xor, dst, src, print_buffer, print_buffer_flag, div10, zero_flag, ret_reg, end { + .mov n, src, x + .zero zero_flag + + // the next three takes ~ (28/93n)*(phi+2 + 11phi+27 + 5phi+28) = n(5.12phi+17.17) < n(6phi+17.5) space + .zero n*28/93+1, print_buffer_flag // all chars are off + rep(n*28/93+1, i) ._.print_dec_uint.div10_step div10, xor, ret_reg, src, print_buffer+i*4*dw, print_buffer_flag+i*dw, zero_flag, start_printing + start_printing: + rep(n*28/93+1, i) ._.print_dec_uint.print_char print_buffer+(n*28/93-i)*4*dw, print_buffer_flag+(n*28/93-i)*dw + + ;end + + div10: + .div10 n, dst, src + fret ret_reg + xor: + .xor n, src, dst // TODO: can double_exact_xor and zero dst too - so to save the "zero n dst" inside the next div10 (save ~n/3(phi+1)) + .if1 n, dst, end_xor + .not zero_flag + end_xor: + fret ret_reg + + // takes n(2+28/93*5) = 3.5n space + dst: .vec n + src: .vec n + print_buffer: .vec (n*28/93+1)*4 + print_buffer_flag: .vec n*28/93+1 + zero_flag: bit + ret_reg: 0;0 + end: + } + ns _ { + ns print_dec_uint { + // Time Complexity: n(6phi+25) + // Space Complexity: 11phi+27 + def div10_step div10, xor, ret_reg, src, ascii_res, char_flag, zero_flag, start_printing { + ...if1 zero_flag, start_printing + fcall div10, ret_reg + ...zero 4, ascii_res + rep(4, i) ...double_exact_xor ascii_res+dbit+i*dw, src+dbit+i*dw, src+i*dw + ...not char_flag + fcall xor, ret_reg + } + + // Complexity: 5phi+28 + def print_char ascii4, char_flag @ end { + ...if0 char_flag, end + rep(4, i) ...output ascii4+i*dw + rep(4, i) output_bit (0x3>>i)&1 + end: + } + } + } + + + def print_dec_int n, x @ do_print { + .if0 x+(n-1)*dw, do_print + output '-' + .neg n, x + do_print: + .print_dec_uint n, x + } +} diff --git a/flipjump/src/stl/mathlib.fj b/flipjump/src/stl/mathlib.fj new file mode 100644 index 0000000..7aa814e --- /dev/null +++ b/flipjump/src/stl/mathlib.fj @@ -0,0 +1,480 @@ +// Every line is (advanced math) bananas! +// Implementation of advanced math operation over bit-vectors + +// should be assembled with both bitlib.fj and runlib.fj files +// This file is independent of the bit-width, and uses the consts defined at runlib.fj + +// Everything after // is ignored, and every whitespace is ignored (besides new line) +// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next) + +// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op. +// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity + +// The complexities are not updated in this file (should be lower/faster). + + + +// ---------- Multiply: + + +ns bit { + // Complexity n(14phi+48) + def mul10 n, x @ twice, end { + .shl n, x + .mov n, twice, x + .shl n, 2, x + .add n, x, twice + ;end + + twice: + .vec n + end: + } + + + // dst, src = src/10, src%10. + // Complexity: n(5phi+23) + def div10 n, dst, src @ zero, end { + .zero n, dst + ._.cmp_sub_10 zero, src+(n-4)*dw, dst+(n-4)*dw + rep(n-4, i) ._.cmp_sub_10 src+(n-1-i)*dw, src+(n-5-i)*dw, dst+(n-5-i)*dw + ;end + zero: bit 0 + end: + } + ns _ { + // if (val > 10) { val-=10; res=!res; }, (for val4:val[3,2,1,0] of length 5, and val <= 18). + // Complexity: 4phi+21 + def cmp_sub_10 val4, val, res @ yes, no, _1xxxx, _1xx0x, _1xx1x, _01x1x { + ..if1 val4, _1xxxx + ..if0 val+3*dw, no + ..if1 val+ dw, _01x1x + ..if0 val+2*dw, no + + ..not val+2*dw + ..not val+3*dw + ;yes + + _01x1x: + ..not val+3*dw + ;yes + + _1xxxx: + ..not val4 + ..if val+dw, _1xx0x, _1xx1x + _1xx0x: + ..not val+2*dw + ;yes + _1xx1x: + ..not val+3*dw + ;yes + + yes: + ..not val+dw + ..not res + no: + } + } + + + // Complexity (b is the number of 1-bits in src): n^2(6phi+18) + n*b(8phi+33) + // Space Complexity: ~O(90n) + def mul_loop n, dst, src @ start, after_add, src_copy, res, end { + .zero n, res + .mov n, src_copy, src + + start: + .if0 src, after_add + .add n, res, dst //Comp: n(8phi+33) + after_add: + .shl n, dst //Comp: n(2phi+5) + .shr n, src //Comp: n(2phi+5) + .if0 n, dst, end //Comp: n(phi+4) + .if0 n, src, end //Comp: n(phi+4) + ;start + + src_copy: + .vec n + res: + .vec n + end: + .mov n, src, src_copy + .mov n, dst, res + } + + + // Complexity (b is the number of 1-bits in src): n*b(8phi+33) + // Space Complexity: ~O(40n^2) + def mul n, dst, src @ shifted_src, res, end { + .zero n, res + .zero n, shifted_src + .mov n, shifted_src+dw*n, src + rep(n, i) _.mul_add_if n, dst+i*dw, res, shifted_src+(n-i)*dw + .mov n, dst, res + ;end + + shifted_src: + .vec 2*n + res: + .vec n + end: + } + ns _ { + def mul_add_if n, flag, dst, src @ end { + ..if0 flag, end + ..add n, dst, src + end: + } + } +} + + + +ns hex { + // Time Complexity: 5phi+32 + // Space Complexity: 4phi+96 + // .mul.add_carry_dst : res += x * .mul.dst + .mul.add_carry_dst + def add_mul res, x @ ret < .mul.dst, .add.dst, .mul.ret, ._.res { + .xor .mul.dst+4, x + .xor .add.dst, res + wflip .mul.ret+w, ret, .mul.dst + ret: // meanwhile - make phi+28 fj ops there + wflip .mul.ret+w, ret + .xor_zero res, ._.res + } + + // Time Complexity: n(5phi+32) + // Space Complexity: n(4phi+96) + // res[n] += a[n] * b[1] + def add_mul n, res, a, b < .mul.dst { + .mul.clear_carry + .xor .mul.dst, b + rep(n, i) .add_mul res+i*dw, a+i*dw + .xor .mul.dst, b + .mul.clear_carry + } + + // Time Complexity: n(n(3phi+8) + b(5phi+32)), for b the minimum of #on-bits in a,b (b ret, dst, add_carry_dst { + // general progression (after jumping to hex.mul.dst with value d): + // dst -> switch+d (set lower4 mul result in add_carry_dst+4) (5) + // add_carry_dst -> add_carry+? (set add result in hex.add.dst +4. sets dst to set_carry_{0/1}. sets add_carry_dst to clean_add) (6) + // add_carry_dst -> clean_add+? (clears the all 8 bits of add_carry_dst. sets add_carry_dst back to add_carry) (9) + // dst -> set_carry_{0/1}+d (set higher4 mul result in add_carry_dst+0. sets dst to clean) (5) + // add_res -> dst-table+?? (set add result in hex._.res +0) (phi-4) + // dst -> clean+d (clears the higher4 bits of dst. sets dst back to switch) (6) + // hex.mul.ret -> ... (1) + + + ;end + + ret: ;0 + dst: ;switch + + add_carry_dst: ;add_carry // the 4-bit carry is in the lower 4bits in here + + + add_res: + wflip .._.ret+w, after_add, ..add.dst + pad 16 + after_add: + wflip .._.ret+w, after_add, .dst + + + pad 16 // not really needed + switch_small_table: + rep(16, d) fj (d==0)?0: (.add_carry_dst+dbit+(#d)+3), (d==((1<<(#d))>>1)) ? .add_carry_dst : switch_small_table +(d^((1<<(#d))>>1))*dw + set_carry_small_table: + rep(16, d) fj (d==0)?0: (.add_carry_dst+dbit+(#d)-1), (d==((1<<(#d))>>1)) ? add_res : set_carry_small_table+(d^((1<<(#d))>>1))*dw + add_carry_small_table: + rep(16, d) fj (d==0) ? .add_carry_dst+dbit+8 : (..add.dst+dbit+(#d)+3), (d==0) ? .add_carry_dst : add_carry_small_table+(d^((1<<(#d))>>1))*dw + clean_small_table: + rep(16, d) fj (d==0) ? .dst+dbit+9 : ( .dst+dbit+(#d)+3), (d==0) ? .ret : clean_small_table +(d^((1<<(#d))>>1))*dw + + + pad 1024 + switch: + rep(256, d) fj 0, switch_small_table + (((d&0xf)*(d>>4)) & 0xf) * dw + set_carry_0: + rep(256, d) fj .dst+dbit+9, set_carry_small_table + (((d&0xf)*(d>>4)) >> 4) * dw + set_carry_1: + rep(256, d) fj .dst+dbit+8, set_carry_small_table + ((((d&0xf)*(d>>4)) >> 4)+1) * dw + clean: + rep(256, d) fj .dst+dbit+8, clean_small_table + (d>>4) * dw + + + // needs to be 1024-padded + add_carry: + rep(256, d) fj .dst+dbit + (((d&0xf)+(d>>4) > 0xf) ? 9 : 8), add_carry_small_table + (((d&0xf)+(d>>4)) & 0xf) * dw + clean_add: + rep(256, d) fj (d==0) ? .add_carry_dst+dbit+8 : (.add_carry_dst+dbit+(#d)-1), (d==0) ? .dst : clean_add +(d^((1<<(#d))>>1))*dw + clean_carry: + rep( 16, d) fj (d==0) ? .add_carry_dst+dbit+9 : (.add_carry_dst+dbit+(#d)-1), (d==0) ? .dst : clean_carry+(d^((1<<(#d))>>1))*dw + + + end: + } + } +} + + +// ---------- Divide: + + +ns bit { + def idiv n, a, b, q, r @ negative_a, negative_b, one_negative, neg_b_1, do_div, neg_b_2, neg_ans, end { + .mov negative_a, a+dw*(n-1) + .mov negative_b, b+dw*(n-1) + .zero one_negative + + .if0 negative_a, neg_b_1 + .not one_negative + .neg n, a + neg_b_1: + .if0 negative_b, do_div + .not one_negative + .neg n, b + do_div: + .div n, a, b, q, r + + .if0 negative_a, neg_b_2 + .neg n, a + .neg n, r + neg_b_2: + .if0 negative_b, neg_ans + .neg n, b + neg_ans: + .if0 one_negative, end + .neg n, q + ;end + + negative_a: + bit + negative_b: + bit + one_negative: + bit + end: + } + + + // Complexity: n^2(10phi+43) + // Space Complexity: ~O(50n^2) + def div n, a, b, q, r @ Q, R, end { + .if0 n, b, end + .zero 2*n, R + .zero n, Q + + rep(n, i) _.div_step n, a+(n-1-i)*dw, b, R+(n-1-i)*dw, Q+(n-1-i)*dw + + .mov n, r, R + .mov n, q, Q + ;end + + R: + .vec 2*n + Q: + var n + end: + } + ns _ { + def div_step n, N, D, R, Q @ do_sub, end { + ..xor R, N + ..cmp n, R, D, end, do_sub, do_sub + do_sub: + ..sub n, R, D + ..not Q + end: + } + } + + + + def idiv_loop n, a, b, q, r @ negative_a, negative_b, one_negative, neg_b_1, do_div, neg_b_2, neg_ans, end { + .mov negative_a, a+dw*(n-1) + .mov negative_b, b+dw*(n-1) + .zero one_negative + + .if0 negative_a, neg_b_1 + .not one_negative + .neg n, a + neg_b_1: + .if0 negative_b, do_div + .not one_negative + .neg n, b + do_div: + .div_loop n, a, b, q, r + + .if0 negative_a, neg_b_2 + .neg n, a + .neg n, r + neg_b_2: + .if0 negative_b, neg_ans + .neg n, b + neg_ans: + .if0 one_negative, end + .neg n, q + ;end + + negative_a: + bit + negative_b: + bit + one_negative: + bit + end: + } + + + // Complexity: n^2(18phi+64) + // Space Complexity: ~O(120n) + def div_loop n, a, b, q, r @ loop, do_sub, loop_end, after_loop, A, Q, R, i, end { + .if0 n, b, end + .zero n, R + .zero n, Q + .mov n, A, a + .zero n, i + .not i+(n-1)*dw + + loop: + .if0 n, i, after_loop //Comp: n(phi+4) + .shl n, R //Comp: n(2phi+5) + .xor R, A+(n-1)*dw + .cmp n, R, b, loop_end, do_sub, do_sub //Comp: n(2phi+8) + do_sub: + .sub n, R, b //Comp: n(8phi+35) + .xor n, Q, i //Comp: n(phi+2) + loop_end: + .shr n, i //Comp: n(2phi+5) + .shl n, A //Comp: n(2phi+5) + ;loop + + after_loop: + .mov n, r, R + .mov n, q, Q + ;end + + A: + .vec n + R: + .vec n + Q: + .vec n + i: + .vec n + + end: + } +} + + +ns hex { + def div n, nb, q, _r, _a, _b, div0 @ loop, after_loop, do_cmp_sub_func, do_sub, jump_to_flip, flip_op, r, b, a, i, ret, end { + .if0 nb, _b, div0 + + .zero q + .zero nb+1, r + + .mov nb, b, _b + .mov n, a, _a + + .set #n, i, n-1 + + loop: + .shl_hex nb+1, b + + .shl_hex n, r + .xor r, a+(n-1)*dw + + fcall do_cmp_sub_func, ret + jump_to_flip+dbit+0; + fcall do_cmp_sub_func, ret + jump_to_flip+dbit+1; + fcall do_cmp_sub_func, ret + jump_to_flip+dbit+0; + fcall do_cmp_sub_func, ret + jump_to_flip+dbit+1; + + .shl_hex n, a + .shl_hex n, q + + .dec #n, i + .sign #n, i, after_loop, loop + + do_cmp_sub_func: + hex.shr_bit nb+1, b + hex.cmp nb+1, r, b, ret, do_sub, do_sub + do_sub: + hex.sub nb+1, r, b + + jump_to_flip: + ;flip_op + pad 4 + flip_op: + q+dbit+0; ret + q+dbit+1; ret + q+dbit+3; ret + q+dbit+2; ret + + r: .vec nb+1 + b: .vec nb+1 + a: .vec n + i: .vec #n + ret: ;0 + + after_loop: + .mov nb, _r, r + end: + } +} + diff --git a/flipjump/src/stl/ptrlib.fj b/flipjump/src/stl/ptrlib.fj new file mode 100644 index 0000000..3879a4a --- /dev/null +++ b/flipjump/src/stl/ptrlib.fj @@ -0,0 +1,293 @@ +// Every line is (pointing) bananas! +// Implementation of pointers (variables which represents a memory-place), stack and functions. + +// should be assembled with both bitlib.fj and runlib.fj files +// This file is independent of the bit-width, and uses the consts defined at runlib.fj + +// Everything after // is ignored, and every whitespace is ignored (besides new line) +// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next) + +// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op. +// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity + +// The complexities are not updated in this file (should be lower/faster). + + + +// ---------- Init + + +ns bit { + def ptr_init { + ._.ptr_init + } + + ns _ { + def ptr_init > to_flip, to_jump, to_flip_var, to_flip_return_var, to_jump_var { + pad 1 + to_flip: + 0;0 + to_jump: + ;0 + + to_flip_var: + bit.vec w, 0 + to_flip_return_var: + bit.vec w, 0 + to_jump_var: + bit.vec w, 0 + } + } +} + + + +// ---------- Jump: + + +ns bit { + // like: ;*ptr + // Complexity w(2phi+6) + def ptr_jump ptr < ._.to_jump, ._.to_jump_var { + .bit_var_xor w, ._.to_jump+w, ._.to_jump_var, ._.to_jump_var + .bit_var_xor w, ._.to_jump+w, ._.to_jump_var, ptr + ;._.to_jump + } +} + + + +// ---------- Flip: + + +ns bit { + // like: *ptr; + // Complexity w(2phi+6) + def ptr_flip ptr @ cleanup < ._.to_flip, ._.to_flip_var { + wflip ._.to_flip+w, cleanup + + .bit_var_xor w, ._.to_flip, ._.to_flip_var, ._.to_flip_var + .bit_var_xor w, ._.to_flip, ._.to_flip_var, ptr + ;._.to_flip + + cleanup: + wflip ._.to_flip+w, cleanup + } + + // like: (*ptr)+dbit; + // Assumes *ptr is dw-aligned + // Complexity w(2phi+7) + // The comp_flip_if executes much less than w/2 operations. + def ptr_flip_dbit ptr { + rep(#dbit, i) comp_flip_if ptr+dbit+i*dw, (dbit>>i)&1 + .ptr_flip ptr + rep(#dbit, i) comp_flip_if ptr+dbit+i*dw, (dbit>>i)&1 + } + + // Assumes *ptr is dw-aligned + def xor_to_ptr ptr, bit @ end { + .if0 bit, end + .ptr_flip_dbit ptr + end: + } + + + // like: wflip *ptr, value + // Assumes *ptr is w-aligned, and value is 2dw-aligned + // Complexity w(3phi+11) + def ptr_wflip ptr, value < ._.to_flip, ._.to_flip_var{ + .bit_var_xor w, ._.to_flip, ._.to_flip_var, ._.to_flip_var + .bit_var_xor w, ._.to_flip, ._.to_flip_var, ptr + rep(w, i) ._.advance_by_one_and_flip__ptr_wflip (#(i^((i+1)%w))), (value>>i)&1 + } + ns _ { + def advance_by_one_and_flip__ptr_wflip n, do_flip @ cleanup, advance < .to_flip { + comp_if0 do_flip, advance + wflip .to_flip+w, cleanup, .to_flip + cleanup: + wflip .to_flip+w, cleanup + advance: + rep(n, i) ..exact_not .to_flip+i + } + } + + // Assumes *ptr is dw-aligned, and value is 2dw-aligned + def ptr_wflip_2nd_word ptr, value { + .not ptr + dw*ww + .ptr_wflip ptr, value + .not ptr + dw*ww + } +} + + + +// ---------- Xor + + +ns bit { + // like: .xor dst *ptr + // assumes *ptr is dw-aligned + // Complexity w(8phi+28) + def xor_from_ptr dst, ptr { + .exact_xor_from_ptr dst+dbit, ptr + } + + def exact_xor_from_ptr dst, ptr @ base_jump_label, cleanup { + .ptr_wflip_2nd_word ptr, base_jump_label + + .ptr_jump ptr + pad 2 + base_jump_label: + ;cleanup + dst; + + cleanup: + .ptr_wflip_2nd_word ptr, base_jump_label + + } +} + + + +// ---------- Stack + + +ns bit { + def stack n { + ._.stack n + } + ns _ { + // sp always points to the last pushed value (at start - to stack[-1]) + def stack n > sp, stack{ + pad 1 + sp: + bit.vec w, .stack-dw + stack: + bit.vec n, 0 + } + } + def get_sp dst < ._.sp { + .mov w, dst, ._.sp + } + + + // Complexity w(2phi+10) + def inc_ptr ptr { + .inc w-dww, ptr+dww*dw + } + + + // Complexity w(2phi+12) + def dec_ptr ptr { + .dec w-dww, ptr+dww*dw + } + + + // Assumes address is 2dw-aligned + // Complexity w(5phi+21) + def push_ret_address address < ._.sp { + .inc_ptr ._.sp + .ptr_wflip_2nd_word ._.sp, address + } + + // Assumes address is 2dw-aligned + // Complexity w(5phi+23) + def pop_ret_address address < ._.sp { + .ptr_wflip_2nd_word ._.sp, address + .dec_ptr ._.sp + } + + + // Complexity: w(4phi+17) + def push bit < ._.sp { + .inc_ptr ._.sp + .xor_to_ptr ._.sp, bit + } + + // Assumes *sp==bit. + // Complexity: w(4phi+19) + def pop bit < ._.sp { + .xor_to_ptr ._.sp, bit + .dec_ptr ._.sp + } + + // Complexity: w(12phi+47) + def pop_res bit < ._.sp { + .zero bit + .xor_from_ptr bit, ._.sp + .pop bit + } +} + + + +// ---------- Functions + + +ns bit { + // Complexity: w(5phi+21) + // the pop_ret_address is counted for the future return + def call address @ return_label { + .push_ret_address return_label + ;address + + pad 2 + return_label: + .pop_ret_address return_label + } + + + // Complexity: w(7phi+29) + // the last-call's pop_ret_address is counted for this return + def return < ._.sp { + .ptr_jump ._.sp + } +} + + + +// ---------- Fast Call + + +def fcall_init { + _.fcall_init +} +ns _ { + def fcall_init > ret_addr1, ret_addr2, ret_addr3 { + ret_addr1: bit 0 + ret_addr2: bit 0 + ret_addr3: bit 0 + } +} + +// Complexity: phi+1 +def fcall label, ret_reg @ ret { + wflip ret_reg+w, ret, label + pad 2 + ret: + wflip ret_reg+w, ret +} + +// Complexity: 1 +def fret ret_reg { + ;ret_reg +} + +def fcall1 label < _.ret_addr1 { + fcall label, _.ret_addr1 +} +def fcall2 label < _.ret_addr2 { + fcall label, _.ret_addr2 +} +def fcall3 label < _.ret_addr3 { + fcall label, _.ret_addr3 +} +def fret1 < _.ret_addr1 { + fret _.ret_addr1 +} +def fret2 < _.ret_addr2 { + fret _.ret_addr2 +} +def fret3 < _.ret_addr3 { + fret _.ret_addr3 +} diff --git a/flipjump/src/stl/runlib.fj b/flipjump/src/stl/runlib.fj new file mode 100644 index 0000000..e69ef4c --- /dev/null +++ b/flipjump/src/stl/runlib.fj @@ -0,0 +1,118 @@ +// Every line is (running) bananas! +// This file contains a width-independent code + +// This file contains constants and labels used by other standard library files. + +// Everything after // is ignored, and every whitespace is ignored (besides new line) +// An opcode is: F;J F; ;J or just ; (no F => F=0; no J => J=next) + +// Complexity note: phi is log2 of the total number of fj operations, counting wflips as one op. +// so 2 wflips with value=label (while label is padded with 2^n) causes phi-n space/time complexity + +// The complexities are not updated in this file (should be lower/faster). + + +// w = ?? // memory and operands width. Is defined at compile time. +dww = #w // double-w-width (log2(2w)) +ww = dww-1 // w-width (log2(w)) +dw = 2 * w // double word size +dbit = w + dww // bit-distance from variable start to bit value (w+dww) + + + +// ---------- Startup Code + + +def startup > IO, code_start { + ;code_start // 0w;1w : code start + IO: + ;0 // 2w;3w : now points to io_handler + + code_start: + // 4w;5w : start of code +} + + +def startup in0_handler, in1_handler { + startup + default_input in0_handler, in1_handler +} + + + +// ---------- Basic Functionality + + +def zero_op { + 0;0 +} + +def fj f, j { + f;j +} + +def wflip_macro dst, val { + wflip dst, val +} + +def wflip_macro dst, val, jmp_addr { + wflip dst, val, jmp_addr +} + +def pad x @ pad_start { + pad_start: + rep((0-pad_start/(2*w))%x, i) zero_op +} + + +// ---------- Compilation Time: +// Complexity: 1 + + +def comp_if expr, l0, l1 { + ; expr ? l1 : l0 +} + +def comp_if0 expr, l0 @ l1 { + comp_if expr, l0, l1 + l1: +} + +def comp_if1 expr, l1 @ l0 { + comp_if expr, l0, l1 + l0: +} + + +def comp_flip_if bit, expr { + (expr ? bit : 0); +} + + + +// ---------- Unconditional Jump +// Complexity: 1 + + +def skip { + ;$ + dw +} + + +def loop { + ;$ - dw +} + + + +// ---------- Input Handler + + +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: +} diff --git a/flipjump/src/tests/calc.fj b/flipjump/src/tests/calc.fj new file mode 100644 index 0000000..26e4e89 --- /dev/null +++ b/flipjump/src/tests/calc.fj @@ -0,0 +1,253 @@ +startup + + +loop: + bit.zero hex_used + bit.print 3, prompt_string + getch + remove_spaces + check_quit should_quit, before_start + should_quit: + getch + remove_spaces + line_ended finish, finish, before_start + before_start: + line_ended loop_new_line, finish, start + loop_new_line: + output '\n' + ;loop + + start: + insert_number a + + remove_spaces + bit.mov 8, op, ascii + line_ended do_print, do_print, advance + advance: + getch + + remove_spaces + insert_number b + + remove_spaces + + bit.zero should_finish + line_ended do_calc, mark_finish, err_loop + mark_finish: + bit.not should_finish + do_calc: + calc a, op, b + bit.if1 error, err_loop + + + do_print: + output '\n' + print_int a + output '\n' + + bit.if should_finish, loop, finish + + err_getch: + getch + err_loop: + line_ended print_err, print_err, err_getch + print_err: + bit.print 8, err_string + line_ended loop, finish, finish + + finish: + loop + + + +def remove_spaces @ main_loop, try2, next_ascii, end < space1, ascii, space2 { + main_loop: + bit.cmp 8, ascii, space1, try2, next_ascii, try2 + try2: + bit.cmp 8, ascii, space2, end, next_ascii, end + next_ascii: + getch + ;main_loop + + end: +} + + + +def insert_number x @ check1, set_minus, check2, before_hex, hex_loop, before_dec, dec_loop, minus_flag, end, after_minus < dec, hex_prefix1, hex_prefix2, t, hex, minus, ascii, error, hex_used { + bit.zero w, x + bit.zero minus_flag + bit.cmp 8, ascii, minus, check1, set_minus, check1 + set_minus: + getch + bit.not minus_flag + check1: + bit.cmp 8, ascii, hex_prefix1, check2, before_hex, check2 + check2: + bit.cmp 8, ascii, hex_prefix2, before_dec, before_hex, before_dec + + before_hex: + getch + bit.one hex_used + hex_loop: + bit.ascii2hex error, hex, ascii + bit.if1 error, end + bit.shl w, 4, x + bit.xor 4, x, hex + getch + ;hex_loop + + before_dec: + bit.zero w-4, t+4*dw + dec_loop: + bit.ascii2dec error, dec, ascii + bit.if1 error, end + bit.mov 4, t, dec + bit.mul10 w, x + bit.add w, x, t + getch + ;dec_loop + + minus_flag: + bit + end: + bit.if0 minus_flag, after_minus + bit.neg w, x + after_minus: + bit.zero error +} + + + +def calc a, op, b @ try_add, try_sub, try_mul, try_mul_loop, try_div, try_mod, add, sub, mul, mul_loop, div_mod, div, mod, bad, div_mod_flag, r, q, end < minus, asterisk, error, percentage, roof, slash, plus { + bit.zero error + + try_add: + bit.cmp 8, op, plus, try_sub, add, try_sub + try_sub: + bit.cmp 8, op, minus, try_mul, sub, try_mul + try_mul: + bit.cmp 8, op, asterisk, try_mul_loop, mul, try_mul_loop + try_mul_loop: + bit.cmp 8, op, roof, try_div, mul_loop, try_div + try_div: + bit.zero div_mod_flag + bit.cmp 8, op, slash, try_mod, div_mod, try_mod + try_mod: + bit.not div_mod_flag + bit.cmp 8, op, percentage, bad, div_mod, bad + add: + bit.add w, a, b + ;end + sub: + bit.sub w, a, b + ;end + mul: +// bit.mul w, a, b +// ;end + mul_loop: + bit.mul_loop w, a, b + ;end + div_mod: +// bit.idiv w, a, b, q, r + bit.idiv_loop w, a, b, q, r + bit.if div_mod_flag, div, mod + div: + bit.mov w, a, q + ;end + mod: + bit.mov w, a, r + ;end + bad: + bit.one error + ;end + + div_mod_flag: + bit + r: + bit.vec w + q: + bit.vec w + end: +} + + + +def line_ended true, end, false @ try_end_line_n < end_line_r, end_line_n, ascii { + bit.if0 8, ascii, end + bit.cmp 8, ascii, end_line_r, try_end_line_n, true, try_end_line_n + try_end_line_n: + bit.cmp 8, ascii, end_line_n, false, true, false +} + + + +def check_quit true, false @ try_quit1 < ascii, quit1, quit2 { + bit.cmp 8, ascii, quit2, try_quit1, true, false + try_quit1: + bit.cmp 8, ascii, quit1, false, true, false +} + + + +// does not print new-line +def getch @ check_n, do_print, end < end_line_r, end_line_n, ascii { + bit.input ascii + bit.cmp 8, ascii, end_line_r, check_n, end, check_n + check_n: + bit.cmp 8, ascii, end_line_n, do_print, end, do_print + do_print: + bit.print ascii + end: +} + + + +def print_int x @ print_hex, end < hex_used { + bit.if1 hex_used, print_hex + bit.print_dec_int w, x + ;end + print_hex: + bit.print_hex_int w, x, 1 + end: +} + + + +op: bit.vec 8, 0 +ascii: bit.vec 8, 0 +error: bit 0 +hex: bit.vec 4, 0 +dec: bit.vec 4, 0 +should_finish: bit 0 +hex_used: bit 0 + +a: bit.vec w, 0 +b: bit.vec w, 0 +t: bit.vec w, 0 + +plus: bit.vec 8, '+' +minus: bit.vec 8, '-' +asterisk: bit.vec 8, '*' +roof: bit.vec 8, '^' +slash: bit.vec 8, '/' +percentage: bit.vec 8, '%' + +hex_prefix1:bit.vec 8, 'x' +hex_prefix2:bit.vec 8, 'X' + +eof: bit.vec 8, '\0' +end_line_r: bit.vec 8, '\r' +end_line_n: bit.vec 8, '\n' +space1: bit.vec 8, ' ' +space2: bit.vec 8, '\t' + +quit1: bit.vec 8, 'Q' +quit2: bit.vec 8, 'q' + + +err_string: bit.str "\nError!\n" +prompt_string: bit.str "> " + +// bit.ptr_init +// bit.stack 20 diff --git a/flipjump/src/tests/casting.fj b/flipjump/src/tests/casting.fj new file mode 100644 index 0000000..cd4e3d6 --- /dev/null +++ b/flipjump/src/tests/casting.fj @@ -0,0 +1,36 @@ +startup + +bit2hex h, b0 +hex.print_as_digit h, 0 +bit2hex h, b1 +hex.print_as_digit h, 0 +output '\n' + +bit2hex 12, hex, bits +//hex.print_as_digit hex+0*dw, 0 +//hex.print_as_digit hex+1*dw, 0 +//hex.print_as_digit hex+2*dw, 0 +hex.print_as_digit 3, hex, 0 +output '\n' +output '\n' + +hex2bit 10, bits2, hex2 +hex.print_as_digit 10, hex2, 0 +output '\n' +bit2hex 40, hex2, bits2 +bit.print_hex_uint 40, bits2, 0 +output '\n' +bit.print_as_digit 40, bits2 +output '\n' + +loop + + +b0: bit 0 +b1: bit 1 +h: hex +bits: bit.vec 12, 0x123 +hex: hex.vec 3 + +hex2: hex.vec 10, 0x123456 +bits2: bit.vec 40 diff --git a/flipjump/src/tests/cat.fj b/flipjump/src/tests/cat.fj new file mode 100644 index 0000000..183ce17 --- /dev/null +++ b/flipjump/src/tests/cat.fj @@ -0,0 +1,20 @@ + startup +start: + bit.input ascii + bit.if0 8, ascii, end + bit.cmp 8, ascii, nl, final_check, end, final_check + final_check: + bit.cmp 8, ascii, cr, print, end, print +print: + bit.print ascii + ;start +end: + loop + + +ascii: + bit.vec 8, 0 +nl: + bit.vec 8, '\n' +cr: + bit.vec 8, '\r' diff --git a/flipjump/src/tests/div10.fj b/flipjump/src/tests/div10.fj new file mode 100644 index 0000000..c0d8cf1 --- /dev/null +++ b/flipjump/src/tests/div10.fj @@ -0,0 +1,18 @@ +startup + +loop: +bit.print_hex_uint w, var, 1 +output ',' +bit.div10 w, dst, var +bit.dec2ascii ascii, var +bit.print ascii +output '\n' +bit.mov w, var, dst +bit.if1 w, var, loop + +loop + + +var: bit.vec w, 1281 // (128, 12, 1) +dst: bit.vec w +ascii: bit.vec 8 diff --git a/flipjump/src/tests/func.fj b/flipjump/src/tests/func.fj new file mode 100644 index 0000000..22442ed --- /dev/null +++ b/flipjump/src/tests/func.fj @@ -0,0 +1,177 @@ +startup + + + +// As with the current variables, should print: +// ABC +// AB~CD~EF +// ABCDE +// ABCDEFGH-1 +// ABC abcdefg ABCD-0 + + + +// Prints "ABC" +test1: + output 'A' + bit.call func1 + output 'C' + output '\n' + ;test2 + +func1: + output 'B' + bit.return + + + +// Prints "AB~CD~EF" +test2: + output 'A' + bit.call func2a + bit.call func2b + output 'F' + output '\n' + ;test3 + +func2a: + output 'B' + bit.call func2c + output 'C' + bit.return +func2b: + output 'D' + bit.call func2c + output 'E' + bit.return +func2c: + output '~' + bit.return + + + +// Prints "ABCDE" +test3: + output 'A' + bit.push x3 + output 'B' + bit.call func3 + output 'D' + bit.pop x3 + output 'E' + output '\n' + ;test4 + +func3: + output 'C' + bit.return + + + +// Prints "ABCDEFGH-" and then 0/1, the invert of x4 +test4: + output 'A' + bit.push x4 + output 'B' + + bit.call func4 + + output 'G' + bit.pop_res x4 + output 'H' + bit.bin2ascii ascii, x4 + output '-' + bit.print ascii + + output '\n' + ;test5 + +func4: + output 'C' + bit.get_sp __func4_arg_ptr + output 'D' + bit.dec_ptr __func4_arg_ptr + output 'E' + bit.ptr_flip_dbit __func4_arg_ptr + output 'F' + bit.return + __func4_arg_ptr: + bit.vec w, 0 + + + +// Prints "ABC abcdefg ABCD-", and then 0/1, the xor of x5,y5 +test5: + output 'A' + bit.push res5 + output 'B' + bit.push x5 + output 'C' + bit.push y5 + + output ' ' + bit.call func5 + output ' ' + + output 'A' + bit.pop y5 + output 'B' + bit.pop x5 + output 'C' + bit.pop_res res5 + output 'D' + + bit.bin2ascii ascii, res5 + output '-' + bit.print ascii + + output '\n' + loop + +// res = arg0 xor arg1 +func5: + bit.zero __func5_res + bit.get_sp __func5_arg_ptr + output 'a' + + bit.dec_ptr __func5_arg_ptr + output 'b' + bit.xor_from_ptr __func5_res, __func5_arg_ptr + output 'c' + bit.dec_ptr __func5_arg_ptr + output 'd' + bit.xor_from_ptr __func5_res, __func5_arg_ptr + output 'e' + + bit.dec_ptr __func5_arg_ptr + output 'f' + bit.xor_to_ptr __func5_arg_ptr, __func5_res + output 'g' + + bit.return + __func5_res: + bit + __func5_arg_ptr: + bit.vec w + + + + x3: + bit 0 + + x4: + bit 0 + + x5: + bit 1 + y5: + bit 1 + res5: + bit 0 + + + ascii: + bit.vec 8 + + bit.ptr_init + bit.stack 10 diff --git a/flipjump/src/tests/hello_no-stl.fj b/flipjump/src/tests/hello_no-stl.fj new file mode 100644 index 0000000..937e5f6 --- /dev/null +++ b/flipjump/src/tests/hello_no-stl.fj @@ -0,0 +1,37 @@ +def startup @ code_start > IO { + ;code_start + IO: + ;0 + code_start: +} + + +def output_bit bit < IO { + IO + bit; +} +def output ascii { + rep(8, i) output_bit ((ascii>>i)&1) +} + +def end_loop @ loop_label { + loop_label: + ;loop_label +} + + startup + + output 'H' + output 'e' + output 'l' + output 'l' + output 'o' + output ',' + output ' ' + output 'W' + output 'o' + output 'r' + output 'l' + output 'd' + output '!' + + end_loop diff --git a/flipjump/src/tests/hello_world.fj b/flipjump/src/tests/hello_world.fj new file mode 100644 index 0000000..330dc6a --- /dev/null +++ b/flipjump/src/tests/hello_world.fj @@ -0,0 +1,3 @@ +startup +output "Hello, World!\n(:" +loop diff --git a/flipjump/src/tests/hello_world_with_str.fj b/flipjump/src/tests/hello_world_with_str.fj new file mode 100644 index 0000000..2ef1366 --- /dev/null +++ b/flipjump/src/tests/hello_world_with_str.fj @@ -0,0 +1,7 @@ + startup + + bit.print_str 20, str + loop + + str: + bit.str "Hello, World!\n(:" diff --git a/flipjump/src/tests/hexlib-2params.fj b/flipjump/src/tests/hexlib-2params.fj new file mode 100644 index 0000000..03dbebb --- /dev/null +++ b/flipjump/src/tests/hexlib-2params.fj @@ -0,0 +1,273 @@ +start: +startup + + +// cmp +output "cmp:\n" +rep(256, i) test_cmp i&0xf, i>>4 +output '\n' + +// cmp n +CMP_N = 0x012345 | (0x123456 << 32) | (0x333333 << 64) | (0x654321 << 96) +rep(16, i) test_cmp_n 8, (CMP_N >> ((i&3)*32)) & ((1<<32)-1), (CMP_N >> ((i>>2)*32)) & ((1<<32)-1) +output "\n\n" + + +// add +output "add:\n" +rep(256, i) test_add i&0xf, i>>4 +output '\n' + +// add n +ADD_N = 0x0000ffff800040a73dd06622dc0594c9e1b9b001 +rep(100, i) test_add_n 4, (ADD_N>>((i%10)*4)&0xf), (ADD_N>>((i/10))*4&0xf) +output "\n\n" + + +// sub +output "sub:\n" +rep(256, i) test_sub i&0xf, i>>4 +output '\n' + +// sub n +SUB_N = 0x0000ffff8000ada41d9d587f40027d6d07f2c898 +rep(100, i) test_sub_n 4, (SUB_N>>((i%10)*4)&0xf), (SUB_N>>((i/10))*4&0xf) +output "\n\n" + + +// or +output "or:\n" +rep(256, i) test_or i&0xf, i>>4 +output '\n' + +// or n +OR_N = 0x0000ffff8000c47b5d8bbebfbe0bf47bc2600b85 +rep(100, i) test_or_n 4, (OR_N>>((i%10)*4)&0xf), (OR_N>>((i/10))*4&0xf) +output "\n\n" + + +// and +output "and:\n" +rep(256, i) test_and i&0xf, i>>4 +output '\n' + +// and n +AND_N = 0x0000ffff8000b32cccc69dea2047c8e0ae1e5299 +rep(100, i) test_and_n 4, (AND_N>>((i%10)*4)&0xf), (AND_N>>((i/10))*4&0xf) +output "\n\n" + + +loop +hex.init + + +def test_cmp a, b @ lt, eq, gt, ah, bh, end { + hex.cmp ah, bh, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + ah: hex a + bh: hex b + end: +} + + +def test_cmp_n n, a, b @ lt, eq, gt, ah, bh, end { + hex.cmp n, ah, bh, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + ah: hex.vec n, a + bh: hex.vec n, b + end: +} + + +def test_add a, b @ c0_1st, c1_1st, print_1st, c0_2nd, c1_2nd, print_2nd, ah_1st, bh, ah_2nd, end { + hex.add.clear_carry + hex.add ah_1st, bh + hex.add.clear_carry c0_1st, c1_1st + c0_1st: + output '0' + ;print_1st + c1_1st: + output '1' + print_1st: + hex.print_as_digit ah_1st, 0 + output '-' + + hex.add.not_carry + hex.add ah_2nd, bh + hex.add.clear_carry c0_2nd, c1_2nd + c0_2nd: + output '0' + ;print_2nd + c1_2nd: + output '1' + print_2nd: + hex.print_as_digit ah_2nd, 0 + output ' ' + ;end + + ah_1st: hex a + ah_2nd: hex a + bh: hex b + end: +} + +def test_add_n n, a, b @ lt, eq, gt, ah, bh, ch, end { + hex.add n, ah, bh + hex.cmp n, ah, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + ah: hex.vec n, a + bh: hex.vec n, b + ch: hex.vec n, a+b + end: +} + + +def test_sub a, b @ c0_1st, c1_1st, print_1st, c0_2nd, c1_2nd, print_2nd, ah_1st, bh, ah_2nd, end < hex.sub.dst { + hex.sub.clear_carry + hex.sub ah_1st, bh + hex.sub.clear_carry c0_1st, c1_1st + c0_1st: + output '0' + ;print_1st + c1_1st: + output 'f' + print_1st: + hex.print_as_digit ah_1st, 0 + output '-' + + hex.sub.not_carry + hex.sub ah_2nd, bh + hex.sub.clear_carry c0_2nd, c1_2nd + c0_2nd: + output '0' + ;print_2nd + c1_2nd: + output 'f' + print_2nd: + hex.print_as_digit ah_2nd, 0 + output ' ' + ;end + + ah_1st: hex a + ah_2nd: hex a + bh: hex b + end: +} + +def test_sub_n n, a, b @ lt, eq, gt, ah, bh, ch, end { + hex.sub n, ah, bh + hex.cmp n, ah, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + ah: hex.vec n, a + bh: hex.vec n, b + ch: hex.vec n, a-b + end: +} + + +def test_or a, b @ ah, ah_copy, bh, end { + hex.or ah, bh + hex.or bh, ah_copy + hex.print_as_digit ah, 0 + hex.print_as_digit bh, 0 + output ' ' + ;end + + ah: hex a + ah_copy: hex a + bh: hex b + end: +} + +def test_or_n n, a, b @ lt, eq, gt, ah, bh, ch, end { + hex.or n, ah, bh + hex.cmp n, ah, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + ah: hex.vec n, a + bh: hex.vec n, b + ch: hex.vec n, a|b + end: +} + + +def test_and a, b @ ah, ah_copy, bh, end { + hex.and ah, bh + hex.and bh, ah_copy + hex.print_as_digit ah, 0 + hex.print_as_digit bh, 0 + output ' ' + ;end + + ah: hex a + ah_copy: hex a + bh: hex b + end: +} + +def test_and_n n, a, b @ lt, eq, gt, ah, bh, ch, end { + hex.and n, ah, bh + hex.cmp n, ah, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + ah: hex.vec n, a + bh: hex.vec n, b + ch: hex.vec n, a&b + end: +} diff --git a/flipjump/src/tests/hexlib-basics1.fj b/flipjump/src/tests/hexlib-basics1.fj new file mode 100644 index 0000000..e09ffd3 --- /dev/null +++ b/flipjump/src/tests/hexlib-basics1.fj @@ -0,0 +1,378 @@ +start: +startup + + +// prints +output "prints:\n" +hex.print_as_digit 16, vars, 0 +output '\n' +hex.print_as_digit 16, vars, 1 +output "\n\n" + + +// xor +output "xor:\n" +rep (16, val) xor_all val +output '\n' + +// zero +output "zero:\n" +hex.zero 16, vars +hex.print_as_digit 16, vars, 0 +output "\n\n" + +// xor (as vec) once again +output "xor n:\n" +hex.xor 16, vars, consts +hex.print_as_digit 16, vars, 0 +output "\n\n" + +// xor_zero +output "xor_zero:\n" +hex.xor_zero 16, vars2, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.print_as_digit 16, vars2, 0 +output "\n\n" + +// mov +output "mov:\n" +hex.mov 16, vars, vars2 +hex.print_as_digit 16, vars, 0 +output '\n' +hex.print_as_digit 16, vars2, 0 +output "\n\n" + +// set +output "set:\n" +rep(16, i) hex.set vars+i*dw, 15-i +hex.print_as_digit 16, vars, 0 +output '\n' +hex.print_as_digit 16, vars2, 0 +output "\n\n" + +// swap +output "swap:\n" +hex.swap 16, vars, vars2 +hex.print_as_digit 16, vars, 0 +output '\n' +hex.print_as_digit 16, vars2, 0 +output "\n\n" + + +// inc1 +output "inc1:\n" +rep(16, i) inc1_print_carry vars+i*dw, vars2+i*dw +hex.print_as_digit 16, vars2, 0 +output '\n' +hex.print_as_digit 16, vars, 0 +output "\n\n" + +// inc, not +output "inc, not:\n" +hex.zero 16, vars +hex.inc 16, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.set vars, 0xf +hex.inc 16, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.zero 16, vars +hex.not 16, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.inc 16, vars +hex.print_as_digit 16, vars, 0 +output "\n\n" + + +// dec1 +output "dec1:\n" +hex.mov 16, vars, consts +rep(16, i) dec1_print_borrow vars+i*dw, vars2+i*dw +hex.print_as_digit 16, vars2, 0 +output '\n' +hex.print_as_digit 16, vars, 0 +output "\n\n" + +// dec +output "dec:\n" +hex.zero 16, vars +hex.set vars, 2 +hex.dec 16, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.dec 16, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.dec 16, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.dec 16, vars +hex.print_as_digit 16, vars, 0 +output "\n\n" + + +// neg +output "neg:\n" +hex.zero 16, vars +hex.neg 16, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.set vars+dw, 3 +hex.neg 16, vars +hex.print_as_digit 16, vars, 0 +output '\n' +hex.neg 16, vars +hex.print_as_digit 16, vars, 0 +output "\n\n" + + +// if_flags +output "if_flags:\n" +// ops = [(randint(0, 15), randint(0,(2**16)-1)) for _ in range(100)] +// hexlib.out line: for h, f in ops: print((f>>h)&1, end='') +// IF_100_NUMS = hex(sum(h+f*16 << (i*20) for i, (h,f) in enumerate(ops))) +IF_FLAGS_NUMS = 0x2098593d070776a83803ed025fcf2630b539677e0a51278ec3b572bfa969f37eb32fa5a27d38f4f1ba10d5900345ee5d4b50f0d9b73a3ef84d8cbd2258f5a9cdedd958464321a1be0a3d2ba53a12ff684678ccaeea178472da56b4559e3b6e1fb5afd9afc3d69a167c53a95b2516817ba4f9890ded69f06b8e4eae281a4968d57d836496ceea29b290de0a64f6352588dc27b156aa22acc8147ff6400f5d71cd956b7021d2175e2f44c5f78c7d2afc97dacc10e9f17d11206ab17f05ffaf20a7af40b9c09c305a72f0dd8782762922df18191171efd38c65b187350bbecbd27c62c480459289ce5599ceda69a776420065898f22b7cf640a898 +rep(100, i) print_if_flags (IF_FLAGS_NUMS>>(i*20))&((i<<20)-1) +output "\n\n" + +// if +output "if:\n" +def print_if hex @ l0, l1 < IO { + hex.if hex, l0, l1 + l0: IO+0;l1+dw + l1: output '1' +} +def print_if0 hex @ l0 < IO { + hex.if0 hex, l0 + IO+1;l0+dw + l0: output '0' +} +def print_if1 hex @ l1 < IO { + hex.if1 hex, l1 + IO+0;l1+dw + l1: output '1' +} +hex.zero vars +print_if vars +print_if0 vars +print_if1 vars + +hex.set vars, 1 +print_if vars +print_if0 vars +print_if1 vars + +hex.set vars, 8 +print_if vars +print_if0 vars +print_if1 vars + +hex.set vars, 15 +print_if vars +print_if0 vars +print_if1 vars +output '\n' + +// if n +def print_if_16 hex @ l0, l1 < IO { + hex.if 16, hex, l0, l1 + l0: IO+0;l1+dw + l1: output '1' +} +def print_if0_16 hex @ l0 < IO { + hex.if0 16, hex, l0 + IO+1;l0+dw + l0: output '0' +} +def print_if1_16 hex @ l1 < IO { + hex.if1 16, hex, l1 + IO+0;l1+dw + l1: output '1' +} +hex.zero 16, vars +print_if_16 vars +print_if0_16 vars +print_if1_16 vars + +hex.set vars, 1 +print_if_16 vars +print_if0_16 vars +print_if1_16 vars + +hex.set vars, 0 +hex.set vars+7*dw, 4 +print_if_16 vars +print_if0_16 vars +print_if1_16 vars + +hex.zero 16, vars +hex.not 16, vars +print_if_16 vars +print_if0_16 vars +print_if1_16 vars +output "\n\n" + +// sign +output "sign:\n" +def test_sign n, x @ neg, zpos, xh, end { + hex.sign n, xh, neg, zpos + + neg: + output '-' + ;end + zpos: + output '+' + ;end + + xh: hex.vec n, x + end: +} +rep( 16, i) test_sign 1, i +output '\n' +rep(256, i) test_sign 2, i +output "\n\n" + + +// input_hex +output "input_hex:\n" +rep(16, i) input2hex vars+i*dw +hex.print_as_digit 16, vars, 0 +input2hex garbage +output '\n' + +// input_hex +rep(64, i) input_hex_print_error +input2hex garbage +output "\n\n" + +// input-print +output "input-print:\n" +hex.input 16, vars +hex.print 16, vars +input2hex garbage +output '\n' +rep(11, i) cat_char +input2hex garbage +output "\n\n" + + +// print_uint +output "print_uint:\n" +rep(5, i) print_uint 16, positive+16*i*dw +output '\n' + +// print_int +output "print_int:\n" +rep(9, i) print_int 16, positive+16*i*dw +output '\n' + + +loop + + +positive: + hex.vec 16, 0x12345AF + hex.vec 16, 0xDeadC0de + hex.vec 16, 0x3 + hex.vec 16, 0x0f0 + hex.vec 16, 0x0 +negative: + hex.vec 16, (0 -0x12345AF)&((1<<64)-1) + hex.vec 16, (0 -0xDeadC0de)&((1<<64)-1) + hex.vec 16, (0 -0x3)&((1<<64)-1) + hex.vec 16, (0 -0x0f0)&((1<<64)-1) + + +vars: rep(16, j) hex j +vars2: hex.vec 16, 0 +consts: rep(16, j) hex j +garbage: hex.vec 2 + + +def xor_all val < vars, consts { + rep (16, i) hex.xor vars+i*dw, consts+val*dw + hex.print_as_digit 16, vars, 0 + output '\n' +} + + +def inc1_print_carry hex, carry @ output1, end { + hex.zero carry + hex.inc1 hex, end, output1 + output1: + carry+dbit; + end: +} + + +def dec1_print_borrow hex, borrow @ output1, end { + hex.zero borrow + hex.dec1 hex, end, output1 + output1: + borrow+dbit; + end: +} + + +def print_if_flags hex_flags_val @ l0, l1, hex < IO { + hex.if_flags hex, hex_flags_val>>4, l0, l1 + hex: hex hex_flags_val & 0xf + l0: + IO+0;l1+dw + l1: + output '1' +} + + +def input2hex hex < garbage { + hex.input_hex hex + hex.input_hex garbage +} + + +def input_hex_print_error @ hex, error, end { + hex.input_as_hex hex, error + hex.print_as_digit hex, 0 + ;end + + hex: hex + error: + output 'X' + end: +} + + +def cat_char @ char, end { + hex.input char + hex.print char + ;end + char: hex.vec 2 + end: +} + + +def print_uint n, x { + hex.print_uint n, x, 1, 0 + output ", " + hex.print_uint n, x, 1, 1 + output ", " + hex.print_uint n, x, 0, 0 + output ", " + hex.print_uint n, x, 0, 1 + output "\n" +} + + +def print_int n, x { + hex.print_int n, x, 1, 0 + output ", " + hex.print_int n, x, 1, 1 + output ", " + hex.print_int n, x, 0, 0 + output ", " + hex.print_int n, x, 0, 1 + output "\n" +} diff --git a/flipjump/src/tests/hexlib-basics2.fj b/flipjump/src/tests/hexlib-basics2.fj new file mode 100644 index 0000000..70a5e9c --- /dev/null +++ b/flipjump/src/tests/hexlib-basics2.fj @@ -0,0 +1,198 @@ +start: +startup + + +// shl_bit +output "shl_bit:\n" +rep(256, i) test_shl_bit 2, i +//rep(256, i) output '=' +output '\n' +SHL_BIT_NUM = 0x5e3091155e7701d4b95e0bdd81e6158bb99d9153530facdd5a6633f23432093875702d2373830ebf73b4f354b080b2fa49a78d5c92ca7ba914117cc4b84fa48d65b2dd3e9cedc68ee6cf1c9101016e6515e01a94d46c39e76688933a80ffd6afeeaf38ee9a426d10d8ecd455dd59ffbe893cbb63078454c86d026aa6dd7d7c35b7a1ed05b4245dc3e503f231ae4fcc2c334d71817cae7ae17943bf12dbcfa4e7a6ca7e85902a8d3da9a816eb1d537e2161d6c1e87ba84bbe7ea11cf0d32c1f5ecc9d999ac47fb40fe59b9de0c10936408e2319d0c881f75c0c7356cd314599fa31b18f24edbb78d756bbeca7b9d113ca6982a0fb71a7bf0eb42bfc56cb3803b3c7d2cea06b4589d6410ade42771340c6d040cfd709f06d0f97536ebc071ea51319dde179407e6d3985a374009ffbb2b5bb1cd887da84dc9c7cf572eef4168f14b8e95a1e42c22aac01c085839f284391e6801d0c29cf9d6190349342d1cd9a33ee32245a52c83ed6ecea02d1d77c3637636d17c288cf79b431e81fe194da167823ca0670f5bea6088d4a6fe36000e4785ef68ad7572d30ae73dddb5725e946fc2161984e0748f157c595e4d263ba2d19d5a0a1e21051da1989cf22397a86ca5698c5710d39ec25baba0613c1a7a49a787261180fd5c3a452a55bd1adde08b50291a318c8eb61a2caecbcb4d8c252d2c70841ec3ee8d6f442ef4e02b4e440f5674f119d300737073ff8a99264010e2a8aba87d45d3f9502b076eb5dc8c7b2f793dca5c4c47e91550684e5cab2998283ba6a3c455fe37c32a5c3e4c3de176cdcbcb8f3cd068aa2d5b6ef949e4a16012184696d08e706cb6f77503b9a7adb708d16ce41daa9b9ea92dc2f98b78272470ddea3a36f838cc94531657ffecbb119088111d6f21384b4ac5af09a0dd5cc808f3d4b88bceff73cab106132c03d84542c3962f07b4965cfc8e1f5ce104946648cbfc5436d167af49c3a7c0b1717d1b5001b80049d59f7c714587d706c04dd687d4a74d665a8b1c98aaace93c978759d0204047d4a4662b60840b8f8c1b2a8db9ab663470545f7ac067489e3db368dd3e62c6dfecd1a0b5b0b646e62b68e68247b696a48e806413d35d1d59994c9b049e2b8 +rep(100, i) test_shl_bit 16, (SHL_BIT_NUM>>(64*i))&((1<<64)-1) +//rep(100, i) output '=' +output "\n\n" + + +// shr_bit +output "shr_bit:\n" +rep(256, i) test_shr_bit 2, i +//rep(256, i) output '=' +output '\n' +SHR_BIT_NUM = 0x7324285bae8ff63ac38c8717f943525011bc19efb9a7adda6c57a717ff701335b31cbc14d0f819e7e591667bd025064426e681c47b039e29ea7dcb67b7d8206ff075d7afd314bc6d6a3dbb19a0b277d00491e438f2a59fa871f2f77e96f047b7b4ecce08a9f721b7e48dc089ef42234d740ce852b64048c0a44c82b03223bf3c9f037c0c15026b8b2157944636505828df8215593ad5d5707789d2b8d4499511d543c0e63ee1e20230546c57c54e1c29ecf6e88b917b401d679869721ca436b5f02eb0d2401bd6f8bc9258e4406a7c49798177cb1cf10aeaf32236a5833d4961aa93b1b9c652c4a33651d66300d88841dfa3c37c9d361633b2c08c41df520c57d8c6af23d5464aab0665eec43370a2324f200d02893d614c500b29e5e7135f4700573e4076f061ef2bb69307e26dc1c317493f99899e8ccf941572188fd797da83160538ea6cb298dc01b047b082dd74ebdfcfdbdb57c209f57a84a830d3dec13a68f9f5b1468ef3a6b1b89a08c6d696f2259dab9d958201b98eab5bcbd7f0ab20c6d5ff78db71ce96528b386671726b610f915d562e6e7aaaa1441b14e2c3e683a6f851a26f721498c45bbeb8a2642d1827505a3adf1bb2ff06410e270e5ef74366cd009a50bcbea3d123bd290303924469b9990009d9cf6e7594fcbf2fbcf055f1f30696a94ade45245ad47fd02c2f54e74faf22ce45709d851824f45ea1581f8981ed4bc06f8dfe5a7e5570d19852e09d486f59c8e027801c32eafdc04a5bff94fe2b7f08141acfa2f6d2f3a0ae6aab07b4d98ebdd95beb544cede407232f7421b45a0472ca9ed8c8c379223383900b765b1356d922e08fcc4ec7b4c79593ecf807d2da23672a472be451a829f4ea60c90ca81858021f52ce967f9090d4e074936d828754952e37c82000a311d79e4158c2c83cc54d5cabc0d44fd7e3b0d1d4d798577995677ddf571d10f506339eb8aecbce54ce032b77c842cf382b82433a35e1b151d22b2784db4a5af66db9b4af0127e8173fd486ea7ec8da30903b335bd2255134eb6656b6737cfe97fef7db1bc5e9427d44e037cc7eaacfeda93bc9f84b342971e5b3b71633d978ee92d38cbb6a1625dbf9156a146d9cbbda0dea7c +rep(100, i) test_shr_bit 16, (SHR_BIT_NUM>>(64*i))&((1<<64)-1) +//rep(100, i) output '=' +output "\n\n" + + +// shl_hex +output "shl_hex:\n" +rep(256, i) test_shl_hex 2, i +//rep(256, i) output '=' +output '\n' +SHL_HEX_NUM = 0x8f709d3be0bddec5f47a29c78ef3826f8720410088424fbb35e1db4e5741ef695493d5585259ff8ec0776881d06f813259ce23661f6cdd9278f226b195e45f57a4a1b7d90f4d1138d1ca6b3f0250d2133eba1306cf9206c42b6daa2daf2043ec5d29570feb16391b2f3b1735be54750cdeaaaae67a9e1614558eb37f4ebe1b0754c6b03abc75d9f30aecb5ce45a5982dd9ee989aed1bb14c5f8cd9f746a752cfff0ef87cfb6608a5af963db202549aad0eaa61ab6b580b5752effe88f960c219d45fa642195a0b9274704ff104a8fabfd59f6ecd72edd60e08b31020eedfbea19268e4a056457d28387857eab13013d9ef2c98de1e2622eeab9564a8d23edd4d1b86d8faaf99d46744362f57b85783c0d975d8cb3bd33c587ffaa5b3e764d311083ce8502ffae3248f799e8aac5827b5c9b2ca7b5897ec0179d2508e51fd6b5f5f0262096cc360d6e3d452cdce674f48e419f25060ddc28b40f29356bbf3c02f1035a9afe8ef217e9c92cf2b86a43098003f9a70b44c6e63ab064259c8816abca3ebb0d32af6124d948e12066337b94838b561582a380505379d324dc461a5146ee4e50fb4eb6fa09d9452c9b0131ae237f863ccb0c746fd4c8608a06b94f0f510463d7e507791679dbe3e1c5a98f7f362b2c157da3e470ff36c8dce1edba3039dd3605da5ac6be62d812e2fe3b6599aed7a4d029f7898a9b83a6a54fd4fb6735f114b27b644cc475cb07d5b8da31abc044db6e9d9e26736f330307f4f9d6b7e889dd48a5c5ec0c989c12a13603c9026c8be2492b01b6208a9e7309c3ed7ee134b4d3de36f43083b550d6c8d0abc9fecb111fc7a890a88aeb9baddde68a08bd915b161ed0f29eb55e93a1feb900eb5e9141dcc9f7de4e50a6894688fb427f67f302e820718f92888dbb21553bd8e0e2a97b40e2fdadf529767cdef0985e7891ddb7a6fae6568d7e5360e1ed4fda22dd67560c364e19fec11a40f6f96579c5fad9782f96118d1f4d79795e09bc30b64d83e5fb5843ff806468cc0db58baf863029c4637082e0a817ba24255b537cea5d8512064d9128c85b9409fda6211fd88833582a42f428d11f76f9fc9fc3e3ad89b5fedaf359a2bd8e9eca86644b3ad57b5 +rep(100, i) test_shl_hex 16, (SHL_HEX_NUM>>(64*i))&((1<<64)-1) +//rep(100, i) output '=' +output "\n\n" + + +// shr_hex +output "shr_hex:\n" +rep(256, i) test_shr_hex 2, i +//rep(256, i) output '=' +output '\n' +SHR_HEX_NUM = 0xcedd8a0a2bef4d7075011cd1a3f22bcb532755598562186d74c59705f1aebca79d4fd2a7962c01512a40c25f62c52cfe0c6ea07c3447ffbbd4146c7399ac497ed0d7789edb1316d6e16c20947891a2544301f2f7750cfdd04c5829221bf7a8f7cb2ca6a6bbdee078cb590a2d7ecd0c0523c9a558a4456994d2c9bb77849ede386e3b71c33c5b3b9c5d17f1ae11e8175471ae1b3903f4d1b8cfdd8ab86f952c946e6d19a7ba9a15bd29b6ece48321e6f0294674d8a24172ac14abd0a21fb829228333da3001ab60159b896112adee47cd26e919db289c05b59fd8deafc4dae3c12411d4b8f2e7d2ada861c2d527b2df7d9abbbd59f46f9f5516ddfb5065ea6dc4d6626d134f4dbbac19f707f07fdc3ceb6719a8bd6c53d5a7e5b016b7f47a0e45d0eab320ec82c11ad4aa9da78b2a60882247f034631ed4dbb3eebbe5ee096710b6cfb3182ffaa96db4c3f81d0d1c64bb399172b832ebef477e192d24c05fe6d641f2f662bea908bb8d7b8f7086915db542145569a614136f26e33657bdd85c477516f2027ee44c2e875df5d39733dd52f44274d61bfafde05010efb4025e0535213c0b48030f84ec88567c91ef44dde4753667ef3f323fd2ef04e2706d6ce953942f0ad12453e82038bd9c9c77ec0d294daad8ee83c594507872ef1f596460cac589374d2a56ceb89968d1d6ed48bf1fb0a24cc0a742e928c0339c71f8e08c446877ab4ba1aa23cbac8c42cd9185794077e6c4f33e39a55386b7f12ae35e172350f70320e588d88343811ef38a3e00399b524be5690672705bc8bc522e9d3150142e3e2ecc8834a9944238a562767d9be8634cf3ce5cdebb7d5f09fa932d3cc221d0878bfb0fb1e51cc9f2534fb024c75256c59c386c21ac4214aa134c4d1381eb02257abdf6557451403018402b22428c9c9e12720ae42569c5d08bf15d24d762160b4644e7ac024cd785a05e7d7f7ab217bc5b173aa1f7f4c6a188c7af5498b9c98475606235e1d7e3f9bb1d95622a6535145f4ded4208e59515746e0893ff43b8709f4a68926769ae434191be6d1c09c18c99862f0cae79457cdbbb869c2829d4ba4d4dba921b47226623c6e3604d754f46c78e95b08414f1ffb5e870fa4 +rep(100, i) test_shr_hex 16, (SHR_HEX_NUM>>(64*i))&((1<<64)-1) +//rep(100, i) output '=' +output "\n\n" + + +// add_count_bits +output "count_bits:\n" +rep(256, i) test_add_count_bits i&0xf, i>>4 +//rep(256, i) output '=' +output '\n' + +// count_bits +CB_NUM = 0x1f4a245bbcb588e8a76ec9f10c25fd21aac218d91e9d6a6bd7965a99ec604d6f9a662865e3c1fd319a75eea0390d3a50f52a60bfdd890f79db7ab0bedc2bab04268d47d95069f296a32a4ef00aed76feecf3260bf6dcf0004fd0cb68df5cc6ebbe0f5636b58665b148d0d8fb4ebd7e2a68efffaf782ebabc1a66d0991dc02ac46b5e25d40cec197b90a4eafc67976da0091f7cac5a58d10a36817702a59e1371f3f64f2298135574768c139833bce2e7b250e9984b65164efe9c77fa1c7b55069c96be65e256bdb6c6087d915c839157df4f67f5feef7483bad6697d7afdda6317290f68febf4701e926b81ea180e5db274d202379cb68b436872060e966afc4e886e8fa7f39f5d31656937c3a6c03ab39b6f99b47a9520c63a69b42f5f38ef0e669d2fe749aa478bd80f5a055f08bd4e930bb5b03f00a48bda48498f83e567cc0dbd585bd3ca29b81cb29ab37d2e9997c07da8353675afe26936c39ba45be43db24a8042b4655c9d4e68a4ae4dd331dd7d10aba78697ff647e7c7f04e5ef7bd8001c0f2eac3ea1f8913940b822026d0f3d44269d61f2a9814d5af4d72550a0c8449d257c6fbf418aaba244af95b4266cba3a57b142977f341f68db4534cc6d47d4ed534c1a07c4b069cd3c913f88471a670a53ef3ac9af50cb0d28739ce7b53abc1e9b5f57d079b58e3403293df0c343386a1358de67b8ebe1c3fc761d6fdd7144676ee4aace3f96c3157a5823609328f34a5b93ca3a7bdf978c725ff8552252b6507b77dd4e356137e8664d1a4eda46cb8abf02c5978e763ea8bc430368c81666a5f468f413d920da5b718ca73161a3d4a85f78668bdac3546b22626267a98d0b653ce275a066b2faa25697eb229ab39c6c1f6581aa8cb68c7d4d57256c54b154f8314d533e349710da4c8054cc5fa3218d0d58cf8624275b92b9f3102e199c376e5258b1332b957c2192cc5c325410b5894510bd5d4470233a97479a0398039c971f468b7cbe0e364f1bf2ebb4c0ddb540bfc80dc1dfc3983e6fb979cbf9bd5631f0e051ece545a3fceb4c8876a5b72b77606d44f73c80111701c790be1c240e843cccda50ed9313c0be528848fd065d80e77428a90c002986c558629426c +rep(100, i) test_count_bits_64 (CB_NUM>>(64*i))&((1<<64)-1) +//rep(100, i) output '=' +output "\n\n" + + +loop +hex.init + + +ah: hex.vec 1 +bh: hex.vec 2 +ch: hex.vec 2 +xh: hex.vec 16 +count: hex.vec 2 + + +ret: ;0 + +add_count_bits_2: + hex.add_count_bits 2, bh, ah + fret ret + +count_bits_64: + hex.count_bits 16, count, xh + fret ret + + +def test_add_count_bits dst, x @ lt, eq, gt, end < ah, bh, ch, add_count_bits_2, ret { + hex.set ah, x + hex.set 2, bh, dst + hex.set 2, ch, dst + ((x>>0)&1) + ((x>>1)&1) + ((x>>2)&1) + ((x>>3)&1) + fcall add_count_bits_2, ret + hex.cmp 2, bh, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + end: +} + +def test_count_bits_64 x @ lt, eq, gt, end < xh, count, ch, count_bits_64, ret { + hex.set 16, xh, x + hex.set 2, ch, ((x>>0)&1)+((x>>1)&1)+((x>>2)&1)+((x>>3)&1)+((x>>4)&1)+((x>>5)&1)+((x>>6)&1)+((x>>7)&1)+((x>>8)&1)+((x>>9)&1)+((x>>10)&1)+((x>>11)&1)+((x>>12)&1)+((x>>13)&1)+((x>>14)&1)+((x>>15)&1)+((x>>16)&1)+((x>>17)&1)+((x>>18)&1)+((x>>19)&1)+((x>>20)&1)+((x>>21)&1)+((x>>22)&1)+((x>>23)&1)+((x>>24)&1)+((x>>25)&1)+((x>>26)&1)+((x>>27)&1)+((x>>28)&1)+((x>>29)&1)+((x>>30)&1)+((x>>31)&1)+((x>>32)&1)+((x>>33)&1)+((x>>34)&1)+((x>>35)&1)+((x>>36)&1)+((x>>37)&1)+((x>>38)&1)+((x>>39)&1)+((x>>40)&1)+((x>>41)&1)+((x>>42)&1)+((x>>43)&1)+((x>>44)&1)+((x>>45)&1)+((x>>46)&1)+((x>>47)&1)+((x>>48)&1)+((x>>49)&1)+((x>>50)&1)+((x>>51)&1)+((x>>52)&1)+((x>>53)&1)+((x>>54)&1)+((x>>55)&1)+((x>>56)&1)+((x>>57)&1)+((x>>58)&1)+((x>>59)&1)+((x>>60)&1)+((x>>61)&1)+((x>>62)&1)+((x>>63)&1) + fcall count_bits_64, ret + hex.cmp 2, count, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + end: +} + + +def test_shl_bit n, x @ lt, eq, gt, xh, ch, end { + hex.shl_bit n, xh + hex.cmp n, xh, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + xh: hex.vec n, x + ch: hex.vec n, (x<<1)&((1<<(4*n))-1) + end: +} + +def test_shr_bit n, x @ lt, eq, gt, xh, ch, end { + hex.shr_bit n, xh + hex.cmp n, xh, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + xh: hex.vec n, x + ch: hex.vec n, (x>>1)&((1<<(4*n))-1) + end: +} + +def test_shl_hex n, x @ lt, eq, gt, xh, ch, end { + hex.shl_hex n, xh + hex.cmp n, xh, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + xh: hex.vec n, x + ch: hex.vec n, (x<<4)&((1<<(4*n))-1) + end: +} + +def test_shr_hex n, x @ lt, eq, gt, xh, ch, end { + hex.shr_hex n, xh + hex.cmp n, xh, ch, lt, eq, gt + + lt: + output '<' + ;end + eq: + output '=' + ;end + gt: + output '>' + ;end + + xh: hex.vec n, x + ch: hex.vec n, (x>>4)&((1<<(4*n))-1) + end: +} diff --git a/flipjump/src/tests/hexlib-mul-div.fj b/flipjump/src/tests/hexlib-mul-div.fj new file mode 100644 index 0000000..c6ab366 --- /dev/null +++ b/flipjump/src/tests/hexlib-mul-div.fj @@ -0,0 +1,285 @@ +start: +startup + + +// mul +output "mul:\n" +ADD_MUL_NUM = 0x3787e7d8c45c5eefb8a2cdd909a9e73210d24441f7c8b13aad24166b69780a672ee724faecddc0fbf42163dd4ba0104c191fcbf934fb8b710e1653d28cf6ef0ade0ecc43805d14a15be12649efc47eb45f46906eeaae3b0660c4b978654076f20fcfbbbfb66e660668d4b10fa5584bd2c8743f9a39cdf8634a09a386c755f8deae1b1b560eaf4e07ce39f30c82a59d7d3112077516d1 +//rep(100, i) test_add_mul (ADD_MUL_NUM>>(3*4*i+8))&0xf, (ADD_MUL_NUM>>(3*4*i+4))&0xf, (ADD_MUL_NUM>>(3*4*i))&0xf +rep(100, i) output '=' +output '\n' +ADD_MUL_64_NUM = 0xf746c656ec44a883061102a194002cb7f236b436cfd35f291c4e52287d93571f2109d73d25af5f85769e7ab1c1a02ce27b9be8b6577c418a420ca8e10d1ce21eee41a8b0f3f47e1a71a776502d7b0dc8c105b9f577a02afe857fb0235be08f7b4f229c8a382e0f77f025ed9e8eb0fe20e855429737cc9a9586da81814bacadb911967eec2bbc1a1ae3f4c36f88b083c78b1aefd8ec266e2a29579cd1c4a7c505cd8a2532f95580bd810c82aac45cbbbd114639f8b1cc5df54508b9a633ef785589802d083e451e319abe491abd60f51242281d5273ac80272756797db773877bae6bce7f66b835bf8791895d4f730c5a3161eb7703e212b4294ae4acb955883e28de343c314d8884a4e2150c9ec61c907dcb3d93b02e3abed11b82847c854243dc6268ed83fd1e79cd53dd98a5a13f4444f7f9255c21e1e44c8d32b447f7de23df0026601ea1f96caf696434a17f2970b39c044e926e4bf5de735f80f4d4d193520beee647d560031bd114a604040ea9c9ec783abf87812e0fa17555ab43e05806fbcaa5634a3f29cc05d4f41ba0959d779ee6a2b94392dbdade04b7709570f59f3dadf915823175a4fd801b412cbe8842e3b5a52f68733746038df31e3a0afec93a5c581f1e92cbb1d3f0c4d5819dc9724d5dd2e1fdb68b419db2d9f4dcaedf0817f866b6a57e6c7b06ac3698952fa843e8a0cab0275d0e13e5f578a562491689ac73d38b30da550bcdebf02acf8f4a0c5eed955337336e1e0029c79092b4309eda7ddb16d043ac6aa8a5a9a3a228c3b908ad14cf2a60d1a5323e9d68f5efbae7c43a362be57f8634887a5b8ede3e72527e06fd20ed39f97f666a7c2933df4617176902453181bc5edec13ca451ee74d4f434c8dd01e9f4a11ad2f1944dd63b74c648305ebc95e25b03789b8725132621d2d001fd079c0d1ed9b2044c8e3f52fa65566edbc726f0791b49a7117078955c925889294845a2b7c793f68e7e833593c2f60cf59f2b4a634733b392e7170a70853b4d6c398c107da1ce5613a03361142d7c213972cab3a92631c034cc2c620fb74286100736617003311b12c5792c60f8d5f9a58940acd42f8c541be45631f7fc70f9a23a0ca8c3adb1443fc035588709bbc83297f6a368788e6328d4f085bb0b301e11da115ac24523f8232cf2b91fb8d78d3b98f9453cbff751f6148b7de63198648de8c7857fa98853d53f11138c4d327a6a53c2cf6c1554c7005e3ad52aed8eeb4bd0cd2af9b3770313a4d12c350eaa2cff67cc2951f4064fcf54ba3f5fa9c2e45543a64a591a34199f2ed80ca59446860fca6fa6335cf01c7c9cc5d719eb45bdf771007e5a5f34d4e7aecbf682d8f70a1f2658580cbc0bb1edd6b8c7098447d1d0e0e1c1ef53523c8722f9a78d9fdea511ebc935e518a0c40dced8f165ef96ad6ac1f2046152ea1932a70a10d3789eef64ded47da94d3726e9616564e522aaa16182af62807c7c97de481b3fe374d7183b9823b74412f0e4a312e6f5d3bac6d315caf52ab41a026234d04d3d190576b8ddf3c76287479141e019ccdda140c36d5bacfcc8273c5993f8527587a3ff624be4ee4a271948470cb797231aa104bb790074cff31761f016bc6946838d4c9d312c920a69c2d5885d25ff237dfbc9a31cf41b75c681ad0348d37cf9e820442da8e1ba2a32bca08bc1deb388164579d99eda40faeac64ede15ed8dfe225183fe03f5ed518d459fd1d6fe6262b385962af779013bbff4bc20307cca4045ef760246a2d5b9cc9b788ded073172e7875dd6a6217043f503b42e97250a1aa5d44433f253752e1c2b1d338bc1c2ec42d2f62a12896ba28d08ecd1a67c7902c354d8c2f39f28f96fadc93e4fff2859cc241d60245b8fd3242e705d0c81d7e11124f1df87ff57c9017899abab7ac3a5bf65830b160d9555ab3d44dc38d427bce2fbcb457c5a836186de2920ac6b2cb1066e51c37e8c839be63fa49430d76a7282b957a200aff5e7cd5fd79546236be19455f7b16f43fdd672b1c65e2851c44232fce9b18ce2dd9eb6fd6d88bb03750dad2d2a7ad3ac4c39db10c4f1a8c385551269de99b53cdf04cd24f2077ee7a5e21615e38e90eab0ea2e66cc6ad52965157a7f0f4274f47ce81f3c68647c1142518e9264b7a175ffe5adbe1e02413049a3d4447ad08f28dcf67b3cd5850e709f67f6f82ea071f3a04c959d5c25f7bd5f1d7c3f1cb9cea9688af1550dbea94c9f6694137cdc7c4bcb79cdcd7f3b98f4d8c32d2a080dd2b124e2436c7ff70337e207c6916ef61b1592a4c30b5bafd2b52c996cbb691792059c63047c829e581b575b7162f7b749217733e57831f17d3ecee9301b5a7d6f399c28c946b070771f5250df01b962071380a32ef8156c624171eba854078c963fa87cd051c67e68709bf9cbf2f4513b89ddc36a062e00a3862732da4e5f385fb9dc978f377adeec1e4598dfd980423d55819bef8b319aa0198eb7a9343d2e3e92309bd1ea1757c074c3457a09897bc11c045842b1e0593d276cc4b0a000c89faa510462e441a0c9acd4e650672be2de11112264b306c4e3eee63573da11922c365a8b7d75f0b8addbbad956d452449123c90d24a773ff4d187f18f75bbd85b04a6c6473d044d7dd589c8dd3a220d757388143cbbd9542d3063a682e68898fb5935c915de056a156d34d198923a948f0838aa678a948b04e0e2c10193fe9348f184cad5d98c3e21461943fdf6c7ca406c6384c4dd0b1ed557b05425ffa1e5ff79411cccbdbc605ceda4b4ba6c118349a5a0013d05b2ca2f9e78565dced2be96650258cc700960f713977db16bf106b150fb775519d08f608fab92306c6b170554f47d6f42bf1f8486f9d31684493771b3aa6d43038f790352728383b65e6f9999a2b813f181b4d320005611988683b79aa0b916cca71259632c5678678ef2815ee04daa6de497a75bbbde002fe52cc688f7d5a528214699a63775544ecf7d8460f63ef6850906adac1d4453d088eb56549a36ad96fe6d3dd125821f868fd7773391f5b47b579040663b3a3627128c589ef07daf7052f0b7119bf9c773758693456885bf25523489cb94f6edefe6f303ca68aa1b71d856a5a23b949b89db4051e3d0e819d5413649ac57707450a9c6b1c552b7086d0d97e7a6afc78ef7567d2afe8181827233dd39ed739b6ac300dd4a782f6b38d3a627586fa6d4029d4ef3bee4de0d96529c44c49558c4f2f26bd1784fca4f9c1e58654b6d5246c63e803f80e25d7f8a1888e44c6682f5c468ce155d03ee97901262893db516213e95666e5de5c98193dc773aa18b003797b1a63ea5076308153eb88f5544d46d4c99d928e7256f517b4fa3625912f3ea82f09d3cd625f0426bef9237334d1955714 +//rep(100, i) test_add_mul_64 (ADD_MUL_64_NUM>>((3*i+2)*64))&0xf, (ADD_MUL_64_NUM>>((3*i+1)*64))&0xf, (ADD_MUL_64_NUM>>((3*i)*64))&0xf +rep(100, i) output '=' +output '\n' +MUL_NUM = 0xeff9afd3e398b0d9480e36c3d14cd6289b2042fa927030786e10e3078377a5e6c06b831c58e89ff13510f0f76f49bb44a8894cf670e676320ad8cec17d41b2763e28bd1c86d45633dedb228e1ce35c5000886f24c35cf8dc58a13818ca057c40e0471c46792b0f3cd9754e0a5d6cf4257d70f75835a56d75d8d6be13e0388f0f3e7f0efe0b6dfff1bde6e74b2f9097544b212fd77e0ea23486d9b37688dc518bd958302327d450e980ff6bf8c330250d4d38a56aa8d447add3ba947d8b50372efbfe0b688f1e693b02f667ae7dd7d3dc7ccbd78d1b170b361f80b2cd702750496de21c98ef8282cf27e014e22d236001ea346ccac2fd760d619c0c86bf2ce55509a780c7fce9bb5d87770724eb43e471989724c7aff112eec5dd184b20467942e8f78b51ff652ff216ba1efd0e0a42eece85864202c6f604ce898fbca66b5e989309b5c30a424a878c8f7a826f6ae8e50df64b548c086fbcc829178ab9440718be0a3c367631f19d933e2dfe966d35f58098bf4bcec254d48de67822157bf2ec93e98841172701565fc1e01e02d3bda981b22ede8f3068fd01085504f5b538727d88b72eecca5c479ac1454f73973457302720b1a8ff05c67b744e93432833839be8f4ebe558a703aa654e69e23581168f80f49de3f7713d4895f88ae593f1000f4e287efb383f4e1dba1ffde820edabf8589059d9b297290cc3a1e4d3cbc548e95a36808dd8113d25edf03e1e59abcd5c69e5ab14e5bc542061f04d69178ea7fd74e5208dd0e1fa1d3990097f8c50b6f16910008b72979c6068b5bf538fd4338cf50cd3cebf09f6fe42e2177700c7379dae6339c7347808c7ce44dabb5ab6c60dec9e7b37b88f01117dc3b40f5f1923fc5fc41b47a9614cc37dca81c1e5964271047ea0c2468b11e3653051ba153f2802b6441d8f9f5d4e07dcdf1dfc49d83a02a4b3ad0bcb55f62c4d825759509336e5ae2503a350eec5641f210681d76a4552e1ae32cf8dd1e2c1dd000f713a6ad98996528a9b21858623561004ecd77965e03665c0de5a3027d39a856796b3591d07bc3bf87ab126ef7d3a1080d8aafce1d28adc9bda23efa7c05915f4b8629dd1558f89d7f771d8f5589bd8e8193e0a5e +//rep(60, i) test_mul 4, mul4, (MUL_NUM>>(32*i))&((1<<16)-1), (MUL_NUM>>(32*i+16))&((1<<16)-1) +//rep(40, i) test_mul 8, mul8, (MUL_NUM>>(64*i))&((1<<32)-1), (MUL_NUM>>(64*i+32))&((1<<32)-1) +rep(100, i) output '=' +output "\n\n" + + +// TODO - test div +output "div:\n" + DIV_NUM = 0x2d37afdff3a29957b1600de68e1476244bb61d73c5233a86e48eb76cfcc5b96eb3b9f64728ae12f8b5694c6718ea7d241ae989003a098a80219fbb1290fa0d866a73564dfcbb62cbe1b91d1c96a0ba40f2b2577c0ca72c2a47b76e3596b67a2363de94a25a9dc66c44406fa8309fff20d5293fa9979d10644a6b3e4dd931970960a950ec082c22f5bfe37ce46d15420bc267bf3b99d34f2aa97cf4b32dd2d2684197f512168ddcd25128f6c7596434bd5bcbe4b389fe0c68b558d2ec17ccadceeb14c34fbd43d8134cefdd6e4b71a01e8815dd0407fa3016f5fb5ff7eca134d31b10fffceb498ff95868d70073ce41a6022eb7b985e8572754254e3f2687e75665266a4a02ced3746af81ef8f22da69914cc88f15c99716573520ce26f5562098eba7edc126a9921dbc0be9e964ae1c467fc9fca732c611cfde1c69dbc09114c34f244c919b8210d7b81e442f5a3281b88e3a212b9fdc5519dcacd972f759e8b6852893d12c5189d43394566284da3c2028eebefc54de104fe93c8a1c5dad73f6475a5f4d06aee2a19135d765bba7f6b3c193c4e7f372e306730ee36afffd2a65fd4b2ee54a4f8e02a3d799fe3ed063af2a4a560c67f7ea375988f42017761ad4e9558b980b4f688dea3927220710ec2a84f1e4aea64d6c48ce28a5b586aea03ed6651d05342b45b97cdfa8c94f9666fc44d05768506f81a926db02a2d803db1f3220433fb68afcba4e0370d110a9357d63164e5209e8286112190f0ce8e1622db3dcdcd332d544ff6f0b1af94ee0cc748cc74232d2ec310ac06ec8a4fceccc08ea9134904060a7b139ee46a679451379066e57bb72cc1e47ec34c3b741f2bd88c07632ad5c2b78a61703eb2d36f134eb9da5e8cbd1231f3233c075ab1f532a66ce50e09ba83ef8b3da5709daa80995dd7fc1a3d6fa4e1d5f3b1fd0cc04e416bf7f054483d9b4a25151b055ee829d52e4f70ec8b3e47320c0fb710280a8c8e2fb3a632c6f3911086c03091823317dd10bd218558b9139b0a2ad1ae75e50af9a666c4bf81557c173ab8a63877694c184d04ed78a925c430a8e0914062ce16ed80f53f09384f637f5769eb3f468b9e894a413eb634760171b84e7a161240b36512 +DIV_B1_NUM = 0xa67d738774eae443169a4a82e86cf9a4b11bbe95147f43b51db9845c8f435cc5491faa6ee3a48591824833862496342dead6 +DIV_B2_NUM = 0x6e287f9d6d301a1d335442d41a1aed5cd0c66a3f69321d412d7b2ad5b09de6c0fb101010c955ce7e30bac0bfe684638ed24f4582ec2b69e7c84f4b092a81752f13cc9b6ca561add4f38bc59b552cbf7a4f423987ee8b4451169fc013c316595ed102 +DIV_B4_NUM = 0x35693c547f39bb78985939825165f49cd015a98a814eda69bd762e66e44f4f44915bc2df73f3a9a41ba3b82ea2d62a85ed4b9be039927eebfe932c86780fa3fa06477bec7b21a6ba527704eda18333a1da94a4dee4ab0865ba05e5bc78b11612b10f66b6128ea96ec120fc12ed6c64b1fc78387147e286347de4352f800e14b48be2acdbf0e1ee6153bcd5da831b5f975d693ffe911114a5a7a16867c87d55ecb6135e9fc0cff7683c99c66d970cf1b93d68a95f843714c809b6d131c9392cf79988461cd +DIV_B8_NUM = 0x70b06b1281c825b68a90ebb74db2e604b7af1091374ea71f9700d06c69cc9f4528e0ce8cb927b9a6c38191bfe3ba2a7a846ab232a6f1bed5cce422495ffd7293d95bcdb3cca6b36912fe1ef9280de585b5b43dfffcf6a6e2e8589a9247bc9a61da78c73dc9f7720e2a5139dcb2d5294a9b816a90cfcac7688bf64f7e0e5e7f81bbf1eb9618da9d74e192e5796b2fff35b2f08fcb69522a01af6a7f4a1466719c9eb0650bc61294a7331a18952b59d9b6f7d1c68bd30962fed55cf6e396610666ab80f1404e9c6695721a69d5e9a3d60b9b0ec0e38d0663006f03e1a2cac891db7b749179001ee03f23999a53f6d3f5c00665a8e64e565ba972dab0d7ca848e56c7722707204421e8f622de3d3ec901dc3f510f7f43c5da7b364521da3e1ece71de150a8c5483c5ba0ddbb4cd31e3376145673113bd4c500a4838367dcb5955b5b0f377e0574fd6d668849b2c5944e5bc6ae6c23776be9cd85fdad7dd60ebed860daec0ab316b6e704c944548b1e48a3c9dfb8437cdf48184ca18c847e4abe2b19381ce80323483280ccd7ca2e +rep(50, i) test_div 4, 1, div4_1, (DIV_NUM>>(16*i+0))&((1<<16)-1), (DIV_B1_NUM>>( 4*i))&((1<< 4)-1) +output '\n' +rep(30, i) test_div 4, 2, div4_2, (DIV_NUM>>(16*i+1))&((1<<16)-1), (DIV_B2_NUM>>( 8*i))&((1<< 8)-1) +output '\n' +rep(20, i) test_div 4, 4, div4_4, (DIV_NUM>>(16*i+2))&((1<<16)-1), (DIV_B4_NUM>>(16*i))&((1<<16)-1) +//rep(100, i) output '=' +output "\n\n" +rep(40, i) test_div 8, 1, div8_1, (DIV_NUM>>(64*i+3))&((1<<32)-1), (DIV_B1_NUM>>( 4*i + 50* 4))&((1<< 4)-1) +output '\n' +rep(30, i) test_div 8, 2, div8_2, (DIV_NUM>>(64*i+4))&((1<<32)-1), (DIV_B2_NUM>>( 8*i + 50* 8))&((1<< 8)-1) +output '\n' +rep(20, i) test_div 8, 4, div8_4, (DIV_NUM>>(64*i+5))&((1<<32)-1), (DIV_B4_NUM>>(16*i + 50*16))&((1<<16)-1) +output '\n' +rep(10, i) test_div 8, 8, div8_8, (DIV_NUM>>(64*i+6))&((1<<32)-1), (DIV_B8_NUM>>(32*i + 50*32))&((1<<32)-1) +//rep(100, i) output '=' +output "\n\n" + + +loop +hex.init + + +ah: hex.vec 16 +bh: hex.vec 16 +res: hex.vec 16 +ch: hex.vec 16 +mod: hex.vec 16 +mh: hex.vec 16 + + +ret: ;0 + +zero_all_4: + hex.zero 16, ah + hex.zero 16, bh + hex.zero 16, ch + hex.zero 16, res + fret ret + +mul4: + hex.mul 4, res, ah, bh + fret ret + +mul8: + hex.mul 8, res, ah, bh + fret ret + +add_mul: + hex.mul.clear_carry + hex.xor hex.mul.dst, bh + hex.add_mul res, ah + hex.xor hex.mul.dst, bh + hex.mul.clear_carry + fret ret + +add_mul_64: + hex.add_mul 16, res, ah, bh + fret ret + +lt_print: + output '\n' + hex.print_uint 16, ah, 1, 0 + output '*' + hex.print_uint 16, bh, 1, 0 + output '=' + hex.print_uint 16, res, 1, 0 + output '<' + hex.print_uint 16, ch, 1, 0 + output '\n' + fret ret + +gt_print: + output '\n' + hex.print_uint 16, ah, 1, 0 + output '*' + hex.print_uint 16, bh, 1, 0 + output '=' + hex.print_uint 16, res, 1, 0 + output '>' + hex.print_uint 16, ch, 1, 0 + output '\n' + fret ret + +add_mul_lt_print: + output '\n' + output "old_res+" + hex.print_uint 16, ah, 1, 0 + output '*' + hex.print_uint 16, bh, 1, 0 + output '=' + hex.print_uint 16, res, 1, 0 + output '<' + hex.print_uint 16, ch, 1, 0 + output '\n' + fret ret + +add_mul_gt_print: + output '\n' + output "old_res+" + hex.print_uint 16, ah, 1, 0 + output '*' + hex.print_uint 16, bh, 1, 0 + output '=' + hex.print_uint 16, res, 1, 0 + output '>' + hex.print_uint 16, ch, 1, 0 + output '\n' + fret ret + +div4_1: + hex.div 4, 1, res, mod, ah, bh, div0 + fret ret + +div4_2: + hex.div 4, 2, res, mod, ah, bh, div0 + fret ret + +div4_4: + hex.div 4, 4, res, mod, ah, bh, div0 + fret ret + +div8_1: + hex.div 8, 1, res, mod, ah, bh, div0 + fret ret + +div8_2: + hex.div 8, 2, res, mod, ah, bh, div0 + fret ret + +div8_4: + hex.div 8, 4, res, mod, ah, bh, div0 + fret ret + +div8_8: + hex.div 8, 8, res, mod, ah, bh, div0 + fret ret + +div0: + output "0" + fret ret + +neq_div_print: + output '\n' + hex.print_uint 16, ah, 1, 0 + output " / " + hex.print_uint 16, bh, 1, 0 + output " = " + hex.print_uint 16, res, 1, 0 + output " != " + hex.print_uint 16, ch, 1, 0 + output '\n' + fret ret + +neq_mod_print: + output '\n' + hex.print_uint 16, ah, 1, 0 + output " % " + hex.print_uint 16, bh, 1, 0 + output " = " + hex.print_uint 16, mod, 1, 0 + output " != " + hex.print_uint 16, mh, 1, 0 + output '\n' + fret ret + + +def test_add_mul r, a, b @ lt, eq, gt, end < ah, bh, res, ch, ret, add_mul_lt_print, add_mul_gt_print, add_mul { + hex.set ah, a + hex.set bh, b + hex.set res, r + hex.set ch, (r+a*b)&0xf + fcall add_mul, ret + hex.cmp res, ch, lt, eq, gt + + lt: + fcall add_mul_lt_print, ret + ;end + eq: + output '=' + ;end + gt: + fcall add_mul_gt_print, ret + ;end + end: +} + +def test_add_mul_64 r, a, b @ lt, eq, gt, end < ah, bh, res, ch, ret, add_mul_lt_print, add_mul_gt_print, add_mul_64, zero_all_4 { + fcall zero_all_4, ret + hex.xor_by 16, ah, a + hex.xor_by 16, bh, b + hex.xor_by 16, res, r + hex.xor_by 16, ch, (r+a*b)&((1<<64)-1) + fcall add_mul_64, ret + hex.cmp 16, res, ch, lt, eq, gt + + lt: + fcall add_mul_lt_print, ret + ;end + eq: + output '=' + ;end + gt: + fcall add_mul_gt_print, ret + ;end + end: +} + +def test_mul n, mul_label, a, b @ lt, eq, gt, end < ah, bh, res, ch, ret, lt_print, gt_print { + hex.set n, ah, a + hex.set n, bh, b + hex.set n, ch, (a*b)&((1<<(4*n))-1) + fcall mul_label, ret + hex.cmp n, res, ch, lt, eq, gt + + lt: + fcall lt_print, ret + ;end + eq: + output '=' + ;end + gt: + fcall gt_print, ret + ;end + end: +} + + +def test_div n, nb, div_label, a, b @ neq_div, eq_div, cmp_mod, neq_mod, eq_mod, end < ah, bh, res, ch, mod, mh, ret, neq_div_print, neq_mod_print { + hex.set n, ah, a + hex.zero nb, bh + fcall div_label, ret + hex.set nb, bh, b + hex.set n, ch, (a/b)&((1<<(4*n ))-1) + hex.set nb, mh, (a%b)&((1<<(4*nb))-1) + fcall div_label, ret + + hex.cmp n, res, ch, neq_div, eq_div, neq_div + + neq_div: + fcall neq_div_print, ret + ;cmp_mod + eq_div: + output '=' + ;cmp_mod + + cmp_mod: + hex.cmp nb, mod, mh, neq_mod, eq_mod, neq_mod + + neq_mod: + fcall neq_mod_print, ret + ;end + eq_mod: + output '=' + ;end + + end: +} diff --git a/flipjump/src/tests/hexprint.fj b/flipjump/src/tests/hexprint.fj new file mode 100644 index 0000000..911532f --- /dev/null +++ b/flipjump/src/tests/hexprint.fj @@ -0,0 +1,12 @@ + startup + bit.add 4, a, b + bit.hex2ascii c, a + bit.print c + loop + + a: + bit.vec 4, 0x5 + b: + bit.vec 4, 0x7 + c: + bit.vec 8 diff --git a/flipjump/src/tests/mathbit.fj b/flipjump/src/tests/mathbit.fj new file mode 100644 index 0000000..8b0ee1c --- /dev/null +++ b/flipjump/src/tests/mathbit.fj @@ -0,0 +1,8 @@ + startup + bit.inc1 x, carry + loop + + x: + bit 0 + carry: + bit 1 diff --git a/flipjump/src/tests/mathvec.fj b/flipjump/src/tests/mathvec.fj new file mode 100644 index 0000000..3f56b76 --- /dev/null +++ b/flipjump/src/tests/mathvec.fj @@ -0,0 +1,6 @@ + startup + bit.inc 2, x + loop + + x: + bit.vec 2, 0 diff --git a/flipjump/src/tests/nadd.fj b/flipjump/src/tests/nadd.fj new file mode 100644 index 0000000..6719463 --- /dev/null +++ b/flipjump/src/tests/nadd.fj @@ -0,0 +1,9 @@ + startup + bit.add 8, a, b + bit.print a + loop + + a: + bit.vec 8, '5' + b: + bit.vec 8, 0x02 diff --git a/flipjump/src/tests/ncat.fj b/flipjump/src/tests/ncat.fj new file mode 100644 index 0000000..1ce46ad --- /dev/null +++ b/flipjump/src/tests/ncat.fj @@ -0,0 +1,20 @@ +startup +start: + bit.input ascii + bit.if0 8, ascii, end + bit.cmp 8, ascii, nl, final_check, end, final_check + final_check: + bit.cmp 8, ascii, cr, print, end, print +print: + bit.not 8, ascii + bit.print ascii + ;start +end: + loop + +ascii: + bit.vec 8 +nl: + bit.vec 8, '\n' +cr: + bit.vec 8, '\r' diff --git a/flipjump/src/tests/ncmp.fj b/flipjump/src/tests/ncmp.fj new file mode 100644 index 0000000..ca73c2c --- /dev/null +++ b/flipjump/src/tests/ncmp.fj @@ -0,0 +1,18 @@ +startup 0, 0 +n=4 +bit.cmp n, a, b, lt, eq, gt + +lt: + output '<' + loop +eq: + output '=' + loop +gt: + output '>' + loop + + a: + bit.vec n, 3 + b: + bit.vec n, 1 diff --git a/flipjump/src/tests/not.fj b/flipjump/src/tests/not.fj new file mode 100644 index 0000000..c855c8c --- /dev/null +++ b/flipjump/src/tests/not.fj @@ -0,0 +1,6 @@ + startup + bit.not x + loop + + x: + bit 0 diff --git a/flipjump/src/tests/pair_ns.fj b/flipjump/src/tests/pair_ns.fj new file mode 100644 index 0000000..9a0cbda --- /dev/null +++ b/flipjump/src/tests/pair_ns.fj @@ -0,0 +1,125 @@ +ns Pair { + first = 0 + len = w + second = .len*dw + size = .len * 2 + + def init this { + bit.zero .len, this+.first + bit.zero .len, this+.second + } + + def add_first this, val { + ._.add this+.first, val + } + + def add_second this, val { + ._.add this+.second, val + } + + def add this, src { + .add_first this, src+.first + .add_second this, src+.second + } + + def print this { + output '(' + ._.print_hex_int this+.first + output ',' + output ' ' + ._.print_hex_int this+.second + output ')' + } + + def init { + ._.init + } + + ns _ { + def add dst, src < .add, .ret_reg, .temp1, .temp2 { + bit.xor ..len, .temp2, src + bit.xor_zero ..len, .temp1, dst + fcall .add, .ret_reg + bit.xor_zero ..len, dst, .temp1 + bit.zero ..len, .temp2 + } + + + def print_hex_int val < .print_hex_int, .ret_reg, .temp1 { + bit.xor ..len, .temp1, val + fcall .print_hex_int, .ret_reg + bit.xor ..len, .temp1, val + } + + def init @ data_end > add, print_hex_int, ret_reg, temp1, temp2 { + ;data_end + + add: + bit.add ..len, .temp1, .temp2 + fret .ret_reg + + print_hex_int: + bit.print_hex_int ..len, .temp1, 1 + fret .ret_reg + + ret_reg: bit 0 + temp1: bit.vec ..len, 0 + temp2: bit.vec ..len, 0 + + data_end: + } + + } + + def swap this { + bit.swap .len, this+.first, this+.second + } + + ns prints { + def print_two p1, p2 { + ..print p1 + output ',' + output ' ' + output ' ' + ..print p2 + output '\n' + } + } +} + +startup + +Pair.init + +Pair.init p1 +Pair.init p2 + +Pair.prints.print_two p1, p2 + +Pair.add_first p1, v08 +Pair.add_second p1, v02 +Pair.prints.print_two p1, p2 + +Pair.add_first p2, vAB +.Pair.add_second p2, vCC +Pair.prints.print_two p1, p2 + +Pair.add p1, p2 +Pair.prints.print_two p1, p2 + +.Pair.add p2, p1 +Pair.prints.print_two p1, p2 + +Pair.swap p1 +Pair.print p1 +output '\n' + +loop + +p1: bit.vec Pair.size +p2: bit.vec Pair.size + +v08: .bit.vec w, 0x08 +v02: bit.vec w, 0x02 +vAB: .bit.vec w, 0xAB +vCC: bit.vec w, 0xCC diff --git a/flipjump/src/tests/print_as_digit.fj b/flipjump/src/tests/print_as_digit.fj new file mode 100644 index 0000000..25ec9ac --- /dev/null +++ b/flipjump/src/tests/print_as_digit.fj @@ -0,0 +1,16 @@ +startup + +bit.print_as_digit b0 +bit.print_as_digit b1 +output '\n' + +rep(16, i) hex.print_as_digit h+i*dw, 0 +output '\n' +rep(16, i) hex.print_as_digit h+i*dw, 1 +output '\n' + +loop + +b0: bit 0 +b1: bit 1 +h: rep(16, i) hex i diff --git a/flipjump/src/tests/print_dec.fj b/flipjump/src/tests/print_dec.fj new file mode 100644 index 0000000..5549389 --- /dev/null +++ b/flipjump/src/tests/print_dec.fj @@ -0,0 +1,23 @@ +startup + +print_int v1 +print_int v2 +print_int v3 +loop + + +v1: bit.vec w, 123456 +v2: bit.vec w, 0 +v3: bit.vec w, 0-123456 +ret_reg: 0;0 + +def print_int v < ret_reg, val, print_int { + bit.mov w, val, v + fcall print_int, ret_reg +} + +print_int: + bit.print_dec_int w, val + output '\n' + fret ret_reg + val: bit.vec w diff --git a/flipjump/src/tests/print_hex_int.fj b/flipjump/src/tests/print_hex_int.fj new file mode 100644 index 0000000..8e1bfd7 --- /dev/null +++ b/flipjump/src/tests/print_hex_int.fj @@ -0,0 +1,7 @@ + startup + + bit.print_hex_int w, a, 1 + loop + + a: + bit.vec w, 0-0xabcdef diff --git a/flipjump/src/tests/ptr.fj b/flipjump/src/tests/ptr.fj new file mode 100644 index 0000000..d396201 --- /dev/null +++ b/flipjump/src/tests/ptr.fj @@ -0,0 +1,73 @@ +startup + +test0: + bit.ptr_flip p0 + bit.if d0, d00, d01 + d00: + output '0' + ;test1 + d01: + output '1' + ;test1 + +test1: + bit.ptr_jump p1 + jump_to6: + output '6' + ;test2 + jump_to7: + output '7' + ;test2 + +test2: + bit.ptr_wflip p2, base_jump_label2 + bit.ptr_jump p2_jump + pad 2 + base_jump_label2: + ;p20 + ;p21 + p20: + output 'N' + ;test3 + p21: + output 'Y' + ;test3 + +test3: + bit.zero d3_var + bit.xor_from_ptr d3_var, p3 + bit.if d3_var, d30, d31 + d30: + output 'F' + loop + d31: + output 'T' + loop + + + + bit.ptr_init + + p0: + bit.vec w, d0+dbit + d0: + bit 0 // 0 => 1, 1 => 0 + + p1: + bit.vec w, d1 + d1: + ;jump_to7 // jump_to6 => 6, jump_to7 => 7 + + p2: + bit.vec w, d2+w + p2_jump: + bit.vec w, d2 + d2: + bit 0 // 0 => N, 1 => Y + + p3: + bit.vec w, d3 + d3: + bit 1 // 0 => F, 1 => T + d3_var: + bit 0 diff --git a/flipjump/src/tests/rep.fj b/flipjump/src/tests/rep.fj new file mode 100644 index 0000000..3abd406 --- /dev/null +++ b/flipjump/src/tests/rep.fj @@ -0,0 +1,6 @@ + startup + rep(7, i) bit.exact_not x+i+i + loop + + x: + bit 0 diff --git a/flipjump/src/tests/segments.fj b/flipjump/src/tests/segments.fj new file mode 100644 index 0000000..19a7b2a --- /dev/null +++ b/flipjump/src/tests/segments.fj @@ -0,0 +1,53 @@ +startup + +X1 = 0x10000000 +X2 = 0x20000000 +X4 = 0x40000000 + +bit.print 4, str_hi + +bit.input 4, X1 + +// both are already zeros because they are reserved: +//zero 20, X2 +//zero 20, num + +rep(4, i) more_digit 20, num, X2, X1+8*dw*i + +;X4 + +back: + bit.print 6, str_bye + ;end + + + error: + bit + + str_hi: + bit.str "Hi!\n" + str_bye: + bit.str "\nBye!\n" + + +def more_digit width, num, inter, ascii < error { + bit.shl width, 4, num + bit.ascii2hex error, inter, ascii + bit.add width, num, inter +} + + +segment X1 + reserve dw*8*4 +segment X2 + reserve dw*20 +segment X4 + bit.add 20, num, num + bit.print_hex_int 20, num, 1 + ;back + end: + loop + + num: + reserve dw*10 + reserve dw*10 diff --git a/flipjump/src/tests/simple.fj b/flipjump/src/tests/simple.fj new file mode 100644 index 0000000..e7c2771 --- /dev/null +++ b/flipjump/src/tests/simple.fj @@ -0,0 +1,9 @@ + skip + IO: + ; + bit.not x + output '0'+#0b111 + loop + + x: + bit 0 diff --git a/flipjump/src/tests/testbit.fj b/flipjump/src/tests/testbit.fj new file mode 100644 index 0000000..32ec5dd --- /dev/null +++ b/flipjump/src/tests/testbit.fj @@ -0,0 +1,12 @@ +startup +bit.if x, l0, l1 + +l0: + output 6 ? 'Z' : '0' + loop +l1: + output '1' + loop + +x: + bit 0 // bit0 => 'Z', bit1 => '1' diff --git a/flipjump/src/tests/testbit_with_nops.fj b/flipjump/src/tests/testbit_with_nops.fj new file mode 100644 index 0000000..ad8bf82 --- /dev/null +++ b/flipjump/src/tests/testbit_with_nops.fj @@ -0,0 +1,45 @@ +startup + +rep(10, i) bit.mov y, z +bit.mov x, x +bit.if x, l0, l1 + +l0: + output 0x5A // 'Z' + ;loop +l1: + output 0x10*3+1*3-4/2 // '1' + ; + ;loop +loop: + ; + + loop + pad 2 + wflip l1, loop + + dloop: + ;dloop + bit.vec 8, 3 + bananas: + output 0x5c + dy=3 + + n=15 + rep(8, q) bit.if x, l0, l1 + bans2: + + rep(n, j) temp_macro x, x + +def temp_macro g, y { + bit.not g + bit.not y +} + + x: + bit 1 // bit0 => 'Z', bit1 => '1' + y: + bit 1 + z: + bit 1 +