flipjump 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flipjump/README.md +95 -0
- flipjump/__init__.py +23 -0
- flipjump/assembler/__init__.py +0 -0
- flipjump/assembler/assembler.py +241 -0
- flipjump/assembler/fj_parser.py +728 -0
- flipjump/assembler/inner_classes/__init__.py +0 -0
- flipjump/assembler/inner_classes/expr.py +129 -0
- flipjump/assembler/inner_classes/ops.py +369 -0
- flipjump/assembler/preprocessor.py +292 -0
- flipjump/fjm/__init__.py +0 -0
- flipjump/fjm/fjm_consts.py +66 -0
- flipjump/fjm/fjm_reader.py +187 -0
- flipjump/fjm/fjm_writer.py +189 -0
- flipjump/flipjump_cli.py +345 -0
- flipjump/flipjump_quickstart.py +342 -0
- flipjump/interpretter/__init__.py +0 -0
- flipjump/interpretter/debugging/__init__.py +0 -0
- flipjump/interpretter/debugging/breakpoints.py +234 -0
- flipjump/interpretter/debugging/macro_usage_graph.py +98 -0
- flipjump/interpretter/fjm_run.py +183 -0
- flipjump/interpretter/io_devices/BrokenIO.py +15 -0
- flipjump/interpretter/io_devices/FixedIO.py +51 -0
- flipjump/interpretter/io_devices/IODevice.py +16 -0
- flipjump/interpretter/io_devices/StandardIO.py +57 -0
- flipjump/interpretter/io_devices/__init__.py +0 -0
- flipjump/stl/README.md +146 -0
- flipjump/stl/bit/casting.fj +168 -0
- flipjump/stl/bit/cond_jumps.fj +97 -0
- flipjump/stl/bit/input.fj +29 -0
- flipjump/stl/bit/logics.fj +128 -0
- flipjump/stl/bit/math.fj +85 -0
- flipjump/stl/bit/memory.fj +113 -0
- flipjump/stl/bit/output.fj +221 -0
- flipjump/stl/bit/pointers.fj +181 -0
- flipjump/stl/bit/shifts.fj +57 -0
- flipjump/stl/casting.fj +52 -0
- flipjump/stl/conf.json +31 -0
- flipjump/stl/hex/advanced_pointers.fj +153 -0
- flipjump/stl/hex/cond_jumps.fj +162 -0
- flipjump/stl/hex/input.fj +87 -0
- flipjump/stl/hex/logics.fj +257 -0
- flipjump/stl/hex/math.fj +281 -0
- flipjump/stl/hex/math_basic.fj +207 -0
- flipjump/stl/hex/memory.fj +122 -0
- flipjump/stl/hex/output.fj +214 -0
- flipjump/stl/hex/pointers.fj +227 -0
- flipjump/stl/hex/shifts.fj +83 -0
- flipjump/stl/hex/tables_init.fj +78 -0
- flipjump/stl/mathlib.fj +516 -0
- flipjump/stl/ptrlib.fj +87 -0
- flipjump/stl/runlib.fj +163 -0
- flipjump/utils/__init__.py +0 -0
- flipjump/utils/classes.py +94 -0
- flipjump/utils/constants.py +17 -0
- flipjump/utils/exceptions.py +54 -0
- flipjump/utils/functions.py +74 -0
- flipjump-1.2.0.dist-info/LICENSE +25 -0
- flipjump-1.2.0.dist-info/METADATA +275 -0
- flipjump-1.2.0.dist-info/RECORD +61 -0
- flipjump-1.2.0.dist-info/WHEEL +4 -0
- flipjump-1.2.0.dist-info/entry_points.txt +3 -0
flipjump/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# FlipJump Source Code
|
|
2
|
+
|
|
3
|
+
In this documentation file you could find information about every python source file in the flipjump module.
|
|
4
|
+
|
|
5
|
+
## The FlipJump Macro-Assembler
|
|
6
|
+
|
|
7
|
+
The assembler has 4 steps:
|
|
8
|
+
- parsing the .fj text files into a dictionary of macros and their ops ([fj_parser.py](assembler/fj_parser.py)).
|
|
9
|
+
- resolving (unwinding) the macros (and reps) to get a straight stream of ops ([preprocessor.py](assembler/preprocessor.py)).
|
|
10
|
+
- resolving the label values and getting the ops binary data ([assembler.py](assembler/assembler.py)).
|
|
11
|
+
- writing the binary data into the executable ([fjm_writer.py](fjm/fjm_writer.py)).
|
|
12
|
+
|
|
13
|
+
The whole process is executed within the [assemble()](assembler/assembler.py) function.
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
- The [ops.py](assembler/inner_classes/ops.py) file contains the classes of the different assembly ops.
|
|
17
|
+
- The [expr.py](assembler/inner_classes/expr.py) file contains the expression class (Expr), which is the code's representation of the assembly mathematical expressions. The expressions are based on numbers and labels.
|
|
18
|
+
|
|
19
|
+
## The FlipJump Interpreter
|
|
20
|
+
|
|
21
|
+
The Interpreter ([fjm_run.py](interpretter/fjm_run.py)) stores the entire memory in a dictionary {address: value}, and supports unaligned-word access.
|
|
22
|
+
|
|
23
|
+
The whole interpretation is done within the [run()](interpretter/fjm_run.py) function (also uses the [fjm_reader.py](fjm/fjm_reader.py) to read the fjm file - i.e. to get the flipjump program memory from the compiled fjm file).
|
|
24
|
+
More about [how to run](../README.md#how-to-run).
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
The Interpreter has a built-in debugger, and it's activated by specifying breakpoints when called (via the [breakpoints.py](interpretter/debugging/breakpoints.py)'s `BreakpointHandler`).
|
|
28
|
+
The debugger can stop on the next breakpoint, or on a fixed number of executed ops after the current breakpoint.
|
|
29
|
+
In order to call the debugger with the right labels, get familiar with the [generating label names](README.md#Generated-Label-Names) (and see the debugger-image there), and use the `-d`/`-b`/`-B` cli options.
|
|
30
|
+
More about [how to debug](../README.md#how-to-debug).
|
|
31
|
+
|
|
32
|
+
The [macro_usage_graph.py](interpretter/debugging/macro_usage_graph.py) file exports a feature to present the macro-usage (which are the most used macros, and what % do they take from the overall flipjump ops) in a graph.
|
|
33
|
+
In order to view it, run the assembler with `--stats` (requires plotly to be installed (installed automatically with `pip install flipjump[stats]`)).
|
|
34
|
+
For example:
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
## The Using-FlipJump Files
|
|
38
|
+
|
|
39
|
+
- The [flipjump_cli.py](flipjump_cli.py) file is the main FlipJump cli-script. run with --help to see its capabilities. The `fj` utility runs the main() of this file.
|
|
40
|
+
- The [flipjump_quickstart.py](flipjump_quickstart.py) file contains the fundamental assemble/run functions that are exposed to the users. They are wrappers to the inner api. These are the functions that will be exported when you `import flipjump`.
|
|
41
|
+
|
|
42
|
+
### FJM versions
|
|
43
|
+
|
|
44
|
+
The .fjm file currently has 4 versions:
|
|
45
|
+
|
|
46
|
+
- Version 0: The basic version
|
|
47
|
+
- Version 1: The normal version (more configurable than the basic version)
|
|
48
|
+
- Version 2: The relative-jumps version (good for further compression)
|
|
49
|
+
- Version 3: The compressed version
|
|
50
|
+
|
|
51
|
+
You can specify the version you want with the `-v VERSION` flag.
|
|
52
|
+
The assembler chooses **by default** version **3** if the `--outfile` is specified, and version **1** if it isn't.
|
|
53
|
+
|
|
54
|
+
### Generated Label Names
|
|
55
|
+
|
|
56
|
+
The generated label string is a concatenation of the macro call tree, each separated by '---', and finish with the label local-name.
|
|
57
|
+
|
|
58
|
+
Each macro call string is as follows:\
|
|
59
|
+
short_file_name **:** line **:** macro_called
|
|
60
|
+
|
|
61
|
+
So if a->bit.b->hex.c->my_label: (a, bit.b called from file f2 lines 3,5; hex.c from file s1, line 72), the label's name will be:\
|
|
62
|
+
f2:3:a---f2:5:bit.b---s1:72:hex.c---my_label
|
|
63
|
+
|
|
64
|
+
On a rep-call (on index==i), the macro call string is:\
|
|
65
|
+
short_file_name : line : rep{i} : macro_called\
|
|
66
|
+
for example: f1:32:rep6:hex.print---f2:17:print_bit---print_label
|
|
67
|
+
|
|
68
|
+
the short_file_name is (by default) s1,s2,s3,... for the standard library files (in the order of [stl/conf.json - all](stl/conf.json)),
|
|
69
|
+
and f1,f2,f3,... for the compiled .fj files, in the order they are mentioned to the compiler (or appear in the test-line).
|
|
70
|
+
|
|
71
|
+
You can place breakpoints to stop on specific labels using the `-d`, followed by a `-b` and a label name (or `-B` and a part of a label name). For example:
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
## More Files
|
|
75
|
+
|
|
76
|
+
- The [fjm_consts.py](fjm/fjm_consts.py) contains the constants needed for interacting with the fjm format (used by the [fjm_reader.py](fjm/fjm_reader.py) + [fjm_writer.py](fjm/fjm_writer.py)).
|
|
77
|
+
- The [utils/](utils) folder contains common utilities used and shared by the entire project:
|
|
78
|
+
- [utils/classes.py](utils/classes.py) - contains the common classes used in the entire project
|
|
79
|
+
- [utils/functions.py](utils/functions.py) - contains the common utility functions used in the entire project
|
|
80
|
+
- [utils/constants.py](utils/constants.py) - contains the project's constants and definitions.
|
|
81
|
+
- [utils/exceptions.py](utils/exceptions.py) - contains all the project's exceptions.
|
|
82
|
+
- The [interpreter/io_devices/](interpretter/io_devices) folder contains modules for different Input/Output-handling classes (can be passed as a parameter to the interpreter).
|
|
83
|
+
- The standard one is [StandardIO.py](interpretter/io_devices/StandardIO.py), which takes its input from the standard input, and write its output to the standard output.
|
|
84
|
+
- The tests use the [FixedIO.py](interpretter/io_devices/FixedIO.py), which takes a defined input and remembers its output.
|
|
85
|
+
- If you want to assert that your program takes no input and generates no output, use the [BrokenIO.py](interpretter/io_devices/BrokenIO.py), which raises exception on every input/output.
|
|
86
|
+
- Finally, the pure abstract IO handler class - [IODevice.py](interpretter/io_devices/IODevice.py).
|
|
87
|
+
|
|
88
|
+
# Read More
|
|
89
|
+
|
|
90
|
+
The FlipJump source is built in a way that allows simple addition of new features.
|
|
91
|
+
|
|
92
|
+
Every addition should be supported from the parsing level, up to the phase that is disappears (and probably is replaced with some flipjump ops). See the `assemble()` function in [assembler](assembler/assembler.py) to better understand the assembler 'pipeline'.
|
|
93
|
+
|
|
94
|
+
For example, if you want to add a new operation `a@b` that calculates _a^2+b^2_ or `a!` for _factorial(a)_, it is simple as adding a parsing rule in [fj_parser.py](assembler/fj_parser.py), and then adding the function to the op_string_to_function() in [expr.py](assembler/inner_classes/expr.py). That's it.
|
|
95
|
+
|
flipjump/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from flipjump.flipjump_cli import assemble_run_according_to_cmd_line_args
|
|
2
|
+
from flipjump.flipjump_quickstart import (assemble, run, debug, run_test_output,
|
|
3
|
+
assemble_and_run, assemble_and_debug, assemble_and_run_test_output,
|
|
4
|
+
FJMVersion, TerminationCause, TerminationStatistics,
|
|
5
|
+
FixedIO, IODevice, StandardIO)
|
|
6
|
+
from flipjump.utils.exceptions import IODeviceException, FlipJumpException
|
|
7
|
+
from flipjump.interpretter.io_devices.BrokenIO import BrokenIO
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
'assemble_run_according_to_cmd_line_args',
|
|
12
|
+
'assemble',
|
|
13
|
+
'run',
|
|
14
|
+
'debug',
|
|
15
|
+
'run_test_output',
|
|
16
|
+
'assemble_and_run',
|
|
17
|
+
'assemble_and_debug',
|
|
18
|
+
'assemble_and_run_test_output',
|
|
19
|
+
'FJMVersion',
|
|
20
|
+
'TerminationCause',
|
|
21
|
+
'TerminationStatistics',
|
|
22
|
+
'FlipJumpException',
|
|
23
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Deque, List, Dict, Tuple, Optional
|
|
5
|
+
|
|
6
|
+
from flipjump.fjm.fjm_writer import Writer
|
|
7
|
+
from flipjump.utils.constants import WFLIP_LABEL_PREFIX
|
|
8
|
+
from flipjump.utils.functions import save_debugging_labels
|
|
9
|
+
from flipjump.utils.classes import PrintTimer
|
|
10
|
+
from flipjump.assembler.fj_parser import parse_macro_tree
|
|
11
|
+
from flipjump.utils.exceptions import FlipJumpAssemblerException, FlipJumpException, FlipJumpWriteFjmException
|
|
12
|
+
from flipjump.assembler.inner_classes.ops import FlipJump, WordFlip, LastPhaseOp, NewSegment, ReserveBits, Padding
|
|
13
|
+
from flipjump.assembler.preprocessor import resolve_macros
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def assert_address_in_memory(memory_width: int, address: int):
|
|
17
|
+
if address < 0 or address >= (1 << memory_width):
|
|
18
|
+
raise FlipJumpAssemblerException(f"Not enough space with the {memory_width}-bits memory-width.")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def validate_addresses(memory_width, first_address, last_address):
|
|
22
|
+
if first_address % memory_width != 0 or last_address % memory_width != 0:
|
|
23
|
+
raise FlipJumpAssemblerException(f'segment boundaries are unaligned: '
|
|
24
|
+
f'[{hex(first_address)}, {hex(last_address - 1)}].')
|
|
25
|
+
|
|
26
|
+
assert_address_in_memory(memory_width, first_address)
|
|
27
|
+
assert_address_in_memory(memory_width, last_address)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def add_segment_to_fjm(memory_width: int,
|
|
31
|
+
fjm_writer: Writer,
|
|
32
|
+
first_address: int, last_address: int,
|
|
33
|
+
fj_words: List[int], wflip_words: List[int]) -> None:
|
|
34
|
+
validate_addresses(memory_width, first_address, last_address)
|
|
35
|
+
if first_address == last_address:
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
data_words = fj_words + wflip_words
|
|
39
|
+
data_start = fjm_writer.add_data(data_words)
|
|
40
|
+
|
|
41
|
+
segment_start_address = first_address // memory_width
|
|
42
|
+
segment_length = (last_address - first_address) // memory_width
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
fjm_writer.add_segment(segment_start_address, segment_length, data_start, len(data_words))
|
|
46
|
+
except FlipJumpWriteFjmException as e:
|
|
47
|
+
exception_message = (f"failed to add the segment: "
|
|
48
|
+
f"{fjm_writer.get_segment_addresses_repr(segment_start_address, segment_length)}.")
|
|
49
|
+
raise FlipJumpAssemblerException(exception_message) from e
|
|
50
|
+
|
|
51
|
+
fj_words.clear()
|
|
52
|
+
wflip_words.clear()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclasses.dataclass
|
|
56
|
+
class WFlipSpot:
|
|
57
|
+
list: List[int]
|
|
58
|
+
index: int
|
|
59
|
+
address: int
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class BinaryData:
|
|
63
|
+
def __init__(self, memory_width: int, first_segment: NewSegment, labels: Dict[str, int]):
|
|
64
|
+
self.memory_width = memory_width
|
|
65
|
+
|
|
66
|
+
self.first_address = first_segment.start_address
|
|
67
|
+
self.wflip_address = first_segment.wflip_start_address
|
|
68
|
+
|
|
69
|
+
self.labels = labels
|
|
70
|
+
self.wflips_so_far = 0
|
|
71
|
+
|
|
72
|
+
self.current_address = self.first_address
|
|
73
|
+
|
|
74
|
+
self.fj_words: List[int] = []
|
|
75
|
+
self.wflip_words: List[int] = []
|
|
76
|
+
|
|
77
|
+
self.padding_ops_indices: List[int] = [] # indices in self.fj_words
|
|
78
|
+
|
|
79
|
+
# return_address -> { (f3, f2, f1, f0) -> start_flip_address }
|
|
80
|
+
self.wflips_dict: Dict[int, Dict[Tuple[int, ...]]] = defaultdict(lambda: {})
|
|
81
|
+
|
|
82
|
+
def get_wflip_spot(self) -> WFlipSpot:
|
|
83
|
+
if self.padding_ops_indices:
|
|
84
|
+
index = self.padding_ops_indices.pop()
|
|
85
|
+
return WFlipSpot(self.fj_words, index, self.first_address + self.memory_width * index)
|
|
86
|
+
|
|
87
|
+
wflip_spot = WFlipSpot(self.wflip_words, len(self.wflip_words), self.wflip_address)
|
|
88
|
+
self.wflip_words += (0, 0)
|
|
89
|
+
self.wflip_address += 2*self.memory_width
|
|
90
|
+
return wflip_spot
|
|
91
|
+
|
|
92
|
+
def close_and_add_segment(self, fjm_writer: Writer) -> None:
|
|
93
|
+
add_segment_to_fjm(self.memory_width, fjm_writer, self.first_address, self.wflip_address, self.fj_words, self.wflip_words)
|
|
94
|
+
|
|
95
|
+
def _insert_wflip_label(self, address: int):
|
|
96
|
+
self.labels[f'{WFLIP_LABEL_PREFIX}{self.wflips_so_far}'] = address
|
|
97
|
+
self.wflips_so_far += 1
|
|
98
|
+
|
|
99
|
+
def insert_fj_op(self, flip: int, jump: int) -> None:
|
|
100
|
+
self.fj_words += (flip, jump)
|
|
101
|
+
self.current_address += 2*self.memory_width
|
|
102
|
+
|
|
103
|
+
def insert_wflip_ops(self, word_address: int, flip_value: int, return_address: int) -> None:
|
|
104
|
+
if 0 == flip_value:
|
|
105
|
+
self.insert_fj_op(0, return_address)
|
|
106
|
+
else:
|
|
107
|
+
assert_address_in_memory(self.memory_width, flip_value)
|
|
108
|
+
|
|
109
|
+
return_dict = self.wflips_dict[return_address]
|
|
110
|
+
|
|
111
|
+
# this is the order of flip_addresses (tested with many other orders) that produces the best
|
|
112
|
+
# found-statistic for searching flip_bit[:i] with different i's in return_dict.
|
|
113
|
+
flip_addresses = [word_address + i for i in range(self.memory_width) if flip_value & (1 << i)][::-1]
|
|
114
|
+
|
|
115
|
+
# insert the first op
|
|
116
|
+
self.insert_fj_op(flip_addresses.pop(), 0)
|
|
117
|
+
last_return_address_index = self.fj_words, len(self.fj_words) - 1
|
|
118
|
+
|
|
119
|
+
while flip_addresses:
|
|
120
|
+
flips_key = tuple(flip_addresses)
|
|
121
|
+
ops_list, last_address_index = last_return_address_index
|
|
122
|
+
|
|
123
|
+
if flips_key in return_dict:
|
|
124
|
+
# connect the last op to the already created wflip-chain
|
|
125
|
+
ops_list[last_address_index] = return_dict[flips_key]
|
|
126
|
+
return
|
|
127
|
+
else:
|
|
128
|
+
# insert a new wflip op, and connect the last one to it
|
|
129
|
+
wflip_spot = self.get_wflip_spot()
|
|
130
|
+
self._insert_wflip_label(wflip_spot.address)
|
|
131
|
+
|
|
132
|
+
ops_list[last_address_index] = wflip_spot.address
|
|
133
|
+
return_dict[flips_key] = wflip_spot.address
|
|
134
|
+
|
|
135
|
+
wflip_spot.list[wflip_spot.index] = flip_addresses.pop()
|
|
136
|
+
last_return_address_index = wflip_spot.list, wflip_spot.index + 1
|
|
137
|
+
|
|
138
|
+
ops_list, last_address_index = last_return_address_index
|
|
139
|
+
ops_list[last_address_index] = return_address
|
|
140
|
+
|
|
141
|
+
def insert_padding(self, ops_count: int) -> None:
|
|
142
|
+
for i in range(len(self.fj_words), len(self.fj_words) + 2 * ops_count, 2):
|
|
143
|
+
self.padding_ops_indices.append(i)
|
|
144
|
+
self.fj_words += (0, 0)
|
|
145
|
+
self.current_address += ops_count * (2 * self.memory_width)
|
|
146
|
+
|
|
147
|
+
def insert_new_segment(self, fjm_writer: Writer, first_address: int, wflip_first_address: int) -> None:
|
|
148
|
+
self.close_and_add_segment(fjm_writer)
|
|
149
|
+
|
|
150
|
+
self.first_address = first_address
|
|
151
|
+
self.wflip_address = wflip_first_address
|
|
152
|
+
self.current_address = self.first_address
|
|
153
|
+
|
|
154
|
+
self.padding_ops_indices.clear()
|
|
155
|
+
|
|
156
|
+
def insert_reserve_bits(self, fjm_writer: Writer, new_first_address: int) -> None:
|
|
157
|
+
add_segment_to_fjm(self.memory_width, fjm_writer, self.first_address, new_first_address, self.fj_words, [])
|
|
158
|
+
|
|
159
|
+
self.first_address = new_first_address
|
|
160
|
+
self.current_address = self.first_address
|
|
161
|
+
|
|
162
|
+
self.padding_ops_indices.clear()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def labels_resolve(ops: Deque[LastPhaseOp], labels: Dict[str, int],
|
|
166
|
+
memory_width: int, fjm_writer: Writer) -> None:
|
|
167
|
+
"""
|
|
168
|
+
resolve the labels and expressions to get the list of fj ops, and add all the data and segments into the fjm_writer.
|
|
169
|
+
@param ops:[in]: the list ops returned from the preprocessor stage
|
|
170
|
+
@param labels:[in]: dictionary from label to its resolved value
|
|
171
|
+
@param memory_width: the memory-width
|
|
172
|
+
@param fjm_writer: [out]: the .fjm file writer
|
|
173
|
+
"""
|
|
174
|
+
first_segment: NewSegment = ops.popleft()
|
|
175
|
+
if not isinstance(first_segment, NewSegment):
|
|
176
|
+
raise FlipJumpAssemblerException(f"The first op must be of type NewSegment (and not {first_segment}).")
|
|
177
|
+
|
|
178
|
+
binary_data = BinaryData(memory_width, first_segment, labels)
|
|
179
|
+
|
|
180
|
+
for op in ops:
|
|
181
|
+
if isinstance(op, FlipJump):
|
|
182
|
+
try:
|
|
183
|
+
binary_data.insert_fj_op(op.get_flip(labels), op.get_jump(labels))
|
|
184
|
+
except FlipJumpException as e:
|
|
185
|
+
raise FlipJumpAssemblerException(f"{e} in op {op}.")
|
|
186
|
+
|
|
187
|
+
elif isinstance(op, WordFlip):
|
|
188
|
+
try:
|
|
189
|
+
binary_data.insert_wflip_ops(op.get_word_address(labels), op.get_flip_value(labels),
|
|
190
|
+
op.get_return_address(labels))
|
|
191
|
+
except FlipJumpException as e:
|
|
192
|
+
raise FlipJumpAssemblerException(f"{e} in op {op}.")
|
|
193
|
+
|
|
194
|
+
elif isinstance(op, Padding):
|
|
195
|
+
binary_data.insert_padding(op.ops_count)
|
|
196
|
+
|
|
197
|
+
elif isinstance(op, NewSegment):
|
|
198
|
+
binary_data.insert_new_segment(fjm_writer, op.start_address, op.wflip_start_address)
|
|
199
|
+
|
|
200
|
+
elif isinstance(op, ReserveBits):
|
|
201
|
+
binary_data.insert_reserve_bits(fjm_writer, op.first_address_after_reserved)
|
|
202
|
+
|
|
203
|
+
else:
|
|
204
|
+
raise FlipJumpAssemblerException(f"Can't resolve/assemble the next opcode - {str(op)}")
|
|
205
|
+
|
|
206
|
+
binary_data.close_and_add_segment(fjm_writer)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def assemble(input_files: List[Tuple[str, Path]], memory_width: int, fjm_writer: Writer, *,
|
|
210
|
+
warning_as_errors: bool = True, debugging_file_path: Optional[Path] = None,
|
|
211
|
+
show_statistics: bool = False, print_time: bool = True)\
|
|
212
|
+
-> None:
|
|
213
|
+
"""
|
|
214
|
+
runs the assembly pipeline. assembles the input files to a .fjm.
|
|
215
|
+
:param input_files:[in]: a list of (short_file_name, fj_file_path). The files will to be parsed in that given order.
|
|
216
|
+
:param memory_width: the memory-width
|
|
217
|
+
:param fjm_writer:[out]: the .fjm file writer
|
|
218
|
+
:param warning_as_errors: treat warnings as errors (stop execution on warnings)
|
|
219
|
+
:param debugging_file_path:[out]: is specified, save debug information in this file
|
|
220
|
+
:param show_statistics: if true shows macro-usage statistics
|
|
221
|
+
:param print_time: if true prints the times of each assemble-stage
|
|
222
|
+
"""
|
|
223
|
+
try:
|
|
224
|
+
with PrintTimer(' parsing: ', print_time=print_time):
|
|
225
|
+
macros = parse_macro_tree(input_files, memory_width, warning_as_errors)
|
|
226
|
+
|
|
227
|
+
with PrintTimer(' macro resolve: ', print_time=print_time):
|
|
228
|
+
ops, labels = resolve_macros(memory_width, macros, show_statistics=show_statistics)
|
|
229
|
+
|
|
230
|
+
with PrintTimer(' labels resolve: ', print_time=print_time):
|
|
231
|
+
labels_resolve(ops, labels, memory_width, fjm_writer)
|
|
232
|
+
|
|
233
|
+
with PrintTimer(' create binary: ', print_time=print_time):
|
|
234
|
+
fjm_writer.write_to_file()
|
|
235
|
+
save_debugging_labels(debugging_file_path, labels)
|
|
236
|
+
|
|
237
|
+
except FlipJumpException as fj_exception:
|
|
238
|
+
raise fj_exception
|
|
239
|
+
except Exception as unknown_exception:
|
|
240
|
+
raise FlipJumpAssemblerException("Unknown exception during assembling the .fj files, please report this bug") \
|
|
241
|
+
from unknown_exception
|