diff --git a/asm/tiny16.c b/asm/tiny16.c index 90e5f04..3440a89 100644 --- a/asm/tiny16.c +++ b/asm/tiny16.c @@ -27,9 +27,7 @@ static char* preprocess_source(const char* filename); int main(int argc, char** argv) { make_and_parse_args(argc, argv); - // // Pass 0: Preprocess (expand macros and includes) - // char* source_content = preprocess_source(args.source_filename); if (source_content == NULL) { @@ -72,9 +70,7 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - // // Pass 1: Collect labels and parse data section - // parser.lexer = lexer_new(source_content, strlen(source_content)); tiny16_parser_next(&parser); @@ -141,9 +137,7 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - // // Pass 2: Emit code section - // parser.current_section = TINY16_PARSER_SECTION_CODE; parser.code_pc = TINY16_MEMORY_CODE_BEGIN; diff --git a/asm/tutorial/01_load_and_halt.asm b/asm/tutorial/01_load_and_halt.asm index 76f7027..1e7bb8a 100644 --- a/asm/tutorial/01_load_and_halt.asm +++ b/asm/tutorial/01_load_and_halt.asm @@ -1,15 +1,12 @@ ; Tutorial 01: Load and Halt ; Level: 1 - Fundamentals -; ; Goal: Load the value 42 into register R0, then halt the program -; ; Instructions to use: LOADI, HALT ; Expected result: R0 = 42 -; ; Hint: LOADI R, imm8 loads an 8-bit immediate value into a register ; Hint: HALT stops program execution section .code -loadi r0, 42 ; Load 42 into R0 -halt ; Halt the program +loadi r0, 42 +halt diff --git a/asm/tutorial/02_add_two_numbers.asm b/asm/tutorial/02_add_two_numbers.asm index 530b2e6..b9c7733 100644 --- a/asm/tutorial/02_add_two_numbers.asm +++ b/asm/tutorial/02_add_two_numbers.asm @@ -1,17 +1,14 @@ ; Tutorial 02: Add Two Numbers ; Level: 1 - Fundamentals -; ; Goal: Load 7 into R0, load 8 into R1, then add them (result = 15 in R0) -; ; Instructions to use: LOADI, ADD, HALT ; Expected result: R0 = 15, R1 = 8 -; ; Hint: ADD R1, R2 means R1 = R1 + R2 (result goes in first register) ; Hint: ADD sets the Z flag if result is 0, C flag if result overflows section .code -loadi r0, 7 ; Load 7 into R0 -loadi r1, 8 ; Load 8 into R1 -add r0, r1 ; Add R1 to R0 (R0 = R0 + R1) -halt ; Halt the program +loadi r0, 7 +loadi r1, 8 +add r0, r1 +halt diff --git a/asm/tutorial/03_copy_register.asm b/asm/tutorial/03_copy_register.asm index a922567..e7d83aa 100644 --- a/asm/tutorial/03_copy_register.asm +++ b/asm/tutorial/03_copy_register.asm @@ -1,16 +1,13 @@ ; Exercise 03: Copy Register ; Level: 1 - Fundamentals -; ; Goal: Load 25 into R0, then copy it to R1 using MOV -; ; Instructions to use: LOADI, MOV, HALT ; Expected result: R0 = 25, R1 = 25 -; ; Hint: MOV R1, R2 means R1 = R2 (copy R2 to R1) ; Hint: MOV does not affect flags or modify R2 section .code -loadi r0, 25 ; Load 25 into R0 -mov r1, r0 ; Copy R0 to R1 -halt ; Halt the program +loadi r0, 25 +mov r1, r0 +halt diff --git a/asm/tutorial/04_simple_subtraction.asm b/asm/tutorial/04_simple_subtraction.asm index 4880569..5bee867 100644 --- a/asm/tutorial/04_simple_subtraction.asm +++ b/asm/tutorial/04_simple_subtraction.asm @@ -1,17 +1,14 @@ ; Exercise 04: Simple Subtraction ; Level: 1 - Fundamentals -; ; Goal: Load 15 into R0, load 10 into R1, then subtract (R0 = R0 - R1 = 5) -; ; Instructions to use: LOADI, SUB, HALT ; Expected result: R0 = 5, R1 = 10 -; ; Hint: SUB R1, R2 means R1 = R1 - R2 (result goes in first register) ; Hint: SUB sets C flag if borrow occurs (R1 < R2) section .code -loadi r0, 15 ; Load 15 into R0 -loadi r1, 10 ; Load 10 into R1 -sub r0, r1 ; Subtract R1 from R0 (R0 = R0 - R1) -halt ; Halt the program +loadi r0, 15 +loadi r1, 10 +sub r0, r1 +halt diff --git a/asm/tutorial/05_increment_decrement.asm b/asm/tutorial/05_increment_decrement.asm index 40479b2..44f933e 100644 --- a/asm/tutorial/05_increment_decrement.asm +++ b/asm/tutorial/05_increment_decrement.asm @@ -1,19 +1,15 @@ ; Exercise 05: Increment and Decrement ; Level: 1 - Fundamentals -; ; Goal: Load 10 into R0, increment it twice, then decrement it once -; ; Instructions to use: LOADI, INC, DEC, HALT ; Expected result: R0 = 11 -; ; Hint: INC R increments register by 1 (R = R + 1) ; Hint: DEC R decrements register by 1 (R = R - 1) ; Hint: INC and DEC set Z flag if result is 0, but always clear C flag section .code - loadi r0, 10 ; Load 10 into R0 -times 2 inc r0 ; Increment R0 (R0 becomes 11) - ; Increment R0 again (R0 becomes 12) - dec r0 ; Decrement R0 (R0 becomes 11) - halt ; Halt the program + loadi r0, 10 +times 2 inc r0 + dec r0 + halt diff --git a/asm/tutorial/06_zero_register.asm b/asm/tutorial/06_zero_register.asm index 98333c8..8e5109c 100644 --- a/asm/tutorial/06_zero_register.asm +++ b/asm/tutorial/06_zero_register.asm @@ -1,17 +1,14 @@ ; Exercise 06: Zero a Register ; Level: 1 - Fundamentals -; ; Goal: Load any value into R0, then set it to 0 using XOR (not using LOADI R0, 0) -; ; Instructions to use: LOADI, XOR, HALT ; Expected result: R0 = 0 -; ; Hint: XOR R, R always equals 0 (any value XOR itself = 0) ; Hint: This is a common assembly idiom to zero a register ; Hint: XOR sets Z=1 (because result is 0) and clears C flag section .code -loadi r0, 99 ; Load any non-zero value into R0 (e.g., 99) -xor r0, r0 ; XOR R0 with itself to zero it -halt ; Halt the program +loadi r0, 99 +xor r0, r0 +halt diff --git a/asm/tutorial/07_double_number.asm b/asm/tutorial/07_double_number.asm index 58a27dc..114a84e 100644 --- a/asm/tutorial/07_double_number.asm +++ b/asm/tutorial/07_double_number.asm @@ -1,11 +1,8 @@ ; Exercise 07: Double a Number ; Level: 1 - Fundamentals -; ; Goal: Load 10 into R0, then double it to 20 -; ; Instructions to use: LOADI, SHL (or ADD), HALT ; Expected result: R0 = 20 -; ; Hint: You can double a number two ways: ; 1. SHL R0 (shift left = multiply by 2) ; 2. ADD R0, R0 (add to itself) @@ -13,6 +10,6 @@ section .code -loadi r0, 10 ; Load 10 into R0 -shl r0 ; Double R0 using SHL or ADD -halt ; Halt the program +loadi r0, 10 +shl r0 +halt diff --git a/asm/tutorial/08_halve_number.asm b/asm/tutorial/08_halve_number.asm index a6a8f0a..963f39b 100644 --- a/asm/tutorial/08_halve_number.asm +++ b/asm/tutorial/08_halve_number.asm @@ -1,16 +1,13 @@ ; Exercise 08: Halve a Number ; Level: 1 - Fundamentals -; ; Goal: Load 20 into R0, then halve it to 10 -; ; Instructions to use: LOADI, SHR, HALT ; Expected result: R0 = 10 -; ; Hint: SHR R (shift right) divides by 2 (rounds down) ; Hint: SHR sets C flag if bit 0 was 1 before shift (odd number) section .code -loadi r0, 20 ; Load 20 into R0 -shr r0 ; Halve R0 using SHR (shift right) -halt ; Halt the program +loadi r0, 20 +shr r0 +halt diff --git a/asm/tutorial/09_unconditional_jump.asm b/asm/tutorial/09_unconditional_jump.asm index 1f5a73c..e7e1efb 100644 --- a/asm/tutorial/09_unconditional_jump.asm +++ b/asm/tutorial/09_unconditional_jump.asm @@ -1,21 +1,18 @@ ; Exercise 09: Unconditional Jump ; Level: 2 - Control Flow -; ; Goal: Create an infinite loop using JMP and a label ; Load different values in each iteration to show it's looping -; ; Instructions to use: LOADI, JMP, INC, HALT ; Expected result: Infinite loop (will need -m flag to limit execution) -; ; Hint: Labels are defined with a colon: loop: ; Hint: JMP label jumps unconditionally to that label ; Hint: Use the emulator with -m 10 to limit to 10 instructions section .code -loadi r0, 0 ; Load 0 into R0 +loadi r0, 0 loop: - inc r0 ; Increment R0 - jmp loop ; Jump back to loop + inc r0 + jmp loop ; Note: This program never reaches HALT - that's the point! diff --git a/asm/tutorial/10_simple_loop.asm b/asm/tutorial/10_simple_loop.asm index 08c46ed..9be46b6 100644 --- a/asm/tutorial/10_simple_loop.asm +++ b/asm/tutorial/10_simple_loop.asm @@ -1,21 +1,18 @@ ; Exercise 10: Simple Loop ; Level: 2 - Control Flow -; ; Goal: Count down from 10 to 0 using a loop ; Use DEC and JNZ to repeat while R0 is not zero -; ; Instructions to use: LOADI, DEC, JNZ, HALT ; Expected result: R0 = 0 (after counting down from 10) -; ; Hint: DEC sets the Z flag when result is 0 ; Hint: JNZ (Jump if Not Zero) jumps when Z=0 ; Hint: This creates a countdown loop section .code -loadi r0, 10 ; Load 10 into R0 +loadi r0, 10 loop: - dec r0 ; Decrement R0 - jnz loop ; Jump to loop if R0 is not zero (JNZ) -halt ; Halt (R0 should be 0) + dec r0 + jnz loop +halt diff --git a/asm/tutorial/11_count_up.asm b/asm/tutorial/11_count_up.asm index c63d2f4..c4d7ccf 100644 --- a/asm/tutorial/11_count_up.asm +++ b/asm/tutorial/11_count_up.asm @@ -1,24 +1,21 @@ ; Exercise 11: Count Up ; Level: 2 - Control Flow -; ; Goal: Count from 0 up to 10 using INC and CMP ; Stop when R0 equals 10 -; ; Instructions to use: LOADI, INC, CMP, JZ, JMP, HALT ; Expected result: R0 = 10 -; ; Hint: CMP R0, R1 compares R0 with R1, sets Z flag if equal ; Hint: JZ (Jump if Zero) jumps when Z=1 (values are equal) ; Hint: Use JMP to continue loop if not equal section .code -loadi r0, 0 ; Load 0 into R0 (counter) -loadi r1, 10 ; Load 10 into R1 (target) +loadi r0, 0 +loadi r1, 10 loop: - cmp r0, r1 ; Compare R0 with R1 - jz done ; If equal (Z=1), jump to done - inc r0 ; Increment R0 - jmp loop ; Jump back to loop + cmp r0, r1 + jz done + inc r0 + jmp loop done: - halt ; Halt (R0 should be 10) + halt diff --git a/asm/tutorial/12_compare_numbers.asm b/asm/tutorial/12_compare_numbers.asm index fe1b2c9..2d720b1 100644 --- a/asm/tutorial/12_compare_numbers.asm +++ b/asm/tutorial/12_compare_numbers.asm @@ -1,24 +1,21 @@ ; Exercise 12: Compare Numbers ; Level: 2 - Control Flow -; ; Goal: Load two numbers (5 and 8) and store the maximum in R0 ; Use CMP and conditional jumps -; ; Instructions to use: LOADI, CMP, JC, JMP, MOV, HALT ; Expected result: R0 = 8 (the maximum) -; ; Hint: CMP R0, R1 computes R0 - R1 and sets flags ; Hint: If R0 < R1, the C flag is set (borrow occurred) ; Hint: JC (Jump if Carry) can be used for "less than" comparisons section .code -loadi r0, 5 ; Load 5 into R0 -loadi r1, 8 ; Load 8 into R1 -cmp r0, r1 ; Compare R0 with R1 -jc r1_larger ; If R0 < R1 (C=1), jump to r1_larger -jmp done ; Jump to done (R0 >= R1, R0 is max) +loadi r0, 5 +loadi r1, 8 +cmp r0, r1 +jc r1_larger +jmp done r1_larger: - mov r0, r1 ; Move R1 to R0 (R1 is the max) + mov r0, r1 done: - halt ; Halt (R0 should be 8) + halt diff --git a/asm/tutorial/13_if_else.asm b/asm/tutorial/13_if_else.asm index 825a147..cfb57fe 100644 --- a/asm/tutorial/13_if_else.asm +++ b/asm/tutorial/13_if_else.asm @@ -1,26 +1,23 @@ ; Exercise 13: If-Else Logic ; Level: 2 - Control Flow -; ; Goal: Implement if-else logic ; If R0 >= 10, set R2 to 100 ; Else, set R2 to 50 -; ; Instructions to use: LOADI, CMP, JC, JMP, HALT ; Expected result: R2 = 50 (since R0 = 7 < 10) -; ; Hint: Structure is: compare, conditional jump to else, then-block, jump over else, else-block ; Hint: CMP followed by JC tests for "less than" section .code -loadi r0, 7 ; Load 7 into R0 -loadi r1, 10 ; Load 10 into R1 (threshold) -cmp r0, r1 ; Compare R0 with R1 -jc else_block ; If R0 < R1 (C=1), jump to else_block +loadi r0, 7 +loadi r1, 10 +cmp r0, r1 +jc else_block then_block: - loadi r2, 100 ; Load 100 into R2 - jmp done ; Jump to done + loadi r2, 100 + jmp done else_block: - loadi r2, 50 ; Load 50 into R2 + loadi r2, 50 done: - halt ; Halt (R2 should be 50) + halt diff --git a/asm/tutorial/14_for_loop.asm b/asm/tutorial/14_for_loop.asm index 19d2040..f513991 100644 --- a/asm/tutorial/14_for_loop.asm +++ b/asm/tutorial/14_for_loop.asm @@ -1,23 +1,20 @@ ; Exercise 14: For Loop ; Level: 2 - Control Flow -; ; Goal: Sum numbers from 1 to 5 using a for-loop pattern ; R0 = accumulator (sum), R1 = counter, R2 = limit -; ; Instructions to use: LOADI, ADD, INC, CMP, JNZ, HALT ; Expected result: R0 = 15 (1+2+3+4+5) -; ; Hint: For-loop pattern: initialize counter, loop body, increment, test, repeat ; Hint: Sum should include: 1+2+3+4+5 = 15 section .code -loadi r0, 0 ; Load 0 into R0 (sum accumulator) -loadi r1, 1 ; Load 1 into R1 (counter, start at 1) -loadi r2 6 ; Load 6 into R2 (limit, stop when counter reaches 6) +loadi r0, 0 +loadi r1, 1 +loadi r2 6 loop: - add r0, r1 ; Add R1 to R0 (accumulate sum) - inc r1 ; Increment R1 (next number) - cmp r1, r2 ; Compare R1 with R2 - jnz loop ; If not equal, jump back to loop -halt ; Halt (R0 should be 15) + add r0, r1 + inc r1 + cmp r1, r2 + jnz loop +halt diff --git a/asm/tutorial/15_while_loop.asm b/asm/tutorial/15_while_loop.asm index bf04c17..277231b 100644 --- a/asm/tutorial/15_while_loop.asm +++ b/asm/tutorial/15_while_loop.asm @@ -1,23 +1,20 @@ ; Exercise 15: While Loop ; Level: 2 - Control Flow -; ; Goal: Implement a while loop - keep doubling R0 until it reaches or exceeds 100 ; Start with R0 = 3, double it repeatedly -; ; Instructions to use: LOADI, SHL (or ADD), CMP, JNC, JMP, HALT ; Expected result: R0 = 192 (3, 6, 12, 24, 48, 96, 192) -; ; Hint: While-loop pattern: test condition first, then body, then loop back ; Hint: Continue while R0 < 100 (use CMP and JNC) section .code -loadi r0, 3 ; Load 3 into R0 -loadi r1, 100 ; Load 100 into R1 (threshold) +loadi r0, 3 +loadi r1, 100 loop: - cmp r0, r1 ; Compare R0 with R1 (R0 - R1) - jnc done ; If R0 >= R1 (no carry), jump to done - shl r0 ; Double R0 (use SHL or ADD R0, R0) - jmp loop ; Jump back to loop + cmp r0, r1 + jnc done + shl r0 + jmp loop done: - halt ; Halt (R0 should be >= 100, specifically 192) + halt diff --git a/asm/tutorial/16_nested_loops.asm b/asm/tutorial/16_nested_loops.asm index 89c7164..00a7c05 100644 --- a/asm/tutorial/16_nested_loops.asm +++ b/asm/tutorial/16_nested_loops.asm @@ -1,27 +1,24 @@ ; Exercise 16: Nested Loops ; Level: 2 - Control Flow -; ; Goal: Implement nested loops to count iterations ; Outer loop: 3 times, Inner loop: 4 times each ; Count total iterations in R0 (should be 3 * 4 = 12) -; ; Instructions to use: LOADI, INC, DEC, JNZ, HALT ; Expected result: R0 = 12 -; ; Hint: Use R1 for outer loop counter, R2 for inner loop counter ; Hint: Must reload R2 for each outer iteration ; Hint: Nested structure: outer_loop { inner_loop { count++ } } section .code -loadi r0, 0 ; Load 0 into R0 (total count) -loadi r1, 3 ; Load 3 into R1 (outer loop iterations) +loadi r0, 0 +loadi r1, 3 outer_loop: - loadi r2, 4 ; Load 4 into R2 (inner loop iterations - reload each time) + loadi r2, 4 inner_loop: - inc r0 ; Increment R0 (count total iterations) - dec r2 ; Decrement R2 - jnz inner_loop ; If R2 != 0, jump to inner_loop - dec r1 ; Decrement R1 (outer counter) - jnz outer_loop ; If R1 != 0, jump to outer_loop -halt ; Halt (R0 should be 12) + inc r0 + dec r2 + jnz inner_loop + dec r1 + jnz outer_loop +halt diff --git a/asm/tutorial/17_load_from_memory.asm b/asm/tutorial/17_load_from_memory.asm index 0fe04eb..596c77c 100644 --- a/asm/tutorial/17_load_from_memory.asm +++ b/asm/tutorial/17_load_from_memory.asm @@ -1,23 +1,20 @@ ; Exercise 17: Load from Memory ; Level: 3 - Memory & Data Structures -; ; Goal: Load a byte from memory address 0x4000 into R0 ; Use register pair R6:R7 to form the 16-bit address -; ; Instructions to use: LOADI, LOAD, HALT ; Expected result: R0 = 42 (the value at 0x4000) -; ; Hint: Register pairs form 16-bit addresses: ADDR = (Rhigh << 8) | Rlow ; Hint: R6:R7 is the conventional pair for memory operations ; Hint: LOAD R, [PAIR] loads byte from memory into register section .code -loadi r6, 0x40 ; Load 0x40 into R6 (high byte of address) -loadi r7, 0x00 ; Load 0x00 into R7 (low byte of address) -load r0, [r6:r7] ; Load from address [R6:R7] into R0 -halt ; Halt (R0 should be 42) +loadi r6, 0x40 +loadi r7, 0x00 +load r0, [r6:r7] +halt section .data -DB 42 ; Byte at address 0x4000 +DB 42 diff --git a/asm/tutorial/18_store_to_memory.asm b/asm/tutorial/18_store_to_memory.asm index 3c0cc7a..92c0b75 100644 --- a/asm/tutorial/18_store_to_memory.asm +++ b/asm/tutorial/18_store_to_memory.asm @@ -1,25 +1,22 @@ ; Exercise 18: Store to Memory ; Level: 3 - Memory & Data Structures -; ; Goal: Store the value 99 from R0 into memory at address 0x4000 ; Then load it back to verify -; ; Instructions to use: LOADI, STORE, LOAD, HALT ; Expected result: R1 = 99 (loaded back from memory) -; ; Hint: STORE R, [PAIR] stores register value to memory ; Hint: Cannot write to code segment (0x0010-0x3FFF) ; Hint: Data section starts at 0x4000 section .code -loadi r6, 0x40 ; Load 0x40 into R6 (high byte) -loadi r7, 0x00 ; Load 0x00 into R7 (low byte) -loadi r0, 99 ; Load 99 into R0 -store r0, [r6:r7] ; Store R0 to address [R6:R7] -load r1, [r6:r7] ; Load from [R6:R7] into R1 to verify -halt ; Halt (R1 should be 99) +loadi r6, 0x40 +loadi r7, 0x00 +loadi r0, 99 +store r0, [r6:r7] +load r1, [r6:r7] +halt section .data -DB 0 ; Reserve space at 0x4000 (initially 0) +DB 0 diff --git a/asm/tutorial/19_array_access.asm b/asm/tutorial/19_array_access.asm index 61cec51..d72e0cc 100644 --- a/asm/tutorial/19_array_access.asm +++ b/asm/tutorial/19_array_access.asm @@ -1,22 +1,19 @@ ; Exercise 19: Array Access ; Level: 3 - Memory & Data Structures -; ; Goal: Access the 3rd element (index 2) of an array using offset addressing ; Array: [10, 20, 30, 40, 50] at 0x4000 -; ; Instructions to use: LOADI, LOAD with offset, HALT ; Expected result: R0 = 30 (array[2]) -; ; Hint: LOAD R, [PAIR + offset] accesses memory at (PAIR + offset) ; Hint: Array indices: 0=10, 1=20, 2=30, 3=40, 4=50 ; Hint: Offset addressing doesn't modify the register pair section .code -loadi r6, 0x40 ; Load 0x40 into R6 (array base address high) -loadi r7, 0x00 ; Load 0x00 into R7 (array base address low) -load r0, [r6:r7+2] ; Load from [R6:R7 + 2] into R0 (3rd element, offset 2) -halt ; Halt (R0 should be 30) +loadi r6, 0x40 +loadi r7, 0x00 +load r0, [r6:r7+2] +halt section .data diff --git a/asm/tutorial/20_post_increment.asm b/asm/tutorial/20_post_increment.asm index 1a92dbc..8538a64 100644 --- a/asm/tutorial/20_post_increment.asm +++ b/asm/tutorial/20_post_increment.asm @@ -1,24 +1,21 @@ ; Exercise 20: Post-Increment Addressing ; Level: 3 - Memory & Data Structures -; ; Goal: Read first 3 elements of an array using post-increment ; Array: [5, 10, 15, 20, 25] at 0x4000 -; ; Instructions to use: LOADI, LOAD with [PAIR]+, HALT ; Expected result: R0=5, R1=10, R2=15, R6:R7=0x4003 -; ; Hint: [PAIR]+ means: access memory at PAIR, then increment PAIR by 1 ; Hint: Post-increment automatically advances to next array element ; Hint: This is the most efficient way to traverse arrays section .code -loadi r6, 0x40 ; Load 0x40 into R6 (array base high) -loadi r7, 0x00 ; Load 0x00 into R7 (array base low) -load r0, [r6:r7]+ ; Load from [R6:R7]+ into R0 (reads 5, R6:R7 becomes 0x4001) -load r1, [r6:r7]+ ; Load from [R6:R7]+ into R1 (reads 10, R6:R7 becomes 0x4002) -load r2, [r6:r7]+ ; Load from [R6:R7]+ into R2 (reads 15, R6:R7 becomes 0x4003) -halt ; Halt +loadi r6, 0x40 +loadi r7, 0x00 +load r0, [r6:r7]+ +load r1, [r6:r7]+ +load r2, [r6:r7]+ +halt section .data diff --git a/asm/tutorial/21_post_decrement.asm b/asm/tutorial/21_post_decrement.asm index 05405fa..239c11a 100644 --- a/asm/tutorial/21_post_decrement.asm +++ b/asm/tutorial/21_post_decrement.asm @@ -1,24 +1,21 @@ ; Exercise 21: Post-Decrement Addressing ; Level: 3 - Memory & Data Structures -; ; Goal: Read array elements in reverse using post-decrement ; Start at end of array (0x4004) and read backwards -; ; Instructions to use: LOADI, LOAD with [PAIR]-, HALT ; Expected result: R0=25, R1=20, R2=15 -; ; Hint: [PAIR]- means: access memory at PAIR, then decrement PAIR by 1 ; Hint: Useful for reverse traversal, stack operations ; Hint: Array at 0x4000: [5, 10, 15, 20, 25], last element at 0x4004 section .code -loadi r6, 0x40 ; Load 0x40 into R6 (high byte) -loadi r7, 0x04 ; Load 0x04 into R7 (low byte - point to last element) -load r0, [r6:r7]- ; Load from [R6:R7]- into R0 (reads 25, R6:R7 becomes 0x4003) -load r1, [r6:r7]- ; Load from [R6:R7]- into R1 (reads 20, R6:R7 becomes 0x4002) -load r2, [r6:r7]- ; Load from [R6:R7]- into R2 (reads 15, R6:R7 becomes 0x4001) -halt ; Halt +loadi r6, 0x40 +loadi r7, 0x04 +load r0, [r6:r7]- +load r1, [r6:r7]- +load r2, [r6:r7]- +halt section .data diff --git a/asm/tutorial/22_offset_addressing.asm b/asm/tutorial/22_offset_addressing.asm index 03c1e37..22fcf78 100644 --- a/asm/tutorial/22_offset_addressing.asm +++ b/asm/tutorial/22_offset_addressing.asm @@ -1,30 +1,27 @@ ; Exercise 22: Offset Addressing for Structs ; Level: 3 - Memory & Data Structures -; ; Goal: Access struct-like data using offset addressing ; Struct at 0x4000: {id: 1, x: 50, y: 75, color: 255} -; ; Instructions to use: LOADI, LOAD with offsets, HALT ; Expected result: R0=1, R1=50, R2=75, R3=255 -; ; Hint: Offset addressing is perfect for struct field access ; Hint: Base address stays constant, offsets reach different fields ; Hint: [PAIR + N] doesn't modify PAIR section .code -loadi r6, 0x40 ; Load 0x40 into R6 (struct base address high) -loadi r7, 0x00 ; Load 0x00 into R7 (struct base address low) -load r0, [r6:r7+0] ; Load field 0 (id) from [R6:R7 + 0] into R0 -load r1, [r6:r7+1] ; Load field 1 (x) from [R6:R7 + 1] into R1 -load r2, [r6:r7+2] ; Load field 2 (y) from [R6:R7 + 2] into R2 -load r3, [r6:r7+3] ; Load field 3 (color) from [R6:R7 + 3] into R3 -halt ; Halt +loadi r6, 0x40 +loadi r7, 0x00 +load r0, [r6:r7+0] +load r1, [r6:r7+1] +load r2, [r6:r7+2] +load r3, [r6:r7+3] +halt section .data entity: - DB 1 ; offset 0: id - DB 50 ; offset 1: x position - DB 75 ; offset 2: y position - DB 255 ; offset 3: color (white) + DB 1 + DB 50 + DB 75 + DB 255 diff --git a/asm/tutorial/23_array_sum.asm b/asm/tutorial/23_array_sum.asm index d48ffaf..475ed9a 100644 --- a/asm/tutorial/23_array_sum.asm +++ b/asm/tutorial/23_array_sum.asm @@ -1,28 +1,25 @@ ; Exercise 23: Array Sum ; Level: 3 - Memory & Data Structures -; ; Goal: Sum all elements in an array using a loop ; Array: [10, 20, 30, 40, 50] at 0x4000 -; ; Instructions to use: LOADI, LOAD with [PAIR]+, ADD, DEC, JNZ, HALT ; Expected result: R0 = 150 (sum of all elements) -; ; Hint: Use post-increment [R6:R7]+ to traverse array ; Hint: Use R0 for accumulator, R1 for loop counter ; Hint: Pattern: load element, add to sum, decrement counter, repeat section .code -loadi r0, 0 ; Load 0 into R0 (sum accumulator) -loadi r1, 5 ; Load 5 into R1 (array length / loop counter) -loadi r6, 0x40 ; Load 0x40 into R6 (array address high) -loadi r7, 0x00 ; Load 0x00 into R7 (array address low) +loadi r0, 0 +loadi r1, 5 +loadi r6, 0x40 +loadi r7, 0x00 loop: - load r2, [r6:r7]+ ; Load from [R6:R7]+ into R2 - add r0, r2 ; Add R2 to R0 - dec r1 ; Decrement R1 - jnz loop ; Jump to loop if R1 != 0 -halt ; Halt (R0 should be 150) + load r2, [r6:r7]+ + add r0, r2 + dec r1 + jnz loop +halt section .data diff --git a/asm/tutorial/24_array_copy.asm b/asm/tutorial/24_array_copy.asm index 6f0c121..8da3bd4 100644 --- a/asm/tutorial/24_array_copy.asm +++ b/asm/tutorial/24_array_copy.asm @@ -1,32 +1,29 @@ ; Exercise 24: Array Copy ; Level: 3 - Memory & Data Structures -; ; Goal: Copy 5 bytes from source (0x4000) to destination (0x4010) ; Use two register pairs: R6:R7 for source, R4:R5 for dest -; ; Instructions to use: LOADI, LOAD, STORE, post-increment, DEC, JNZ, HALT ; Expected result: Bytes at 0x4010-0x4014 = [10, 20, 30, 40, 50] -; ; Hint: Use R6:R7 for source, R4:R5 for destination ; Hint: Post-increment on both pairs: [R6:R7]+ and [R4:R5]+ ; Hint: Load from source, store to destination, repeat section .code -loadi r0, 5 ; Load 5 into R0 (counter) -loadi r6, 0x40 ; Load 0x40 into R6, 0x00 into R7 (source address 0x4000) +loadi r0, 5 +loadi r6, 0x40 loadi r7, 0x00 -loadi r4, 0x40 ; Load 0x40 into R4, 0x10 into R5 (dest address 0x4010) +loadi r4, 0x40 loadi r5, 0x10 loop: - load r1, [r6:r7]+ ; Load byte from [R6:R7]+ into R1 - store r1, [r4:r5]+ ; Store R1 to [R4:R5]+ - dec r0 ; Decrement R0 - jnz loop ; Jump to loop if R0 != 0 -halt ; Halt + load r1, [r6:r7]+ + store r1, [r4:r5]+ + dec r0 + jnz loop +halt section .data source: DB 10, 20, 30, 40, 50 - TIMES 11 DB 0 ; Padding to reach offset 0x10 -dest: TIMES 5 DB 0 ; Destination buffer + TIMES 11 DB 0 +dest: TIMES 5 DB 0 diff --git a/asm/tutorial/25_push_pop.asm b/asm/tutorial/25_push_pop.asm index a331eb3..0348f79 100644 --- a/asm/tutorial/25_push_pop.asm +++ b/asm/tutorial/25_push_pop.asm @@ -1,12 +1,9 @@ ; Tutorial 25: Push and Pop ; Level: 4 - Stack & Subroutines -; ; Goal: Learn basic stack operations - push values onto stack and pop them back ; Push R0, R1, R2, then pop them back in reverse order -; ; Instructions to use: LOADI, PUSH, POP, HALT ; Expected result: R3=30, R4=20, R5=10 (values popped in reverse order) -; ; Hint: PUSH R stores register value at SP, then decrements SP ; Hint: POP R increments SP, then loads value into register ; Hint: Stack is LIFO: Last In, First Out @@ -14,13 +11,13 @@ section .code -loadi r0, 10 ; Load 10 into R0 -loadi r1, 20 ; Load 20 into R1 -loadi r2, 30 ; Load 30 into R2 -push r0 ; Push R0 (10 goes on stack) -push r1 ; Push R1 (20 goes on stack) -push r2 ; Push R2 (30 goes on stack) -pop r3 ; Pop into R3 (gets 30 - last pushed) -pop r4 ; Pop into R4 (gets 20) -pop r5 ; Pop into R5 (gets 10 - first pushed) -halt ; Halt (R3=30, R4=20, R5=10) +loadi r0, 10 +loadi r1, 20 +loadi r2, 30 +push r0 +push r1 +push r2 +pop r3 +pop r4 +pop r5 +halt diff --git a/asm/tutorial/26_preserve_registers.asm b/asm/tutorial/26_preserve_registers.asm index 2496681..75a1bea 100644 --- a/asm/tutorial/26_preserve_registers.asm +++ b/asm/tutorial/26_preserve_registers.asm @@ -1,22 +1,19 @@ ; Exercise 26: Preserve Registers ; Level: 4 - Stack & Subroutines -; ; Goal: Save register values before modifying them, then restore ; Simulate a function that uses R1 temporarily without clobbering it -; ; Instructions to use: LOADI, PUSH, POP, ADD, HALT ; Expected result: R0=15, R1=100 (R1 preserved despite being used) -; ; Hint: Pattern: PUSH before modifying, POP to restore ; Hint: This is essential for writing reusable functions ; Hint: Caller expects R1 to remain unchanged section .code -loadi r0, 5 ; Load 5 into R0 -loadi r1, 100 ; Load 100 into R1 (important value we need to preserve) -push r1 ; Push R1 (save it before using R1 for temp work) -loadi r1, 10 ; Load 10 into R1 (use R1 as temp) -add r0, r1 ; Add R1 to R0 (R0 = 5 + 10 = 15) -pop r1 ; Pop R1 (restore original value of 100) -halt ; Halt (R0=15, R1=100) +loadi r0, 5 +loadi r1, 100 +push r1 +loadi r1, 10 +add r0, r1 +pop r1 +halt diff --git a/asm/tutorial/27_simple_subroutine.asm b/asm/tutorial/27_simple_subroutine.asm index e70f6d5..b7478a3 100644 --- a/asm/tutorial/27_simple_subroutine.asm +++ b/asm/tutorial/27_simple_subroutine.asm @@ -1,12 +1,9 @@ ; Exercise 27: Simple Subroutine ; Level: 4 - Stack & Subroutines -; ; Goal: Create a subroutine that doubles R0 using CALL and RET ; Main: R0 = 5, call double_it, result R0 = 10 -; ; Instructions to use: LOADI, CALL, RET, ADD, HALT ; Expected result: R0 = 10 -; ; Hint: CALL pushes return address (PC) and jumps to subroutine ; Hint: RET pops return address and jumps back ; Hint: Subroutine can modify registers passed to it @@ -14,10 +11,10 @@ section .code -loadi r0, 5 ; Load 5 into R0 -call double_it ; Call double_it subroutine -halt ; Halt (R0 should be 10) +loadi r0, 5 +call double_it +halt double_it: - add r0, r0 ; Add R0 to itself (R0 = R0 + R0) - ret ; Return to caller + add r0, r0 + ret diff --git a/asm/tutorial/28_subroutine_with_args.asm b/asm/tutorial/28_subroutine_with_args.asm index c879ac9..9d26ad2 100644 --- a/asm/tutorial/28_subroutine_with_args.asm +++ b/asm/tutorial/28_subroutine_with_args.asm @@ -1,23 +1,20 @@ ; Exercise 28: Subroutine with Arguments ; Level: 4 - Stack & Subroutines -; ; Goal: Pass two arguments via registers to an add function ; add_fn(R0=5, R1=7) returns R0=12 -; ; Instructions to use: LOADI, CALL, RET, ADD, HALT ; Expected result: R0 = 12 -; ; Hint: Calling convention: pass args in R0, R1; return result in R0 ; Hint: Function adds R1 to R0 and returns ; Hint: This demonstrates parameter passing section .code -loadi r0, 5 ; Load 5 into R0 (first argument) -loadi r1, 7 ; Load 7 into R1 (second argument) -call add_fn ; Call add_fn -halt ; Halt (R0 should be 12) +loadi r0, 5 +loadi r1, 7 +call add_fn +halt add_fn: - add r0, r1 ; Add R1 to R0 (R0 = R0 + R1) - ret ; Return + add r0, r1 + ret diff --git a/asm/tutorial/29_nested_calls.asm b/asm/tutorial/29_nested_calls.asm index 41f41b5..90f6383 100644 --- a/asm/tutorial/29_nested_calls.asm +++ b/asm/tutorial/29_nested_calls.asm @@ -1,26 +1,23 @@ ; Exercise 29: Nested Subroutine Calls ; Level: 4 - Stack & Subroutines -; ; Goal: Call a function that calls another function (nested calls) ; outer() calls inner(), demonstrating call stack management -; ; Instructions to use: LOADI, CALL, RET, INC, HALT ; Expected result: R0 = 11 (10 + 1 from inner function) -; ; Hint: Each CALL pushes return address on stack ; Hint: Each RET pops correct return address ; Hint: Stack manages multiple return addresses automatically section .code -call outer ; Call outer -halt ; Halt (R0 should be 11) +call outer +halt outer: - loadi r0, 10 ; Load 10 into R0 - call inner ; Call inner (nested call) - ret ; Return to main + loadi r0, 10 + call inner + ret inner: - inc r0 ; Increment R0 (R0 = 11) - ret ; Return to outer + inc r0 + ret diff --git a/asm/tutorial/30_recursive_countdown.asm b/asm/tutorial/30_recursive_countdown.asm index 4203142..2435ac4 100644 --- a/asm/tutorial/30_recursive_countdown.asm +++ b/asm/tutorial/30_recursive_countdown.asm @@ -1,12 +1,9 @@ ; Exercise 30: Recursive Countdown ; Level: 4 - Stack & Subroutines -; ; Goal: Implement countdown(n) recursively ; countdown(5) -> 5, 4, 3, 2, 1, 0 stored in memory -; ; Instructions to use: LOADI, CALL, RET, DEC, OR, JZ, JMP, HALT ; Expected result: R0 = 0 (countdown complete) -; ; Hint: Base case: if R0 == 0, return ; Hint: Recursive case: decrement R0, call countdown ; Hint: Each recursive call uses stack space @@ -14,13 +11,13 @@ section .code -loadi r0, 5 ; Load 5 into R0 -call countdown ; Call countdown -halt ; Halt (R0 should be 0) +loadi r0, 5 +call countdown +halt countdown: - or r0, r0 ; Check if R0 == 0 (sets Z flag if R0 is zero) - jz done ; If R0 == 0, return (base case) - dec r0 ; Decrement R0 - jmp countdown ; Call countdown recursively - done: ret ; Return + or r0, r0 + jz done + dec r0 + jmp countdown + done: ret diff --git a/asm/tutorial/31_recursive_factorial.asm b/asm/tutorial/31_recursive_factorial.asm index cb4e784..5b25ef9 100644 --- a/asm/tutorial/31_recursive_factorial.asm +++ b/asm/tutorial/31_recursive_factorial.asm @@ -1,12 +1,9 @@ ; Exercise 31: Recursive Factorial ; Level: 4 - Stack & Subroutines -; ; Goal: Compute factorial(5) = 120 using recursion ; factorial(n) = n * factorial(n-1), base case: factorial(0) = 1 -; ; Instructions to use: LOADI, CALL, RET, DEC, CMP, JZ, PUSH, POP, HALT ; Expected result: R0 = 120 (5! = 5*4*3*2*1) -; ; Hint: This is ADVANCED - requires preserving R0 across recursive calls ; Hint: Pattern: save R0, decrement, recurse, restore R0, multiply ; Hint: Base case: if R0 <= 1, return 1 @@ -16,22 +13,21 @@ section .code loadi r0, 5 call factorial -halt ; R0 = 120 +halt factorial: loadi r1, 1 cmp r0, r1 - jc base_case ; if r0 < 1 - jz base_case ; if r0 == 1 + jc base_case + jz base_case - push r0 ; save n - dec r0 ; n-1 - call factorial ; factorial(n-1) - pop r1 ; restore n + push r0 + dec r0 + call factorial + pop r1 - ; multiply: r0 (result) by r1 (n) - mov r2, r0 ; save result - loadi r0, 0 ; accumulator + mov r2, r0 + loadi r0, 0 multiply: add r0, r2 dec r1 diff --git a/asm/tutorial/32_stack_frame.asm b/asm/tutorial/32_stack_frame.asm index 1641089..92d04d8 100644 --- a/asm/tutorial/32_stack_frame.asm +++ b/asm/tutorial/32_stack_frame.asm @@ -1,20 +1,16 @@ ; Exercise 32: Stack-Based Parameters with Frame Pointer ; Level: 4 - Stack & Subroutines -; ; Goal: Pass three arguments via the stack to a function ; Function uses frame pointer to access arguments, computes sum ; Also demonstrates local variables with negative offsets ; Call sum(5, 10, 15) and get R0 = 30 -; ; Instructions to use: LOADI, PUSH, MOVSPR, LOAD, STORE, ADD, CALL, RET, HALT ; Expected result: R0 = 30 -; ; Hint: Push arguments in reverse order: arg3, arg2, arg1 ; Hint: Function uses MOVSPR to get frame pointer (SP into R6:R7) ; Hint: Access arguments via POSITIVE offset: [R6:R7 + offset] ; Hint: Access local variables via NEGATIVE offset: [R6:R7 - offset] ; Hint: Signed offsets range from -128 to +127 -; ; Stack layout after MOVSPR and local allocation: ; Higher addresses ; [FP + 5] = arg1 (5) - first pushed @@ -30,33 +26,28 @@ section .code ; Push arguments in order: arg1, arg2, arg3 loadi r0, 5 -push r0 ; arg1 +push r0 loadi r0, 10 -push r0 ; arg2 +push r0 loadi r0, 15 -push r0 ; arg3 +push r0 call sum_three halt sum_three: - movspr r6:r7 ; R6:R7 = SP (frame pointer) - ; Allocate space for local variable + movspr r6:r7 loadi r0, 0 - push r0 ; local1 at [FP - 1] + push r0 - ; Load arguments using positive offsets - load r0, [r6:r7 + 5] ; arg1 (5) at FP+5 (first pushed) - load r1, [r6:r7 + 4] ; arg2 (10) at FP+4 - add r0, r1 ; R0 = 5 + 10 = 15 + load r0, [r6:r7 + 5] + load r1, [r6:r7 + 4] + add r0, r1 - ; Store intermediate result in local variable using negative offset - store r0, [r6:r7 - 1] ; Store 15 in local1 + store r0, [r6:r7 - 1] - ; Load local and add final argument - load r0, [r6:r7 - 1] ; Load local1 (15) - load r2, [r6:r7 + 3] ; arg3 (15) at FP+3 (last pushed) - add r0, r2 ; R0 = 15 + 15 = 30 + load r0, [r6:r7 - 1] + load r2, [r6:r7 + 3] + add r0, r2 - ; Clean up local variable pop r1 ret diff --git a/asm/tutorial/33_16bit_addition.asm b/asm/tutorial/33_16bit_addition.asm index 6bc1cfd..57eecc9 100644 --- a/asm/tutorial/33_16bit_addition.asm +++ b/asm/tutorial/33_16bit_addition.asm @@ -1,12 +1,9 @@ ; Tutorial 33: 16-bit Addition ; Level: 5 - Advanced Arithmetic -; ; Goal: Add two 16-bit numbers using ADC (add with carry) ; 0x01FF + 0x0002 = 0x0201 (511 + 2 = 513) -; ; Instructions to use: LOADI, ADD, ADC, HALT ; Expected result: R6:R7 = 0x0201 (R6 = 0x02, R7 = 0x01) -; ; Hint: ADC R1, R2 means R1 = R1 + R2 + C (add with carry flag) ; Hint: First add low bytes (sets C if overflow), then ADC high bytes ; Hint: 16-bit number stored as high:low (R6:R7) @@ -15,18 +12,18 @@ section .code ; First number: 0x01FF (R6:R7) -loadi r6, 0x01 ; Load 0x01 into R6 (high byte) -loadi r7, 0xff ; Load 0xFF into R7 (low byte) +loadi r6, 0x01 +loadi r7, 0xff ; Second number: 0x0002 (R0:R1) -loadi r0, 0x00 ; Load 0x00 into R0 (high byte) -loadi r1, 0x02 ; Load 0x02 into R1 (low byte) +loadi r0, 0x00 +loadi r1, 0x02 ; Add low bytes first -add r7, r1 ; ADD R7, R1 (R7 = 0xFF + 0x02 = 0x01, sets C=1 because overflow) +add r7, r1 ; Add high bytes with carry -adc r6, r0 ; ADC R6, R0 (R6 = 0x01 + 0x00 + C = 0x02) +adc r6, r0 ; Result: R6:R7 = 0x0201 -halt ; Halt +halt diff --git a/asm/tutorial/34_16bit_subtraction.asm b/asm/tutorial/34_16bit_subtraction.asm index 57a2e60..95170f5 100644 --- a/asm/tutorial/34_16bit_subtraction.asm +++ b/asm/tutorial/34_16bit_subtraction.asm @@ -1,12 +1,9 @@ ; Exercise 34: 16-bit Subtraction ; Level: 5 - Advanced Arithmetic -; ; Goal: Subtract two 16-bit numbers using SBC (subtract with carry/borrow) ; 0x0201 - 0x00FF = 0x0102 (513 - 255 = 258) -; ; Instructions to use: LOADI, SUB, SBC, HALT ; Expected result: R6:R7 = 0x0102 (R6 = 0x01, R7 = 0x02) -; ; Hint: SBC R1, R2 means R1 = R1 - R2 - C (subtract with borrow) ; Hint: First subtract low bytes (sets C if borrow), then SBC high bytes ; Hint: C flag = 1 means borrow occurred @@ -14,18 +11,18 @@ section .code ; First number: 0x0201 (R6:R7) -loadi r6, 0x02 ; Load 0x02 into R6 (high byte) -loadi r7, 0x01 ; Load 0x01 into R7 (low byte) +loadi r6, 0x02 +loadi r7, 0x01 ; Second number: 0x00FF (R0:R1) -loadi r0, 0x00 ; Load 0x00 into R0 (high byte) -loadi r1, 0xFF ; Load 0xFF into R1 (low byte) +loadi r0, 0x00 +loadi r1, 0xFF ; Subtract low bytes first -sub r7, r1 ; SUB R7, R1 (R7 = 0x01 - 0xFF, sets C=1 because borrow) +sub r7, r1 ; Subtract high bytes with borrow -sbc r6, r0 ; SBC R6, R0 (R6 = 0x02 - 0x00 - C = 0x01) +sbc r6, r0 ; Result: R6:R7 = 0x0102 -halt ; Halt +halt diff --git a/asm/tutorial/35_multiply_simple.asm b/asm/tutorial/35_multiply_simple.asm index 75ebc70..8ca236f 100644 --- a/asm/tutorial/35_multiply_simple.asm +++ b/asm/tutorial/35_multiply_simple.asm @@ -1,23 +1,20 @@ ; Exercise 35: 8-bit Multiplication (Simple) ; Level: 5 - Advanced Arithmetic -; ; Goal: Multiply 7 * 6 = 42 using repeated addition ; result = a + a + a + ... (b times) -; ; Instructions to use: LOADI, ADD, DEC, JNZ, HALT ; Expected result: R0 = 42 -; ; Hint: Multiplication is repeated addition: 7*6 = 7+7+7+7+7+7 ; Hint: Use loop counter for number of additions ; Hint: Pattern: result = 0; loop b times: result += a section .code -loadi r1, 1 ; Load 7 into R1 (multiplicand - number to add) -loadi r2, 255 ; Load 6 into R2 (multiplier - how many times) -loadi r0, 0 ; Load 0 into R0 (result accumulator) +loadi r1, 1 +loadi r2, 255 +loadi r0, 0 loop: - add r0, r1 ; Add R1 to R0 - dec r2 ; Decrement R2 - jnz loop ; Jump to loop if R2 != 0 -halt ; Halt (R0 should be 42) + add r0, r1 + dec r2 + jnz loop +halt diff --git a/asm/tutorial/36_multiply_fast.asm b/asm/tutorial/36_multiply_fast.asm index 7e86154..a27d317 100644 --- a/asm/tutorial/36_multiply_fast.asm +++ b/asm/tutorial/36_multiply_fast.asm @@ -1,49 +1,43 @@ ; Exercise 36: Small-value Multiplication (Shift-and-Add) ; Level: 5 - Advanced Arithmetic -; ; Goal: Multiply 1 * 255 = 255 using shift-and-add algorithm ; Repeated addition would need 255 loops; this needs only 8 -; ; Instructions to use: LOADI, ADD, SHL, SHR, AND, JZ, JMP, HALT ; Expected result: R0 = 255 -; ; How it works: Any number is a sum of powers of 2 (its binary representation) ; 1 × 255 = 1 × (128 + 64 + 32 + 16 + 8 + 4 + 2 + 1) ; = 1×2⁷ + 1×2⁶ + 1×2⁵ + 1×2⁴ + 1×2³ + 1×2² + 1×2¹ + 1×2⁰ -; ; Algorithm: For each bit in multiplier (right to left): ; - If bit is 1: add multiplicand to result ; - Double multiplicand (shift left) → next power of 2 ; - Halve multiplier (shift right) → next bit -; ; Example with 12 × 5 = 60: ; 5 = 0b101 (bits 0 and 2 are set) = 4 + 1 ; Iter 1: bit=1, add 12×1 = 12 → result = 12 ; Iter 2: bit=0, skip → result = 12 ; Iter 3: bit=1, add 12×4 = 48 → result = 60 ; Only 3 iterations instead of 5! -; ; Note: This is how hardware multipliers work ; Note: Limited to results that fit in 8-bit register (max 255) section .code -loadi r1, 1 ; Multiplicand -loadi r2, 255 ; Multiplier -loadi r0, 0 ; Result accumulator +loadi r1, 1 +loadi r2, 255 +loadi r0, 0 loop: - xor r3, r3 ; Test if multiplier reached 0 + xor r3, r3 cmp r2, r3 jz done - loadi r3, 1 ; Test if rightmost bit is 1 - and r3, r2 ; R3 = R2 & 1 (isolate bit) - jz shift ; If bit is 0, skip addition + loadi r3, 1 + and r3, r2 + jz shift - add r0, r1 ; If bit is 1, add multiplicand to result + add r0, r1 shift: - shl r1 ; Double multiplicand (next power of 2) - shr r2 ; Halve multiplier (move to next bit) + shl r1 + shr r2 jmp loop done: - halt ; Result in R0 + halt diff --git a/asm/tutorial/37_divide.asm b/asm/tutorial/37_divide.asm index 633b99b..7af07ae 100644 --- a/asm/tutorial/37_divide.asm +++ b/asm/tutorial/37_divide.asm @@ -1,26 +1,23 @@ ; Exercise 37: 8-bit Division ; Level: 5 - Advanced Arithmetic -; ; Goal: Divide 42 / 7 = 6 using repeated subtraction ; Count how many times divisor can be subtracted from dividend -; ; Instructions to use: LOADI, SUB, INC, CMP, JC, HALT ; Expected result: R0 = 6 (quotient) -; ; Hint: Division is repeated subtraction: 42-7-7-7-7-7-7 = 0 (6 times) ; Hint: Count subtractions until dividend < divisor ; Hint: Use CMP and JC to detect when dividend < divisor section .code -loadi r1, 42 ; Load 42 into R1 (dividend) -loadi r2, 7 ; Load 7 into R2 (divisor) -loadi r0, 0 ; Load 0 into R0 (quotient counter) +loadi r1, 42 +loadi r2, 7 +loadi r0, 0 loop: - cmp r1, r2 ; Compare R1 with R2 (check if R1 < R2) - jc done ; If R1 < R2 (C=1), jump to done - sub r1, r2 ; Subtract R2 from R1 - inc r0 ; Increment R0 (count subtractions) - jmp loop ; Jump back to loop + cmp r1, r2 + jc done + sub r1, r2 + inc r0 + jmp loop done: - halt ; Halt (R0=6 quotient, R1=0 remainder) + halt diff --git a/asm/tutorial/38_modulo.asm b/asm/tutorial/38_modulo.asm index 5093cdb..d197204 100644 --- a/asm/tutorial/38_modulo.asm +++ b/asm/tutorial/38_modulo.asm @@ -1,24 +1,21 @@ ; Exercise 38: Modulo Operation ; Level: 5 - Advanced Arithmetic -; ; Goal: Compute 17 % 5 = 2 (remainder after division) ; Keep subtracting divisor until remainder < divisor -; ; Instructions to use: LOADI, SUB, CMP, JC, HALT ; Expected result: R0 = 2 (remainder) -; ; Hint: Modulo returns remainder: 17 = 3*5 + 2, so 17%5 = 2 ; Hint: Similar to division but we keep the remainder, not the count ; Hint: Stop when dividend < divisor, remainder is what's left section .code -loadi r0, 17 ; Load 17 into R0 (dividend/remainder) -loadi r1, 5 ; Load 5 into R1 (divisor) +loadi r0, 17 +loadi r1, 5 loop: - cmp r0, r1 ; Compare R0 with R1 (check if R0 < R1) - jc done ; If R0 < R1 (C=1), jump to done (R0 is the remainder) - sub r0, r1 ; Subtract R1 from R0 - jmp loop ; Jump back to loop + cmp r0, r1 + jc done + sub r0, r1 + jmp loop done: - halt ; Halt (R0 should be 2) + halt diff --git a/asm/tutorial/39_set_clear_bits.asm b/asm/tutorial/39_set_clear_bits.asm index 9b2cd58..a8ba5de 100644 --- a/asm/tutorial/39_set_clear_bits.asm +++ b/asm/tutorial/39_set_clear_bits.asm @@ -1,23 +1,20 @@ ; Exercise 39: Set and Clear Bits ; Level: 6 - Bit Manipulation -; ; Goal: Set specific bits to 1 using OR, clear specific bits to 0 using AND ; Start with 0x00, set bits 0 and 4, then clear bit 0 -; ; Instructions to use: LOADI, OR, AND, HALT ; Expected result: R0 = 0x10 (only bit 4 set) -; ; Hint: OR with 1-bits sets those bits: value | mask ; Hint: AND with 0-bits clears those bits: value & ~mask ; Hint: To clear bit N: AND with value that has bit N = 0, all others = 1 section .code -loadi r0, 0b00000000 ; Load 0x00 into R0 (start with all bits clear) -loadi r1, 0b00010001 ; Load 0x11 into R1 (mask for bits 0 and 4: 00010001) -or r0, r1 ; OR R0 with R1 (set bits 0 and 4: R0 = 0x11) +loadi r0, 0b00000000 +loadi r1, 0b00010001 +or r0, r1 ; 0b00010001 -loadi r1, 0b11111110 ; Load 0xFE into R1 (mask to clear bit 0: 11111110) -and r0, r1 ; AND R0 with R1 (clear bit 0: R0 = 0x10) +loadi r1, 0b11111110 +and r0, r1 ; 0b00010000 -halt ; Halt (R0 should be 0x10) +halt diff --git a/asm/tutorial/40_test_bit.asm b/asm/tutorial/40_test_bit.asm index 24b0607..aa15b6d 100644 --- a/asm/tutorial/40_test_bit.asm +++ b/asm/tutorial/40_test_bit.asm @@ -1,26 +1,23 @@ ; Exercise 40: Test if Bit is Set ; Level: 6 - Bit Manipulation -; ; Goal: Test if bit 5 is set in a value (0x2A = 00101010) ; Use AND to isolate the bit, then check if result is zero -; ; Instructions to use: LOADI, AND, JZ, HALT ; Expected result: R0 = 1 (bit 5 is set) -; ; Hint: Test bit N: AND with (1 << N), if result != 0, bit was set ; Hint: 0x2A = 00101010, bit 5 = 0, bit 3 = 1, bit 1 = 1 ; Hint: AND sets Z flag if result is 0 section .code -loadi r0, 0b00101010 ; Load 0x2A into R0 (00101010) -loadi r1, 0b00100000 ; Load 0x20 into R1 (mask for bit 5: 00100000) -and r0, r1 ; AND R0 with R1 (isolate bit 5) +loadi r0, 0b00101010 +loadi r1, 0b00100000 +and r0, r1 ; 0b00100000 -jz bit_clear ; If result is 0 (Z=1), jump to bit_clear -loadi r0, 1 ; Load 1 into R0 (bit was set) -jmp done ; Jump to done +jz bit_clear +loadi r0, 1 +jmp done bit_clear: - loadi r0, 0 ; Load 0 into R0 (bit was clear) + loadi r0, 0 done: - halt ; Halt (R0=1 since bit 5 is set in 0x2A) + halt diff --git a/asm/tutorial/41_toggle_bits.asm b/asm/tutorial/41_toggle_bits.asm index c6b1c55..ba290d7 100644 --- a/asm/tutorial/41_toggle_bits.asm +++ b/asm/tutorial/41_toggle_bits.asm @@ -1,20 +1,17 @@ ; Exercise 41: Toggle Bits ; Level: 6 - Bit Manipulation -; ; Goal: Toggle (flip) specific bits using XOR ; Start with 0xAA (10101010), toggle bits 0 and 7 -; ; Instructions to use: LOADI, XOR, HALT ; Expected result: R0 = 0x2B (00101011) -; ; Hint: XOR with 1-bits toggles those bits: 0→1, 1→0 ; Hint: XOR is used for flipping bits, encryption, checksums ; Hint: 0xAA = 10101010, toggle bits 0,7 → 00101011 = 0x2B section .code -loadi r0, 0b10101010 ; Load 0xAA into R0 (10101010) -loadi r1, 0b10000001 ; Load 0x81 into R1 (mask for bits 0 and 7: 10000001) -xor r0, r1 ; XOR R0 with R1 (toggle bits 0 and 7) +loadi r0, 0b10101010 +loadi r1, 0b10000001 +xor r0, r1 ; 0b00101011 -halt ; Halt (R0 should be 0x2B = 00101011) +halt diff --git a/asm/tutorial/42_count_set_bits.asm b/asm/tutorial/42_count_set_bits.asm index 0340b55..647e79e 100644 --- a/asm/tutorial/42_count_set_bits.asm +++ b/asm/tutorial/42_count_set_bits.asm @@ -1,32 +1,27 @@ ; Exercise 42: Count Set Bits (Population Count) ; Level: 6 - Bit Manipulation -; ; Goal: Count how many bits are set to 1 in a value ; Value: 0x57 (01010111) has 5 bits set -; ; Instructions to use: LOADI, AND, JZ, INC, SHR, JMP, HALT ; Expected result: R0 = 5 (number of 1-bits in 0x57) -; ; Hint: Algorithm: test lowest bit, if 1 increment count, shift right, repeat ; Hint: Continue until all bits shifted out (value becomes 0) ; Hint: 0x57 = 01010111 has bits 0,1,2,4,6 set = 5 bits section .code -loadi r1, 0b01010111 ; Load 0x57 into R1 (value to count) -loadi r0, 0 ; Load 0 into R0 (bit counter) +loadi r1, 0b01010111 +loadi r0, 0 loop: - ; Check if R1 == 0 (done when no bits left) loadi r2, 0 cmp r1, r2 - jz done ; If R1 == 0, jump to done - ; Test lowest bit: AND R1 with 1, store in R2 + jz done loadi r2, 1 and r2, r1 - jz next ; If bit is 0 (Z=1), skip increment - inc r0 ; If bit is 1, increment R0 + jz next + inc r0 next: - shr r1 ; Shift R1 right (test next bit) - jmp loop ; Jump back to loop + shr r1 + jmp loop done: - halt ; Halt (R0 should be 5) + halt diff --git a/asm/tutorial/43_rotate_left.asm b/asm/tutorial/43_rotate_left.asm index 4a8ba9d..347a54d 100644 --- a/asm/tutorial/43_rotate_left.asm +++ b/asm/tutorial/43_rotate_left.asm @@ -1,16 +1,12 @@ ; Exercise 43: Rotate Left ; Level: 6 - Bit Manipulation -; ; Goal: Rotate bits left (circular shift): bit 7 wraps to bit 0 ; Value: 0x81 (10000001) rotate left → 0x03 (00000011) -; ; Note: Tiny16 immediates can only be used with LOADI (and with LOAD/STORE ; address operands). For bit masks like 0x80/0x01, LOADI them into a ; register first, then AND/OR with that register. -; ; Instructions to use: LOADI, MOV, SHL, AND, OR, JNC, HALT ; Expected result: R0 = 0x03 -; ; Hint: Rotate left = shift left + wrap bit 7 to bit 0 ; Hint: Algorithm: save bit 7, shift left, if bit 7 was set, set bit 0 ; Hint: Test bit 7 before shift using AND with 0x80 @@ -18,17 +14,17 @@ section .code -loadi r0, 0b10000001 ; Load 0x81 into R0 (10000001) -mov r1, r0 ; Copy R0 to R1 (save for bit 7 test) +loadi r0, 0b10000001 +mov r1, r0 loadi r2, 0x80 -and r1, r2 ; AND R1 with 0x80 (test bit 7) +and r1, r2 -shl r0 ; SHL R0 (shift left: 10000001 → 00000010) (1 goes into C) -jnc done ; If bit 7 was not set (C=0), skip wrapping bit 0 +shl r0 +jnc done -loadi r3, 0x01 ; Load bit-0 mask (0x01) into R3 -or r0, r3 ; Set bit 0 (wrap): R0 |= 0x01 +loadi r3, 0x01 +or r0, r3 done: - halt ; Halt (R0 should be 0x03 = 00000011) + halt diff --git a/asm/tutorial/44_byte_swap.asm b/asm/tutorial/44_byte_swap.asm index 4d84031..40db6a3 100644 --- a/asm/tutorial/44_byte_swap.asm +++ b/asm/tutorial/44_byte_swap.asm @@ -1,16 +1,12 @@ ; Exercise 44: Byte Swap (Nibble Swap) ; Level: 6 - Bit Manipulation -; ; Goal: Swap high and low nibbles (4-bit halves) of a byte ; Value: 0xAB (1010 1011) → 0xBA (1011 1010) -; ; Note: Tiny16 immediates can only be used with LOADI (and with LOAD/STORE ; address operands). For masks like 0x0F, LOADI them into a register ; first, then AND/OR with that register. -; ; Instructions to use: LOADI, MOV, SHL, SHR, AND, OR, HALT ; Expected result: R0 = 0xBA -; ; Hint: Extract high nibble: (value >> 4) & 0x0F ; Hint: Extract low nibble: value & 0x0F ; Hint: Swap: (low << 4) | high @@ -18,16 +14,16 @@ section .code -loadi r0, 0b10101011 ; LOADI 0xAB into R0 (1010 1011) -mov r1, r0 ; MOV R0 to R1 (save original) -loadi r2, 0x0F ; LOADI 0x0F into R2 (nibble mask) +loadi r0, 0b10101011 +mov r1, r0 +loadi r2, 0x0F -and r0, r2 ; AND R0 with R2 (extract low nibble: 0x0B) -times 4 shl r0 ; Shift R0 left 4 times (move low nibble to high: 0xB0) -mov r3, r1 ; MOV R1 to R3 (get original value) -times 4 shr r3 ; Shift R3 right 4 times (move high nibble to low: 0x0A) +and r0, r2 +times 4 shl r0 +mov r3, r1 +times 4 shr r3 -and r3, r2 ; AND R3 with R2 (mask to ensure only low nibble: 0x0A) -or r0, r3 ; OR R0 with R3 (combine: 0xB0 | 0x0A = 0xBA) +and r3, r2 +or r0, r3 -halt ; Halt (R0 should be 0xBA) +halt diff --git a/asm/tutorial/45_constants_and_expressions.asm b/asm/tutorial/45_constants_and_expressions.asm index 29076d8..7baa9fa 100644 --- a/asm/tutorial/45_constants_and_expressions.asm +++ b/asm/tutorial/45_constants_and_expressions.asm @@ -1,14 +1,12 @@ ; Tutorial 45: Constants and Expressions ; Level: 7 - Assembler Power Features -; ; Goal: Use constants and expressions to compute immediates ; Expected result: R0 = 24, R1 = 0x13 -; ; Hint: You can define constants with NAME = expression ; Hint: Expressions support + - * / % << >> & ^ | and parentheses -VALUE = (6 + 2) * 3 ; 24 -MASK = (1 << 4) | 0x03 ; 0x13 +VALUE = (6 + 2) * 3 +MASK = (1 << 4) | 0x03 section .code diff --git a/asm/tutorial/46_sections_and_org.asm b/asm/tutorial/46_sections_and_org.asm index a289987..a012a27 100644 --- a/asm/tutorial/46_sections_and_org.asm +++ b/asm/tutorial/46_sections_and_org.asm @@ -1,9 +1,7 @@ ; Tutorial 46: Sections and ORG ; Level: 7 - Assembler Power Features -; ; Goal: Read array at 0x4020, compute sum, store at 0x4100 ; Expected: Memory[0x4100] = 0x96 (150 = sum of 10,20,30,40,50) -; ; Concepts: Multiple ORG directives, expressions in immediates ARRAY_ADDR = 0x4020 diff --git a/asm/tutorial/47_macros.asm b/asm/tutorial/47_macros.asm index ebedb51..735f5a6 100644 --- a/asm/tutorial/47_macros.asm +++ b/asm/tutorial/47_macros.asm @@ -1,9 +1,7 @@ ; Tutorial 47: Macros ; Level: 7 - Assembler Power Features -; ; Goal: Use a macro to add immediate values to a register ; Expected result: R0 = 22 -; ; Hint: Macros are expanded before assembly (pass 0) ; Hint: Use a scratch register inside the macro (R7 here) diff --git a/asm/tutorial/48_includes.asm b/asm/tutorial/48_includes.asm index b4802e2..8c7753d 100644 --- a/asm/tutorial/48_includes.asm +++ b/asm/tutorial/48_includes.asm @@ -1,9 +1,7 @@ ; Tutorial 48: Includes ; Level: 7 - Assembler Power Features -; ; Goal: Reuse constants and macros from another file with .include ; Expected result: R0 = 16 -; ; Hint: The include path is relative to this file .include "includes/constants.inc" diff --git a/sec/parser.c b/sec/parser.c index 85b34f1..f76954f 100644 --- a/sec/parser.c +++ b/sec/parser.c @@ -83,7 +83,7 @@ AstNode* se_parser_parse_form(SeParser* parser) { // Skip quotes when copying size_t len = parser->current.text_len; if (len >= 2) { - len -= 2; // remove quotes + len -= 2; if (len >= SE_MAX_SYMBOL_LEN) len = SE_MAX_SYMBOL_LEN - 1; memcpy(node->as.symbol.name, parser->current.text + 1, len); node->as.symbol.name[len] = '\0'; @@ -118,7 +118,7 @@ static bool is_symbol(SeParser* parser, const char* name) { // Parse (def name value) static AstNode* parse_def(SeParser* parser) { - advance(parser); // skip 'def' + advance(parser); if (parser->current.kind != SE_TOKEN_SYMBOL) { parser_set_error(parser, SE_PARSE_ERROR_EXPECTED_SYMBOL, "def requires a name"); @@ -148,7 +148,7 @@ static AstNode* parse_def(SeParser* parser) { // Parse (defn name (params) body...) static AstNode* parse_defn(SeParser* parser) { - advance(parser); // skip 'defn' + advance(parser); if (parser->current.kind != SE_TOKEN_SYMBOL) { parser_set_error(parser, SE_PARSE_ERROR_EXPECTED_SYMBOL, "defn requires a name"); @@ -207,7 +207,7 @@ static AstNode* parse_defn(SeParser* parser) { // Parse (let (var val var val ...) body...) static AstNode* parse_let(SeParser* parser) { - advance(parser); // skip 'let' + advance(parser); if (parser->current.kind != SE_TOKEN_LPAREN) { parser_set_error(parser, SE_PARSE_ERROR_EXPECTED_LPAREN, "let requires binding list"); @@ -272,7 +272,7 @@ static AstNode* parse_let(SeParser* parser) { // Parse (set var value) static AstNode* parse_set(SeParser* parser) { - advance(parser); // skip 'set' + advance(parser); if (parser->current.kind != SE_TOKEN_SYMBOL) { parser_set_error(parser, SE_PARSE_ERROR_EXPECTED_SYMBOL, "set requires variable name"); @@ -302,7 +302,7 @@ static AstNode* parse_set(SeParser* parser) { // Parse (if cond then else) static AstNode* parse_if(SeParser* parser) { - advance(parser); // skip 'if' + advance(parser); AstNode* node = alloc_node(parser, AST_IF); if (!node) return NULL; @@ -336,7 +336,7 @@ static AstNode* parse_if(SeParser* parser) { // Parse (while cond body...) static AstNode* parse_while(SeParser* parser) { - advance(parser); // skip 'while' + advance(parser); AstNode* node = alloc_node(parser, AST_WHILE); if (!node) return NULL; @@ -369,7 +369,7 @@ static AstNode* parse_while(SeParser* parser) { // Parse (do expr...) static AstNode* parse_do(SeParser* parser) { - advance(parser); // skip 'do' + advance(parser); AstNode* node = alloc_node(parser, AST_DO); if (!node) return NULL; @@ -396,7 +396,7 @@ static AstNode* parse_do(SeParser* parser) { // Parse (data name [addr] body...) static AstNode* parse_data(SeParser* parser) { - advance(parser); // skip 'data' + advance(parser); if (parser->current.kind != SE_TOKEN_SYMBOL) { parser_set_error(parser, SE_PARSE_ERROR_EXPECTED_SYMBOL, "data requires name"); @@ -455,7 +455,7 @@ static AstNode* parse_data(SeParser* parser) { // Parse (db values...) static AstNode* parse_db(SeParser* parser) { - advance(parser); // skip 'db' + advance(parser); AstNode* node = alloc_node(parser, AST_DB); if (!node) return NULL; @@ -482,7 +482,7 @@ static AstNode* parse_db(SeParser* parser) { // Parse (repeat count form) static AstNode* parse_repeat(SeParser* parser) { - advance(parser); // skip 'repeat' + advance(parser); AstNode* node = alloc_node(parser, AST_REPEAT); if (!node) return NULL; @@ -512,7 +512,7 @@ static AstNode* parse_repeat(SeParser* parser) { // Parse (ns name) or (ns name (require ...)) // Returns just the ns node; any require forms need separate handling static AstNode* parse_ns(SeParser* parser) { - advance(parser); // skip 'ns' + advance(parser); if (parser->current.kind != SE_TOKEN_SYMBOL) { parser_set_error(parser, SE_PARSE_ERROR_EXPECTED_SYMBOL, "ns requires a namespace symbol"); @@ -554,7 +554,7 @@ static AstNode* parse_ns(SeParser* parser) { // Parse (require name...) or (require (name1 name2...)) static AstNode* parse_require(SeParser* parser) { - advance(parser); // skip 'require' + advance(parser); AstNode* node = alloc_node(parser, AST_REQUIRE); if (!node) return NULL; @@ -564,7 +564,7 @@ static AstNode* parse_require(SeParser* parser) { // Check if first element is a list (Clojure-style) if (parser->current.kind == SE_TOKEN_LPAREN) { - advance(parser); // skip '(' + advance(parser); // Parse symbols/strings inside the list while (parser->current.kind != SE_TOKEN_RPAREN && parser->current.kind != SE_TOKEN_END) { @@ -588,7 +588,7 @@ static AstNode* parse_require(SeParser* parser) { parser_set_error(parser, SE_PARSE_ERROR_EXPECTED_RPAREN, NULL); return NULL; } - advance(parser); // skip ')' + advance(parser); } else { // Original style: (require name1 name2...) while (parser->current.kind != SE_TOKEN_RPAREN && parser->current.kind != SE_TOKEN_END) { @@ -620,7 +620,7 @@ static AstNode* parse_require(SeParser* parser) { // Parse binary operation static AstNode* parse_binary(SeParser* parser, AstKind kind) { - advance(parser); // skip operator + advance(parser); AstNode* node = alloc_node(parser, kind); if (!node) return NULL; @@ -648,7 +648,7 @@ static AstNode* parse_binary(SeParser* parser, AstKind kind) { // Parse unary operation static AstNode* parse_unary(SeParser* parser, AstKind kind) { - advance(parser); // skip operator + advance(parser); AstNode* node = alloc_node(parser, kind); if (!node) return NULL; @@ -670,7 +670,7 @@ static AstNode* parse_unary(SeParser* parser, AstKind kind) { // Parse (addr hi lo) static AstNode* parse_addr(SeParser* parser) { - advance(parser); // skip 'addr' + advance(parser); AstNode* node = alloc_node(parser, AST_ADDR); if (!node) return NULL; @@ -698,7 +698,7 @@ static AstNode* parse_addr(SeParser* parser) { // Parse (addr16 value) - 16-bit address that auto-splits to hi/lo static AstNode* parse_addr16(SeParser* parser) { - advance(parser); // skip 'addr16' + advance(parser); AstNode* node = alloc_node(parser, AST_ADDR16); if (!node) return NULL; @@ -720,7 +720,7 @@ static AstNode* parse_addr16(SeParser* parser) { // Parse (load addr-expr) static AstNode* parse_load(SeParser* parser) { - advance(parser); // skip 'load' + advance(parser); AstNode* node = alloc_node(parser, AST_LOAD); if (!node) return NULL; @@ -742,7 +742,7 @@ static AstNode* parse_load(SeParser* parser) { // Parse (peek hi lo) - syntactic sugar for (load (addr hi lo)) static AstNode* parse_peek(SeParser* parser) { - advance(parser); // skip 'peek' + advance(parser); // Create inner addr node AstNode* addr_node = alloc_node(parser, AST_ADDR); @@ -776,7 +776,7 @@ static AstNode* parse_peek(SeParser* parser) { // Parse (peek16 addr) - syntactic sugar for (load (addr16 addr)) static AstNode* parse_peek16(SeParser* parser) { - advance(parser); // skip 'peek16' + advance(parser); // Create inner addr16 node AstNode* addr16_node = alloc_node(parser, AST_ADDR16); @@ -805,7 +805,7 @@ static AstNode* parse_peek16(SeParser* parser) { // Parse (peek* hi lo) - syntactic sugar for (load (addr16 (addr hi lo))) // This dereferences a pointer stored at [hi:lo] static AstNode* parse_peek_ptr(SeParser* parser) { - advance(parser); // skip 'peek*' + advance(parser); // Create innermost addr node AstNode* addr_node = alloc_node(parser, AST_ADDR); @@ -844,7 +844,7 @@ static AstNode* parse_peek_ptr(SeParser* parser) { // Parse (store addr-expr value) static AstNode* parse_store(SeParser* parser) { - advance(parser); // skip 'store' + advance(parser); AstNode* node = alloc_node(parser, AST_STORE); if (!node) return NULL; @@ -872,7 +872,7 @@ static AstNode* parse_store(SeParser* parser) { // Parse (poke hi lo value) - syntactic sugar for (store (addr hi lo) value) static AstNode* parse_poke(SeParser* parser) { - advance(parser); // skip 'poke' + advance(parser); // Create inner addr node AstNode* addr_node = alloc_node(parser, AST_ADDR); @@ -912,7 +912,7 @@ static AstNode* parse_poke(SeParser* parser) { // Parse (poke16 addr value) - syntactic sugar for (store (addr16 addr) value) static AstNode* parse_poke16(SeParser* parser) { - advance(parser); // skip 'poke16' + advance(parser); // Create inner addr16 node AstNode* addr16_node = alloc_node(parser, AST_ADDR16); @@ -946,7 +946,7 @@ static AstNode* parse_poke16(SeParser* parser) { // Parse (include "filename") static AstNode* parse_import(SeParser* parser) { - advance(parser); // skip 'include' + advance(parser); if (parser->current.kind != SE_TOKEN_STRING) { parser_set_error(parser, SE_PARSE_ERROR_UNEXPECTED_TOKEN, @@ -978,7 +978,7 @@ static AstNode* parse_import(SeParser* parser) { // Parse (asm "raw assembly...") static AstNode* parse_asm(SeParser* parser) { - advance(parser); // skip 'asm' + advance(parser); if (parser->current.kind != SE_TOKEN_STRING) { parser_set_error(parser, SE_PARSE_ERROR_UNEXPECTED_TOKEN, "asm requires string"); @@ -1036,7 +1036,7 @@ static AstNode* parse_call(SeParser* parser) { } static AstNode* parse_list(SeParser* parser) { - advance(parser); // skip '(' + advance(parser); if (parser->current.kind == SE_TOKEN_RPAREN) { // Empty list - treat as nil/0 @@ -1068,8 +1068,8 @@ static AstNode* parse_list(SeParser* parser) { if (is_symbol(parser, "+") || is_symbol(parser, "add")) return parse_binary(parser, AST_ADD); if (is_symbol(parser, "-") || is_symbol(parser, "sub")) { // Could be binary sub or unary neg - (void)se_lexer_peek(&parser->lexer); // peek not needed, just checking next form - advance(parser); // skip '-' or 'sub' + (void)se_lexer_peek(&parser->lexer); + advance(parser); AstNode* first = se_parser_parse_form(parser); if (!first) return NULL; @@ -1151,12 +1151,12 @@ bool se_parser_parse_ns_with_requires(SeParser* parser, AstProgram* program) { return false; } - advance(parser); // skip '(' - advance(parser); // skip 'ns' + advance(parser); + advance(parser); if (parser->current.kind != SE_TOKEN_SYMBOL) { parser_set_error(parser, SE_PARSE_ERROR_EXPECTED_SYMBOL, "ns requires a namespace symbol"); - return true; // consumed ns form + return true; } AstNode* ns_node = alloc_node(parser, AST_NS); @@ -1184,7 +1184,7 @@ bool se_parser_parse_ns_with_requires(SeParser* parser, AstProgram* program) { } advance(parser); - return true; // consumed ns form + return true; } bool se_parser_parse_program(SeParser* parser, AstProgram* program) { diff --git a/sec/tutorial/01_expressions.se b/sec/tutorial/01_expressions.se index 475015b..0151d95 100644 --- a/sec/tutorial/01_expressions.se +++ b/sec/tutorial/01_expressions.se @@ -1,5 +1,4 @@ ; Tutorial 01: Expressions & Constants -; ; Build: ; ./build/tiny16-sec sec/tutorial/01_expressions.se build/01_expressions.asm ; ./build/tiny16-asm build/01_expressions.asm build/01_expressions.tiny16 @@ -10,5 +9,4 @@ (def RESULT (+ BASE OFFSET)) (defn main () - ; Evaluate a simple expression and return the result in R0. (+ RESULT 3)) diff --git a/sec/tutorial/02_variables.se b/sec/tutorial/02_variables.se index 0809bff..ade261a 100644 --- a/sec/tutorial/02_variables.se +++ b/sec/tutorial/02_variables.se @@ -1,5 +1,4 @@ ; Tutorial 02: Variables & Mutation -; ; Build: ; ./build/tiny16-sec sec/tutorial/02_variables.se build/02_variables.asm ; ./build/tiny16-asm build/02_variables.asm build/02_variables.tiny16 @@ -11,5 +10,4 @@ total 0) (set total (+ a b)) (set a (+ total 1)) - ; Return a + total (should be 12). (+ a total))) diff --git a/sec/tutorial/03_control_flow.se b/sec/tutorial/03_control_flow.se index b4b37cc..f69ef56 100644 --- a/sec/tutorial/03_control_flow.se +++ b/sec/tutorial/03_control_flow.se @@ -1,5 +1,4 @@ ; Tutorial 03: Control Flow (if/while) -; ; Build: ; ./build/tiny16-sec sec/tutorial/03_control_flow.se build/03_control_flow.asm ; ./build/tiny16-asm build/03_control_flow.asm build/03_control_flow.tiny16 @@ -11,5 +10,4 @@ (while (< i 5) (set sum (+ sum i)) (set i (inc i))) - ; sum = 0+1+2+3+4 = 10, return 1 if true. (if (= sum 10) 1 0))) diff --git a/sec/tutorial/04_functions.se b/sec/tutorial/04_functions.se index 21f3da4..ce8d7b7 100644 --- a/sec/tutorial/04_functions.se +++ b/sec/tutorial/04_functions.se @@ -1,5 +1,4 @@ ; Tutorial 04: Functions & Composition -; ; Build: ; ./build/tiny16-sec sec/tutorial/04_functions.se build/04_functions.asm ; ./build/tiny16-asm build/04_functions.asm build/04_functions.tiny16 @@ -15,5 +14,4 @@ (defn main () (let (result (add3 4 5 6)) - ; 4+5+6 = 15, clamp to 0..10 -> 10 (clamp result 0 10))) diff --git a/sec/tutorial/05_data_memory.se b/sec/tutorial/05_data_memory.se index 50f7671..9d8ac6a 100644 --- a/sec/tutorial/05_data_memory.se +++ b/sec/tutorial/05_data_memory.se @@ -1,5 +1,4 @@ ; Tutorial 05: Data & Memory -; ; Build: ; ./build/tiny16-sec sec/tutorial/05_data_memory.se build/05_data_memory.asm ; ./build/tiny16-asm build/05_data_memory.asm build/05_data_memory.tiny16 @@ -24,5 +23,4 @@ (while (< i DATA_COUNT) (set sum (+ sum (copy-byte i))) (set i (inc i))) - ; Return sum of numbers while copying into buffer. sum)) diff --git a/stdlib/asm/constants.inc b/stdlib/asm/constants.inc index ac13749..d6e7100 100644 --- a/stdlib/asm/constants.inc +++ b/stdlib/asm/constants.inc @@ -9,20 +9,20 @@ MMIO_BASE = 0xBF00 MMIO_HI = MMIO_BASE >> 8 ; Input devices (read-only) -KEYS_STATE_ADDR = MMIO_BASE + 0x00 ; Current keyboard state -KEYS_PRESSED_ADDR = MMIO_BASE + 0x01 ; Edge-triggered key presses -MOUSE_X_ADDR = MMIO_BASE + 0x02 ; Mouse X coordinate (0-127) -MOUSE_Y_ADDR = MMIO_BASE + 0x03 ; Mouse Y coordinate (0-127) -MOUSE_BUTTONS_ADDR = MMIO_BASE + 0x04 ; Mouse button state +KEYS_STATE_ADDR = MMIO_BASE + 0x00 +KEYS_PRESSED_ADDR = MMIO_BASE + 0x01 +MOUSE_X_ADDR = MMIO_BASE + 0x02 +MOUSE_Y_ADDR = MMIO_BASE + 0x03 +MOUSE_BUTTONS_ADDR = MMIO_BASE + 0x04 ; Display timing (read-only) -FRAME_COUNT_ADDR = MMIO_BASE + 0x22 ; Increments at 60 Hz +FRAME_COUNT_ADDR = MMIO_BASE + 0x22 ; PPU control (read/write) -PPU_CTRL_ADDR = MMIO_BASE + 0x30 ; Graphics control register -PPU_SCROLL_X_ADDR = MMIO_BASE + 0x31 ; Horizontal scroll (0-255) -PPU_SCROLL_Y_ADDR = MMIO_BASE + 0x32 ; Vertical scroll (0-255) -PPU_STATUS_ADDR = MMIO_BASE + 0x33 ; PPU status register +PPU_CTRL_ADDR = MMIO_BASE + 0x30 +PPU_SCROLL_X_ADDR = MMIO_BASE + 0x31 +PPU_SCROLL_Y_ADDR = MMIO_BASE + 0x32 +PPU_STATUS_ADDR = MMIO_BASE + 0x33 ; Pre-computed hi/lo bytes for fast MMIO access KEYS_STATE_HI = KEYS_STATE_ADDR >> 8 @@ -47,28 +47,28 @@ PPU_STATUS_HI = PPU_STATUS_ADDR >> 8 PPU_STATUS_LO = PPU_STATUS_ADDR & 0xFF ; Graphics memory map -FRAMEBUFFER_BASE = 0xC000 ; 128x128 framebuffer (RGB332) +FRAMEBUFFER_BASE = 0xC000 FRAMEBUFFER_HI = FRAMEBUFFER_BASE >> 8 FRAMEBUFFER_LO = FRAMEBUFFER_BASE & 0xFF -GFX_TILES_BASE = 0x5000 ; Tile data (8x8, 4bpp) -GFX_OAM_BASE = 0x7800 ; Object Attribute Memory (sprites) -GFX_PALETTE_BASE = 0x7900 ; Color palette +GFX_TILES_BASE = 0x5000 +GFX_OAM_BASE = 0x7800 +GFX_PALETTE_BASE = 0x7900 -GFX_OAM_SPRITE_COUNT = 64 ; Maximum sprites -GFX_OAM_ENTRY_SIZE = 4 ; Bytes per OAM entry +GFX_OAM_SPRITE_COUNT = 64 +GFX_OAM_ENTRY_SIZE = 4 ; PPU control bits -PPU_CTRL_SPRITES = 0x02 ; Enable sprite rendering -PPU_CTRL_RENDER_NOW = 0x80 ; Trigger immediate render -PPU_CTRL_SPRITES_ON = PPU_CTRL_SPRITES | PPU_CTRL_RENDER_NOW ; 0x82 +PPU_CTRL_SPRITES = 0x02 +PPU_CTRL_RENDER_NOW = 0x80 +PPU_CTRL_SPRITES_ON = PPU_CTRL_SPRITES | PPU_CTRL_RENDER_NOW ; Key bit definitions -KEY_SELECT = 0x01 ; bit 0 -KEY_START = 0x02 ; bit 1 -KEY_A = 0x04 ; bit 2 -KEY_B = 0x08 ; bit 3 -KEY_RIGHT = 0x10 ; bit 4 -KEY_LEFT = 0x20 ; bit 5 -KEY_UP = 0x40 ; bit 6 -KEY_DOWN = 0x80 ; bit 7 +KEY_SELECT = 0x01 +KEY_START = 0x02 +KEY_A = 0x04 +KEY_B = 0x08 +KEY_RIGHT = 0x10 +KEY_LEFT = 0x20 +KEY_UP = 0x40 +KEY_DOWN = 0x80 diff --git a/stdlib/asm/tiny16.inc b/stdlib/asm/tiny16.inc index 0e39733..5f08d51 100644 --- a/stdlib/asm/tiny16.inc +++ b/stdlib/asm/tiny16.inc @@ -2,25 +2,20 @@ ; ============================================================================= ; TINY16 STANDARD LIBRARY ; ============================================================================= -; ; A comprehensive collection of macros and constants for Tiny16 assembly. -; ; QUICK START: ; .include "../stdlib/tiny16.inc" -; ; .section code ; main: ; CLEAR_SCREEN 0x03 ; Dark blue background ; APU_INIT 12 ; Enable audio ; APU_CH0_NOTE NOTE_A4, 12, APU_DUTY_50 ; Play A4 ; HALT -; ; CONVENTIONS: ; - R6:R7 = Standard address pointer pair ; - R0 = Return value (where applicable) ; - Most macros clobber R6, R7 (documented per macro) ; - Register pairs: high byte first, low byte second (e.g., R0:R1 = 0x1234) -; ; MODULES (auto-included): ; - constants.inc : Hardware constants, MMIO addresses, key definitions ; - apu.inc : Audio Processing Unit macros and note table @@ -30,10 +25,8 @@ ; - input.inc : Keyboard and mouse input ; - timing.inc : VSYNC and frame timing ; - ppu.inc : PPU, sprites/OAM, and framebuffer utilities -; ; OPTIONAL MODULES (include separately in code section): ; - text.inc : Text rendering as sprites (draw_text_line function) -; ; ============================================================================= .include "constants.inc" diff --git a/tools/png2tiles.c b/tools/png2tiles.c index 24a8925..046548d 100644 --- a/tools/png2tiles.c +++ b/tools/png2tiles.c @@ -31,9 +31,9 @@ typedef struct { } RGBA; uint8_t rgba_to_rgb332(RGBA color) { - uint8_t r = (color.r >> 5) & 0x07; // 3 bits - uint8_t g = (color.g >> 5) & 0x07; // 3 bits - uint8_t b = (color.b >> 6) & 0x03; // 2 bits + uint8_t r = (color.r >> 5) & 0x07; + uint8_t g = (color.g >> 5) & 0x07; + uint8_t b = (color.b >> 6) & 0x03; return (r << 5) | (g << 2) | b; } @@ -102,7 +102,7 @@ int palette_find_color(Palette* pal, RGBA color) { } typedef struct { - uint8_t data[32]; // 8x8 pixels, 4 bits per pixel (2 pixels per byte) + uint8_t data[32]; } Tile; void extract_tile(uint8_t* image, int image_width, int image_height, int tile_x, int tile_y, @@ -146,9 +146,7 @@ void output_asm_include(FILE* f, Tile* tiles, int tile_count, Palette* pal, cons fprintf(f, "; vim: set ft=asm:\n"); fprintf(f, "; generated by png2tiles\n\n"); - // Tiles (skip if palette_only mode) if (!palette_only) { - // Calculate starting tile index from address int start_tile = (tiles_addr - 0x5000) / 32; fprintf(f, "; tiles (%d total, 32 bytes each, 4bpp)\n", tile_count); @@ -169,7 +167,6 @@ void output_asm_include(FILE* f, Tile* tiles, int tile_count, Palette* pal, cons } } - // Palette (skip if skip_palette mode) if (!skip_palette) { if (!palette_only) fprintf(f, "\n"); fprintf(f, "; palette (%d colors, max 16 for 4bpp)\n", pal->count); @@ -206,7 +203,6 @@ int main(int argc, char** argv) { const char* output_file = args.output_inc; const char* symbol_name = args.name; - // extract symbol name from filename if not provided char auto_name[256] = {0}; if (!symbol_name || symbol_name[0] == '\0') { const char* basename = strrchr(input_file, '/'); @@ -223,7 +219,6 @@ int main(int argc, char** argv) { symbol_name = auto_name; } - // load png int width, height, channels; uint8_t* image = stbi_load(input_file, &width, &height, &channels, 4); @@ -234,14 +229,12 @@ int main(int argc, char** argv) { printf("Loaded %s: %dx%d, %d channels\n", input_file, width, height, channels); - // validate dimensions if (width % TINY16_TILE_WIDTH != 0 || height % TINY16_TILE_HEIGHT != 0) { fprintf(stderr, "Warning: Image dimensions (%dx%d) are not multiples of tile size (%dx%d)\n", width, height, TINY16_TILE_WIDTH, TINY16_TILE_HEIGHT); } - // extract tiles int tiles_x = width / TINY16_TILE_WIDTH; int tiles_y = height / TINY16_TILE_HEIGHT; int tile_count = tiles_x * tiles_y; @@ -251,7 +244,6 @@ int main(int argc, char** argv) { tile_count = 256; } - // extract palette from entire image Palette palette; palette_init(&palette); @@ -282,7 +274,6 @@ int main(int argc, char** argv) { } } - // parse palette slot (0-3) int pal_slot = 0; if (args.palette_slot && args.palette_slot[0]) { pal_slot = atoi(args.palette_slot); @@ -294,9 +285,7 @@ int main(int argc, char** argv) { return 1; } - // Tile memory: 256 tiles at 0x5000-0x6FFF (32 bytes each) uint32_t tiles_addr = 0x5000; - // Palette slots 0-3 at 0x9200, 0x9210, 0x9220, 0x9230 uint32_t palette_addr = 0x9200 + pal_slot * 16; if (tile_count > 256) { @@ -306,7 +295,6 @@ int main(int argc, char** argv) { return 1; } - // write output (assembly format) FILE* out = fopen(output_file, "w"); if (!out) { fprintf(stderr, "Error: Failed to open '%s' for writing\n", output_file); diff --git a/vm/cpu.c b/vm/cpu.c index ce1a071..353472a 100644 --- a/vm/cpu.c +++ b/vm/cpu.c @@ -179,27 +179,24 @@ bool tiny16_cpu_step(Tiny16CPU* cpu, void* memory_context, tiny16_mem_read_fn me case TINY16_OPCODE_LOAD: case TINY16_OPCODE_STORE: { - // // BYTE 0 : OPCODE (LOAD / STORE) // BYTE 1 : REG | MODE | PAIR // BYTE 2 : AUX (offset or 0) - // // BYTE 1 bits 7–5 : REG (Rd or Rs) // bits 4–3 : MODE (addressing mode) // bits 2–1 : PAIR (00–11) // bit 0 : unused (0) - // uint8_t reg = (arg1 >> 5) & 0x7; Tiny16AddrMode mode = (arg1 >> 3) & 0x3; uint8_t pair = (arg1 >> 1) & 0x3; // PAIR: 0=R0:R1, 1=R2:R3, 2=R4:R5, 3=R6:R7 - uint8_t* hi = &cpu->R[pair * 2]; // even (high byte) - uint8_t* lo = &cpu->R[pair * 2 + 1]; // odd (low byte) + uint8_t* hi = &cpu->R[pair * 2]; + uint8_t* lo = &cpu->R[pair * 2 + 1]; uint16_t addr = ((uint16_t)(*hi << 8)) | *lo; - uint16_t ea = addr; // effective address + uint16_t ea = addr; if (mode == TINY16_ADDR_MODE_OFFSET) ea = addr + (int8_t)arg2; diff --git a/vm/memory.h b/vm/memory.h index 03ba9e1..8f61114 100644 --- a/vm/memory.h +++ b/vm/memory.h @@ -10,25 +10,17 @@ typedef struct { uint8_t bytes[TINY16_MEMORY_SIZE]; } Tiny16Memory; -// // Signature (0x0000 - 0x000F) -// -// // Code -// #define TINY16_MEMORY_CODE_BEGIN 0x0010 #define TINY16_MEMORY_CODE_END 0x3FFF /* CODE, ~16 KB */ -// // User Data (contiguous, arbitrary) -// #define TINY16_MEMORY_DATA_BEGIN 0x4000 #define TINY16_MEMORY_DATA_END 0x4FFF /* USER DATA, 4 KB */ -// // Graphics (PPU-visible, expanded layout) -// #define TINY16_MEMORY_GFX_TILES_BASE 0x5000 #define TINY16_MEMORY_GFX_TILES_END 0x6FFF // TILES, 256 x 32 B = 8 KB @@ -41,15 +33,11 @@ typedef struct { #define TINY16_MEMORY_GFX_PALETTE_BASE 0x9200 #define TINY16_MEMORY_GFX_PALETTE_END 0x923F // PALETTE, 4 x 16 colors = 64 B -// // Stack -// #define TINY16_MEMORY_STACK_BEGIN 0xA000 #define TINY16_MEMORY_STACK_END 0xBEFF // STACK, ~7.7 KB -// // MMIO -// // Input #define TINY16_MMIO_KEYS_STATE 0xBF00 @@ -159,30 +147,22 @@ typedef struct { // RESERVED (0xBFF0 - 0xBFFF) -// // Data section range: covers user data + all graphics memory -// #define TINY16_DATA_BEGIN TINY16_MEMORY_DATA_BEGIN // 0x4000 #define TINY16_DATA_END TINY16_MEMORY_GFX_PALETTE_END // 0x923F -// // Framebuffer (direct bitmap) -// #define TINY16_FRAMEBUFFER 0xC000 #define TINY16_FRAMEBUFFER_SIZE_WIDTH 128 #define TINY16_FRAMEBUFFER_SIZE_HEIGHT 128 #define TINY16_FRAMEBUFFER_ADDR(x, y) (TINY16_FRAMEBUFFER + ((y) << 7u) + (x)) -// // Memory helpers -// void tiny16_memory_print(const Tiny16Memory* memory, bool framebuffer); void tiny16_memory_reset(Tiny16Memory* memory); size_t tiny16_memory_load_from_file(Tiny16Memory* memory, const char* filename); -// // Bus interface (used by CPU) -// typedef uint8_t (*tiny16_mem_read_fn)(void* ctx, uint16_t addr); typedef void (*tiny16_mem_write_fn)(void* ctx, uint16_t addr, uint8_t value); diff --git a/vm/ppu.c b/vm/ppu.c index 384d5e6..1d1d2b9 100644 --- a/vm/ppu.c +++ b/vm/ppu.c @@ -60,7 +60,7 @@ static void tiny16_ppu_render_tile(uint8_t* framebuffer, const Tiny16Tile* tile, // Even pixels (0,2,4,6) use high nibble, odd pixels (1,3,5,7) use low nibble uint8_t palette_idx = (src_x & 1) ? (byte_data & 0x0F) : (byte_data >> 4); - if (palette_idx == 0) continue; // transparent + if (palette_idx == 0) continue; framebuffer[py * TINY16_FRAMEBUFFER_SIZE_WIDTH + px] = palette->entries[palette_idx].color; diff --git a/vm/ppu.h b/vm/ppu.h index 4c90adf..964ffa3 100644 --- a/vm/ppu.h +++ b/vm/ppu.h @@ -2,66 +2,58 @@ #include -// // Tile (4bpp - 2 pixels per byte) -// #define TINY16_TILE_WIDTH 8 #define TINY16_TILE_HEIGHT 8 -#define TINY16_TILE_BPP 4 // bits per pixel -#define TINY16_TILE_ROW_BYTES 4 // 8 pixels * 4bpp / 8 = 4 bytes per row -#define TINY16_TILE_SIZE 32 // 8 rows * 4 bytes = 32 bytes per tile -#define TINY16_TILE_COUNT 255 // 255 tiles * 32 bytes = 8160 bytes (~8 KB) +#define TINY16_TILE_BPP 4 +#define TINY16_TILE_ROW_BYTES 4 +#define TINY16_TILE_SIZE 32 +#define TINY16_TILE_COUNT 255 typedef struct { uint8_t rows[TINY16_TILE_HEIGHT][TINY16_TILE_ROW_BYTES]; } Tiny16Tile; -// // Tilemap (combined tile + attributes) -// #define TINY16_TILEMAP_WIDTH 128 #define TINY16_TILEMAP_HEIGHT 32 -#define TINY16_TILEMAP_PIXEL_WIDTH (TINY16_TILEMAP_WIDTH * TINY16_TILE_WIDTH) // 1024 -#define TINY16_TILEMAP_PIXEL_HEIGHT (TINY16_TILEMAP_HEIGHT * TINY16_TILE_HEIGHT) // 256 +#define TINY16_TILEMAP_PIXEL_WIDTH (TINY16_TILEMAP_WIDTH * TINY16_TILE_WIDTH) +#define TINY16_TILEMAP_PIXEL_HEIGHT (TINY16_TILEMAP_HEIGHT * TINY16_TILE_HEIGHT) // Tilemap entry attributes enum { TINY16_TILEMAP_ATTR_FLIP_H = 1 << 0, TINY16_TILEMAP_ATTR_FLIP_V = 1 << 1, TINY16_TILEMAP_ATTR_PALETTE_SHIFT = 2, - TINY16_TILEMAP_ATTR_PALETTE_MASK = 0x0C, // bits 2-3: palette index (0-3) + TINY16_TILEMAP_ATTR_PALETTE_MASK = 0x0C, }; // Combined tilemap entry: 2 bytes per tile typedef struct { - uint8_t tile; // Tile index (0-255) - uint8_t attr; // Attributes: [------VH] V=vflip, H=hflip + uint8_t tile; + uint8_t attr; } Tiny16TilemapEntry; typedef struct { Tiny16TilemapEntry entries[TINY16_TILEMAP_HEIGHT][TINY16_TILEMAP_WIDTH]; } Tiny16Tilemap; -// // Palette -// #define TINY16_PALETTE_SIZE 16 #define TINY16_PALETTE_COUNT 4 typedef struct { - uint8_t color; // RGB332: RRRGGGBB + uint8_t color; } Tiny16PaletteEntry; typedef struct { Tiny16PaletteEntry entries[TINY16_PALETTE_SIZE]; } Tiny16Palette; -// // OAM -// enum { - TINY16_OAM_ATTR_PALETTE_MASK = 0x03, // bits 0-1: palette index (0-3) - TINY16_OAM_ATTR_BEHIND_BG = 1 << 5, // Render behind opaque background pixels + TINY16_OAM_ATTR_PALETTE_MASK = 0x03, + TINY16_OAM_ATTR_BEHIND_BG = 1 << 5, TINY16_OAM_ATTR_FLIP_H = 1 << 6, TINY16_OAM_ATTR_FLIP_V = 1 << 7, }; @@ -70,15 +62,13 @@ enum { #define TINY16_OAM_SPRITE_HIDDEN 0xFF typedef struct { - uint8_t y; // Y position (0xFF = hidden) - uint8_t x; // X position - uint8_t tile; // Tile index (0-255) - uint8_t attr; // Attributes: [VHB__PPP] V=vflip, H=hflip, B=behind BG, P=palette (0-3) + uint8_t y; + uint8_t x; + uint8_t tile; + uint8_t attr; } Tiny16OAMEntry; -// // PPU -// enum { TINY16_PPU_CTRL_ENABLE_BG = 1 << 0, TINY16_PPU_CTRL_ENABLE_SPRITES = 1 << 1,