Skip to content

Commit 7aceece

Browse files
authored
Merge pull request #2 from sql-hkr/feat/avr-instructions
Improve CPU flag handling and expand instruction set #1
2 parents ea69aea + a187737 commit 7aceece

13 files changed

Lines changed: 1362 additions & 325 deletions

README.md

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
Tiny8 is a minimal, easy-to-use library for working with compact data structures and simple in-memory storage patterns. It is designed for learning, experimentation, and small-scale projects where a lightweight dependency footprint is desirable. This documentation covers installation, examples, and the API to help you get started quickly.
99

10-
![](/docs/_static/examples/bubblesort.gif)
10+
![bubblesort](/docs/_static/examples/bubblesort.gif)
1111

1212
## Installation
1313

@@ -59,66 +59,66 @@ bubblesort.asm:
5959
```asm
6060
; Bubble sort using RAM (addresses 100..131) - 32 elements
6161
; Purpose: fill RAM[100..131] with pseudo-random bytes and sort them
62-
; Registers:
63-
; R0 - base address (start = 100)
64-
; R1 - index / loop counter for initialization
65-
; R2 - PRNG state (seed)
66-
; R3..R8 - temporary registers used in loops and swaps
67-
; R9 - PRNG multiplier (kept aside to avoid clobber in MUL)
62+
; Registers (use R16..R31 for LDI immediates):
63+
; R16 - base address (start = 100)
64+
; R17 - index / loop counter for initialization
65+
; R18 - PRNG state (seed)
66+
; R19..R24 - temporary registers used in loops and swaps
67+
; R25 - PRNG multiplier (kept aside to avoid clobber in MUL)
6868
;
6969
; The code below is split into two phases:
7070
; 1) init_loop: generate and store 32 pseudo-random bytes at RAM[100..131]
7171
; 2) outer/inner loops: perform a simple bubble sort over those 32 bytes
7272
7373
; initialize pointers and PRNG
74-
ldi r0, 100 ; base address
75-
ldi r1, 0 ; index = 0
76-
ldi r2, 123 ; PRNG seed
77-
ldi r9, 75 ; PRNG multiplier (kept in r9 so mul doesn't clobber it)
74+
ldi r16, 100 ; base address
75+
ldi r17, 0 ; index = 0
76+
ldi r18, 123 ; PRNG seed
77+
ldi r25, 75 ; PRNG multiplier (kept in r25 so mul doesn't clobber it)
7878
7979
init_loop:
8080
; PRNG step: r2 := lowbyte(r2 * 75), then tweak
81-
mul r2, r9 ; r2 = low byte of (r2 * 75)
82-
inc r2 ; small increment to avoid repeating patterns
81+
mul r18, r25 ; r18 = low byte of (r18 * 75)
82+
inc r18 ; small increment to avoid repeating patterns
8383
; store generated byte into memory at base + index
84-
st r0, r2 ; RAM[base] = r2
85-
inc r0 ; advance base pointer
86-
inc r1 ; increment index
87-
ldi r7, 32
88-
cp r1, r7
84+
st r16, r18 ; RAM[base] = r18
85+
inc r16 ; advance base pointer
86+
inc r17 ; increment index
87+
ldi r23, 32
88+
cp r17, r23
8989
brne init_loop
9090
9191
; Bubble sort for 32 elements (perform passes until i == 31)
92-
ldi r2, 0 ; i = 0 (outer loop counter)
92+
ldi r18, 0 ; i = 0 (outer loop counter)
9393
outer_loop:
94-
ldi r3, 0 ; j = 0 (inner loop counter)
94+
ldi r19, 0 ; j = 0 (inner loop counter)
9595
inner_loop:
9696
; compute address of element A = base + j
97-
ldi r4, 100
98-
add r4, r3
99-
ld r5, r4 ; r5 = A
97+
ldi r20, 100
98+
add r20, r19
99+
ld r21, r20 ; r21 = A
100100
; compute address of element B = base + j + 1
101-
ldi r6, 100
102-
add r6, r3
103-
ldi r7, 1
104-
add r6, r7
105-
ld r8, r6 ; r8 = B
101+
ldi r22, 100
102+
add r22, r19
103+
ldi r23, 1
104+
add r22, r23
105+
ld r24, r22 ; r24 = B
106106
; compare A and B (we'll swap if A > B)
107-
cp r8, r5 ; sets carry if r8 < r5 (unsigned)
108-
brcs no_swap ; branch if carry set => r8 < r5 => A > B? (keep original order)
107+
cp r24, r21 ; sets carry if r24 < r21 (unsigned)
108+
brcs no_swap ; branch if carry set => r24 < r21 => A > B? (keep original order)
109109
; swap A and B: store B into A's address, A into B's address
110-
st r4, r8
111-
st r6, r5
110+
st r20, r24
111+
st r22, r21
112112
no_swap:
113-
inc r3
114-
ldi r7, 31
115-
cp r3, r7
113+
inc r19
114+
ldi r23, 31
115+
cp r19, r23
116116
breq end_inner
117117
jmp inner_loop
118118
end_inner:
119-
inc r2
120-
ldi r7, 31
121-
cp r2, r7
119+
inc r18
120+
ldi r23, 31
121+
cp r18, r23
122122
breq done
123123
jmp outer_loop
124124
@@ -153,7 +153,7 @@ viz.animate_combined(
153153
Example Output:
154154

155155
```bash
156-
[6, 10, 15, 23, 26, 34, 50, 54, 94, 102, 106, 127, 130, 135, 139, 142, 150, 155, 159, 167, 171, 186, 187, 190, 195, 210, 211, 227, 238, 239, 243, 247]
156+
[247, 243, 239, 238, 227, 211, 210, 195, 190, 187, 186, 171, 167, 159, 155, 150, 142, 139, 135, 130, 127, 106, 102, 94, 54, 50, 34, 26, 23, 15, 10, 6]
157157
```
158158

159159
## API Reference
55.3 KB
Loading

docs/examples/bubblesort.rst

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,73 +11,74 @@ This example demonstrates a simple bubble sort algorithm implemented in assembly
1111
1212
; Bubble sort using RAM (addresses 100..131) - 32 elements
1313
; Purpose: fill RAM[100..131] with pseudo-random bytes and sort them
14-
; Registers:
15-
; R0 - base address (start = 100)
16-
; R1 - index / loop counter for initialization
17-
; R2 - PRNG state (seed)
18-
; R3..R8 - temporary registers used in loops and swaps
19-
; R9 - PRNG multiplier (kept aside to avoid clobber in MUL)
14+
; Registers (use R16..R31 for LDI immediates):
15+
; R16 - base address (start = 100)
16+
; R17 - index / loop counter for initialization
17+
; R18 - PRNG state (seed)
18+
; R19..R24 - temporary registers used in loops and swaps
19+
; R25 - PRNG multiplier (kept aside to avoid clobber in MUL)
2020
;
2121
; The code below is split into two phases:
2222
; 1) init_loop: generate and store 32 pseudo-random bytes at RAM[100..131]
2323
; 2) outer/inner loops: perform a simple bubble sort over those 32 bytes
2424
2525
; initialize pointers and PRNG
26-
ldi r0, 100 ; base address
27-
ldi r1, 0 ; index = 0
28-
ldi r2, 123 ; PRNG seed
29-
ldi r9, 75 ; PRNG multiplier (kept in r9 so mul doesn't clobber it)
26+
ldi r16, 100 ; base address
27+
ldi r17, 0 ; index = 0
28+
ldi r18, 123 ; PRNG seed
29+
ldi r25, 75 ; PRNG multiplier (kept in r25 so mul doesn't clobber it)
3030
3131
init_loop:
3232
; PRNG step: r2 := lowbyte(r2 * 75), then tweak
33-
mul r2, r9 ; r2 = low byte of (r2 * 75)
34-
inc r2 ; small increment to avoid repeating patterns
33+
mul r18, r25 ; r18 = low byte of (r18 * 75)
34+
inc r18 ; small increment to avoid repeating patterns
3535
; store generated byte into memory at base + index
36-
st r0, r2 ; RAM[base] = r2
37-
inc r0 ; advance base pointer
38-
inc r1 ; increment index
39-
ldi r7, 32
40-
cp r1, r7
36+
st r16, r18 ; RAM[base] = r18
37+
inc r16 ; advance base pointer
38+
inc r17 ; increment index
39+
ldi r23, 32
40+
cp r17, r23
4141
brne init_loop
4242
4343
; Bubble sort for 32 elements (perform passes until i == 31)
44-
ldi r2, 0 ; i = 0 (outer loop counter)
44+
ldi r18, 0 ; i = 0 (outer loop counter)
4545
outer_loop:
46-
ldi r3, 0 ; j = 0 (inner loop counter)
46+
ldi r19, 0 ; j = 0 (inner loop counter)
4747
inner_loop:
4848
; compute address of element A = base + j
49-
ldi r4, 100
50-
add r4, r3
51-
ld r5, r4 ; r5 = A
49+
ldi r20, 100
50+
add r20, r19
51+
ld r21, r20 ; r21 = A
5252
; compute address of element B = base + j + 1
53-
ldi r6, 100
54-
add r6, r3
55-
ldi r7, 1
56-
add r6, r7
57-
ld r8, r6 ; r8 = B
53+
ldi r22, 100
54+
add r22, r19
55+
ldi r23, 1
56+
add r22, r23
57+
ld r24, r22 ; r24 = B
5858
; compare A and B (we'll swap if A > B)
59-
cp r8, r5 ; sets carry if r8 < r5 (unsigned)
60-
brcs no_swap ; branch if carry set => r8 < r5 => A > B? (keep original order)
59+
cp r24, r21 ; sets carry if r24 < r21 (unsigned)
60+
brcs no_swap ; branch if carry set => r24 < r21 => A > B? (keep original order)
6161
; swap A and B: store B into A's address, A into B's address
62-
st r4, r8
63-
st r6, r5
62+
st r20, r24
63+
st r22, r21
6464
no_swap:
65-
inc r3
66-
ldi r7, 31
67-
cp r3, r7
65+
inc r19
66+
ldi r23, 31
67+
cp r19, r23
6868
breq end_inner
6969
jmp inner_loop
7070
end_inner:
71-
inc r2
72-
ldi r7, 31
73-
cp r2, r7
71+
inc r18
72+
ldi r23, 31
73+
cp r18, r23
7474
breq done
7575
jmp outer_loop
7676
7777
done:
7878
jmp done
7979
8080
81+
8182
.. code-block:: python
8283
:caption: bubblesort.py
8384
@@ -105,4 +106,4 @@ This example demonstrates a simple bubble sort algorithm implemented in assembly
105106
.. code-block:: bash
106107
:caption: Example Output
107108
108-
[6, 10, 15, 23, 26, 34, 50, 54, 94, 102, 106, 127, 130, 135, 139, 142, 150, 155, 159, 167, 171, 186, 187, 190, 195, 210, 211, 227, 238, 239, 243, 247]
109+
[247, 243, 239, 238, 227, 211, 210, 195, 190, 187, 186, 171, 167, 159, 155, 150, 142, 139, 135, 130, 127, 106, 102, 94, 54, 50, 34, 26, 23, 15, 10, 6]

examples/bubblesort.asm

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,65 @@
11
; Bubble sort using RAM (addresses 100..131) - 32 elements
22
; Purpose: fill RAM[100..131] with pseudo-random bytes and sort them
3-
; Registers:
4-
; R0 - base address (start = 100)
5-
; R1 - index / loop counter for initialization
6-
; R2 - PRNG state (seed)
7-
; R3..R8 - temporary registers used in loops and swaps
8-
; R9 - PRNG multiplier (kept aside to avoid clobber in MUL)
3+
; Registers (use R16..R31 for LDI immediates):
4+
; R16 - base address (start = 100)
5+
; R17 - index / loop counter for initialization
6+
; R18 - PRNG state (seed)
7+
; R19..R24 - temporary registers used in loops and swaps
8+
; R25 - PRNG multiplier (kept aside to avoid clobber in MUL)
99
;
1010
; The code below is split into two phases:
1111
; 1) init_loop: generate and store 32 pseudo-random bytes at RAM[100..131]
1212
; 2) outer/inner loops: perform a simple bubble sort over those 32 bytes
1313

1414
; initialize pointers and PRNG
15-
ldi r0, 100 ; base address
16-
ldi r1, 0 ; index = 0
17-
ldi r2, 123 ; PRNG seed
18-
ldi r9, 75 ; PRNG multiplier (kept in r9 so mul doesn't clobber it)
15+
ldi r16, 100 ; base address
16+
ldi r17, 0 ; index = 0
17+
ldi r18, 123 ; PRNG seed
18+
ldi r25, 75 ; PRNG multiplier (kept in r25 so mul doesn't clobber it)
1919

2020
init_loop:
2121
; PRNG step: r2 := lowbyte(r2 * 75), then tweak
22-
mul r2, r9 ; r2 = low byte of (r2 * 75)
23-
inc r2 ; small increment to avoid repeating patterns
22+
mul r18, r25 ; r18 = low byte of (r18 * 75)
23+
inc r18 ; small increment to avoid repeating patterns
2424
; store generated byte into memory at base + index
25-
st r0, r2 ; RAM[base] = r2
26-
inc r0 ; advance base pointer
27-
inc r1 ; increment index
28-
ldi r7, 32
29-
cp r1, r7
25+
st r16, r18 ; RAM[base] = r18
26+
inc r16 ; advance base pointer
27+
inc r17 ; increment index
28+
ldi r23, 32
29+
cp r17, r23
3030
brne init_loop
3131

3232
; Bubble sort for 32 elements (perform passes until i == 31)
33-
ldi r2, 0 ; i = 0 (outer loop counter)
33+
ldi r18, 0 ; i = 0 (outer loop counter)
3434
outer_loop:
35-
ldi r3, 0 ; j = 0 (inner loop counter)
35+
ldi r19, 0 ; j = 0 (inner loop counter)
3636
inner_loop:
3737
; compute address of element A = base + j
38-
ldi r4, 100
39-
add r4, r3
40-
ld r5, r4 ; r5 = A
38+
ldi r20, 100
39+
add r20, r19
40+
ld r21, r20 ; r21 = A
4141
; compute address of element B = base + j + 1
42-
ldi r6, 100
43-
add r6, r3
44-
ldi r7, 1
45-
add r6, r7
46-
ld r8, r6 ; r8 = B
42+
ldi r22, 100
43+
add r22, r19
44+
ldi r23, 1
45+
add r22, r23
46+
ld r24, r22 ; r24 = B
4747
; compare A and B (we'll swap if A > B)
48-
cp r8, r5 ; sets carry if r8 < r5 (unsigned)
49-
brcs no_swap ; branch if carry set => r8 < r5 => A > B? (keep original order)
48+
cp r24, r21 ; sets carry if r24 < r21 (unsigned)
49+
brcs no_swap ; branch if carry set => r24 < r21 => A > B? (keep original order)
5050
; swap A and B: store B into A's address, A into B's address
51-
st r4, r8
52-
st r6, r5
51+
st r20, r24
52+
st r22, r21
5353
no_swap:
54-
inc r3
55-
ldi r7, 31
56-
cp r3, r7
54+
inc r19
55+
ldi r23, 31
56+
cp r19, r23
5757
breq end_inner
5858
jmp inner_loop
5959
end_inner:
60-
inc r2
61-
ldi r7, 31
62-
cp r2, r7
60+
inc r18
61+
ldi r23, 31
62+
cp r18, r23
6363
breq done
6464
jmp outer_loop
6565

0 commit comments

Comments
 (0)