taracpu 1.0.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.
- src/__init__.py +1 -0
- src/assembler/__init__.py +1 -0
- src/assembler/asm.py +241 -0
- src/assets/delete.jpeg +0 -0
- src/assets/logo/logo1.png +0 -0
- src/assets/logo/logo2.png +0 -0
- src/assets/logo/logo2_cropped.png +0 -0
- src/assets/logo/logo2_text.png +0 -0
- src/assets/rename.png +0 -0
- src/examples/__init__.py +1 -0
- src/examples/examples.py +17 -0
- src/examples/progs/binary_search.tara +71 -0
- src/examples/progs/display_bouncing_ball.tara +349 -0
- src/examples/progs/display_rectangle.tara +70 -0
- src/examples/progs/display_triangle.tara +80 -0
- src/examples/progs/drawline.tara +380 -0
- src/examples/progs/factorial_via_mul_n_6.tara +9 -0
- src/examples/progs/fibonacci_n_10.tara +14 -0
- src/examples/progs/gcd_a_48_b_18.tara +12 -0
- src/examples/progs/generate_prime.tara +62 -0
- src/examples/progs/image.tara +18 -0
- src/examples/progs/matrix_multiplication.tara +224 -0
- src/examples/progs/ping_pong.tara +206 -0
- src/examples/progs/prime_test_n_17.tara +19 -0
- src/examples/progs/sort_bubble.tara +49 -0
- src/examples/progs/sort_insertion.tara +52 -0
- src/examples/progs/testprog.tara +1 -0
- src/paths.py +30 -0
- src/run_sim.py +14 -0
- src/simulation/__init__.py +1 -0
- src/simulation/cpu.py +246 -0
- src/ui/__init__.py +1 -0
- src/ui/app.py +673 -0
- src/ui/assets.py +49 -0
- src/ui/isa_dialog.py +121 -0
- src/ui/panels.py +2988 -0
- src/ui/theme.py +322 -0
- taracpu/__init__.py +3 -0
- taracpu/__main__.py +3 -0
- taracpu-1.0.0.dist-info/METADATA +105 -0
- taracpu-1.0.0.dist-info/RECORD +44 -0
- taracpu-1.0.0.dist-info/WHEEL +5 -0
- taracpu-1.0.0.dist-info/entry_points.txt +2 -0
- taracpu-1.0.0.dist-info/top_level.txt +2 -0
src/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
src/assembler/asm.py
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TARA Assembler
|
|
3
|
+
Converts TARA assembly text into 16-bit machine words.
|
|
4
|
+
Supports labels, comments (;), and all instruction formats.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
from src.simulation.cpu import OP, FMT, sext
|
|
9
|
+
|
|
10
|
+
class AssemblerError(Exception):
|
|
11
|
+
def __init__(self, msg, line=None):
|
|
12
|
+
self.msg = msg
|
|
13
|
+
self.line = line
|
|
14
|
+
super().__init__(msg)
|
|
15
|
+
|
|
16
|
+
def __str__(self):
|
|
17
|
+
return f"Line {self.line}: {self.msg}" if self.line else self.msg
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def parse_reg(tok):
|
|
21
|
+
"""Parse Rn or rn → integer 0-7."""
|
|
22
|
+
tok = tok.strip().upper()
|
|
23
|
+
if tok.startswith('R') and tok[1:].isdigit():
|
|
24
|
+
n = int(tok[1:])
|
|
25
|
+
if 0 <= n <= 7:
|
|
26
|
+
return n
|
|
27
|
+
raise AssemblerError(f"Invalid register '{tok}'")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def parse_int(tok, label_map=None, pc=None):
|
|
31
|
+
"""Parse a literal integer or label reference."""
|
|
32
|
+
tok = tok.strip()
|
|
33
|
+
if tok.startswith('0x') or tok.startswith('0X'):
|
|
34
|
+
return int(tok, 16)
|
|
35
|
+
if tok.startswith('0b') or tok.startswith('0B'):
|
|
36
|
+
return int(tok, 2)
|
|
37
|
+
if tok.lstrip('-').isdigit():
|
|
38
|
+
return int(tok)
|
|
39
|
+
if label_map is not None and tok in label_map:
|
|
40
|
+
return label_map[tok]
|
|
41
|
+
raise AssemblerError(f"Cannot parse value '{tok}'")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def parse_mem(tok):
|
|
45
|
+
"""Parse off(Rbase) → (offset_str, reg_str)."""
|
|
46
|
+
m = re.match(r'^(-?\d+|0x[0-9a-fA-F]+)\(([Rr]\d)\)$', tok.strip())
|
|
47
|
+
if not m:
|
|
48
|
+
raise AssemblerError(f"Invalid memory operand '{tok}'")
|
|
49
|
+
return m.group(1), m.group(2)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
OPERAND_COUNTS = {
|
|
53
|
+
'NOP': 0, 'HLT': 0, 'RET': 0,
|
|
54
|
+
'ADD': 3, 'SUB': 3, 'MUL': 3, 'AND': 3, 'OR': 3, 'XOR': 3, 'SLT': 3,
|
|
55
|
+
'MOV': 2, 'NOT': 2,
|
|
56
|
+
'LIL': 2, 'LIH': 2, 'ADDI': 2, 'SHL': 2, 'SHR': 2,
|
|
57
|
+
'LDW': 2, 'LDB': 2, 'STW': 2, 'STB': 2,
|
|
58
|
+
'BZ': 2, 'BN': 2,
|
|
59
|
+
'JMP': 1, 'CALL': 1,
|
|
60
|
+
'PUSH': 1, 'POP': 1,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _parse_operands(ops_str, mnem):
|
|
65
|
+
operands = [o.strip() for o in ops_str.split(',') if o.strip()]
|
|
66
|
+
expected = OPERAND_COUNTS[mnem]
|
|
67
|
+
if len(operands) != expected:
|
|
68
|
+
suffix = "" if expected == 1 else "s"
|
|
69
|
+
raise AssemblerError(
|
|
70
|
+
f"{mnem} expects {expected} operand{suffix}, got {len(operands)}"
|
|
71
|
+
)
|
|
72
|
+
return operands
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _label_rel(target_s, iaddr, label_map):
|
|
76
|
+
"""Resolve a branch/jump target to a signed word-offset relative to iaddr+2."""
|
|
77
|
+
if target_s in label_map:
|
|
78
|
+
return (label_map[target_s] - (iaddr + 2)) // 2
|
|
79
|
+
return parse_int(target_s, label_map)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _encode_f0(op):
|
|
83
|
+
return (op << 11)
|
|
84
|
+
|
|
85
|
+
def _encode_f1(op, rd, rA, rB):
|
|
86
|
+
return (op << 11) | (rd << 8) | (rA << 5) | (rB << 2)
|
|
87
|
+
|
|
88
|
+
def _encode_f2(op, rd, rs):
|
|
89
|
+
return (op << 11) | (rd << 8) | (rs << 5)
|
|
90
|
+
|
|
91
|
+
def _encode_f3(op, rd, imm8):
|
|
92
|
+
imm8 = imm8 & 0xFF
|
|
93
|
+
return (op << 11) | (rd << 8) | imm8
|
|
94
|
+
|
|
95
|
+
def _encode_f4(op, rdata, rbase, off5):
|
|
96
|
+
off5 = off5 & 0x1F
|
|
97
|
+
return (op << 11) | (rdata << 8) | (rbase << 5) | off5
|
|
98
|
+
|
|
99
|
+
def _encode_f5(op, rtest, rel8):
|
|
100
|
+
rel8 = rel8 & 0xFF
|
|
101
|
+
return (op << 11) | (rtest << 8) | rel8
|
|
102
|
+
|
|
103
|
+
def _encode_f6(op, rel11):
|
|
104
|
+
rel11 = rel11 & 0x7FF
|
|
105
|
+
return (op << 11) | rel11
|
|
106
|
+
|
|
107
|
+
def _encode_f7(op, rstk):
|
|
108
|
+
return (op << 11) | (rstk << 8)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def assemble(source):
|
|
112
|
+
"""
|
|
113
|
+
Assemble source text → (words, listing, errors)
|
|
114
|
+
words : list of (byte_addr, 16-bit int)
|
|
115
|
+
listing: list of dict per assembled instruction
|
|
116
|
+
errors : list of AssemblerError
|
|
117
|
+
"""
|
|
118
|
+
lines = source.splitlines()
|
|
119
|
+
errors = []
|
|
120
|
+
label_map = {} # label → byte address
|
|
121
|
+
parsed = [] # list of (lineno, addr, mnemonic, operands_str, original)
|
|
122
|
+
|
|
123
|
+
# ── Pass 1: strip comments, collect labels, count addresses ───────────────
|
|
124
|
+
addr = 0
|
|
125
|
+
for lineno, raw in enumerate(lines, 1):
|
|
126
|
+
line = raw.split(';')[0].strip()
|
|
127
|
+
if not line:
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
# Extract label(s)
|
|
131
|
+
while ':' in line:
|
|
132
|
+
colon = line.index(':')
|
|
133
|
+
label = line[:colon].strip()
|
|
134
|
+
if label:
|
|
135
|
+
label_map[label] = addr
|
|
136
|
+
line = line[colon+1:].strip()
|
|
137
|
+
|
|
138
|
+
if not line:
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
parts = line.split(None, 1)
|
|
142
|
+
mnem = parts[0].upper()
|
|
143
|
+
ops = parts[1].strip() if len(parts) > 1 else ''
|
|
144
|
+
|
|
145
|
+
if mnem not in OP:
|
|
146
|
+
errors.append(AssemblerError(f"Unknown mnemonic '{mnem}'", lineno))
|
|
147
|
+
continue
|
|
148
|
+
|
|
149
|
+
parsed.append((lineno, addr, mnem, ops, raw.rstrip()))
|
|
150
|
+
addr += 2
|
|
151
|
+
|
|
152
|
+
# ── Pass 2: encode instructions ───────────────────────────────────────────
|
|
153
|
+
words = []
|
|
154
|
+
listing = []
|
|
155
|
+
|
|
156
|
+
for (lineno, iaddr, mnem, ops_str, original) in parsed:
|
|
157
|
+
opcode = OP[mnem]
|
|
158
|
+
word = 0
|
|
159
|
+
err = None
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
operands = _parse_operands(ops_str, mnem)
|
|
163
|
+
if mnem in ('NOP', 'HLT', 'RET'):
|
|
164
|
+
word = _encode_f0(opcode)
|
|
165
|
+
|
|
166
|
+
elif mnem in ('ADD', 'SUB', 'MUL', 'AND', 'OR', 'XOR', 'SLT'):
|
|
167
|
+
# rd, rA, rB
|
|
168
|
+
rd = parse_reg(operands[0])
|
|
169
|
+
rA = parse_reg(operands[1])
|
|
170
|
+
rB = parse_reg(operands[2])
|
|
171
|
+
word = _encode_f1(opcode, rd, rA, rB)
|
|
172
|
+
|
|
173
|
+
elif mnem in ('MOV', 'NOT'):
|
|
174
|
+
# rd, rs
|
|
175
|
+
rd = parse_reg(operands[0])
|
|
176
|
+
rs = parse_reg(operands[1])
|
|
177
|
+
word = _encode_f2(opcode, rd, rs)
|
|
178
|
+
|
|
179
|
+
elif mnem in ('LIL', 'LIH', 'ADDI'):
|
|
180
|
+
rd = parse_reg(operands[0])
|
|
181
|
+
imm = parse_int(operands[1], label_map)
|
|
182
|
+
word = _encode_f3(opcode, rd, imm)
|
|
183
|
+
|
|
184
|
+
elif mnem in ('SHL', 'SHR'):
|
|
185
|
+
# rd, shamt
|
|
186
|
+
rd = parse_reg(operands[0])
|
|
187
|
+
shamt = parse_int(operands[1], label_map)
|
|
188
|
+
word = _encode_f3(opcode, rd, shamt)
|
|
189
|
+
|
|
190
|
+
elif mnem in ('LDW', 'LDB'):
|
|
191
|
+
# rd, off(rbase)
|
|
192
|
+
rd = parse_reg(operands[0])
|
|
193
|
+
off_s, base_s = parse_mem(operands[1])
|
|
194
|
+
off = parse_int(off_s, label_map)
|
|
195
|
+
rbase = parse_reg(base_s)
|
|
196
|
+
word = _encode_f4(opcode, rd, rbase, off)
|
|
197
|
+
|
|
198
|
+
elif mnem in ('STW', 'STB'):
|
|
199
|
+
# rs, off(rbase)
|
|
200
|
+
rs = parse_reg(operands[0])
|
|
201
|
+
off_s, base_s = parse_mem(operands[1])
|
|
202
|
+
off = parse_int(off_s, label_map)
|
|
203
|
+
rbase = parse_reg(base_s)
|
|
204
|
+
word = _encode_f4(opcode, rs, rbase, off)
|
|
205
|
+
|
|
206
|
+
elif mnem in ('BZ', 'BN'):
|
|
207
|
+
rtest = parse_reg(operands[0])
|
|
208
|
+
rel = _label_rel(operands[1], iaddr, label_map)
|
|
209
|
+
word = _encode_f5(opcode, rtest, rel)
|
|
210
|
+
|
|
211
|
+
elif mnem in ('JMP', 'CALL'):
|
|
212
|
+
rel = _label_rel(operands[0], iaddr, label_map)
|
|
213
|
+
word = _encode_f6(opcode, rel)
|
|
214
|
+
|
|
215
|
+
elif mnem in ('PUSH', 'POP'):
|
|
216
|
+
rs = parse_reg(operands[0])
|
|
217
|
+
word = _encode_f7(opcode, rs)
|
|
218
|
+
|
|
219
|
+
else:
|
|
220
|
+
raise AssemblerError(f"Unhandled mnemonic '{mnem}'")
|
|
221
|
+
|
|
222
|
+
except (AssemblerError, ValueError, IndexError) as e:
|
|
223
|
+
if not isinstance(e, AssemblerError):
|
|
224
|
+
e = AssemblerError(str(e))
|
|
225
|
+
e.line = lineno
|
|
226
|
+
errors.append(e)
|
|
227
|
+
err = e
|
|
228
|
+
word = 0xDEAD
|
|
229
|
+
|
|
230
|
+
words.append((iaddr, word))
|
|
231
|
+
listing.append({
|
|
232
|
+
'lineno': lineno,
|
|
233
|
+
'addr': iaddr,
|
|
234
|
+
'word': word,
|
|
235
|
+
'mnem': mnem,
|
|
236
|
+
'ops': ops_str,
|
|
237
|
+
'original': original,
|
|
238
|
+
'error': bool(err),
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
return words, listing, errors, label_map
|
src/assets/delete.jpeg
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
src/assets/rename.png
ADDED
|
Binary file
|
src/examples/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
src/examples/examples.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from src.paths import PROGS_DIR
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _display_name(path):
|
|
7
|
+
return path.stem.replace('_', ' ').title()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load_examples():
|
|
11
|
+
examples = {}
|
|
12
|
+
progs = Path(PROGS_DIR)
|
|
13
|
+
if not progs.exists():
|
|
14
|
+
return examples
|
|
15
|
+
for path in sorted(progs.glob('*.tara')):
|
|
16
|
+
examples[_display_name(path)] = path.read_text(encoding='utf-8', errors='replace')
|
|
17
|
+
return examples
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
; Binary search for a sorted byte array.
|
|
2
|
+
;
|
|
3
|
+
; Interface at label "search":
|
|
4
|
+
; R0 = starting byte address of sorted array
|
|
5
|
+
; R1 = number of elements
|
|
6
|
+
; R2 = search key
|
|
7
|
+
;
|
|
8
|
+
; Return value:
|
|
9
|
+
; R3 = index of matching element, or 0xFFFF if not found
|
|
10
|
+
;
|
|
11
|
+
; The demo setup below searches for 7 in [1,3,5,7,9,11] at 0x0400.
|
|
12
|
+
; After HLT, R3 contains 3.
|
|
13
|
+
|
|
14
|
+
; ---- Demo setup -----------------------------------------------------
|
|
15
|
+
LIL R0, 0
|
|
16
|
+
LIH R0, 4 ; R0 = 0x0400
|
|
17
|
+
LIL R1, 6 ; N = 6 byte elements
|
|
18
|
+
LIL R2, 7 ; key = 7
|
|
19
|
+
|
|
20
|
+
LIL R3, 1
|
|
21
|
+
STB R3, 0(R0)
|
|
22
|
+
LIL R3, 3
|
|
23
|
+
STB R3, 1(R0)
|
|
24
|
+
LIL R3, 5
|
|
25
|
+
STB R3, 2(R0)
|
|
26
|
+
LIL R3, 7
|
|
27
|
+
STB R3, 3(R0)
|
|
28
|
+
LIL R3, 9
|
|
29
|
+
STB R3, 4(R0)
|
|
30
|
+
LIL R3, 11
|
|
31
|
+
STB R3, 5(R0)
|
|
32
|
+
|
|
33
|
+
; ---- Binary search --------------------------------------------------
|
|
34
|
+
; R3 = result index
|
|
35
|
+
; R4 = low index
|
|
36
|
+
; R5 = high index
|
|
37
|
+
; R6 = mid index
|
|
38
|
+
; R7 = scratch / loaded array value
|
|
39
|
+
|
|
40
|
+
search: LIL R3, 255
|
|
41
|
+
LIH R3, 255 ; default result = 0xFFFF (not found)
|
|
42
|
+
LIL R4, 0 ; low = 0
|
|
43
|
+
MOV R5, R1
|
|
44
|
+
ADDI R5, -1 ; high = N - 1
|
|
45
|
+
|
|
46
|
+
loop: SUB R7, R5, R4
|
|
47
|
+
BN R7, done ; high < low
|
|
48
|
+
|
|
49
|
+
MOV R6, R4
|
|
50
|
+
ADD R6, R6, R5
|
|
51
|
+
SHR R6, 1 ; mid = (low + high) / 2
|
|
52
|
+
|
|
53
|
+
ADD R7, R0, R6
|
|
54
|
+
LDB R7, 0(R7) ; R7 = A[mid]
|
|
55
|
+
SUB R7, R7, R2 ; compare A[mid] - key
|
|
56
|
+
|
|
57
|
+
BZ R7, found
|
|
58
|
+
BN R7, go_right ; A[mid] < key
|
|
59
|
+
|
|
60
|
+
MOV R5, R6 ; A[mid] > key, high = mid - 1
|
|
61
|
+
ADDI R5, -1
|
|
62
|
+
JMP loop
|
|
63
|
+
|
|
64
|
+
go_right:
|
|
65
|
+
MOV R4, R6 ; low = mid + 1
|
|
66
|
+
ADDI R4, 1
|
|
67
|
+
JMP loop
|
|
68
|
+
|
|
69
|
+
found: MOV R3, R6
|
|
70
|
+
|
|
71
|
+
done: HLT
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
; Bouncing glyph demo for the TARA memory-mapped display.
|
|
2
|
+
;
|
|
3
|
+
; Display map:
|
|
4
|
+
; 0x0600-0x07FF framebuffer
|
|
5
|
+
; 64x64 pixels, 1 bit per pixel, 8 horizontal pixels per byte
|
|
6
|
+
; framebuffer row stride = 8 bytes
|
|
7
|
+
;
|
|
8
|
+
; Glyph map:
|
|
9
|
+
; 0x0400 byte glyph width in pixels
|
|
10
|
+
; 0x0401 byte glyph height in pixels
|
|
11
|
+
; 0x0402... packed 1-bit row-major glyph bytes
|
|
12
|
+
;
|
|
13
|
+
; Glyph rows are stored top-to-bottom. Each row is padded to a whole
|
|
14
|
+
; number of bytes: row_bytes = ceil(width / 8). This matches the image
|
|
15
|
+
; import tool's "Glyph asset" format.
|
|
16
|
+
;
|
|
17
|
+
; Animation state:
|
|
18
|
+
; 0x0580 byte x byte-column, so x pixel = x * 8
|
|
19
|
+
; 0x0581 byte y bottom row
|
|
20
|
+
; 0x0582 byte dx, 0=left, 1=right
|
|
21
|
+
; 0x0583 byte dy, 0=down, 1=up
|
|
22
|
+
;
|
|
23
|
+
; The blitter is byte-aligned horizontally. Import a ball glyph at
|
|
24
|
+
; 0x0400, or let this program create a default 16x16 ball there.
|
|
25
|
+
|
|
26
|
+
; ---- Ensure a glyph exists at 0x0400 -------------------------------
|
|
27
|
+
LIL R6, 0
|
|
28
|
+
LIH R6, 4 ; R6 = 0x0400 glyph base
|
|
29
|
+
LDB R0, 0(R6) ; width
|
|
30
|
+
BZ R0, init_glyph
|
|
31
|
+
JMP init_state
|
|
32
|
+
|
|
33
|
+
; Default 16x16 ball glyph. Header = width,height, then 16 rows x 2 bytes.
|
|
34
|
+
init_glyph:
|
|
35
|
+
LIL R6, 0
|
|
36
|
+
LIH R6, 4
|
|
37
|
+
LIL R0, 16
|
|
38
|
+
STB R0, 0(R6) ; width
|
|
39
|
+
STB R0, 1(R6) ; height
|
|
40
|
+
ADDI R6, 2
|
|
41
|
+
|
|
42
|
+
LIL R0, 3
|
|
43
|
+
STB R0, 0(R6)
|
|
44
|
+
ADDI R6, 1
|
|
45
|
+
LIL R0, 192
|
|
46
|
+
STB R0, 0(R6)
|
|
47
|
+
ADDI R6, 1
|
|
48
|
+
|
|
49
|
+
LIL R0, 15
|
|
50
|
+
STB R0, 0(R6)
|
|
51
|
+
ADDI R6, 1
|
|
52
|
+
LIL R0, 240
|
|
53
|
+
STB R0, 0(R6)
|
|
54
|
+
ADDI R6, 1
|
|
55
|
+
|
|
56
|
+
LIL R0, 31
|
|
57
|
+
STB R0, 0(R6)
|
|
58
|
+
ADDI R6, 1
|
|
59
|
+
LIL R0, 248
|
|
60
|
+
STB R0, 0(R6)
|
|
61
|
+
ADDI R6, 1
|
|
62
|
+
|
|
63
|
+
LIL R0, 63
|
|
64
|
+
STB R0, 0(R6)
|
|
65
|
+
ADDI R6, 1
|
|
66
|
+
LIL R0, 252
|
|
67
|
+
STB R0, 0(R6)
|
|
68
|
+
ADDI R6, 1
|
|
69
|
+
|
|
70
|
+
LIL R0, 127
|
|
71
|
+
STB R0, 0(R6)
|
|
72
|
+
ADDI R6, 1
|
|
73
|
+
LIL R0, 254
|
|
74
|
+
STB R0, 0(R6)
|
|
75
|
+
ADDI R6, 1
|
|
76
|
+
|
|
77
|
+
LIL R0, 127
|
|
78
|
+
STB R0, 0(R6)
|
|
79
|
+
ADDI R6, 1
|
|
80
|
+
LIL R0, 254
|
|
81
|
+
STB R0, 0(R6)
|
|
82
|
+
ADDI R6, 1
|
|
83
|
+
|
|
84
|
+
LIL R0, 255
|
|
85
|
+
STB R0, 0(R6)
|
|
86
|
+
ADDI R6, 1
|
|
87
|
+
STB R0, 0(R6)
|
|
88
|
+
ADDI R6, 1
|
|
89
|
+
|
|
90
|
+
LIL R0, 255
|
|
91
|
+
STB R0, 0(R6)
|
|
92
|
+
ADDI R6, 1
|
|
93
|
+
STB R0, 0(R6)
|
|
94
|
+
ADDI R6, 1
|
|
95
|
+
|
|
96
|
+
LIL R0, 255
|
|
97
|
+
STB R0, 0(R6)
|
|
98
|
+
ADDI R6, 1
|
|
99
|
+
STB R0, 0(R6)
|
|
100
|
+
ADDI R6, 1
|
|
101
|
+
|
|
102
|
+
LIL R0, 255
|
|
103
|
+
STB R0, 0(R6)
|
|
104
|
+
ADDI R6, 1
|
|
105
|
+
STB R0, 0(R6)
|
|
106
|
+
ADDI R6, 1
|
|
107
|
+
|
|
108
|
+
LIL R0, 127
|
|
109
|
+
STB R0, 0(R6)
|
|
110
|
+
ADDI R6, 1
|
|
111
|
+
LIL R0, 254
|
|
112
|
+
STB R0, 0(R6)
|
|
113
|
+
ADDI R6, 1
|
|
114
|
+
|
|
115
|
+
LIL R0, 127
|
|
116
|
+
STB R0, 0(R6)
|
|
117
|
+
ADDI R6, 1
|
|
118
|
+
LIL R0, 254
|
|
119
|
+
STB R0, 0(R6)
|
|
120
|
+
ADDI R6, 1
|
|
121
|
+
|
|
122
|
+
LIL R0, 63
|
|
123
|
+
STB R0, 0(R6)
|
|
124
|
+
ADDI R6, 1
|
|
125
|
+
LIL R0, 252
|
|
126
|
+
STB R0, 0(R6)
|
|
127
|
+
ADDI R6, 1
|
|
128
|
+
|
|
129
|
+
LIL R0, 31
|
|
130
|
+
STB R0, 0(R6)
|
|
131
|
+
ADDI R6, 1
|
|
132
|
+
LIL R0, 248
|
|
133
|
+
STB R0, 0(R6)
|
|
134
|
+
ADDI R6, 1
|
|
135
|
+
|
|
136
|
+
LIL R0, 15
|
|
137
|
+
STB R0, 0(R6)
|
|
138
|
+
ADDI R6, 1
|
|
139
|
+
LIL R0, 240
|
|
140
|
+
STB R0, 0(R6)
|
|
141
|
+
ADDI R6, 1
|
|
142
|
+
|
|
143
|
+
LIL R0, 3
|
|
144
|
+
STB R0, 0(R6)
|
|
145
|
+
ADDI R6, 1
|
|
146
|
+
LIL R0, 192
|
|
147
|
+
STB R0, 0(R6)
|
|
148
|
+
|
|
149
|
+
; ---- Initial state --------------------------------------------------
|
|
150
|
+
init_state:
|
|
151
|
+
LIL R7, 128
|
|
152
|
+
LIH R7, 5 ; R7 = 0x0580 state base
|
|
153
|
+
|
|
154
|
+
LIL R0, 0
|
|
155
|
+
STB R0, 0(R7) ; x byte-column = 0
|
|
156
|
+
STB R0, 1(R7) ; y bottom row = 0
|
|
157
|
+
|
|
158
|
+
LIL R0, 1
|
|
159
|
+
STB R0, 2(R7) ; dx = right
|
|
160
|
+
STB R0, 3(R7) ; dy = up
|
|
161
|
+
|
|
162
|
+
; ---- Animation loop -------------------------------------------------
|
|
163
|
+
main_loop:
|
|
164
|
+
LIL R7, 128
|
|
165
|
+
LIH R7, 5 ; state base
|
|
166
|
+
|
|
167
|
+
LDB R1, 0(R7) ; R1 = x byte-column
|
|
168
|
+
LDB R2, 1(R7) ; R2 = y bottom row
|
|
169
|
+
|
|
170
|
+
; ---- Erase old glyph only ------------------------------------------
|
|
171
|
+
; This is much less flickery than clearing the whole framebuffer.
|
|
172
|
+
erase_setup:
|
|
173
|
+
LIL R7, 0
|
|
174
|
+
LIH R7, 4 ; glyph base
|
|
175
|
+
LDB R4, 0(R7) ; width
|
|
176
|
+
ADDI R4, 7
|
|
177
|
+
SHR R4, 3 ; row_bytes
|
|
178
|
+
LDB R5, 1(R7) ; height
|
|
179
|
+
|
|
180
|
+
MOV R6, R2
|
|
181
|
+
ADD R6, R6, R5
|
|
182
|
+
ADDI R6, -1 ; top display row = y + height - 1
|
|
183
|
+
SHL R6, 3 ; row * 8 bytes
|
|
184
|
+
LIL R0, 0
|
|
185
|
+
LIH R0, 6 ; framebuffer base
|
|
186
|
+
ADD R6, R6, R0
|
|
187
|
+
ADD R6, R6, R1
|
|
188
|
+
LIL R0, 0 ; erase byte
|
|
189
|
+
|
|
190
|
+
erase_row:
|
|
191
|
+
BZ R5, reload_state
|
|
192
|
+
MOV R3, R4 ; bytes remaining in this glyph row
|
|
193
|
+
|
|
194
|
+
erase_byte:
|
|
195
|
+
BZ R3, erase_row_done
|
|
196
|
+
STB R0, 0(R6)
|
|
197
|
+
ADDI R6, 1
|
|
198
|
+
ADDI R3, -1
|
|
199
|
+
JMP erase_byte
|
|
200
|
+
|
|
201
|
+
erase_row_done:
|
|
202
|
+
SUB R6, R6, R4 ; back to row start
|
|
203
|
+
ADDI R6, -8 ; next lower display row
|
|
204
|
+
ADDI R5, -1
|
|
205
|
+
JMP erase_row
|
|
206
|
+
|
|
207
|
+
reload_state:
|
|
208
|
+
LIL R7, 128
|
|
209
|
+
LIH R7, 5
|
|
210
|
+
LDB R1, 0(R7) ; R1 = x byte-column
|
|
211
|
+
LDB R2, 1(R7) ; R2 = y bottom row
|
|
212
|
+
LDB R3, 2(R7) ; R3 = dx
|
|
213
|
+
LDB R4, 3(R7) ; R4 = dy
|
|
214
|
+
|
|
215
|
+
; ---- Move x and bounce at left/right walls -------------------------
|
|
216
|
+
move_x:
|
|
217
|
+
BZ R3, move_left
|
|
218
|
+
ADDI R1, 1
|
|
219
|
+
JMP check_x
|
|
220
|
+
|
|
221
|
+
move_left:
|
|
222
|
+
ADDI R1, -1
|
|
223
|
+
|
|
224
|
+
check_x:
|
|
225
|
+
BN R1, hit_left
|
|
226
|
+
|
|
227
|
+
LIL R6, 0
|
|
228
|
+
LIH R6, 4 ; glyph base
|
|
229
|
+
LDB R5, 0(R6) ; glyph width
|
|
230
|
+
ADDI R5, 7
|
|
231
|
+
SHR R5, 3 ; row_bytes = ceil(width / 8)
|
|
232
|
+
LIL R6, 8
|
|
233
|
+
SUB R5, R6, R5 ; max x byte-column = 8 - row_bytes
|
|
234
|
+
SUB R5, R5, R1 ; max_x - x
|
|
235
|
+
BN R5, hit_right
|
|
236
|
+
JMP x_done
|
|
237
|
+
|
|
238
|
+
hit_left:
|
|
239
|
+
LIL R1, 0
|
|
240
|
+
LIL R3, 1 ; dx = right
|
|
241
|
+
JMP x_done
|
|
242
|
+
|
|
243
|
+
hit_right:
|
|
244
|
+
LIL R6, 0
|
|
245
|
+
LIH R6, 4
|
|
246
|
+
LDB R1, 0(R6)
|
|
247
|
+
ADDI R1, 7
|
|
248
|
+
SHR R1, 3 ; row_bytes
|
|
249
|
+
LIL R5, 8
|
|
250
|
+
SUB R1, R5, R1 ; x = max_x
|
|
251
|
+
LIL R3, 0 ; dx = left
|
|
252
|
+
|
|
253
|
+
x_done:
|
|
254
|
+
|
|
255
|
+
; ---- Move y and bounce at bottom/top walls -------------------------
|
|
256
|
+
BZ R4, move_down
|
|
257
|
+
ADDI R2, 1
|
|
258
|
+
JMP check_y
|
|
259
|
+
|
|
260
|
+
move_down:
|
|
261
|
+
ADDI R2, -1
|
|
262
|
+
|
|
263
|
+
check_y:
|
|
264
|
+
BN R2, hit_bottom
|
|
265
|
+
|
|
266
|
+
LIL R6, 0
|
|
267
|
+
LIH R6, 4
|
|
268
|
+
LDB R5, 1(R6) ; glyph height
|
|
269
|
+
LIL R6, 64
|
|
270
|
+
SUB R5, R6, R5 ; max y = 64 - height
|
|
271
|
+
SUB R5, R5, R2 ; max_y - y
|
|
272
|
+
BN R5, hit_top
|
|
273
|
+
JMP y_done
|
|
274
|
+
|
|
275
|
+
hit_bottom:
|
|
276
|
+
LIL R2, 0
|
|
277
|
+
LIL R4, 1 ; dy = up
|
|
278
|
+
JMP y_done
|
|
279
|
+
|
|
280
|
+
hit_top:
|
|
281
|
+
LIL R6, 0
|
|
282
|
+
LIH R6, 4
|
|
283
|
+
LDB R2, 1(R6)
|
|
284
|
+
LIL R5, 64
|
|
285
|
+
SUB R2, R5, R2 ; y = max_y
|
|
286
|
+
LIL R4, 0 ; dy = down
|
|
287
|
+
|
|
288
|
+
y_done:
|
|
289
|
+
LIL R7, 128
|
|
290
|
+
LIH R7, 5
|
|
291
|
+
STB R1, 0(R7)
|
|
292
|
+
STB R2, 1(R7)
|
|
293
|
+
STB R3, 2(R7)
|
|
294
|
+
STB R4, 3(R7)
|
|
295
|
+
|
|
296
|
+
; ---- Draw glyph into framebuffer -----------------------------------
|
|
297
|
+
; Registers during draw:
|
|
298
|
+
; R1 = x byte-column
|
|
299
|
+
; R2 = y bottom row
|
|
300
|
+
; R4 = row_bytes
|
|
301
|
+
; R5 = rows remaining
|
|
302
|
+
; R6 = framebuffer row pointer
|
|
303
|
+
; R7 = glyph source pointer
|
|
304
|
+
draw_setup:
|
|
305
|
+
LIL R7, 0
|
|
306
|
+
LIH R7, 4 ; glyph base
|
|
307
|
+
LDB R4, 0(R7) ; width
|
|
308
|
+
ADDI R4, 7
|
|
309
|
+
SHR R4, 3 ; row_bytes
|
|
310
|
+
LDB R5, 1(R7) ; height
|
|
311
|
+
ADDI R7, 2 ; source points at first glyph row, top first
|
|
312
|
+
|
|
313
|
+
MOV R6, R2
|
|
314
|
+
ADD R6, R6, R5
|
|
315
|
+
ADDI R6, -1 ; top display row = y + height - 1
|
|
316
|
+
SHL R6, 3 ; row * 8 bytes
|
|
317
|
+
LIL R0, 0
|
|
318
|
+
LIH R0, 6 ; framebuffer base
|
|
319
|
+
ADD R6, R6, R0
|
|
320
|
+
ADD R6, R6, R1
|
|
321
|
+
|
|
322
|
+
draw_row:
|
|
323
|
+
BZ R5, delay_setup
|
|
324
|
+
MOV R3, R4 ; bytes remaining in this glyph row
|
|
325
|
+
|
|
326
|
+
draw_byte:
|
|
327
|
+
BZ R3, row_done
|
|
328
|
+
LDB R0, 0(R7)
|
|
329
|
+
NOT R0, R0
|
|
330
|
+
STB R0, 0(R6)
|
|
331
|
+
ADDI R7, 1
|
|
332
|
+
ADDI R6, 1
|
|
333
|
+
ADDI R3, -1
|
|
334
|
+
JMP draw_byte
|
|
335
|
+
|
|
336
|
+
row_done:
|
|
337
|
+
SUB R6, R6, R4 ; back to row start
|
|
338
|
+
ADDI R6, -8 ; next lower display row
|
|
339
|
+
ADDI R5, -1
|
|
340
|
+
JMP draw_row
|
|
341
|
+
|
|
342
|
+
; ---- Delay so motion is visible ------------------------------------
|
|
343
|
+
delay_setup:
|
|
344
|
+
LIL R6, 80
|
|
345
|
+
|
|
346
|
+
delay_loop:
|
|
347
|
+
ADDI R6, -1
|
|
348
|
+
BZ R6, main_loop
|
|
349
|
+
JMP delay_loop
|