From 0ee9d02b5af7afc5f665b2bc828a06259526c50d Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Sun, 8 Sep 2024 15:32:05 +0200 Subject: [PATCH 01/13] compiler: test: tac codegen: re-enable Expr * test The testcase was disabled but seems to be working. Signed-off-by: Alexander Hansen --- .../main/avr_code_gen/cg_avr_basic_block.c | 12 ++- compiler/main/gen_tac/gen_tac_call.c | 74 ++++++++++++++++--- stdlib/Makefile | 17 +++-- stdlib/collections/array.dg | 16 +--- stdlib/collections/arraylist.dg | 18 ++--- stdlib/collections/intbintree.dg | 47 ++++++------ stdlib/collections/linkedlist.dg | 46 ++++++------ stdlib/math.dg | 16 ++-- stdlib/primes.dg | 4 +- tables/sst/sst.c | 5 +- tac/tac.c | 8 ++ tac/tac.h | 4 + tac/tac_str.c | 7 ++ 13 files changed, 170 insertions(+), 104 deletions(-) diff --git a/compiler/main/avr_code_gen/cg_avr_basic_block.c b/compiler/main/avr_code_gen/cg_avr_basic_block.c index 0f3258e9..3460bddd 100644 --- a/compiler/main/avr_code_gen/cg_avr_basic_block.c +++ b/compiler/main/avr_code_gen/cg_avr_basic_block.c @@ -1,6 +1,7 @@ #include #include +#include "compiler/cli/flags/flags.h" #include "tables/symtable/symtable.h" #include "tac/tac.h" @@ -21,6 +22,10 @@ void emit_asm_avr_basic_block(struct BasicBlock* block, struct Ctx* ctx, struct if (block == NULL || block->visited_emit_asm) return; + if (flags_debug(ctx_flags(ctx))) { + printf("%s\n", __func__); + } + block->visited_emit_asm = true; //create register allocation table for the basic block. @@ -32,15 +37,16 @@ void emit_asm_avr_basic_block(struct BasicBlock* block, struct Ctx* ctx, struct //TODO: use better approach allocate_registers(block->buffer, rat, ctx_tables(ctx)); + if (flags_debug(ctx_flags(ctx))) { + rat_print(rat); + } + for (size_t i = 0; i < tacbuffer_count(block->buffer); i++) { struct TAC* t = tacbuffer_get(block->buffer, i); emit_asm_avr_single_tac(rat, t, ctx, ibu); } - //if(ctx->flags->debug) - //rat_print(rat); - rat_dtor(rat); //false/default branch gets emitted first, diff --git a/compiler/main/gen_tac/gen_tac_call.c b/compiler/main/gen_tac/gen_tac_call.c index f0027376..d3669c3d 100644 --- a/compiler/main/gen_tac/gen_tac_call.c +++ b/compiler/main/gen_tac/gen_tac_call.c @@ -11,26 +11,80 @@ #include "gen_tac.h" -void tac_call(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx) { +static void tac_call_case_sst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx); +static void tac_call_case_lvst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx); - const char* fname = call->callable->simple_var->name; +static void tac_call_prep_param(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx, int i, const bool push16) { + struct Expr* expr = call->args[i]; - struct SST* sst = ctx_tables(ctx)->sst; - struct SSTLine* line = sst_get(sst, fname); + tac_expr(buffer, expr, ctx); - for (size_t i = 0; i < call->count_args; i++) { + struct TAC* t = makeTACParam(tacbuffer_last_dest(buffer), push16); + + tacbuffer_append(buffer, t); +} - struct Expr* expr = call->args[i]; +static void tac_call_prep_params_case_sst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx, struct MethodDecl* decl) { + for (size_t i = 0; i < call->count_args; i++) { + const bool push16 = 16 == lvst_sizeof_type(decl->args[i]->type); + tac_call_prep_param(buffer, call, ctx, i, push16); + } +} - tac_expr(buffer, expr, ctx); +static void tac_call_prep_params_case_lvst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx, struct LVSTLine* line) { + for (size_t i = 0; i < call->count_args; i++) { + struct Type* arg_type = line->type->basic_type->subr_type->arg_types[i]; + const bool push16 = 16 == lvst_sizeof_type(arg_type); + tac_call_prep_param(buffer, call, ctx, i, push16); + } +} - const bool push16 = 16 == lvst_sizeof_type(line->method->decl->args[i]->type); +void tac_call(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx) { - struct TAC* t = makeTACParam(tacbuffer_last_dest(buffer), push16); + char* fname = call->callable->simple_var->name; + struct SST* sst = ctx_tables(ctx)->sst; + struct LVST* lvst = ctx_tables(ctx)->lvst; - tacbuffer_append(buffer, t); + if (sst_contains(sst, fname)) { + tac_call_case_sst(buffer, call, ctx); + return; + } + if (lvst_contains(lvst, fname)) { + tac_call_case_lvst(buffer, call, ctx); + return; } + fprintf(stderr, "did not find symbol '%s' in LVST or SST, cannot call.\n", fname); + fprintf(stderr, "exiting."); + exit(1); +} + +static void tac_call_case_lvst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx) { + + struct LVST* lvst = ctx_tables(ctx)->lvst; + char* fname = call->callable->simple_var->name; + + struct LVSTLine* line = lvst_get(lvst, fname); + tac_call_prep_params_case_lvst(buffer, call, ctx, line); + uint32_t tmp = make_temp(); + struct TAC* t1 = makeTACLoadLocal(tmp, lvst_index_of(lvst, fname)); + struct TAC* t2 = makeTACICall(make_temp(), tmp); + + tacbuffer_append(buffer, t1); + tacbuffer_append(buffer, t2); +} + +static void tac_call_case_sst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx) { + + const char* fname = call->callable->simple_var->name; + + struct SST* sst = ctx_tables(ctx)->sst; + struct SSTLine* line = sst_get(sst, fname); + + struct MethodDecl* decl = line->method->decl; + + tac_call_prep_params_case_sst(buffer, call, ctx, decl); + if (call->callable->member_access != NULL) { printf("member access calls currently unsupported on avr_code_gen\n"); exit(1); diff --git a/stdlib/Makefile b/stdlib/Makefile index aae81479..00f75c3a 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -11,18 +11,21 @@ TESTS := tests/test_matrix.dg \ #tests/collections/test_stack.dg \ SOURCES := test.dg \ - #math.dg \ - #collections/intbintree.dg \ - #collections/linkedlist.dg \ - #collections/arraylist.dg - #collections/array.dg \ - #primes.dg \ + math.dg \ + collections/linkedlist.dg \ + collections/arraylist.dg \ + collections/array.dg \ + primes.dg \ + collections/intbintree.dg \ #polynomial.dg \ #collections/set.dg \ #collections/stack.dg \ test: $(SOURCES) clean - sd $(SOURCES) + sd $(SOURCES) + +debug: $(SOURCES) clean + sd -debug $(SOURCES) clean: rm -f a.out diff --git a/stdlib/collections/array.dg b/stdlib/collections/array.dg index 3e7b5b23..ffa2980a 100644 --- a/stdlib/collections/array.dg +++ b/stdlib/collections/array.dg @@ -1,21 +1,7 @@ #include //simple functions dealing with arrays of integers -fn array_reduce( - [?T0] arr, - uint size, - ((?T0, ?T0) -> ?T0) reducer, - ?T0 initial -) -> ?T0 { - - ?T0 current = initial; - for i in 0 .. (size - 1) { - current = reducer(current, arr[i]); - } - return current; -} - -fn array_contains([?T0] arr, uint size, ?T0 elem) -> bool { +fn array_contains([int] arr, uint size, int elem) -> bool { for i in 0 .. (size - 1) { if arr[i] == elem { return true; } diff --git a/stdlib/collections/arraylist.dg b/stdlib/collections/arraylist.dg index e5477808..21a0a253 100644 --- a/stdlib/collections/arraylist.dg +++ b/stdlib/collections/arraylist.dg @@ -1,23 +1,23 @@ -struct ArrayList { +struct ArrayList { - @private [?T0] arr; + @private [int] arr; @private uint size; @private uint capacity; } -fn arraylist_size(ArrayList list) -> uint { +fn arraylist_size(ArrayList list) -> uint { return list.size; } -fn arraylist_at(ArrayList list, uint index) -> ?T0 { - +fn arraylist_at(ArrayList list, uint index) -> int { + return list.arr[index]; } -fn arraylist_contains(ArrayList list, ?T0 elem) -> bool { +fn arraylist_contains(ArrayList list, int elem) -> bool { for i in 0 .. (list.size - 1) { if list.arr[i] == elem { return true; } @@ -25,15 +25,15 @@ fn arraylist_contains(ArrayList list, ?T0 elem) -> bool { return false; } -fn arraylist_index_of(ArrayList list, ?T0 elem) -> int { - +fn arraylist_index_of(ArrayList list, int elem) -> int { + for i in 0 .. (list.size - 1) { if list.arr[i] == elem { return i; } } return -1; } -fn arraylist_clear(ArrayList list) ~> bool { +fn arraylist_clear(ArrayList list) ~> bool { list.size = 0; return true; } diff --git a/stdlib/collections/intbintree.dg b/stdlib/collections/intbintree.dg index f09f60d1..5819ecdc 100644 --- a/stdlib/collections/intbintree.dg +++ b/stdlib/collections/intbintree.dg @@ -1,36 +1,35 @@ -#include //an implementation of a binary tree for integers -struct IntBinTree { +struct IntBinTree { @private bool has_root; @private - IntBinTreeNode root; + IntBinTreeNode root; } @private struct IntBinTreeNode { int key; - + bool has_left; IntBinTreeNode left; - + bool has_right; IntBinTreeNode right; } fn intbintree_contains(IntBinTree t, int key) -> bool { - + return intbintreenode_contains(t.root, key); } fn intbintree_size(IntBinTree t) -> uint { if !t.has_root { return 0; } - + return intbintreenode_size(t.root); } @@ -46,22 +45,22 @@ fn intbintree_visit (IntBinTree t, ( (int)->bool ) visitor) -> bool { fn intbintreenode_contains(IntBinTreeNode t, int key) -> bool { current = t; - + while true { - switch compare(key, current.key) { - case 0 { return true; } - case -1 { - if !current.has_left { return false; } - current = current.left; - } - case 1 { - if !current.has_right { return false; } - current = current.right; - } + int c = compare(key, current.key); + + if c == 0 { return true; } + if c == -1 { + if !current.has_left { return false; } + current = current.left; + } + if c == 1 { + if !current.has_right { return false; } + current = current.right; } } - + return false; } @@ -69,20 +68,20 @@ fn intbintreenode_contains(IntBinTreeNode t, int key) -> bool { fn intbintreenode_size(IntBinTreeNode t) -> uint { res = 1; - + if t.has_left { res += intbintreenode_size(t.left); - } + } if t.has_right { res += intbintreenode_size(t.right); } - + return res; } @private fn intbintreenode_visit(IntBinTreeNode t, ((int)->bool) visitor) -> bool { - + if t.has_left { intbintreenode_visit(t.left, visitor); } @@ -90,7 +89,7 @@ fn intbintreenode_visit(IntBinTreeNode t, ((int)->bool) visitor) -> bool { if t.has_right { intbintreenode_visit(t.right, visitor); } - + return true; } diff --git a/stdlib/collections/linkedlist.dg b/stdlib/collections/linkedlist.dg index 95e300db..efef63c3 100644 --- a/stdlib/collections/linkedlist.dg +++ b/stdlib/collections/linkedlist.dg @@ -2,54 +2,54 @@ //A simple double-linked list -struct LinkedList { +struct LinkedList { @private uint size; - + @private bool is_empty; - @private LLNode head; - @private LLNode tail; + @private LLNode head; + @private LLNode tail; } @private -struct LLNode { +struct LLNode { - ?T0 value; + int value; bool has_next; - - LLNode prev; - LLNode next; + + LLNode prev; + LLNode next; } @halts -fn linkedlist_size(LinkedList l) -> uint { - return l.size; +fn linkedlist_size(LinkedList l) -> uint { + return l.size; } -fn linkedlist_contains(LinkedList l, ?T0 value) -> bool { - +fn linkedlist_contains(LinkedList l, int value) -> bool { + return linkedlist_index_of(l, value) >= 0; } -fn linkedlist_index_of(LinkedList l, ?T0 value) -> int { - - LLNode current = l.head; +fn linkedlist_index_of(LinkedList l, int value) -> int { + + LLNode current = l.head; int index = 0; - + while current.has_next { - - if current.value == value { + + if current.value == value { return index; } - + current = current.next; index++; } - - if current.value == value { + + if current.value == value { return index; } - + return -1; } diff --git a/stdlib/math.dg b/stdlib/math.dg index a5724bd7..9d0156d0 100644 --- a/stdlib/math.dg +++ b/stdlib/math.dg @@ -42,7 +42,7 @@ fn min (int a,int b) -> int { if a < b {return a;} return b; } -/* + fn gcd (int a, int b) -> int { if a==0 {return b;} return gcd(mod(b,a), a); @@ -60,30 +60,30 @@ fn mod(int a, int b) -> int { } fn div(int a, int b) -> int { - + //TODO x=0; return x; } -*/ + @halts fn fib(uint n) -> uint { uint a = 0; uint b = 1; - + for i in 1 .. (n-1) { - + uint k = a+b; a = b; b = k; } - + return a; } @halts -fn iseven(int x) -> bool { return x & 0x01 == 0; } +fn iseven(int x) -> bool { return (x & 0x01) == 0; } @halts -fn isodd(int x) -> bool { return x & 0x01 == 1; } +fn isodd(int x) -> bool { return (x & 0x01) == 1; } diff --git a/stdlib/primes.dg b/stdlib/primes.dg index 58c3bca2..43ba5a62 100644 --- a/stdlib/primes.dg +++ b/stdlib/primes.dg @@ -3,11 +3,11 @@ @halts fn isprime(uint n) -> bool { - + uint count = 0; for k in 1 .. n { - + if mod(n, k) == 0 { count++; } } diff --git a/tables/sst/sst.c b/tables/sst/sst.c index 2fb6ceb8..94fd909b 100644 --- a/tables/sst/sst.c +++ b/tables/sst/sst.c @@ -15,7 +15,7 @@ #define ERR_SAME_NAME "[SST][Error] 2 subroutines with same name\n" -#define ERR_NOT_FOUND "[SST][Error] subroutine not found\n" +#define ERR_NOT_FOUND "[SST][Error] subroutine not found" struct SST { //Subroutine Symbol Table (SST) @@ -159,8 +159,7 @@ struct SSTLine* sst_get(struct SST* sst, char* name) { if (strcmp(line->name, name) == 0) { return line; } } - printf(ERR_NOT_FOUND); - printf("\t%s in sst_get\n", name); + printf("%s: '%s'\n", ERR_NOT_FOUND, name); exit(1); return NULL; } diff --git a/tac/tac.c b/tac/tac.c index 49ff9b75..a8c030a3 100644 --- a/tac/tac.c +++ b/tac/tac.c @@ -242,6 +242,14 @@ struct TAC* makeTACCall(uint32_t tmp, uint32_t function_index) { return t; } +struct TAC* makeTACICall(uint32_t tmp, uint32_t tmp_call) { + struct TAC* t = makeTAC(); + t->kind = TAC_ICALL; + t->dest = tmp; + t->arg1 = tmp_call; + return t; +} + struct TAC* makeTACSetupStackframe(uint32_t frame_size) { struct TAC* t = makeTAC(); t->kind = TAC_SETUP_STACKFRAME; diff --git a/tac/tac.h b/tac/tac.h index dcf15933..8989867c 100644 --- a/tac/tac.h +++ b/tac/tac.h @@ -57,6 +57,9 @@ enum TAC_KIND { TAC_CONST_VALUE, TAC_CALL, //call to a label (string) without anything else + TAC_ICALL, // call to a temporary 't1 = call t2'. + // So we can comput arbitrary address to call. + // Good for calling function pointers TAC_PARAM, TAC_RETURN, //return, without arguments @@ -134,6 +137,7 @@ struct TAC* makeTACLoadConstAddr(uint32_t dest, uint32_t addr); struct TAC* makeTACParam(uint32_t dest, bool push16); struct TAC* makeTACCall(uint32_t tmp, uint32_t function_index); +struct TAC* makeTACICall(uint32_t tmp, uint32_t tmp_call); struct TAC* makeTACSetupStackframe(uint32_t frame_size); struct TAC* makeTACSetupSP(); diff --git a/tac/tac_str.c b/tac/tac_str.c index 8449fb64..7ebcaa4e 100644 --- a/tac/tac_str.c +++ b/tac/tac_str.c @@ -129,6 +129,9 @@ char* tac_tostring(struct TAC* t, struct Ctx* ctx) { } sprintf(buffer, "t%d = call %s", t->dest, function_name); } break; + case TAC_ICALL: { + sprintf(buffer, "t%d = call t%ld", t->dest, t->arg1); + } break; case TAC_PARAM: sprintf(buffer, "param t%d", t->arg1); @@ -146,6 +149,10 @@ char* tac_tostring(struct TAC* t, struct Ctx* ctx) { case TAC_SETUP_SP: sprintf(buffer, "setup SP"); break; + default: + printf("unhandled in %s\n", __func__); + exit(1); + break; } strcat(res, buffer); From 678320e010235dc753cdc6a9bca9f1ca1bd75e86 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Sun, 22 Sep 2024 14:00:06 +0200 Subject: [PATCH 02/13] stdlib/examples restructuring --- .../compile_ir/compile_tac_param.c | 24 +++++++++++--- .../compile_ir/compile_tac_store_const_addr.c | 8 ++++- compiler/main/compiler.c | 8 +++-- compiler/main/gen_tac/gen_tac_call.c | 11 +++++-- compiler/main/typechecker/tc_assignstmt.c | 4 +++ compiler/main/typechecker/tc_forstmt.c | 6 +++- compiler/main/typechecker/tc_ifstmt.c | 4 +++ compiler/main/typechecker/tc_method.c | 6 +++- compiler/main/typechecker/tc_methodcall.c | 13 ++++++++ compiler/main/typechecker/tc_retstmt.c | 4 +++ compiler/main/typechecker/tc_stmts.c | 5 +++ compiler/main/typechecker/tc_whilestmt.c | 4 +++ compiler/main/typechecker/tcctx.h | 2 ++ compiler/main/typechecker/typecheck.c | 19 ++++++++++- compiler/main/typechecker/typecheck.h | 4 ++- compiler/main/typeinference/typeinfer_const.c | 6 +++- compiler/main/util/fill_tables.c | 4 +++ .../compile_ir/test_compile_tac_param.c | 4 +-- compiler/test/gen_tac/test_gen_tac.h | 3 +- compiler/test/gen_tac/test_gen_tac_call.c | 32 ++++++++++++++++-- compiler/test/testcases.c | 3 +- .../test/typechecker/test_typechecker_util.c | 2 +- examples/Makefile | 14 ++++---- examples/led_blink/Makefile | 13 -------- examples/led_blink_no_timer/Makefile | 10 ++++++ .../led_blink_no_timer.dg | 0 examples/led_blink_timer/Makefile | 11 +++++++ .../led_blink.dg | 11 +++---- examples/portb/Makefile | 11 +++++++ examples/portb/test_portb.dg | 33 +++++++++++++++++++ stdlib/Makefile | 19 ++++++----- stdlib/{ => avr}/portb.dg | 4 +-- stdlib/{ => avr}/timer0.dg | 0 stdlib/{ => base}/math.dg | 0 stdlib/{ => base}/polynomial.dg | 0 stdlib/{ => base}/primes.dg | 0 stdlib/collections/set.dg | 18 +++++----- stdlib/collections/stack.dg | 16 ++++----- tables/lvst/lvst.c | 1 + tables/sst/sst.c | 2 +- tables/stst/stst_print.c | 2 +- tables/symtable/symtable.c | 2 +- 42 files changed, 266 insertions(+), 77 deletions(-) delete mode 100644 examples/led_blink/Makefile create mode 100644 examples/led_blink_no_timer/Makefile rename examples/{led_blink => led_blink_no_timer}/led_blink_no_timer.dg (100%) create mode 100644 examples/led_blink_timer/Makefile rename examples/{led_blink => led_blink_timer}/led_blink.dg (79%) create mode 100644 examples/portb/Makefile create mode 100644 examples/portb/test_portb.dg rename stdlib/{ => avr}/portb.dg (66%) rename stdlib/{ => avr}/timer0.dg (100%) rename stdlib/{ => base}/math.dg (100%) rename stdlib/{ => base}/polynomial.dg (100%) rename stdlib/{ => base}/primes.dg (100%) diff --git a/compiler/main/avr_code_gen/compile_ir/compile_tac_param.c b/compiler/main/avr_code_gen/compile_ir/compile_tac_param.c index 915b64dc..3129eeb6 100644 --- a/compiler/main/avr_code_gen/compile_ir/compile_tac_param.c +++ b/compiler/main/avr_code_gen/compile_ir/compile_tac_param.c @@ -1,5 +1,6 @@ #include #include +#include #include "rat/rat.h" @@ -8,12 +9,27 @@ void compile_tac_param(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu) { - const char* c = "TAC_PARAM"; + char* c = "TAC_PARAM"; const int reg_dest = rat_get_register(rat, tac->dest); - push(reg_dest, c); + assert(tac->const_value % 8 == 0); + assert(tac->const_value <= 64); + + if (tac->const_value == 16) { + // this means it's a 16 bit parameter + // so we must push twice + + //TODO: ensure that the temporary has the correct width in RAT + //assert(rat_is_wide(rat, tac->dest)); - if (rat_is_wide(rat, tac->dest) && tac->const_value == 16) - push(reg_dest + 1, c); + if (rat_is_wide(rat, tac->dest)) { + push(reg_dest + 1, c); + } else { + ldi(rat_scratch_reg(rat), 0, c); + push(rat_scratch_reg(rat), c); + } + } + + push(reg_dest, c); } diff --git a/compiler/main/avr_code_gen/compile_ir/compile_tac_store_const_addr.c b/compiler/main/avr_code_gen/compile_ir/compile_tac_store_const_addr.c index c99c82a5..4b0cfc69 100644 --- a/compiler/main/avr_code_gen/compile_ir/compile_tac_store_const_addr.c +++ b/compiler/main/avr_code_gen/compile_ir/compile_tac_store_const_addr.c @@ -10,5 +10,11 @@ void compile_tac_store_const_addr(struct RAT* rat, struct TAC* tac, struct IBuff const uint32_t addr = tac->const_value; - sts(addr, reg_src, "TAC_STORE_CONST_ADDR"); + char* c = "TAC_STORE_CONST_ADDR"; + + sts(addr, reg_src, c); + + if (rat_is_wide(rat, tac->arg1)) { + sts(addr + 1, reg_src + 1, c); + } } diff --git a/compiler/main/compiler.c b/compiler/main/compiler.c index fafe4ad6..997d5a50 100644 --- a/compiler/main/compiler.c +++ b/compiler/main/compiler.c @@ -58,16 +58,20 @@ bool compile(struct Flags* flags) { ast->namespaces[i] = ns; } - struct Ctx* ctx = ctx_ctor(flags, st_ctor(flags_debug(flags))); + struct Ctx* ctx = ctx_ctor(flags, st_ctor()); fill_tables(ast, ctx); - struct TCError* errors = typecheck_ast(ast, ctx_tables(ctx), true); + struct TCError* errors = typecheck_ast(ast, ctx, true); if (errors != NULL) { return false; } + if (flags_debug(flags)) { + printf("[debug] running analyzers...\n"); + } + analyze_functions(ctx_tables(ctx), ast); analyze_dead_code(ctx_tables(ctx), ast); analyze_termination(ctx_tables(ctx)); diff --git a/compiler/main/gen_tac/gen_tac_call.c b/compiler/main/gen_tac/gen_tac_call.c index d3669c3d..006f4861 100644 --- a/compiler/main/gen_tac/gen_tac_call.c +++ b/compiler/main/gen_tac/gen_tac_call.c @@ -1,5 +1,6 @@ #include #include +#include #include "tac/tac.h" #include "tac/tacbuffer.h" @@ -26,7 +27,10 @@ static void tac_call_prep_param(struct TACBuffer* buffer, struct Call* call, str static void tac_call_prep_params_case_sst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx, struct MethodDecl* decl) { for (size_t i = 0; i < call->count_args; i++) { - const bool push16 = 16 == lvst_sizeof_type(decl->args[i]->type); + const uint32_t param_width = lvst_sizeof_type(decl->args[i]->type); + assert(param_width <= 8); + const bool push16 = param_width == 2; + tac_call_prep_param(buffer, call, ctx, i, push16); } } @@ -34,7 +38,10 @@ static void tac_call_prep_params_case_sst(struct TACBuffer* buffer, struct Call* static void tac_call_prep_params_case_lvst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx, struct LVSTLine* line) { for (size_t i = 0; i < call->count_args; i++) { struct Type* arg_type = line->type->basic_type->subr_type->arg_types[i]; - const bool push16 = 16 == lvst_sizeof_type(arg_type); + const uint32_t param_width = lvst_sizeof_type(arg_type); + assert(param_width <= 8); + const bool push16 = param_width == 2; + tac_call_prep_param(buffer, call, ctx, i, push16); } } diff --git a/compiler/main/typechecker/tc_assignstmt.c b/compiler/main/typechecker/tc_assignstmt.c index bbedeb2b..4437aa3c 100644 --- a/compiler/main/typechecker/tc_assignstmt.c +++ b/compiler/main/typechecker/tc_assignstmt.c @@ -25,6 +25,10 @@ static bool check_type_rules_assign(struct AssignStmt* a, struct TCCtx* tcctx); bool tc_assignstmt(struct AssignStmt* a, struct TCCtx* tcctx) { + if (tcctx->debug) { + printf("[debug] typecheck assign stmt\n"); + } + tcctx->current_line_num = a->super.line_num; struct LVSTLine* line = lvst_get(tcctx->st->lvst, a->var->simple_var->name); diff --git a/compiler/main/typechecker/tc_forstmt.c b/compiler/main/typechecker/tc_forstmt.c index e9382a1d..ab5ac96b 100644 --- a/compiler/main/typechecker/tc_forstmt.c +++ b/compiler/main/typechecker/tc_forstmt.c @@ -16,6 +16,10 @@ bool tc_forstmt(struct ForStmt* f, struct TCCtx* tcctx) { + if (tcctx->debug) { + printf("[debug] typecheck for stmt\n"); + } + tcctx->current_line_num = f->super.line_num; if (!tc_range(f->range, tcctx)) { return false; } @@ -25,4 +29,4 @@ bool tc_forstmt(struct ForStmt* f, struct TCCtx* tcctx) { tcctx->depth_inside_loop--; return is_ok; -} \ No newline at end of file +} diff --git a/compiler/main/typechecker/tc_ifstmt.c b/compiler/main/typechecker/tc_ifstmt.c index 8fa5d1df..3a53bfda 100644 --- a/compiler/main/typechecker/tc_ifstmt.c +++ b/compiler/main/typechecker/tc_ifstmt.c @@ -16,6 +16,10 @@ bool tc_ifstmt(struct IfStmt* i, struct TCCtx* tcctx) { + if (tcctx->debug) { + printf("[debug] typecheck if stmt\n"); + } + tcctx->current_line_num = i->super.line_num; struct Type* type = infer_type_expr(tcctx->st, i->condition); diff --git a/compiler/main/typechecker/tc_method.c b/compiler/main/typechecker/tc_method.c index b494558b..38499cff 100644 --- a/compiler/main/typechecker/tc_method.c +++ b/compiler/main/typechecker/tc_method.c @@ -16,6 +16,10 @@ bool tc_method(struct Method* m, struct TCCtx* tcctx) { + if (tcctx->debug) { + printf("[debug] typecheck method: %s\n", m->decl->name); + } + tcctx->current_line_num = m->super.line_num; tcctx->current_fn = m; @@ -24,4 +28,4 @@ bool tc_method(struct Method* m, struct TCCtx* tcctx) { lvst_fill(m, tcctx->st); return tc_stmtblock(m->block, tcctx); -} \ No newline at end of file +} diff --git a/compiler/main/typechecker/tc_methodcall.c b/compiler/main/typechecker/tc_methodcall.c index 6c21938b..4971a1a5 100644 --- a/compiler/main/typechecker/tc_methodcall.c +++ b/compiler/main/typechecker/tc_methodcall.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -36,6 +37,10 @@ static bool tc_methodcall_arg( bool tc_methodcall(struct Call* m, struct TCCtx* tcctx) { + if (tcctx->debug) { + printf("[debug] typecheck methodcall\n"); + } + tcctx->current_line_num = m->super.line_num; if (!tc_var(m->callable, tcctx)) { return false; } @@ -73,6 +78,11 @@ static bool tc_methodcall_args( struct Type** expect_types, uint8_t expect_args, struct TCCtx* tcctx) { + + if (tcctx->debug) { + printf("[debug] typecheck methodcall args\n"); + } + const uint8_t actual_args = m->count_args; if (actual_args != expect_args) { @@ -108,6 +118,9 @@ static bool tc_methodcall_arg( struct Type* actual_type = infer_type_expr(tcctx->st, actual_expr); + assert(expect_type != NULL); + assert(actual_type != NULL); + //TODO: we can get rid of the integer special cases maybe //thansk to tc_type_contains if (is_integer_type(expect_type) && is_integer_type(actual_type)) { return true; } diff --git a/compiler/main/typechecker/tc_retstmt.c b/compiler/main/typechecker/tc_retstmt.c index 101f1d4c..83a18ce0 100644 --- a/compiler/main/typechecker/tc_retstmt.c +++ b/compiler/main/typechecker/tc_retstmt.c @@ -17,6 +17,10 @@ bool tc_retstmt(struct RetStmt* r, struct TCCtx* tcctx) { + if (tcctx->debug) { + printf("[debug] typecheck return stmt\n"); + } + tcctx->current_line_num = r->super.line_num; struct Type* returnType = tcctx->current_fn->decl->return_type; diff --git a/compiler/main/typechecker/tc_stmts.c b/compiler/main/typechecker/tc_stmts.c index ba2c13fd..7ba78c4e 100644 --- a/compiler/main/typechecker/tc_stmts.c +++ b/compiler/main/typechecker/tc_stmts.c @@ -11,11 +11,16 @@ #include "typechecker/util/tc_errors.h" #include "typechecker/util/tc_utils.h" #include "tcctx.h" +#include bool tc_stmt(struct Stmt* s, struct TCCtx* tcctx) { tcctx->current_line_num = s->super.line_num; + if (tcctx->debug) { + printf("[debug] typecheck statement line %d\n", tcctx->current_line_num); + } + switch (s->kind) { case 1: return tc_methodcall(s->ptr.m1, tcctx); diff --git a/compiler/main/typechecker/tc_whilestmt.c b/compiler/main/typechecker/tc_whilestmt.c index 104e47b1..66a05847 100644 --- a/compiler/main/typechecker/tc_whilestmt.c +++ b/compiler/main/typechecker/tc_whilestmt.c @@ -16,6 +16,10 @@ bool tc_whilestmt(struct WhileStmt* w, struct TCCtx* tcctx) { + if (tcctx->debug) { + printf("[debug] typecheck while stmt\n"); + } + tcctx->current_line_num = w->super.line_num; struct Type* type = infer_type_expr(tcctx->st, w->condition); diff --git a/compiler/main/typechecker/tcctx.h b/compiler/main/typechecker/tcctx.h index ace236ef..3093c9a5 100644 --- a/compiler/main/typechecker/tcctx.h +++ b/compiler/main/typechecker/tcctx.h @@ -68,6 +68,8 @@ struct TCCtx { char* current_filename; uint32_t current_line_num; + + bool debug; }; #endif diff --git a/compiler/main/typechecker/typecheck.c b/compiler/main/typechecker/typecheck.c index b11416bc..e12375f7 100644 --- a/compiler/main/typechecker/typecheck.c +++ b/compiler/main/typechecker/typecheck.c @@ -6,8 +6,11 @@ #include "ast/ast.h" //Table Includes +#include "compiler/cli/flags/flags.h" #include "tables/symtable/symtable.h" +#include "util/ctx.h" + //Typechecker Includes #include "_tc.h" #include "typecheck.h" @@ -16,15 +19,27 @@ static void init_tcctx(struct TCCtx* tcctx); -struct TCError* typecheck_ast(struct AST* ast, struct ST* st, bool print_errors) { +struct TCError* typecheck_ast(struct AST* ast, struct Ctx* ctx, bool print_errors) { + + if (flags_debug(ctx_flags(ctx))) { + printf("[debug] typechecking AST...\n"); + } + struct ST* st = ctx_tables(ctx); struct TCCtx* tcctx = exit_malloc(sizeof(struct TCCtx)); init_tcctx(tcctx); tcctx->print_errors = print_errors; tcctx->st = st; + tcctx->debug = flags_debug(ctx_flags(ctx)); for (uint16_t i = 0; i < ast->count_namespaces; i++) { + + if (tcctx->debug) { + printf("[debug] typecheck namespace: %d\n", i); + printf("[debug] src_path: %s\n", ast->namespaces[i]->src_path); + } + tc_namespace(ast->namespaces[i], tcctx); } @@ -71,4 +86,6 @@ static void init_tcctx(struct TCCtx* tcctx) { tcctx->current_fn = NULL; tcctx->depth_inside_loop = 0; + + tcctx->debug = false; } diff --git a/compiler/main/typechecker/typecheck.h b/compiler/main/typechecker/typecheck.h index 4f3abdf2..ef6a61e9 100644 --- a/compiler/main/typechecker/typecheck.h +++ b/compiler/main/typechecker/typecheck.h @@ -5,6 +5,8 @@ struct AST; struct ST; #include "tcctx.h" +#include "util/ctx.h" + /* This Module provides Facilities * for typechecking smalldragon Programs. * @@ -24,6 +26,6 @@ struct ST; * inferring the type of '3 + myfunction' */ -struct TCError* typecheck_ast(struct AST* ast, struct ST* st, bool print_errors); +struct TCError* typecheck_ast(struct AST* ast, struct Ctx* ctx, bool print_errors); #endif diff --git a/compiler/main/typeinference/typeinfer_const.c b/compiler/main/typeinference/typeinfer_const.c index bf395fdd..e4f645a7 100644 --- a/compiler/main/typeinference/typeinfer_const.c +++ b/compiler/main/typeinference/typeinfer_const.c @@ -32,7 +32,11 @@ struct Type* infer_type_constvalue(struct ST* st, struct ConstValue* cv) { case 1: return typeFromStrPrimitive(st, "bool"); case 2: return infer_type_constvalue_int(st, cv->ptr.m2_int_const); case 3: return typeFromStrPrimitive(st, "char"); + case 6: // binary constant case 5: return infer_type_constvalue_int(st, cv->ptr.m5_hex_const); - default: return NULL; + default: + fprintf(stderr, "in %s: could not infer type of const value, extiting.\n", __func__); + exit(1); + return NULL; } } diff --git a/compiler/main/util/fill_tables.c b/compiler/main/util/fill_tables.c index 0c62e6a5..6e826239 100644 --- a/compiler/main/util/fill_tables.c +++ b/compiler/main/util/fill_tables.c @@ -12,6 +12,10 @@ void fill_tables(struct AST* ast, struct Ctx* ctx) { + if (flags_debug(ctx_flags(ctx))) { + printf("[debug] filling SST, STST tables...\n"); + } + sst_clear(ctx_tables(ctx)->sst); for (int i = 0; i < ast->count_namespaces; i++) { diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_param.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_param.c index ace06bd6..102416f7 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_param.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_param.c @@ -86,8 +86,8 @@ void test_compile_tac_param_case_16bit() { assert(sp == sp_old - 2); //assert that fixed_value is on the stack - assert((uint8_t)vmcu_system_read_data(system, sp_old - 1) == 0x0a); - assert((uint8_t)vmcu_system_read_data(system, sp_old) == 0xbc); + assert((uint8_t)vmcu_system_read_data(system, sp_old) == 0x0a); + assert((uint8_t)vmcu_system_read_data(system, sp_old - 1) == 0xbc); vmcu_system_dtor(system); } diff --git a/compiler/test/gen_tac/test_gen_tac.h b/compiler/test/gen_tac/test_gen_tac.h index 70dae1ef..25dd843d 100644 --- a/compiler/test/gen_tac/test_gen_tac.h +++ b/compiler/test/gen_tac/test_gen_tac.h @@ -71,7 +71,8 @@ void test_gen_tac_variable_case_2_member_access(); // call void test_gen_tac_call_case_no_args(); void test_gen_tac_call_case_1_args_return(); -void test_gen_tac_call_case_1_args_write(); +void test_gen_tac_call_case_1_args_write_8bit(); +void test_gen_tac_call_case_1_args_write_16bit(); void test_gen_tac_call_case_1_args_write_3fns(); void test_gen_tac_call_case_2_args(); diff --git a/compiler/test/gen_tac/test_gen_tac_call.c b/compiler/test/gen_tac/test_gen_tac_call.c index 2f917ff9..3779bb86 100644 --- a/compiler/test/gen_tac/test_gen_tac_call.c +++ b/compiler/test/gen_tac/test_gen_tac_call.c @@ -55,9 +55,9 @@ void test_gen_tac_call_case_1_args_return() { vmcu_system_dtor(system); } -void test_gen_tac_call_case_1_args_write() { +void test_gen_tac_call_case_1_args_write_8bit() { - status_test_codegen_tac("Call - 1 args - write to SRAM"); + status_test_codegen_tac("Call - 1 args - write to SRAM (8 bit)"); const uint8_t expected = 0xab; @@ -76,6 +76,34 @@ void test_gen_tac_call_case_1_args_write() { vmcu_system_dtor(system); } +void test_gen_tac_call_case_1_args_write_16bit() { + + status_test_codegen_tac("Call - 1 args - write to SRAM (16 bit)"); + + const uint16_t expected = 0x5973; + + char snippet[200]; + char* template = "fn main()->int{ f(%d); return 0; } fn f(uint16 a)->int { [0x100]=a; return 0; }"; + sprintf(snippet, template, expected); + + vmcu_system_t* system = prepare_vmcu_system_from_code_snippet(snippet); + + vmcu_system_step_n(system, 50); + + const uint8_t actual_low = vmcu_system_read_data(system, 0x100); + const uint8_t actual_high = vmcu_system_read_data(system, 0x101); + const uint16_t actual = (actual_high << 8) | actual_low; + + if (actual != expected) { + printf("actual: 0x%x\n", actual); + printf("expected: 0x%x\n", expected); + } + + assert(actual == expected); + + vmcu_system_dtor(system); +} + void test_gen_tac_call_case_1_args_write_3fns() { status_test_codegen_tac("Call - 1 args - write to SRAM - 3 functions"); diff --git a/compiler/test/testcases.c b/compiler/test/testcases.c index fcf745d3..501e5360 100644 --- a/compiler/test/testcases.c +++ b/compiler/test/testcases.c @@ -241,7 +241,8 @@ void (*tests_tac_codegen[])() = { // call test_gen_tac_call_case_no_args, test_gen_tac_call_case_1_args_return, - test_gen_tac_call_case_1_args_write, + test_gen_tac_call_case_1_args_write_8bit, + test_gen_tac_call_case_1_args_write_16bit, test_gen_tac_call_case_1_args_write_3fns, test_gen_tac_call_case_2_args, diff --git a/compiler/test/typechecker/test_typechecker_util.c b/compiler/test/typechecker/test_typechecker_util.c index d176bf94..e1a7340a 100644 --- a/compiler/test/typechecker/test_typechecker_util.c +++ b/compiler/test/typechecker/test_typechecker_util.c @@ -36,7 +36,7 @@ struct TCError* typecheck_file(char* filename) { fill_tables(ast, ctx); - struct TCError* errors = typecheck_ast(ast, ctx_tables(ctx), false); + struct TCError* errors = typecheck_ast(ast, ctx, false); ctx_dtor(ctx); diff --git a/examples/Makefile b/examples/Makefile index 5880b1b3..edfa1d5e 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -9,15 +9,17 @@ all: test test: @echo "[Examples] Compiling Example Programs..." - $(CALL2) ifstatement/ifstatement.dg + $(CALL2) ifstatement/ifstatement.dg $(CALL2) local_variables/simple.dg - $(CALL2) loops/whileloop.dg - $(CALL2) loops/forloop.dg - $(CALL2) mathematics/fibonacci.dg - $(CALL2) methodCalls/methodcall.dg - $(CALL2) other/everything.dg + $(CALL2) loops/whileloop.dg + $(CALL2) loops/forloop.dg + $(CALL2) mathematics/fibonacci.dg + $(CALL2) methodCalls/methodcall.dg + $(CALL2) other/everything.dg $(CALL2) typeinference/localvartypeinference.dg $(CALL2) array/array.dg + $(MAKE) -C led_blink_timer + $(MAKE) -C led_blink_no_timer @echo "[Examples] done" diff --git a/examples/led_blink/Makefile b/examples/led_blink/Makefile deleted file mode 100644 index 2f321bad..00000000 --- a/examples/led_blink/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -help: - @echo "make timer, make notimer, make clean" - -timer: clean - sd -debug led_blink.dg ../../stdlib/portb.dg ../../stdlib/timer0.dg - sudo avrdude -c arduino -p atmega328p -P /dev/ttyACM0 -U flash:w:led_blink.hex - -notimer: - sd -debug led_blink_no_timer.dg - sudo avrdude -c arduino -p atmega328p -P /dev/ttyACM0 -U flash:w:led_blink_no_timer.hex -clean: - rm -f *.hex *.obj *.cof *.asm - diff --git a/examples/led_blink_no_timer/Makefile b/examples/led_blink_no_timer/Makefile new file mode 100644 index 00000000..b1998237 --- /dev/null +++ b/examples/led_blink_no_timer/Makefile @@ -0,0 +1,10 @@ +main: compile + +compile: + sd led_blink_no_timer.dg + +flash: + sudo avrdude -c arduino -p atmega328p -P /dev/ttyACM0 -U flash:w:led_blink_no_timer.hex +clean: + rm -f *.hex *.obj *.cof *.asm *.png *.dot + diff --git a/examples/led_blink/led_blink_no_timer.dg b/examples/led_blink_no_timer/led_blink_no_timer.dg similarity index 100% rename from examples/led_blink/led_blink_no_timer.dg rename to examples/led_blink_no_timer/led_blink_no_timer.dg diff --git a/examples/led_blink_timer/Makefile b/examples/led_blink_timer/Makefile new file mode 100644 index 00000000..a1f015c0 --- /dev/null +++ b/examples/led_blink_timer/Makefile @@ -0,0 +1,11 @@ +main: compile + +compile: clean + sd led_blink.dg ../../stdlib/avr/portb.dg ../../stdlib/avr/timer0.dg + +flash: + sudo avrdude -c arduino -p atmega328p -P /dev/ttyACM0 -U flash:w:led_blink.hex + +clean: + rm -f *.hex *.obj *.cof *.asm *.png *.dot + diff --git a/examples/led_blink/led_blink.dg b/examples/led_blink_timer/led_blink.dg similarity index 79% rename from examples/led_blink/led_blink.dg rename to examples/led_blink_timer/led_blink.dg index 43b08790..d42492a8 100644 --- a/examples/led_blink/led_blink.dg +++ b/examples/led_blink_timer/led_blink.dg @@ -18,18 +18,16 @@ D13 PIN -------------------| fn main () ~> int { //set D13 / PB5 - //set PORTB Data Direction Register (DDRB) to enable DDRB5 - //[0x24] = 0b00100000; - - //set everything to output - portb_ddrd(0xff); + portb_ddrd(0xff); // set everything to output while(true){ portb_write(0b00010000); delay(); + delay(); portb_write(0b00100000); delay(); + delay(); } return 1; } @@ -42,8 +40,7 @@ fn delay() -> int { timer0_mode(0x0); //TCCR0B = 0b00000101, set prescaler to 1024 - //timer0_prescaler(0b00000101); - [0x45] = 0x5; + timer0_prescaler(0x5); //while(TCNT0 != 0xfe){} while(timer0_read() != 0xfe){} diff --git a/examples/portb/Makefile b/examples/portb/Makefile new file mode 100644 index 00000000..c20f2569 --- /dev/null +++ b/examples/portb/Makefile @@ -0,0 +1,11 @@ +main: compile + +compile: clean + sd test_portb.dg ../../stdlib/avr/portb.dg + +flash: + sudo avrdude -c arduino -p atmega328p -P /dev/ttyACM0 -U flash:w:test_portb.hex + +clean: + rm -f *.hex *.obj *.cof *.asm *.png *.dot + diff --git a/examples/portb/test_portb.dg b/examples/portb/test_portb.dg new file mode 100644 index 00000000..57146f69 --- /dev/null +++ b/examples/portb/test_portb.dg @@ -0,0 +1,33 @@ +//Program to make an LED glow + +//Arduino Board: +//https://docs.arduino.cc/resources/datasheets/A000066-datasheet.pdf + +/* Hardware Setup + + GND ----- LED ----- Resistor + | +D13 PIN -------------------| + +*/ + +//LED_BUILTIN PB5 +//PB5 is on D13 on the Arduino + +fn main () ~> int { + //set D13 / PB5 + + //set PORTB Data Direction Register (DDRB) to enable DDRB5 + //[0x24] = 0b00100000; + + portb_ddrd(0xff); // set everything to output + + portb_write(0b00010000); + portb_write(0b00100000); + + while(true){ + + } + return 1; +} + diff --git a/stdlib/Makefile b/stdlib/Makefile index 00f75c3a..1955f88d 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -3,7 +3,7 @@ TESTS := tests/test_matrix.dg \ #tests/test_math.dg \ #tests/collections/test_intbintree.dg \ #tests/collections/test_arraylist.dg \ - #tests/collections/test_linkedlist.dg + #tests/collections/test_linkedlist.dg \ #tests/collections/test_array.dg \ #tests/test_primes.dg \ #tests/test_polynomial.dg \ @@ -11,15 +11,17 @@ TESTS := tests/test_matrix.dg \ #tests/collections/test_stack.dg \ SOURCES := test.dg \ - math.dg \ collections/linkedlist.dg \ collections/arraylist.dg \ collections/array.dg \ - primes.dg \ + collections/set.dg \ + collections/stack.dg \ collections/intbintree.dg \ - #polynomial.dg \ - #collections/set.dg \ - #collections/stack.dg \ + base/math.dg \ + base/primes.dg \ + base/polynomial.dg \ + avr/portb.dg \ + avr/timer0.dg \ test: $(SOURCES) clean sd $(SOURCES) @@ -28,5 +30,6 @@ debug: $(SOURCES) clean sd -debug $(SOURCES) clean: - rm -f a.out - rm -f *.c + rm -f a.out + rm -f *.c *.asm *.hex *.obj + rm -f *.dot *.png diff --git a/stdlib/portb.dg b/stdlib/avr/portb.dg similarity index 66% rename from stdlib/portb.dg rename to stdlib/avr/portb.dg index 3f2fcaad..905188fa 100644 --- a/stdlib/portb.dg +++ b/stdlib/avr/portb.dg @@ -2,13 +2,13 @@ // PORTB 0x25 // DDRB 0x24 -fn portb_ddrd(uint16 value) -> int { +fn portb_ddrd(uint8 value) -> int { [0x24] = value; return 0; } -fn portb_write(uint16 value) -> int { +fn portb_write(uint8 value) -> int { [0x25] = value; return 0; diff --git a/stdlib/timer0.dg b/stdlib/avr/timer0.dg similarity index 100% rename from stdlib/timer0.dg rename to stdlib/avr/timer0.dg diff --git a/stdlib/math.dg b/stdlib/base/math.dg similarity index 100% rename from stdlib/math.dg rename to stdlib/base/math.dg diff --git a/stdlib/polynomial.dg b/stdlib/base/polynomial.dg similarity index 100% rename from stdlib/polynomial.dg rename to stdlib/base/polynomial.dg diff --git a/stdlib/primes.dg b/stdlib/base/primes.dg similarity index 100% rename from stdlib/primes.dg rename to stdlib/base/primes.dg diff --git a/stdlib/collections/set.dg b/stdlib/collections/set.dg index 72a9256b..db8115b0 100644 --- a/stdlib/collections/set.dg +++ b/stdlib/collections/set.dg @@ -1,37 +1,37 @@ #include -struct Set { +struct Set { @private uint size; @private uint capacity; - @private [?T0] arr; + @private [int] arr; } -fn set_size(Set s) -> uint { - +fn set_size(Set s) -> uint { + return s.size; } -fn set_contains(Set s, ?T0 x) -> bool { +fn set_contains(Set s, int x) -> bool { for i in 1 .. s.size { if s.arr[i-1] == x { return true; } } - + return false; } -fn set_remove(Set s, ?T0 x) -> bool { +fn set_remove(Set s, int x) -> bool { if !set_contains(s, x) { return true; } //find the index of the element uint index = 0; for i in 0 .. s.size - 1 { - if s.arr[i] == x { - + if s.arr[i] == x { + index = i; break; } diff --git a/stdlib/collections/stack.dg b/stdlib/collections/stack.dg index 0ff9107f..f9f4fa6f 100644 --- a/stdlib/collections/stack.dg +++ b/stdlib/collections/stack.dg @@ -2,19 +2,19 @@ //A naive implementation of a stack -struct Stack { +struct Stack { @private uint size; @private uint capacity; - @private [?T0] arr; + @private [int] arr; } -fn stack_size(Stack s) -> uint { +fn stack_size(Stack s) -> uint { return s.size; } -fn stack_contains(Stack s, ?T0 elem) -> bool { - +fn stack_contains(Stack s, int elem) -> bool { + for i in 0 .. (s.size - 1) { if s.arr[i] == elem { return true; } } @@ -22,15 +22,15 @@ fn stack_contains(Stack s, ?T0 elem) -> bool { } -fn stack_peek(Stack s) -> ?T0 { +fn stack_peek(Stack s) -> int { return s.arr[s.size - 1]; } -fn stack_pop(Stack s) -> ?T0 { +fn stack_pop(Stack s) -> int { res = stack_peek(s); s.size--; - + return res; } diff --git a/tables/lvst/lvst.c b/tables/lvst/lvst.c index e7524055..4095ac2c 100644 --- a/tables/lvst/lvst.c +++ b/tables/lvst/lvst.c @@ -220,6 +220,7 @@ uint32_t lvst_sizeof_arraytype(struct ArrayType* at) { return 2; } +// returns the size in number of bytes uint32_t lvst_sizeof_type(struct Type* type) { if (type == NULL) { diff --git a/tables/sst/sst.c b/tables/sst/sst.c index 94fd909b..a0c0ec20 100644 --- a/tables/sst/sst.c +++ b/tables/sst/sst.c @@ -39,7 +39,7 @@ struct SST* sst_ctor() { const int nbytes = sizeof(struct SSTLine*) * sst->capacity; sst->count = 0; - sst->lines = malloc(nbytes); + sst->lines = exit_malloc(nbytes); return sst; } diff --git a/tables/stst/stst_print.c b/tables/stst/stst_print.c index ee701e6c..5968c197 100644 --- a/tables/stst/stst_print.c +++ b/tables/stst/stst_print.c @@ -7,7 +7,7 @@ static char* fmt = "%16s|%16s|\n"; void stst_print(struct STST* stst) { - printf("[STST] Struct Symbol Table\n"); + printf("[STST] Struct Symbol Table (%d elements)\n", stst_size(stst)); printf(fmt, "struct name", "member name"); //-------- diff --git a/tables/symtable/symtable.c b/tables/symtable/symtable.c index f4328523..aed01525 100644 --- a/tables/symtable/symtable.c +++ b/tables/symtable/symtable.c @@ -17,7 +17,7 @@ struct ST* st_ctor() { const uint32_t nbytes = sizeof(struct Type*) * st->inferred_types_capacity; - st->inferred_types = malloc(nbytes); + st->inferred_types = exit_malloc(nbytes); st->sst = sst_ctor(); st->stst = stst_ctor(); From 1d8d48742a98bc3f9405e2a3fc0053284ce964d2 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Sun, 22 Sep 2024 22:08:27 +0200 Subject: [PATCH 03/13] avr: restore frame pointer YL:YH after a call The frame pointer could have been changed by the function that was called. Since it is using YL:YH also for it's frame pointer. So the frame pointer needs to be restored after a call. --- .../compile_ir/compile_tac_call.c | 5 ++ compiler/test/gen_tac/test_gen_tac.h | 2 + compiler/test/gen_tac/test_gen_tac_call.c | 75 +++++++++++++++++++ compiler/test/testcases.c | 2 + 4 files changed, 84 insertions(+) diff --git a/compiler/main/avr_code_gen/compile_ir/compile_tac_call.c b/compiler/main/avr_code_gen/compile_ir/compile_tac_call.c index 153be69d..161a9c9c 100644 --- a/compiler/main/avr_code_gen/compile_ir/compile_tac_call.c +++ b/compiler/main/avr_code_gen/compile_ir/compile_tac_call.c @@ -40,4 +40,9 @@ void compile_tac_call(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu, str for (uint32_t i = 0; i < size; i++) { pop(RAT_SCRATCH_REG, "remove call params"); } + + // load possibly corrupted frame pointer + //load base pointer Y + in(YL, SPL, "restore frame pointer Y after call"); + in(YH, SPH, "restore frame pointer Y after call"); } diff --git a/compiler/test/gen_tac/test_gen_tac.h b/compiler/test/gen_tac/test_gen_tac.h index 25dd843d..2f287649 100644 --- a/compiler/test/gen_tac/test_gen_tac.h +++ b/compiler/test/gen_tac/test_gen_tac.h @@ -75,6 +75,8 @@ void test_gen_tac_call_case_1_args_write_8bit(); void test_gen_tac_call_case_1_args_write_16bit(); void test_gen_tac_call_case_1_args_write_3fns(); void test_gen_tac_call_case_2_args(); +void test_gen_tac_call_case_frame_pointer_restored_after_call(); +void test_gen_tac_call_case_frame_pointer_restored_after_call_caller_has_locals(); // struct decl void test_gen_tac_structdecl_case_read_struct(); diff --git a/compiler/test/gen_tac/test_gen_tac_call.c b/compiler/test/gen_tac/test_gen_tac_call.c index 3779bb86..0e5d9cdb 100644 --- a/compiler/test/gen_tac/test_gen_tac_call.c +++ b/compiler/test/gen_tac/test_gen_tac_call.c @@ -55,6 +55,81 @@ void test_gen_tac_call_case_1_args_return() { vmcu_system_dtor(system); } +void test_gen_tac_call_case_frame_pointer_restored_after_call() { + + status_test_codegen_tac("Call - frame pointer YL:YH restored after call (caller has no locals)"); + + char* template = "fn main()->int{ return f(3); }" + " fn f(uint8 a)->int{ " + "uint8 b = 83; " + "uint8 c = 3; " + "uint8 d = 4; " + "return b; " + "}"; + + vmcu_system_t* system = prepare_vmcu_system_from_code_snippet(template); + + vmcu_system_step_n(system, 50); + + const uint8_t r0 = vmcu_system_read_gpr(system, 0); + + assert(r0 == 83); + + uint16_t sp = vmcu_system_read_sp(system); + uint16_t y = vmcu_system_read_y(system); + + if (sp != y + 2) { + printf("sp=0x%x, Y=0x%x\n", sp, y); + } + + // This is because 'main' was not called, + // it is the first function to run after the initial boilerplate. + // So since we did return, SP will be higher by 2 + assert(sp == y + 2); + + vmcu_system_dtor(system); +} + +void test_gen_tac_call_case_frame_pointer_restored_after_call_caller_has_locals() { + + status_test_codegen_tac("Call - frame pointer YL:YH restored after call (caller has locals)"); + + char* template = "fn main()->int{ " + "uint8 x = 3; " + "return f(3); " + "} " + "fn f(uint8 a)->int{ " + "uint8 b = 73; " + "return b; " + "} "; + + vmcu_system_t* system = prepare_vmcu_system_from_code_snippet(template); + + vmcu_system_step_n(system, 50); + + const uint8_t r0 = vmcu_system_read_gpr(system, 0); + + assert(r0 == 73); + + uint16_t sp = vmcu_system_read_sp(system); + uint16_t y = vmcu_system_read_y(system); + + if (sp != y + 3) { + printf("sp=0x%x, Y=0x%x\n", sp, y); + } + + // This is because 'main' was not called, + // it is the first function to run after the initial boilerplate. + // So since we did return, SP will be higher by 2. + // And since the frame pointer YL:YH is created after space has been made on the stack + // for local variables + // (our frame pointer only ever applies offsets >= 0 for both locals and args), + // YL:YH will further be higher by 1 byte due to the uint8 local variable. + assert(sp == y + 3); + + vmcu_system_dtor(system); +} + void test_gen_tac_call_case_1_args_write_8bit() { status_test_codegen_tac("Call - 1 args - write to SRAM (8 bit)"); diff --git a/compiler/test/testcases.c b/compiler/test/testcases.c index 501e5360..f41423fa 100644 --- a/compiler/test/testcases.c +++ b/compiler/test/testcases.c @@ -245,6 +245,8 @@ void (*tests_tac_codegen[])() = { test_gen_tac_call_case_1_args_write_16bit, test_gen_tac_call_case_1_args_write_3fns, test_gen_tac_call_case_2_args, + test_gen_tac_call_case_frame_pointer_restored_after_call, + test_gen_tac_call_case_frame_pointer_restored_after_call_caller_has_locals, // struct decl test_gen_tac_structdecl_case_read_struct, From 82feaf1a714eef550e1bfb5dadda44286b0f8015 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Sun, 22 Sep 2024 22:27:49 +0200 Subject: [PATCH 04/13] examples: simple USART example This example is for the atmega328p. It's showing how to transmit increasing numbers and how to configure the USART peripheral. It's been tested with logic analyzer and USART protocol decoder but not yet connected to an actual USART receiver / usb to serial converter. --- examples/usart/Makefile | 11 ++++ examples/usart/main.dg | 110 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 examples/usart/Makefile create mode 100644 examples/usart/main.dg diff --git a/examples/usart/Makefile b/examples/usart/Makefile new file mode 100644 index 00000000..922fad6e --- /dev/null +++ b/examples/usart/Makefile @@ -0,0 +1,11 @@ +main: compile + +compile: clean + sd main.dg ../../stdlib/avr/timer0.dg + +flash: + sudo avrdude -c arduino -p atmega328p -P /dev/ttyACM0 -U flash:w:main.hex + +clean: + rm -f *.hex *.obj *.cof *.asm *.png *.dot + diff --git a/examples/usart/main.dg b/examples/usart/main.dg new file mode 100644 index 00000000..1fde4f16 --- /dev/null +++ b/examples/usart/main.dg @@ -0,0 +1,110 @@ +// for the atmega328p + +// to debug this, can use cheap AZ Delivery Logic Analyzer +// and following packages (arch linux) +// +// - sigrok-cli +// - sigrok-firmware-fx2lafw (this is needed so it correctly recognizes the logic analyzer) +// - pulseview (gui viewer) + +// in pulseview, add the decoder for USART, then specify: +// +// - baudrate 9600 +// - 8 data bits +// - even parity bit +// - 1 stop bit (even though we send 2, selecting that is not possible) +// - bit order is lsb-first +// - data format is hex for this example (sending increasing numbers) + +fn main () ~> int { + + usart_init(); + + uint8 c = 0; + while(true){ + c++; + usart_tx(c); + delay(); + } + + return 0; +} + +fn delay() -> int { + + //using Timer0 + + //TCCR0A = 0x0, set timer mode + timer0_mode(0x0); + + //TCCR0B = 0b00000101, set prescaler to 1024 + timer0_prescaler(0x5); + + //while(TCNT0 != 0xfe){} + while(timer0_read() != 0xfe){} + + return 1; +} + +fn usart_tx (uint8 c) ~> uint8 { + + uint8 ucsr0a = [0xc0]; // UCSR0A + // look at UDRE0 (USART data register empty) + + // UCSR0A: RXC0 TXC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0 + while ((ucsr0a & 0b100000) == 0){ + ucsr0a = [0xc0]; + } + + // put data into transmit buffer + // UDR0 = c; + [0xc6] = c; + + return 0; +} + +fn usart_init_baudrate() ~> uint8 { + // baudrate 9600 + // according to the formula on page 227 + // our frequency is 16 MHz + // int(16000000/(16*9600)) -1 + // = 104 - 1 = 103 + + // set baudrate + // UBRR0L = 0xc4 + // UBRR0H = 0xc5 + [0xc4] = 103; + [0xc5] = 0x00; + + return 0; +} + +fn usart_set_ucsr0b () ~> uint8 { + // UCSR0B: RXCIE0 TXCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80 + + // enable receiver and transmitter + // UCSR0B = (1 << RXEN0) | (1 << TXEN0) + //[0xc1] = (1 << 4) | (1 << 3); + [0xc1] = 0b01000; + + return 0; +} + +fn usart_set_ucsr0c () ~> uint8 { + // UCSR0C: UMSEL01 UMSEL00 UPM01 UPM00 USBS0 (UCSZ01 / UDORD0) (UCSZ00 / UCPHA0) UCPOL0 + + // set frame format: 8 data, 2 stop bit + // UCSR0C = (1 << USBS0) | (3 << UCSZ00) + [0xc2] = 0b00101110; + + return 0; +} + +fn usart_init () ~> uint8 { + usart_init_baudrate(); + usart_set_ucsr0b(); + usart_set_ucsr0c(); + + return 0; +} + From d2d0b2590107e56287a36abc852afb0a2edc3b0b Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Mon, 23 Sep 2024 22:52:25 +0200 Subject: [PATCH 05/13] compiler: avr: return 16 bit values correctly This incomplete implementation just looks if the temporary for the value being returned is wide. It can be completed by also checking the with of the type of the value being returned. --- .../compile_ir/compile_tac_call.c | 10 +++++- .../compile_ir/test_compile_tac.h | 3 +- .../compile_ir/test_compile_tac_call.c | 36 +++++++++++++++++-- compiler/test/testcases.c | 3 +- format-code.sh | 2 +- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/compiler/main/avr_code_gen/compile_ir/compile_tac_call.c b/compiler/main/avr_code_gen/compile_ir/compile_tac_call.c index 161a9c9c..00c6cd9f 100644 --- a/compiler/main/avr_code_gen/compile_ir/compile_tac_call.c +++ b/compiler/main/avr_code_gen/compile_ir/compile_tac_call.c @@ -14,6 +14,8 @@ void compile_tac_call(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu, str int reg_dest = rat_get_register(rat, tac->dest); const int RAT_SCRATCH_REG = rat_scratch_reg(rat); + const bool wide_dest = rat_is_wide(rat, tac->dest); + //in case of tests, where SST may not be filled correctly char* function_name = "main"; @@ -23,9 +25,15 @@ void compile_tac_call(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu, str call(function_name, "TAC_CALL"); - if (reg_dest != 0) + if (reg_dest != 0) { mov(reg_dest, 0, "TAC_CALL"); + if (wide_dest) { + // TODO: check if function return type is wide + mov(reg_dest + 1, 1, "TAC_CALL"); + } + } + struct SST* sst = ctx_tables(ctx)->sst; //for the case of tests on raw TACBuffers diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h index 41a00629..81ed0e6f 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h @@ -106,7 +106,8 @@ void test_compile_tac_param_case_16bit(); // TAC_CALL void test_compile_tac_call_case_recurses(); -void test_compile_tac_call_case_returns_value(); +void test_compile_tac_call_case_returns_value_8bit(); +void test_compile_tac_call_case_returns_value_16bit(); void test_compile_tac_call_case_1_param(); // TAC_LOAD diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_call.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_call.c index 9f760dc0..85e67875 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_call.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_call.c @@ -44,9 +44,9 @@ void test_compile_tac_call_case_recurses() { vmcu_system_dtor(system); } -void test_compile_tac_call_case_returns_value() { +void test_compile_tac_call_case_returns_value_8bit() { - status_test_codegen("TAC_CALL - returns value"); + status_test_codegen("TAC_CALL - returns value (8 bit)"); const int8_t value = 0x63; @@ -67,6 +67,38 @@ void test_compile_tac_call_case_returns_value() { vmcu_system_dtor(system); } +void test_compile_tac_call_case_returns_value_16bit() { + + status_test_codegen("TAC_CALL - returns value (16 bit)"); + + const uint16_t value = 0x6385; + + struct TACBuffer* b = tacbuffer_ctor(); + + //main + tacbuffer_append(b, makeTACLabelFunction(0)); + tacbuffer_append(b, makeTACConst(0, value)); + + tacbuffer_append(b, makeTACReturn(0)); + + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + + vmcu_system_step_n(system, 20); + + const uint8_t r0 = vmcu_system_read_gpr(system, 0); + const uint8_t r1 = vmcu_system_read_gpr(system, 1); + + const uint16_t retval = (r1 << 8) | r0; + + if (retval != value) { + printf("retval = 0x%x, value = 0x%x\n)", retval, value); + } + + assert(retval == value); + + vmcu_system_dtor(system); +} + void test_compile_tac_call_case_1_param() { status_test_codegen("TAC_CALL - 1 param [TODO]"); diff --git a/compiler/test/testcases.c b/compiler/test/testcases.c index f41423fa..b88b35f6 100644 --- a/compiler/test/testcases.c +++ b/compiler/test/testcases.c @@ -153,7 +153,8 @@ void (*tests_avr_codegen[])() = { // TAC_CALL test_compile_tac_call_case_recurses, - test_compile_tac_call_case_returns_value, + test_compile_tac_call_case_returns_value_8bit, + test_compile_tac_call_case_returns_value_16bit, test_compile_tac_call_case_1_param, // TAC_SETUP_STACKFRAME diff --git a/format-code.sh b/format-code.sh index 6ae22cfb..a22eccd1 100755 --- a/format-code.sh +++ b/format-code.sh @@ -6,7 +6,7 @@ SCRIPT_DIR=$(realpath $(dirname $0)) echo "running from" $SCRIPT_DIR -SRC=$(find $SCRIPT_DIR -type d \( -name 'build' -o -name 'dependencies' \) -prune -o \( -name '*.c' -o -name '*.h' \) -print) +SRC=$(find $SCRIPT_DIR -type d \( -name 'build' -o -name 'dependencies' -o -name 'stdlib' -o -name 'examples' \) -prune -o \( -name '*.c' -o -name '*.h' \) -print) echo $SRC From 0dcf69b52df6ff21a07eda42bb353100572937e5 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Mon, 23 Sep 2024 23:50:44 +0200 Subject: [PATCH 06/13] [wip] avr: add concept of 'width' to TAC_LOAD This needs to be expanded further and put into all LOAD/STORE IR instructions. --- compiler/main/avr_code_gen/cg_avr_basic_block.c | 6 +++++- compiler/main/gen_tac/gen_tac_mdirect.c | 3 ++- compiler/main/gen_tac/gen_tac_simplevar.c | 5 ++++- compiler/main/gen_tac/gen_tac_variable.c | 5 ++++- compiler/main/gen_tac/helper_gen_tac_derefll.c | 3 ++- .../test/avr_code_gen/compile_ir/test_compile_tac_load.c | 4 ++-- .../test/x86_code_gen/compile_ir/test_compile_tac_load.c | 2 +- docs/html/tac.html | 2 +- tac/tac.c | 6 +++++- tac/tac.h | 2 +- 10 files changed, 27 insertions(+), 11 deletions(-) diff --git a/compiler/main/avr_code_gen/cg_avr_basic_block.c b/compiler/main/avr_code_gen/cg_avr_basic_block.c index 3460bddd..8d44238a 100644 --- a/compiler/main/avr_code_gen/cg_avr_basic_block.c +++ b/compiler/main/avr_code_gen/cg_avr_basic_block.c @@ -125,12 +125,16 @@ static void allocate_registers_single_tac(struct TAC* t, struct RAT* rat, struct case TAC_LOAD_CONST_ADDR: rat_ensure_register(rat, t->dest, false, true); + //TODO: know the width of the load break; case TAC_LOAD: //sadly we do not know what is all going to be added/subtracted //from what we load there, could be a pointer, so it must be wide - rat_ensure_register(rat, t->dest, false, true); + { + const bool iswide = t->const_value >= 2; + rat_ensure_register(rat, t->dest, false, iswide); + } break; default: break; diff --git a/compiler/main/gen_tac/gen_tac_mdirect.c b/compiler/main/gen_tac/gen_tac_mdirect.c index 81340b25..84704617 100644 --- a/compiler/main/gen_tac/gen_tac_mdirect.c +++ b/compiler/main/gen_tac/gen_tac_mdirect.c @@ -33,7 +33,8 @@ static void case_variable_addr(struct TACBuffer* buffer, struct Expr* expr, stru tac_expr(buffer, expr, ctx); - struct TAC* t = makeTACLoad(make_temp(), tacbuffer_last_dest(buffer)); + // TODO: for x86, this needs to be 8 bytes, not 2 + struct TAC* t = makeTACLoad(make_temp(), tacbuffer_last_dest(buffer), 2); tacbuffer_append(buffer, t); } diff --git a/compiler/main/gen_tac/gen_tac_simplevar.c b/compiler/main/gen_tac/gen_tac_simplevar.c index 1f2bcc69..a84f3945 100644 --- a/compiler/main/gen_tac/gen_tac_simplevar.c +++ b/compiler/main/gen_tac/gen_tac_simplevar.c @@ -20,7 +20,10 @@ void tac_simplevar(struct TACBuffer* buffer, struct SimpleVar* v, struct Ctx* ct uint32_t tlast = tacbuffer_last_dest(buffer); - tacbuffer_append(buffer, makeTACLoad(make_temp(), tlast)); + struct LVST* lvst = ctx_tables(ctx)->lvst; + const uint8_t simplevar_width = lvst_sizeof_var(lvst, v->name); + + tacbuffer_append(buffer, makeTACLoad(make_temp(), tlast, simplevar_width)); } void tac_simplevar_addr(struct TACBuffer* buffer, struct SimpleVar* sv, struct Ctx* ctx) { diff --git a/compiler/main/gen_tac/gen_tac_variable.c b/compiler/main/gen_tac/gen_tac_variable.c index 4521f259..8e014e2d 100644 --- a/compiler/main/gen_tac/gen_tac_variable.c +++ b/compiler/main/gen_tac/gen_tac_variable.c @@ -20,7 +20,10 @@ void tac_variable(struct TACBuffer* buffer, struct Variable* v, struct Ctx* ctx) uint32_t tlast = tacbuffer_last_dest(buffer); - tacbuffer_append(buffer, makeTACLoad(make_temp(), tlast)); + // TODO: do not assume the variable has 2 bytes + // on avr, it can only be 1 byte + // on x86 it can be up to 8 + tacbuffer_append(buffer, makeTACLoad(make_temp(), tlast, 2)); } void tac_variable_addr(struct TACBuffer* buffer, struct Variable* v, struct Ctx* ctx) { diff --git a/compiler/main/gen_tac/helper_gen_tac_derefll.c b/compiler/main/gen_tac/helper_gen_tac_derefll.c index 4df4aafe..9bcd1f76 100644 --- a/compiler/main/gen_tac/helper_gen_tac_derefll.c +++ b/compiler/main/gen_tac/helper_gen_tac_derefll.c @@ -46,7 +46,8 @@ void tac_derefll_single(struct TACBuffer* buffer, struct DerefLL* dll, struct Ty } break; case DEREFLL_DEREF: - tacbuffer_append(buffer, makeTACLoad(make_temp(), tacbuffer_last_dest(buffer))); + // TODO: the width there needs to be architecture specific, for x86 it's not 2 but 8 bytes + tacbuffer_append(buffer, makeTACLoad(make_temp(), tacbuffer_last_dest(buffer), 2)); break; } } diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load.c index cdb61864..1a245954 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load.c @@ -26,7 +26,7 @@ void test_compile_tac_load_case_8bit_addr() { tacbuffer_append(b, makeTACConst(1, 0x00)); tacbuffer_append(b, makeTACConst(2, addr)); - tacbuffer_append(b, makeTACLoad(1, 2)); + tacbuffer_append(b, makeTACLoad(1, 2, 1)); tacbuffer_append(b, makeTACReturn(1)); vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); @@ -54,7 +54,7 @@ void test_compile_tac_load_case_16bit_addr() { tacbuffer_append(b, makeTACConst(1, 0x00)); tacbuffer_append(b, makeTACConst(2, addr)); - tacbuffer_append(b, makeTACLoad(1, 2)); + tacbuffer_append(b, makeTACLoad(1, 2, 1)); tacbuffer_append(b, makeTACReturn(1)); vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); diff --git a/compiler/test/x86_code_gen/compile_ir/test_compile_tac_load.c b/compiler/test/x86_code_gen/compile_ir/test_compile_tac_load.c index 613acf3b..d5076854 100644 --- a/compiler/test/x86_code_gen/compile_ir/test_compile_tac_load.c +++ b/compiler/test/x86_code_gen/compile_ir/test_compile_tac_load.c @@ -30,7 +30,7 @@ static void test_fixed_value(uint64_t fixed_value, bool debug) { tacbuffer_append(b, makeTACConst(1, 0x00)); tacbuffer_append(b, makeTACConst(2, addr)); - tacbuffer_append(b, makeTACLoad(1, 2)); + tacbuffer_append(b, makeTACLoad(1, 2, 8)); struct sd_uc_engine* system = sd_uc_engine_from_tacbuffer_v2(b, debug); diff --git a/docs/html/tac.html b/docs/html/tac.html index 5fb40c20..75835657 100644 --- a/docs/html/tac.html +++ b/docs/html/tac.html @@ -231,7 +231,7 @@

Load/Store

t1 = [t2] TMP TMP - - + number of bytes to load (1 or 2) - - diff --git a/tac/tac.c b/tac/tac.c index a8c030a3..14ed3fc3 100644 --- a/tac/tac.c +++ b/tac/tac.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -276,11 +277,14 @@ struct TAC* makeTACReturn(uint32_t tmp) { return t; } -struct TAC* makeTACLoad(uint32_t tmp, uint32_t taddr) { +struct TAC* makeTACLoad(uint32_t tmp, uint32_t taddr, uint8_t width) { struct TAC* t = makeTAC(); t->kind = TAC_LOAD; t->dest = tmp; t->arg1 = taddr; + + assert(width <= 8); + t->const_value = width; return t; } diff --git a/tac/tac.h b/tac/tac.h index 8989867c..d122784b 100644 --- a/tac/tac.h +++ b/tac/tac.h @@ -144,6 +144,6 @@ struct TAC* makeTACSetupSP(); struct TAC* makeTACNop(); -struct TAC* makeTACLoad(uint32_t tmp, uint32_t taddr); +struct TAC* makeTACLoad(uint32_t tmp, uint32_t taddr, uint8_t width); struct TAC* makeTACStore(uint32_t taddr, uint32_t tmp); #endif From 0b08c0ffdda4b0bfbabab3b671bd9a0aef42fca6 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Wed, 2 Oct 2024 22:19:11 +0200 Subject: [PATCH 07/13] stdlib: add basic support for usart tx on atmega328p --- examples/usart/Makefile | 5 ++- examples/usart/main.dg | 70 +++----------------------------- stdlib/avr/usart.dg | 89 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 65 deletions(-) create mode 100644 stdlib/avr/usart.dg diff --git a/examples/usart/Makefile b/examples/usart/Makefile index 922fad6e..e30ad8ac 100644 --- a/examples/usart/Makefile +++ b/examples/usart/Makefile @@ -1,7 +1,10 @@ main: compile compile: clean - sd main.dg ../../stdlib/avr/timer0.dg + sd \ + main.dg \ + ../../stdlib/avr/timer0.dg \ + ../../stdlib/avr/usart.dg flash: sudo avrdude -c arduino -p atmega328p -P /dev/ttyACM0 -U flash:w:main.hex diff --git a/examples/usart/main.dg b/examples/usart/main.dg index 1fde4f16..8d8bb8c5 100644 --- a/examples/usart/main.dg +++ b/examples/usart/main.dg @@ -18,12 +18,16 @@ fn main () ~> int { - usart_init(); + usart_init(2400); uint8 c = 0; while(true){ c++; - usart_tx(c); + usart_tx_char('h'); + usart_tx_char('e'); + usart_tx_char('l'); + usart_tx_char('l'); + usart_tx_char('o'); delay(); } @@ -46,65 +50,3 @@ fn delay() -> int { return 1; } -fn usart_tx (uint8 c) ~> uint8 { - - uint8 ucsr0a = [0xc0]; // UCSR0A - // look at UDRE0 (USART data register empty) - - // UCSR0A: RXC0 TXC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0 - while ((ucsr0a & 0b100000) == 0){ - ucsr0a = [0xc0]; - } - - // put data into transmit buffer - // UDR0 = c; - [0xc6] = c; - - return 0; -} - -fn usart_init_baudrate() ~> uint8 { - // baudrate 9600 - // according to the formula on page 227 - // our frequency is 16 MHz - // int(16000000/(16*9600)) -1 - // = 104 - 1 = 103 - - // set baudrate - // UBRR0L = 0xc4 - // UBRR0H = 0xc5 - [0xc4] = 103; - [0xc5] = 0x00; - - return 0; -} - -fn usart_set_ucsr0b () ~> uint8 { - // UCSR0B: RXCIE0 TXCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80 - - // enable receiver and transmitter - // UCSR0B = (1 << RXEN0) | (1 << TXEN0) - //[0xc1] = (1 << 4) | (1 << 3); - [0xc1] = 0b01000; - - return 0; -} - -fn usart_set_ucsr0c () ~> uint8 { - // UCSR0C: UMSEL01 UMSEL00 UPM01 UPM00 USBS0 (UCSZ01 / UDORD0) (UCSZ00 / UCPHA0) UCPOL0 - - // set frame format: 8 data, 2 stop bit - // UCSR0C = (1 << USBS0) | (3 << UCSZ00) - [0xc2] = 0b00101110; - - return 0; -} - -fn usart_init () ~> uint8 { - usart_init_baudrate(); - usart_set_ucsr0b(); - usart_set_ucsr0c(); - - return 0; -} - diff --git a/stdlib/avr/usart.dg b/stdlib/avr/usart.dg new file mode 100644 index 00000000..7038d56e --- /dev/null +++ b/stdlib/avr/usart.dg @@ -0,0 +1,89 @@ +// wip usart driver for the atmega328p + +fn usart_tx_char (char c) ~> uint8 { + + usart_tx_wait_udre(); + [0xc6] = c; +} + +fn usart_tx (uint8 c) ~> uint8 { + + usart_tx_wait_udre(); + + // put data into transmit buffer (UDR0) + [0xc6] = c; + + return 0; +} + +fn usart_tx_wait_udre() ~> uint8 { + + uint8 ucsr0a = [0xc0]; // UCSR0A + // look at UDRE0 (USART data register empty) + + // UCSR0A: RXC0 TXC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0 + while ((ucsr0a & 0b100000) == 0){ + ucsr0a = [0xc0]; + } + + return 0; +} + +fn usart_calc_ubrr0(uint16 baudrate) ~> uint16 { + // assuming clock of 16 MHz + // only listing the most common values here + // reference table 24-7 (Examples of UBRRn) + if (baudrate == 2400) { return 416; } + if (baudrate == 4800) { return 207; } + if (baudrate == 9600) { return 103; } + if (baudrate == 14400) { return 68; } + if (baudrate == 19200) { return 51; } + if (baudrate == 115200) { return 8; } + + return 103; // default 9600 baud +} + +fn usart_init_baudrate(uint16 baudrate) ~> uint8 { + // int(16000000/(16*9600)) -1 + // = 1000000 / 9600 - 1 + // = 104 - 1 = 103 + + uint16 value = usart_calc_ubrr0(baudrate); + + // UBRR0L = 0xc4 + // UBRR0H = 0xc5 + [0xc4] = value & 0xff; + [0xc5] = (value >> 8) & 0xff; + + return 0; +} + +fn usart_set_ucsr0b () ~> uint8 { + // UCSR0B: RXCIE0 TXCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80 + + // enable receiver and transmitter + // UCSR0B = (1 << RXEN0) | (1 << TXEN0) + //[0xc1] = (1 << 4) | (1 << 3); + [0xc1] = 0b01000; + + return 0; +} + +fn usart_set_ucsr0c () ~> uint8 { + // UCSR0C: UMSEL01 UMSEL00 UPM01 UPM00 USBS0 (UCSZ01 / UDORD0) (UCSZ00 / UCPHA0) UCPOL0 + + // set frame format: 8 data, 2 stop bit + // UCSR0C = (1 << USBS0) | (3 << UCSZ00) + [0xc2] = 0b00101110; + + return 0; +} + +fn usart_init (uint16 baudrate) ~> uint8 { + usart_init_baudrate(baudrate); + usart_set_ucsr0b(); + usart_set_ucsr0c(); + + return 0; +} + From aac9a6ad67c42cea0236ff97e435a0e76104db27 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Thu, 3 Oct 2024 12:31:47 +0200 Subject: [PATCH 08/13] test: avr: start using redzone for test create a redzone in memory to detect unintended writes around the target address. --- .../compile_ir/test_compile_tac.h | 8 +- .../compile_ir/test_compile_tac_store.c | 118 +++++++++++++----- compiler/test/libvmcu_utils/libvmcu_utils.c | 8 ++ compiler/test/libvmcu_utils/libvmcu_utils.h | 2 + compiler/test/testcases.c | 6 +- 5 files changed, 106 insertions(+), 36 deletions(-) diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h index 81ed0e6f..8da7e51a 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h @@ -115,8 +115,12 @@ void test_compile_tac_load_case_8bit_addr(); void test_compile_tac_load_case_16bit_addr(); // TAC_STORE -void test_compile_tac_store_case_8bit_value_8bit_addr(); -void test_compile_tac_store_case_16bit_value_8bit_addr(); +void test_compile_tac_store_case_8bit_value_8bit_addr_c7(); +void test_compile_tac_store_case_8bit_value_8bit_addr_c8(); + +void test_compile_tac_store_case_16bit_value_8bit_addr_c7_f03(); +void test_compile_tac_store_case_16bit_value_8bit_addr_c8_f03(); + void test_compile_tac_store_case_8bit_value_16bit_addr(); void test_compile_tac_store_case_16bit_value_16bit_addr(); diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store.c index d40f56c7..1d03678a 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store.c @@ -15,9 +15,9 @@ #include "test_compile_tac.h" -static vmcu_system_t* common(uint16_t addr, int16_t value); +static vmcu_system_t* common(uint16_t addr, int16_t value, uint8_t redzone); -static vmcu_system_t* common(uint16_t addr, int16_t value) { +static vmcu_system_t* common(uint16_t addr, int16_t value, uint8_t redzone) { struct TACBuffer* b = tacbuffer_ctor(); @@ -25,54 +25,109 @@ static vmcu_system_t* common(uint16_t addr, int16_t value) { tacbuffer_append(b, makeTACConst(2, addr)); tacbuffer_append(b, makeTACStore(2, 1)); - tacbuffer_append(b, makeTACReturn(1)); - vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + // fill the area with red zone to detect unintended writes + // around the address + for (uint16_t a = addr - 2; a < addr + 4; a++) { + vmcu_system_write_data(system, a, redzone); + } + vmcu_system_step_n(system, 10); return system; } -void test_compile_tac_store_case_8bit_value_8bit_addr() { +static void assert_redzone(vmcu_system_t* system, uint16_t addr, uint8_t width, uint8_t redzone) { - status_test_codegen("TAC_STORE (8 bit value, 8 bit addr)"); + const uint16_t addr1 = addr - 1; + const uint16_t addr2 = addr + width; - for (uint16_t addr = 0xc7; addr < 0xcb; addr++) { + const uint8_t before = vmcu_system_read_data(system, addr1); + const uint8_t after = vmcu_system_read_data(system, addr2); - for (int8_t fixed_value = 1; fixed_value < 3; fixed_value++) { + if ((before != redzone) || (after != redzone)) { + for (uint16_t a = addr1 - 1; a <= addr2 + 1; a++) { + const uint8_t value = vmcu_system_read_data(system, a); + printf("[0x%x] = 0x%x\n", a, value); + } + } + assert(before == redzone); + assert(after == redzone); +} - vmcu_system_t* system = common(addr, fixed_value); +void test_compile_tac_store_case_8bit_value_8bit_addr_c7() { - const int8_t stored = vmcu_system_read_data(system, addr); + status_test_codegen("TAC_STORE (8 bit value, 8 bit addr = 0xc7)"); - assert(stored == fixed_value); + const uint16_t addr = 0xc7; + const uint8_t fixed_value = 0x2; + const uint8_t redzone = 0xff; - vmcu_system_dtor(system); - } - } + vmcu_system_t* system = common(addr, fixed_value, redzone); + + const uint8_t stored = vmcu_system_read_data(system, addr); + + assert_redzone(system, addr, 1, redzone); + + vmcu_system_dtor(system); } -void test_compile_tac_store_case_16bit_value_8bit_addr() { +void test_compile_tac_store_case_8bit_value_8bit_addr_c8() { + + status_test_codegen("TAC_STORE (8 bit value, 8 bit addr = 0xc8)"); - status_test_codegen("TAC_STORE (16 bit value, 8 bit addr)"); + const uint16_t addr = 0xc8; + const uint8_t fixed_value = 0x2; + const uint8_t redzone = 0xff; - for (uint16_t addr = 0xc7; addr < 0xcb; addr++) { + vmcu_system_t* system = common(addr, fixed_value, redzone); - for (uint16_t fixed_value = 0x0f00; fixed_value < 0x0f03; fixed_value++) { + const uint8_t stored = vmcu_system_read_data(system, addr); - vmcu_system_t* system = common(addr, fixed_value); + assert(stored == fixed_value); - const uint8_t low = vmcu_system_read_data(system, addr); - const uint8_t high = vmcu_system_read_data(system, addr + 1); + assert_redzone(system, addr, 1, redzone); - const int16_t stored = (high << 8) | low; + vmcu_system_dtor(system); +} - assert(stored == fixed_value); +void test_compile_tac_store_case_16bit_value_8bit_addr_c7_f03() { - vmcu_system_dtor(system); - } - } + status_test_codegen("TAC_STORE (16 bit value = 0xf03, 8 bit addr = 0xc7)"); + + const uint8_t redzone = 0xff; + const uint16_t addr = 0xc7; + const uint16_t fixed_value = 0x0f03; + + vmcu_system_t* system = common(addr, fixed_value, redzone); + + const uint16_t stored = vmcu_system_read_data16(system, addr); + + assert(stored == fixed_value); + + assert_redzone(system, addr, 2, redzone); + + vmcu_system_dtor(system); +} + +void test_compile_tac_store_case_16bit_value_8bit_addr_c8_f03() { + + status_test_codegen("TAC_STORE (16 bit value = 0xf03, 8 bit addr = 0xc8)"); + + const uint8_t redzone = 0xff; + const uint16_t addr = 0xc7; + const uint16_t fixed_value = 0x0f03; + + vmcu_system_t* system = common(addr, fixed_value, redzone); + + const uint16_t stored = vmcu_system_read_data16(system, addr); + + assert(stored == fixed_value); + + assert_redzone(system, addr, 2, redzone); + + vmcu_system_dtor(system); } void test_compile_tac_store_case_8bit_value_16bit_addr() { @@ -80,10 +135,11 @@ void test_compile_tac_store_case_8bit_value_16bit_addr() { status_test_codegen("TAC_STORE (8 bit value, 16 bit addr)"); const uint16_t addr = 1200; + const uint8_t redzone = 0xff; for (int8_t fixed_value = 1; fixed_value < 3; fixed_value++) { - vmcu_system_t* system = common(addr, fixed_value); + vmcu_system_t* system = common(addr, fixed_value, redzone); const int8_t stored = vmcu_system_read_data(system, addr); @@ -98,15 +154,13 @@ void test_compile_tac_store_case_16bit_value_16bit_addr() { status_test_codegen("TAC_STORE (16 bit value, 16 bit addr)"); const uint16_t addr = 1200; + const uint8_t redzone = 0xff; for (uint16_t fixed_value = 0x0f00; fixed_value < 0x0f03; fixed_value++) { - vmcu_system_t* system = common(addr, fixed_value); - - const uint8_t low = vmcu_system_read_data(system, addr); - const uint8_t high = vmcu_system_read_data(system, addr + 1); + vmcu_system_t* system = common(addr, fixed_value, redzone); - const int16_t stored = (high << 8) | low; + const uint16_t stored = vmcu_system_read_data16(system, addr); assert(stored == fixed_value); diff --git a/compiler/test/libvmcu_utils/libvmcu_utils.c b/compiler/test/libvmcu_utils/libvmcu_utils.c index 41f61e13..da9adb71 100644 --- a/compiler/test/libvmcu_utils/libvmcu_utils.c +++ b/compiler/test/libvmcu_utils/libvmcu_utils.c @@ -36,3 +36,11 @@ uint16_t vmcu_system_read_y(vmcu_system_t* system) { return (YH << 8 | YL); } + +uint16_t vmcu_system_read_data16(vmcu_system_t* system, uint16_t addr) { + + const uint8_t low = vmcu_system_read_data(system, addr); + const uint8_t high = vmcu_system_read_data(system, addr + 1); + + return (high << 8) | low; +} diff --git a/compiler/test/libvmcu_utils/libvmcu_utils.h b/compiler/test/libvmcu_utils/libvmcu_utils.h index 5db55f97..f929bf2f 100644 --- a/compiler/test/libvmcu_utils/libvmcu_utils.h +++ b/compiler/test/libvmcu_utils/libvmcu_utils.h @@ -12,4 +12,6 @@ uint16_t vmcu_system_read_sp(vmcu_system_t* system); uint16_t vmcu_system_read_y(vmcu_system_t* system); +uint16_t vmcu_system_read_data16(vmcu_system_t* system, uint16_t addr); + #endif diff --git a/compiler/test/testcases.c b/compiler/test/testcases.c index b88b35f6..b586f86e 100644 --- a/compiler/test/testcases.c +++ b/compiler/test/testcases.c @@ -165,8 +165,10 @@ void (*tests_avr_codegen[])() = { test_compile_tac_load_case_16bit_addr, // TAC_STORE - test_compile_tac_store_case_8bit_value_8bit_addr, - test_compile_tac_store_case_16bit_value_8bit_addr, + test_compile_tac_store_case_8bit_value_8bit_addr_c7, + test_compile_tac_store_case_8bit_value_8bit_addr_c8, + test_compile_tac_store_case_16bit_value_8bit_addr_c7_f03, + test_compile_tac_store_case_16bit_value_8bit_addr_c8_f03, test_compile_tac_store_case_8bit_value_16bit_addr, test_compile_tac_store_case_16bit_value_16bit_addr, From 434a54f058f04bbe9aab43814b4257aec326b9e1 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Thu, 3 Oct 2024 13:20:03 +0200 Subject: [PATCH 09/13] test: avr: introduce vmcu_system_read_2_gpr new wrapper function to simplify reading a value from 2 adjacent registers. --- .../compile_ir/test_compile_tac_binary_op.c | 39 ++++++------------- .../test_compile_tac_binary_op_immediate.c | 37 ++++-------------- .../compile_ir/test_compile_tac_call.c | 5 +-- .../compile_ir/test_compile_tac_const_value.c | 10 ++--- .../compile_ir/test_compile_tac_copy.c | 8 +--- .../compile_ir/test_compile_tac_unary_op.c | 10 +---- .../test/gen_tac/test_gen_tac_assignstmt.c | 6 +-- compiler/test/gen_tac/test_gen_tac_call.c | 4 +- compiler/test/libvmcu_utils/libvmcu_utils.c | 7 ++++ compiler/test/libvmcu_utils/libvmcu_utils.h | 3 ++ 10 files changed, 39 insertions(+), 90 deletions(-) diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_binary_op.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_binary_op.c index f5183305..a8728621 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_binary_op.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_binary_op.c @@ -15,10 +15,6 @@ #include "test_compile_tac.h" -static int16_t make16(uint8_t high, uint8_t low) { - return (high << 8) | low; -} - void test_compile_tac_binary_op_add_8bit() { status_test_codegen("TAC_BINARY_OP + (8 bit)"); @@ -73,10 +69,9 @@ void test_compile_tac_binary_op_add_16bit() { vmcu_system_step_n(system, 8); - const int8_t r0 = vmcu_system_read_gpr(system, 0); - const int8_t r1 = vmcu_system_read_gpr(system, 1); + const int16_t actual = vmcu_system_read_2_gpr(system, 0); - assert(make16(r1, r0) == expected); + assert(actual == expected); vmcu_system_dtor(system); } @@ -132,10 +127,9 @@ void test_compile_tac_binary_op_sub_16bit() { vmcu_system_step_n(system, 8); - const uint8_t r0 = vmcu_system_read_gpr(system, 0); - const uint8_t r1 = vmcu_system_read_gpr(system, 1); + const int16_t actual = vmcu_system_read_2_gpr(system, 0); - assert(make16(r1, r0) == expected); + assert(actual == expected); vmcu_system_dtor(system); } @@ -191,10 +185,9 @@ void test_compile_tac_binary_op_and_16bit() { vmcu_system_step_n(system, 8); - int8_t r0 = vmcu_system_read_gpr(system, 0); - int8_t r1 = vmcu_system_read_gpr(system, 1); + const int16_t actual = vmcu_system_read_2_gpr(system, 0); - assert(make16(r1, r0) == expected); + assert(actual == expected); vmcu_system_dtor(system); } @@ -249,10 +242,9 @@ void test_compile_tac_binary_op_or_16bit() { vmcu_system_step_n(system, 8); - uint8_t r0 = vmcu_system_read_gpr(system, 0); - uint8_t r1 = vmcu_system_read_gpr(system, 1); + const int16_t actual = vmcu_system_read_2_gpr(system, 0); - assert(make16(r1, r0) == expected); + assert(actual == expected); vmcu_system_dtor(system); } @@ -307,10 +299,7 @@ void test_compile_tac_binary_op_xor_16bit() { vmcu_system_step_n(system, 10); - uint8_t r0 = vmcu_system_read_gpr(system, 0); - uint8_t r1 = vmcu_system_read_gpr(system, 1); - - uint16_t actual = make16(r1, r0); + const uint16_t actual = vmcu_system_read_2_gpr(system, 0); //printf("0x%x ^ 0x%x == 0x%x (actual: 0x%x)\n", start, change, expected, actual); @@ -340,10 +329,7 @@ void test_compile_tac_binary_op_xor_mixed1() { vmcu_system_step_n(system, 10); - uint8_t r0 = vmcu_system_read_gpr(system, 0); - uint8_t r1 = vmcu_system_read_gpr(system, 1); - - uint16_t actual = make16(r1, r0); + const uint16_t actual = vmcu_system_read_2_gpr(system, 0); assert(actual == 0xff00); @@ -372,10 +358,7 @@ void test_compile_tac_binary_op_xor_mixed2() { vmcu_system_step_n(system, 10); - uint8_t r0 = vmcu_system_read_gpr(system, 0); - uint8_t r1 = vmcu_system_read_gpr(system, 1); - - uint16_t actual = make16(r1, r0); + const uint16_t actual = vmcu_system_read_2_gpr(system, 0); assert(actual == expected); diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_binary_op_immediate.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_binary_op_immediate.c index 109bebf4..289d6fdf 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_binary_op_immediate.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_binary_op_immediate.c @@ -68,12 +68,7 @@ void test_compile_tac_binary_op_immediate_case_add_16bit() { vmcu_system_step_n(system, 20); - uint8_t r0 = vmcu_system_read_gpr(system, 0); - uint8_t r1 = vmcu_system_read_gpr(system, 1); - - //printf("r0 = 0x%x, r1 = 0x%x\n", r0, r1); - - int16_t actual = r0 | (r1 << 8); + int16_t actual = vmcu_system_read_2_gpr(system, 0); //printf("actual %d (0x%x)\n", actual, actual); //printf("expected %d (0x%x)\n", expected, expected); @@ -133,10 +128,7 @@ void test_compile_tac_binary_op_immediate_case_sub_16bit() { vmcu_system_step_n(system, 10); - uint8_t r0 = (uint8_t)vmcu_system_read_gpr(system, 0); - uint8_t r1 = (uint8_t)vmcu_system_read_gpr(system, 1); - - int16_t actual = (int16_t)(r0 | (r1 << 8)); + int16_t actual = vmcu_system_read_2_gpr(system, 0); //printf("expected: %d\n", expected); //printf("actual: %d\n", actual); @@ -191,10 +183,7 @@ void test_compile_tac_binary_op_immediate_case_and_16bit() { vmcu_system_step_n(system, 12); - uint8_t r0 = vmcu_system_read_gpr(system, 0); - uint8_t r1 = vmcu_system_read_gpr(system, 1); - - uint16_t actual = (r1 << 8) | r0; + int16_t actual = vmcu_system_read_2_gpr(system, 0); assert(actual == expected); @@ -246,10 +235,7 @@ void test_compile_tac_binary_op_immediate_case_or_16bit() { vmcu_system_step_n(system, 10); - uint8_t r0 = vmcu_system_read_gpr(system, 0); - uint8_t r1 = vmcu_system_read_gpr(system, 1); - - uint16_t actual = (r1 << 8) | r0; + uint16_t actual = vmcu_system_read_2_gpr(system, 0); assert(actual == expected); @@ -301,10 +287,7 @@ void test_compile_tac_binary_op_immediate_case_xor_16bit() { vmcu_system_step_n(system, 10); - uint8_t r0 = vmcu_system_read_gpr(system, 0); - uint8_t r1 = vmcu_system_read_gpr(system, 1); - - uint16_t actual = (r1 << 8) | r0; + uint16_t actual = vmcu_system_read_2_gpr(system, 0); assert(actual == expected); @@ -362,10 +345,7 @@ void test_compile_tac_binary_op_immediate_case_shift_left_16bit() { vmcu_system_step_n(system, 8 + change * 2); - uint8_t r0 = (uint8_t)vmcu_system_read_gpr(system, 0); - uint8_t r1 = (uint8_t)vmcu_system_read_gpr(system, 1); - - uint16_t actual = (r1 << 8) | r0; + uint16_t actual = vmcu_system_read_2_gpr(system, 0); //printf("actual 0x%x\n", actual); @@ -423,10 +403,7 @@ void test_compile_tac_binary_op_immediate_case_shift_right_16bit() { vmcu_system_step_n(system, 8 + change * 2); - uint8_t r0 = (uint8_t)vmcu_system_read_gpr(system, 0); - uint8_t r1 = (uint8_t)vmcu_system_read_gpr(system, 1); - - uint16_t actual = (r1 << 8) | r0; + uint16_t actual = vmcu_system_read_2_gpr(system, 0); assert(actual == expected); diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_call.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_call.c index 85e67875..782ece65 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_call.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_call.c @@ -85,10 +85,7 @@ void test_compile_tac_call_case_returns_value_16bit() { vmcu_system_step_n(system, 20); - const uint8_t r0 = vmcu_system_read_gpr(system, 0); - const uint8_t r1 = vmcu_system_read_gpr(system, 1); - - const uint16_t retval = (r1 << 8) | r0; + const uint16_t retval = vmcu_system_read_2_gpr(system, 0); if (retval != value) { printf("retval = 0x%x, value = 0x%x\n)", retval, value); diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_const_value.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_const_value.c index 9b343c82..f9cfd1e9 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_const_value.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_const_value.c @@ -61,14 +61,12 @@ void test_compile_tac_const_value_test_16bit() { //and the upper half to the reg above it bool found = false; - for (int i = 0; i < 32; i++) { - - if (vmcu_system_read_gpr(system, i) == (int8_t)(fixed_value & 0xff)) { - found = true; + for (int i = 0; i < 31; i++) { - int8_t rn = vmcu_system_read_gpr(system, i + 1); + const int16_t value = (int16_t)vmcu_system_read_2_gpr(system, i); - assert(rn == (int8_t)((fixed_value >> 8) & 0xff)); + if (value == fixed_value) { + found = true; } } diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_copy.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_copy.c index 0fe700b8..51a24547 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_copy.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_copy.c @@ -53,13 +53,9 @@ void test_compile_tac_copy_case_16bit() { vmcu_system_step_n(system, 10); - int8_t r0 = vmcu_system_read_gpr(system, 0); - int8_t r1 = vmcu_system_read_gpr(system, 1); + const uint16_t value = vmcu_system_read_2_gpr(system, 0); - //printf("r0 0x%x %d, r1 0x%x %d\n", r0, (uint8_t)r0, r1, (uint8_t)r1); - - assert((uint8_t)r0 == (fixed_value & 0xff)); - assert((uint8_t)r1 == (fixed_value & 0xff00) >> 8); + assert(value == fixed_value); vmcu_system_dtor(system); } diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_unary_op.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_unary_op.c index a2f581e4..050a1a1f 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_unary_op.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_unary_op.c @@ -55,10 +55,7 @@ void test_compile_tac_unary_op_case_minus_16bit() { vmcu_system_step_n(system, 20); - const uint8_t r0 = vmcu_system_read_gpr(system, 0); - const uint8_t r1 = vmcu_system_read_gpr(system, 1); - - int16_t actual = (r1 << 8) | r0; + int16_t actual = (int16_t)vmcu_system_read_2_gpr(system, 0); assert(actual == -start); @@ -132,10 +129,7 @@ void test_compile_tac_unary_op_case_bitwise_neg_16bit() { vmcu_system_step_n(system, 10); - const uint8_t r0 = vmcu_system_read_gpr(system, 0); - const uint8_t r1 = vmcu_system_read_gpr(system, 1); - - const uint16_t actual = (r1 << 8) | r0; + const uint16_t actual = vmcu_system_read_2_gpr(system, 0); assert(actual == expect); diff --git a/compiler/test/gen_tac/test_gen_tac_assignstmt.c b/compiler/test/gen_tac/test_gen_tac_assignstmt.c index 752a3a57..db4487b0 100644 --- a/compiler/test/gen_tac/test_gen_tac_assignstmt.c +++ b/compiler/test/gen_tac/test_gen_tac_assignstmt.c @@ -40,11 +40,7 @@ void test_gen_tac_assignstmt_case_local_int_16bit() { vmcu_system_step_n(system, 30); - //assert that value is returned in r0 as it should be - - uint8_t value1_low = vmcu_system_read_gpr(system, 0); - uint8_t value1_high = vmcu_system_read_gpr(system, 1); - const uint16_t value1 = (value1_high << 8) | value1_low; + const uint16_t value1 = vmcu_system_read_2_gpr(system, 0); assert(value1 == value); diff --git a/compiler/test/gen_tac/test_gen_tac_call.c b/compiler/test/gen_tac/test_gen_tac_call.c index 0e5d9cdb..54f96dc2 100644 --- a/compiler/test/gen_tac/test_gen_tac_call.c +++ b/compiler/test/gen_tac/test_gen_tac_call.c @@ -165,9 +165,7 @@ void test_gen_tac_call_case_1_args_write_16bit() { vmcu_system_step_n(system, 50); - const uint8_t actual_low = vmcu_system_read_data(system, 0x100); - const uint8_t actual_high = vmcu_system_read_data(system, 0x101); - const uint16_t actual = (actual_high << 8) | actual_low; + const uint16_t actual = vmcu_system_read_data16(system, 0x100); if (actual != expected) { printf("actual: 0x%x\n", actual); diff --git a/compiler/test/libvmcu_utils/libvmcu_utils.c b/compiler/test/libvmcu_utils/libvmcu_utils.c index da9adb71..447f59d1 100644 --- a/compiler/test/libvmcu_utils/libvmcu_utils.c +++ b/compiler/test/libvmcu_utils/libvmcu_utils.c @@ -44,3 +44,10 @@ uint16_t vmcu_system_read_data16(vmcu_system_t* system, uint16_t addr) { return (high << 8) | low; } + +uint16_t vmcu_system_read_2_gpr(vmcu_system_t* system, const int low_reg) { + + const uint8_t low = vmcu_system_read_gpr(system, low_reg); + const uint8_t high = vmcu_system_read_gpr(system, low_reg + 1); + return (high << 8) | low; +} diff --git a/compiler/test/libvmcu_utils/libvmcu_utils.h b/compiler/test/libvmcu_utils/libvmcu_utils.h index f929bf2f..d675060b 100644 --- a/compiler/test/libvmcu_utils/libvmcu_utils.h +++ b/compiler/test/libvmcu_utils/libvmcu_utils.h @@ -14,4 +14,7 @@ uint16_t vmcu_system_read_y(vmcu_system_t* system); uint16_t vmcu_system_read_data16(vmcu_system_t* system, uint16_t addr); +// read 16 bit value from 2 adjacent gprs +uint16_t vmcu_system_read_2_gpr(vmcu_system_t* system, const int low_reg); + #endif From 7ec38373f17c2bd2423e0c8e3e2e120df48f92a0 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Thu, 3 Oct 2024 14:24:45 +0200 Subject: [PATCH 10/13] test: avr: TAC_RETURN with 16 bit values --- .../compile_ir/test_compile_tac.h | 5 +- .../compile_ir/test_compile_tac_return.c | 101 +++++++++++++++--- compiler/test/testcases.c | 5 +- 3 files changed, 92 insertions(+), 19 deletions(-) diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h index 8da7e51a..286e3275 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h @@ -94,7 +94,10 @@ void test_compile_tac_if_cmp_goto_case_ge_false_8bit(); void test_compile_tac_if_cmp_goto_case_ge_false_16bit(); // TAC_RETURN -void test_compile_tac_return(); +void test_compile_tac_return_case_8bit_0x54(); +void test_compile_tac_return_case_8bit_0x55(); +void test_compile_tac_return_case_16bit_0x5432(); +void test_compile_tac_return_case_16bit_0x4321(); // TAC_COPY void test_compile_tac_copy_case_8bit(); diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_return.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_return.c index d845ead7..6ffb73c2 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_return.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_return.c @@ -1,9 +1,9 @@ #include -#include +//#include #include #include "libvmcu/libvmcu_system.h" -#include "libvmcu/libvmcu_analyzer.h" +//#include "libvmcu/libvmcu_analyzer.h" #include "avr_code_gen/cg_avr.h" #include "avr_code_gen/cg_avr_basic_block.h" @@ -15,27 +15,94 @@ #include "test_compile_tac.h" -void test_compile_tac_return() { +void test_compile_tac_return_case_8bit_0x54() { - status_test_codegen("TAC_RETURN"); + status_test_codegen("TAC_RETURN (8 bit value = 0x54)"); - for (int8_t value = 0x54; value < 0x58; value++) { + const int8_t value = 0x54; - struct TACBuffer* b = tacbuffer_ctor(); + struct TACBuffer* b = tacbuffer_ctor(); - tacbuffer_append(b, makeTACSetupSP()); - tacbuffer_append(b, makeTACConst(0, value + 1)); - tacbuffer_append(b, makeTACConst(1, value)); - tacbuffer_append(b, makeTACConst(2, value - 1)); - tacbuffer_append(b, makeTACReturn(1)); + tacbuffer_append(b, makeTACSetupSP()); + tacbuffer_append(b, makeTACConst(0, value + 1)); + tacbuffer_append(b, makeTACConst(1, value)); + tacbuffer_append(b, makeTACConst(2, value - 1)); + tacbuffer_append(b, makeTACReturn(1)); - vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); - vmcu_system_step_n(system, 8); + vmcu_system_step_n(system, 8); - //returned value should be in r0 - assert(vmcu_system_read_gpr(system, 0) == value); + assert(vmcu_system_read_gpr(system, 0) == value); - vmcu_system_dtor(system); - } + vmcu_system_dtor(system); +} + +void test_compile_tac_return_case_8bit_0x55() { + + status_test_codegen("TAC_RETURN (8 bit value = 0x55)"); + + const int8_t value = 0x55; + + struct TACBuffer* b = tacbuffer_ctor(); + + tacbuffer_append(b, makeTACSetupSP()); + tacbuffer_append(b, makeTACConst(0, value + 1)); + tacbuffer_append(b, makeTACConst(1, value)); + tacbuffer_append(b, makeTACConst(2, value - 1)); + tacbuffer_append(b, makeTACReturn(1)); + + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + + vmcu_system_step_n(system, 8); + + assert(vmcu_system_read_gpr(system, 0) == value); + + vmcu_system_dtor(system); +} + +void test_compile_tac_return_case_16bit_0x5432() { + + status_test_codegen("TAC_RETURN (16 bit value = 0x5432)"); + + const uint16_t value = 0x5432; + + struct TACBuffer* b = tacbuffer_ctor(); + + tacbuffer_append(b, makeTACSetupSP()); + tacbuffer_append(b, makeTACConst(0, value + 1)); + tacbuffer_append(b, makeTACConst(1, value)); + tacbuffer_append(b, makeTACConst(2, value - 1)); + tacbuffer_append(b, makeTACReturn(1)); + + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + + vmcu_system_step_n(system, 12); + + assert(vmcu_system_read_2_gpr(system, 0) == value); + + vmcu_system_dtor(system); +} + +void test_compile_tac_return_case_16bit_0x4321() { + + status_test_codegen("TAC_RETURN (16 bit value = 0x4321)"); + + const uint16_t value = 0x4321; + + struct TACBuffer* b = tacbuffer_ctor(); + + tacbuffer_append(b, makeTACSetupSP()); + tacbuffer_append(b, makeTACConst(0, value + 1)); + tacbuffer_append(b, makeTACConst(1, value)); + tacbuffer_append(b, makeTACConst(2, value - 1)); + tacbuffer_append(b, makeTACReturn(1)); + + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + + vmcu_system_step_n(system, 12); + + assert(vmcu_system_read_2_gpr(system, 0) == value); + + vmcu_system_dtor(system); } diff --git a/compiler/test/testcases.c b/compiler/test/testcases.c index b586f86e..dab8e14b 100644 --- a/compiler/test/testcases.c +++ b/compiler/test/testcases.c @@ -141,7 +141,10 @@ void (*tests_avr_codegen[])() = { test_compile_tac_if_cmp_goto_case_ge_false_16bit, // TAC_RETURN - test_compile_tac_return, + test_compile_tac_return_case_8bit_0x54, + test_compile_tac_return_case_8bit_0x55, + test_compile_tac_return_case_16bit_0x5432, + test_compile_tac_return_case_16bit_0x4321, // TAC_COPY test_compile_tac_copy_case_8bit, From 3d0433c04c72f1a371800007023fe4a83e8798e6 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Thu, 3 Oct 2024 21:25:10 +0200 Subject: [PATCH 11/13] test: avr codegen: TAC_STORE_CONST_ADDR 16 bit also test 16 bit values for TAC_STORE_CONST_ADDR --- .../compile_ir/test_compile_tac.h | 5 +- .../compile_ir/test_compile_tac_store.c | 26 +------ .../test_compile_tac_store_const_addr.c | 70 +++++++++++++++---- .../avr_code_gen/test_avr_code_gen_util.c | 34 ++++++++- .../avr_code_gen/test_avr_code_gen_util.h | 7 ++ compiler/test/testcases.c | 5 +- 6 files changed, 104 insertions(+), 43 deletions(-) diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h index 286e3275..9c72d276 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h @@ -9,7 +9,10 @@ void test_compile_tac_nop(); void test_compile_tac_const_value_test_8bit(); void test_compile_tac_const_value_test_16bit(); -void test_compile_tac_store_const_addr(); +void test_compile_tac_store_const_addr_case_8bit_value_addr_0x118(); +void test_compile_tac_store_const_addr_case_8bit_value_addr_0x119(); +void test_compile_tac_store_const_addr_case_16bit_value_addr_0x118(); +void test_compile_tac_store_const_addr_case_16bit_value_addr_0x119(); void test_compile_tac_load_const_addr(); // TAC_BINARY_OP_IMMEDIATE diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store.c index 1d03678a..2890f65a 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store.c @@ -25,37 +25,13 @@ static vmcu_system_t* common(uint16_t addr, int16_t value, uint8_t redzone) { tacbuffer_append(b, makeTACConst(2, addr)); tacbuffer_append(b, makeTACStore(2, 1)); - vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); - - // fill the area with red zone to detect unintended writes - // around the address - for (uint16_t a = addr - 2; a < addr + 4; a++) { - vmcu_system_write_data(system, a, redzone); - } + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer_with_redzone(b, addr, redzone); vmcu_system_step_n(system, 10); return system; } -static void assert_redzone(vmcu_system_t* system, uint16_t addr, uint8_t width, uint8_t redzone) { - - const uint16_t addr1 = addr - 1; - const uint16_t addr2 = addr + width; - - const uint8_t before = vmcu_system_read_data(system, addr1); - const uint8_t after = vmcu_system_read_data(system, addr2); - - if ((before != redzone) || (after != redzone)) { - for (uint16_t a = addr1 - 1; a <= addr2 + 1; a++) { - const uint8_t value = vmcu_system_read_data(system, a); - printf("[0x%x] = 0x%x\n", a, value); - } - } - assert(before == redzone); - assert(after == redzone); -} - void test_compile_tac_store_case_8bit_value_8bit_addr_c7() { status_test_codegen("TAC_STORE (8 bit value, 8 bit addr = 0xc7)"); diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store_const_addr.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store_const_addr.c index 455f99cc..1b6786e6 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store_const_addr.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_store_const_addr.c @@ -15,30 +15,70 @@ #include "test_compile_tac.h" -void test_compile_tac_store_const_addr() { +static void common(const uint16_t addr, const uint16_t fixed_value, bool wide) { - status_test_codegen("TAC_STORE_CONST_ADDR"); + //const uint16_t addr = 0x118; + //const uint8_t fixed_value = 0x44; + const uint8_t redzone = 0xff; - for (uint16_t addr = 0x118; addr < 0x140; addr += 5) { + struct TACBuffer* b = tacbuffer_ctor(); - const int8_t fixed_value = 0x44; + tacbuffer_append(b, makeTACConst(1, fixed_value)); + tacbuffer_append(b, makeTACStoreConstAddr(addr, 1)); - struct TACBuffer* b = tacbuffer_ctor(); + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer_with_redzone(b, addr, redzone); - tacbuffer_append(b, makeTACConst(1, fixed_value)); - tacbuffer_append(b, makeTACStoreConstAddr(addr, 1)); - tacbuffer_append(b, makeTACReturn(1)); + vmcu_system_step_n(system, 10); - vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + uint16_t value; + if (wide) { + value = vmcu_system_read_data16(system, addr); + } else { + value = vmcu_system_read_data(system, addr); + } - vmcu_system_step_n(system, 10); + if (value != fixed_value) { + printf("[0x%x] == 0x%x, expected 0x%x\n", addr, value, fixed_value); + } - //check that the value was written + //check that the value was written + assert(value == fixed_value); - int8_t value = vmcu_system_read_data(system, addr); + assert_redzone(system, addr, (wide) ? 2 : 1, redzone); - assert(value == fixed_value); + vmcu_system_dtor(system); +} +void test_compile_tac_store_const_addr_case_8bit_value_addr_0x118() { - vmcu_system_dtor(system); - } + status_test_codegen("TAC_STORE_CONST_ADDR (8 bit value, address = 0x118)"); + + const uint16_t addr = 0x118; + const uint8_t fixed_value = 0x44; + common(addr, fixed_value, false); +} + +void test_compile_tac_store_const_addr_case_8bit_value_addr_0x119() { + + status_test_codegen("TAC_STORE_CONST_ADDR (8 bit value, address = 0x119)"); + + const uint16_t addr = 0x119; + const uint8_t fixed_value = 0x45; + common(addr, fixed_value, false); +} +void test_compile_tac_store_const_addr_case_16bit_value_addr_0x118() { + + status_test_codegen("TAC_STORE_CONST_ADDR (16 bit value, address = 0x118)"); + + const uint16_t addr = 0x118; + const uint16_t fixed_value = 0x4567; + common(addr, fixed_value, true); +} + +void test_compile_tac_store_const_addr_case_16bit_value_addr_0x119() { + + status_test_codegen("TAC_STORE_CONST_ADDR (16 bit value, address = 0x119)"); + + const uint16_t addr = 0x119; + const uint16_t fixed_value = 0x5678; + common(addr, fixed_value, true); } diff --git a/compiler/test/avr_code_gen/test_avr_code_gen_util.c b/compiler/test/avr_code_gen/test_avr_code_gen_util.c index 812d244f..b9fc873b 100644 --- a/compiler/test/avr_code_gen/test_avr_code_gen_util.c +++ b/compiler/test/avr_code_gen/test_avr_code_gen_util.c @@ -1,4 +1,4 @@ - +#include #include #include #include "libvmcu/libvmcu_system.h" @@ -26,6 +26,38 @@ static void print_defs(FILE* fout); +void assert_redzone(vmcu_system_t* system, uint16_t addr, uint8_t width, uint8_t redzone) { + + assert(width <= 8); + + const uint16_t addr1 = addr - 1; + const uint16_t addr2 = addr + width; + + const uint8_t before = vmcu_system_read_data(system, addr1); + const uint8_t after = vmcu_system_read_data(system, addr2); + + if ((before != redzone) || (after != redzone)) { + for (uint16_t a = addr1 - 1; a <= addr2 + 1; a++) { + const uint8_t value = vmcu_system_read_data(system, a); + printf("[0x%x] = 0x%x\n", a, value); + } + } + assert(before == redzone); + assert(after == redzone); +} + +vmcu_system_t* prepare_vmcu_system_from_tacbuffer_with_redzone(struct TACBuffer* buffer, uint16_t addr_redzone, uint8_t redzone) { + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(buffer); + + // fill the area with red zone to detect unintended writes + // and reads around the address + for (uint16_t a = addr_redzone - 2; a < addr_redzone + 4; a++) { + vmcu_system_write_data(system, a, redzone); + } + + return system; +} + vmcu_system_t* prepare_vmcu_system_from_tacbuffer(struct TACBuffer* buffer) { //create the file diff --git a/compiler/test/avr_code_gen/test_avr_code_gen_util.h b/compiler/test/avr_code_gen/test_avr_code_gen_util.h index 419a24b8..8181f081 100644 --- a/compiler/test/avr_code_gen/test_avr_code_gen_util.h +++ b/compiler/test/avr_code_gen/test_avr_code_gen_util.h @@ -13,4 +13,11 @@ struct TACBuffer; vmcu_system_t* prepare_vmcu_system_from_tacbuffer(struct TACBuffer* buffer); +// additionally creates a red zone around the given address, +// to be able to later check if any unintended writes or reads happened there +vmcu_system_t* prepare_vmcu_system_from_tacbuffer_with_redzone(struct TACBuffer* buffer, uint16_t addr_redzone, uint8_t redzone); + +// assert that the values around the address still have 'redzone' value +void assert_redzone(vmcu_system_t* system, uint16_t addr, uint8_t width, uint8_t redzone); + #endif diff --git a/compiler/test/testcases.c b/compiler/test/testcases.c index dab8e14b..a1f0aa01 100644 --- a/compiler/test/testcases.c +++ b/compiler/test/testcases.c @@ -56,7 +56,10 @@ void (*tests_avr_codegen[])() = { test_compile_tac_const_value_test_8bit, test_compile_tac_const_value_test_16bit, - test_compile_tac_store_const_addr, + test_compile_tac_store_const_addr_case_8bit_value_addr_0x118, + test_compile_tac_store_const_addr_case_8bit_value_addr_0x119, + test_compile_tac_store_const_addr_case_16bit_value_addr_0x118, + test_compile_tac_store_const_addr_case_16bit_value_addr_0x119, test_compile_tac_load_const_addr, //TAC_BINARY_OP_IMMEDIATE From c2922c11c82e2bf9c35912302d8c81464fc91bf1 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Thu, 3 Oct 2024 21:49:40 +0200 Subject: [PATCH 12/13] test: avr codegen: TAC_LOAD_CONST_ADDR 16 bit test 16 bit values for TAC_LOAD_CONST_ADDR --- .../compile_ir/compile_tac_load_const_addr.c | 8 +- .../compile_ir/test_compile_tac.h | 5 +- .../test_compile_tac_load_const_addr.c | 82 +++++++++++++++---- compiler/test/testcases.c | 5 +- 4 files changed, 78 insertions(+), 22 deletions(-) diff --git a/compiler/main/avr_code_gen/compile_ir/compile_tac_load_const_addr.c b/compiler/main/avr_code_gen/compile_ir/compile_tac_load_const_addr.c index 28b6c554..43cd0f0c 100644 --- a/compiler/main/avr_code_gen/compile_ir/compile_tac_load_const_addr.c +++ b/compiler/main/avr_code_gen/compile_ir/compile_tac_load_const_addr.c @@ -1,5 +1,3 @@ -#include - #include "tac/tacbuffer.h" #include "tac/tac.h" #include "avr_code_gen/compile_ir/compile_tac.h" @@ -8,7 +6,13 @@ void compile_tac_load_const_addr(struct RAT* rat, struct TAC* tac, struct IBuffe const int reg_dest = rat_get_register(rat, tac->dest); + const bool is_wide = rat_is_wide(rat, tac->dest); + const uint32_t addr = tac->const_value; lds(reg_dest, addr, "TAC_LOAD_CONST_ADDR"); + + if (is_wide) { + lds(reg_dest + 1, addr + 1, "TAC_LOAD_CONST_ADDR"); + } } diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h index 9c72d276..4906392b 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h @@ -13,7 +13,10 @@ void test_compile_tac_store_const_addr_case_8bit_value_addr_0x118(); void test_compile_tac_store_const_addr_case_8bit_value_addr_0x119(); void test_compile_tac_store_const_addr_case_16bit_value_addr_0x118(); void test_compile_tac_store_const_addr_case_16bit_value_addr_0x119(); -void test_compile_tac_load_const_addr(); +void test_compile_tac_load_const_addr_case_8bit_value_0x55(); +void test_compile_tac_load_const_addr_case_8bit_value_0x56(); +void test_compile_tac_load_const_addr_case_16bit_value_0x1234(); +void test_compile_tac_load_const_addr_case_16bit_value_0x4321(); // TAC_BINARY_OP_IMMEDIATE void test_compile_tac_binary_op_immediate_case_add_8bit(); diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load_const_addr.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load_const_addr.c index 404543ff..d79cb482 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load_const_addr.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load_const_addr.c @@ -1,11 +1,8 @@ #include -#include #include #include "libvmcu/libvmcu_system.h" -#include "libvmcu/libvmcu_analyzer.h" -#include "avr_code_gen/cg_avr.h" #include "avr_code_gen/cg_avr_basic_block.h" #include "tac/tacbuffer.h" @@ -15,31 +12,80 @@ #include "test_compile_tac.h" -void test_compile_tac_load_const_addr() { +static void common(const uint16_t addr, const uint16_t fixed_value, bool wide) { - status_test_codegen("TAC_LOAD_CONST_ADDR"); + const uint8_t redzone = 0xff; + + struct TACBuffer* b = tacbuffer_ctor(); + + tacbuffer_append(b, makeTACConst(1, 0xf1f1)); + tacbuffer_append(b, makeTACLoadConstAddr(1, addr)); + tacbuffer_append(b, makeTACReturn(1)); + + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer_with_redzone(b, addr, redzone); + + //write value to be read later + vmcu_system_write_data(system, addr, fixed_value & 0xff); + if (wide) { + vmcu_system_write_data(system, addr + 1, (fixed_value >> 8) & 0xff); + } + + vmcu_system_step_n(system, 10); + + uint16_t value; + if (wide) { + value = vmcu_system_read_2_gpr(system, 0); + } else { + value = vmcu_system_read_gpr(system, 0); + } + + if (value != fixed_value) { + printf("[0x%x] (may read 2 bytes) = 0x%x, expected 0x%x\n", addr, value, fixed_value); + } + + assert(value == fixed_value); + + assert_redzone(system, addr, (wide) ? 2 : 1, redzone); + + vmcu_system_dtor(system); +} + +void test_compile_tac_load_const_addr_case_8bit_value_0x55() { + + status_test_codegen("TAC_LOAD_CONST_ADDR (8 bit value = 0x55)"); const uint16_t addr = 0x100 + 17; + const uint8_t fixed_value = 0x55; - for (int8_t fixed_value = 0x55; fixed_value < 0x65; fixed_value += 2) { + common(addr, fixed_value, false); +} - struct TACBuffer* b = tacbuffer_ctor(); +void test_compile_tac_load_const_addr_case_8bit_value_0x56() { - tacbuffer_append(b, makeTACConst(1, 0x00)); - tacbuffer_append(b, makeTACLoadConstAddr(1, addr)); - tacbuffer_append(b, makeTACReturn(1)); + status_test_codegen("TAC_LOAD_CONST_ADDR (8 bit value = 0x56)"); - vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + const uint16_t addr = 0x100 + 17; + const uint8_t fixed_value = 0x56; - //write value to be read later - vmcu_system_write_data(system, addr, fixed_value); + common(addr, fixed_value, false); +} - vmcu_system_step_n(system, 10); +void test_compile_tac_load_const_addr_case_16bit_value_0x1234() { - int8_t r0 = vmcu_system_read_gpr(system, 0); + status_test_codegen("TAC_LOAD_CONST_ADDR (16 bit value = 0x1234)"); - assert(r0 == fixed_value); + const uint16_t addr = 0x100 + 17; + const uint16_t fixed_value = 0x1234; - vmcu_system_dtor(system); - } + common(addr, fixed_value, true); +} + +void test_compile_tac_load_const_addr_case_16bit_value_0x4321() { + + status_test_codegen("TAC_LOAD_CONST_ADDR (16 bit value = 0x4321)"); + + const uint16_t addr = 0x100 + 17; + const uint16_t fixed_value = 0x4321; + + common(addr, fixed_value, true); } diff --git a/compiler/test/testcases.c b/compiler/test/testcases.c index a1f0aa01..7dcfa393 100644 --- a/compiler/test/testcases.c +++ b/compiler/test/testcases.c @@ -60,7 +60,10 @@ void (*tests_avr_codegen[])() = { test_compile_tac_store_const_addr_case_8bit_value_addr_0x119, test_compile_tac_store_const_addr_case_16bit_value_addr_0x118, test_compile_tac_store_const_addr_case_16bit_value_addr_0x119, - test_compile_tac_load_const_addr, + test_compile_tac_load_const_addr_case_8bit_value_0x55, + test_compile_tac_load_const_addr_case_8bit_value_0x56, + test_compile_tac_load_const_addr_case_16bit_value_0x1234, + test_compile_tac_load_const_addr_case_16bit_value_0x4321, //TAC_BINARY_OP_IMMEDIATE test_compile_tac_binary_op_immediate_case_add_8bit, From 4f4a09f5e9167a47af2f3a4a3073e4baa6871094 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Thu, 3 Oct 2024 23:15:40 +0200 Subject: [PATCH 13/13] test: avr codegen: TAC_LOAD 16 bit values --- .../compile_ir/compile_tac_load.c | 10 ++- .../compile_ir/test_compile_tac.h | 6 +- .../compile_ir/test_compile_tac_load.c | 84 +++++++++++-------- compiler/test/testcases.c | 6 +- 4 files changed, 66 insertions(+), 40 deletions(-) diff --git a/compiler/main/avr_code_gen/compile_ir/compile_tac_load.c b/compiler/main/avr_code_gen/compile_ir/compile_tac_load.c index e1f0c91c..3ca31f0c 100644 --- a/compiler/main/avr_code_gen/compile_ir/compile_tac_load.c +++ b/compiler/main/avr_code_gen/compile_ir/compile_tac_load.c @@ -24,12 +24,20 @@ void compile_tac_load(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu) { else ldi(XH, 0, c); - if (rat_is_wide(rat, tac->dest)) { + // TODO: make a 'wide' property in struct TAC + // to avoid encoding this in different places + const bool tac_says_wide = tac->const_value == 2; + + if (tac_says_wide) { // what if we want to load a 16 bit value? ldXpostInc(reg_dest, c); ldX(reg_dest + 1, c); } else { ldX(reg_dest, c); + + if (rat_is_wide(rat, tac->dest)) { + clr(reg_dest + 1, c); + } } } diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h index 4906392b..86dfb16e 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac.h @@ -120,8 +120,10 @@ void test_compile_tac_call_case_returns_value_16bit(); void test_compile_tac_call_case_1_param(); // TAC_LOAD -void test_compile_tac_load_case_8bit_addr(); -void test_compile_tac_load_case_16bit_addr(); +void test_compile_tac_load_case_8bit_addr_8bit_value(); +void test_compile_tac_load_case_8bit_addr_16bit_value(); +void test_compile_tac_load_case_16bit_addr_8bit_value(); +void test_compile_tac_load_case_16bit_addr_16bit_value(); // TAC_STORE void test_compile_tac_store_case_8bit_value_8bit_addr_c7(); diff --git a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load.c b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load.c index 1a245954..adb9bb55 100644 --- a/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load.c +++ b/compiler/test/avr_code_gen/compile_ir/test_compile_tac_load.c @@ -1,11 +1,8 @@ #include -#include #include #include "libvmcu/libvmcu_system.h" -#include "libvmcu/libvmcu_analyzer.h" -#include "avr_code_gen/cg_avr.h" #include "avr_code_gen/cg_avr_basic_block.h" #include "tac/tacbuffer.h" @@ -15,58 +12,75 @@ #include "test_compile_tac.h" -void test_compile_tac_load_case_8bit_addr() { +static void common(const uint16_t addr, const uint16_t fixed_value, bool wide) { - status_test_codegen("TAC_LOAD (8 bit address)"); + const uint8_t redzone = 0xff; - const uint16_t addr = 0xc7; - for (int8_t fixed_value = 0x33; fixed_value < 0x36; fixed_value++) { + struct TACBuffer* b = tacbuffer_ctor(); - struct TACBuffer* b = tacbuffer_ctor(); + tacbuffer_append(b, makeTACConst(1, 0x1010)); + tacbuffer_append(b, makeTACConst(2, addr)); + tacbuffer_append(b, makeTACLoad(1, 2, (wide) ? 2 : 1)); + tacbuffer_append(b, makeTACReturn(1)); - tacbuffer_append(b, makeTACConst(1, 0x00)); - tacbuffer_append(b, makeTACConst(2, addr)); - tacbuffer_append(b, makeTACLoad(1, 2, 1)); - tacbuffer_append(b, makeTACReturn(1)); + vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer_with_redzone(b, addr, redzone); - vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + vmcu_system_write_data(system, addr, fixed_value); + if (wide) { + vmcu_system_write_data(system, addr + 1, (fixed_value >> 8)); + } - vmcu_system_write_data(system, addr, fixed_value); + vmcu_system_step_n(system, 20); - vmcu_system_step_n(system, 20); + const uint16_t value = vmcu_system_read_2_gpr(system, 0); - int8_t r0 = vmcu_system_read_gpr(system, 0); + if (value != fixed_value) { + printf("[0x%x] (may read 2 bytes) == 0x%x, expected 0x%x\n", addr, value, fixed_value); + } - assert(r0 == fixed_value); + assert(value == fixed_value); - vmcu_system_dtor(system); - } + assert_redzone(system, addr, (wide) ? 2 : 1, redzone); + + vmcu_system_dtor(system); } -void test_compile_tac_load_case_16bit_addr() { +void test_compile_tac_load_case_8bit_addr_8bit_value() { - status_test_codegen("TAC_LOAD (16 bit address)"); + status_test_codegen("TAC_LOAD (8 bit addr, 8 bit value)"); - const uint16_t addr = 0x0103; - for (int8_t fixed_value = 0x20; fixed_value < 0x24; fixed_value++) { + const uint16_t addr = 0xc7; + const uint8_t fixed_value = 0x33; - struct TACBuffer* b = tacbuffer_ctor(); + common(addr, fixed_value, false); +} - tacbuffer_append(b, makeTACConst(1, 0x00)); - tacbuffer_append(b, makeTACConst(2, addr)); - tacbuffer_append(b, makeTACLoad(1, 2, 1)); - tacbuffer_append(b, makeTACReturn(1)); +void test_compile_tac_load_case_8bit_addr_16bit_value() { - vmcu_system_t* system = prepare_vmcu_system_from_tacbuffer(b); + status_test_codegen("TAC_LOAD (8 bit addr, 16 bit value)"); - vmcu_system_write_data(system, addr, fixed_value); + const uint16_t addr = 0xc7; + const uint16_t fixed_value = 0x3456; - vmcu_system_step_n(system, 20); + common(addr, fixed_value, true); +} - int8_t r0 = vmcu_system_read_gpr(system, 0); +void test_compile_tac_load_case_16bit_addr_8bit_value() { - assert(r0 == fixed_value); + status_test_codegen("TAC_LOAD (16 bit addr, 8 bit value)"); - vmcu_system_dtor(system); - } + const uint16_t addr = 0x0103; + const int8_t fixed_value = 0x20; + + common(addr, fixed_value, false); +} + +void test_compile_tac_load_case_16bit_addr_16bit_value() { + + status_test_codegen("TAC_LOAD (16 bit addr, 16 bit value)"); + + const uint16_t addr = 0x0103; + const uint16_t fixed_value = 0x2087; + + common(addr, fixed_value, true); } diff --git a/compiler/test/testcases.c b/compiler/test/testcases.c index 7dcfa393..7ef6e463 100644 --- a/compiler/test/testcases.c +++ b/compiler/test/testcases.c @@ -170,8 +170,10 @@ void (*tests_avr_codegen[])() = { test_compile_tac_setup_stackframe, // TAC_LOAD - test_compile_tac_load_case_8bit_addr, - test_compile_tac_load_case_16bit_addr, + test_compile_tac_load_case_8bit_addr_8bit_value, + test_compile_tac_load_case_8bit_addr_16bit_value, + test_compile_tac_load_case_16bit_addr_8bit_value, + test_compile_tac_load_case_16bit_addr_16bit_value, // TAC_STORE test_compile_tac_store_case_8bit_value_8bit_addr_c7,