Skip to content

Commit a9b84fd

Browse files
committed
Add AVR unit tests.
Signed-off-by: Glenn Baker <[email protected]>
1 parent 77d7e28 commit a9b84fd

File tree

2 files changed

+266
-0
lines changed

2 files changed

+266
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ if (UNICORN_HAS_AVR)
13591359
set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} avr-softmmu)
13601360
set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_avr)
13611361
target_link_libraries(avr-softmmu unicorn-common)
1362+
set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_avr)
13621363
endif()
13631364

13641365
# Extra tests

tests/unit/test_avr.c

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
#include <assert.h>
2+
#include "unicorn_test.h"
3+
4+
#define ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
5+
6+
#define PAGE_SIZE 256
7+
#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & -PAGE_SIZE)
8+
9+
enum {
10+
ADDR__init__,
11+
ADDR_test_func,
12+
ADDR_test_1,
13+
ADDR_main,
14+
ADDR_abort,
15+
ADDR_exit,
16+
ADDR__stop_program,
17+
ADDR__data__,
18+
};
19+
20+
static const uint16_t ADDR[] = {
21+
0x0000, // __init__
22+
0x001a, // test_func()
23+
0x0030, // test_1()
24+
0x0058, // main()
25+
0x0062, // abort()
26+
0x006c, // _exit()
27+
0x006e, // __stop_program()
28+
0x0070, // __data__
29+
0x0072, // __size__
30+
};
31+
32+
static const uint8_t FLASH[] =
33+
// 00000000 <__ctors_end>:
34+
"\x12\xe0" // ldi r17, 0x02
35+
"\xa0\xe0" // ldi r26, 0x00
36+
"\xb2\xe0" // ldi r27, 0x02
37+
"\xe0\xe7" // ldi r30, 0x70
38+
"\xf0\xe0" // ldi r31, 0x00
39+
"\x00\xe0" // ldi r16, 0x00
40+
"\x0b\xbf" // out 0x3b, r16
41+
"\x02\xc0" // rjmp .+4
42+
"\x07\x90" // elpm r0, Z+
43+
"\x0d\x92" // st X+, r0
44+
"\xa2\x30" // cpi r26, 0x02
45+
"\xb1\x07" // cpc r27, r17
46+
"\xd9\xf7" // brne .-10
47+
48+
// 0000001a <test_func>:
49+
"\x20\x91\x00\x02" // lds r18, 0x0200
50+
"\x30\x91\x01\x02" // lds r19, 0x0201
51+
"\x86\x0f" // add r24, r22
52+
"\x97\x1f" // adc r25, r23
53+
"\x88\x0f" // add r24, r24
54+
"\x99\x1f" // adc r25, r25
55+
"\x82\x0f" // add r24, r18
56+
"\x93\x1f" // adc r25, r19
57+
"\x08\x95" // ret
58+
59+
// 00000030 <test_1>:
60+
"\x62\xe0" // ldi r22, 0x02
61+
"\x70\xe0" // ldi r23, 0x00
62+
"\x81\xe0" // ldi r24, 0x01
63+
"\x90\xe0" // ldi r25, 0x00
64+
"\x0e\x94\x0d\x00" // call 0x1a
65+
"\x07\x97" // sbiw r24, 0x07
66+
"\x11\xf0" // breq .+4
67+
"\x0e\x94\x31\x00" // call 0x62
68+
"\x60\xe8" // ldi r22, 0x80
69+
"\x70\xe0" // ldi r23, 0x00
70+
"\x80\xe4" // ldi r24, 0x40
71+
"\x90\xe0" // ldi r25, 0x00
72+
"\x0e\x94\x0d\x00" // call 0x1a
73+
"\x81\x38" // cpi r24, 0x81
74+
"\x91\x40" // sbci r25, 0x01
75+
"\xa9\xf7" // brne .-22
76+
"\x08\x95" // ret
77+
78+
// 00000058 <main>:
79+
"\x0e\x94\x18\x00" // call 0x30
80+
"\x80\xe0" // ldi r24, 0x00
81+
"\x90\xe0" // ldi r25, 0x00
82+
"\x08\x95" // ret
83+
84+
// 00000062 <abort>:
85+
"\x81\xe0" // ldi r24, 0x01
86+
"\x90\xe0" // ldi r25, 0x00
87+
"\xf8\x94" // cli
88+
"\x0c\x94\x36\x00" // jmp 0x6c
89+
90+
// 0000006c <_exit>:
91+
"\xf8\x94" // cli
92+
93+
// 0000006e <__stop_program>:
94+
"\xff\xcf" // rjmp .-2
95+
96+
// 0x000070 .data
97+
"\x01\x00"
98+
;
99+
const uint64_t FLASH_SIZE = sizeof(FLASH);
100+
101+
const uint64_t MEM_BASE = 0x0200;
102+
const uint64_t MEM_SIZE = 0x0100;
103+
104+
static void uc_common_setup(uc_engine **uc, uc_cpu_avr cpu_model,
105+
const uint8_t *code, uint64_t code_size)
106+
{
107+
OK(uc_open(UC_ARCH_AVR, UC_MODE_LITTLE_ENDIAN, uc));
108+
if (cpu_model != 0)
109+
OK(uc_ctl_set_cpu_model(*uc, cpu_model));
110+
111+
OK(uc_mem_map(*uc, UC_AVR_MEM_FLASH, PAGE_ALIGN(code_size),
112+
UC_PROT_READ|UC_PROT_EXEC));
113+
OK(uc_mem_write(*uc, UC_AVR_MEM_FLASH, code, code_size));
114+
OK(uc_mem_map(*uc, MEM_BASE, MEM_SIZE, UC_PROT_READ|UC_PROT_WRITE));
115+
}
116+
117+
static void test_avr_basic_alu(void)
118+
{
119+
uc_engine *uc = NULL;
120+
uint8_t r[32] = {0,};
121+
uint16_t r_func_arg0 = 1, r_func_arg1 = 2, r_func_ret;
122+
r[24] = 1;
123+
r[22] = 2;
124+
125+
uc_common_setup(&uc, 0, FLASH, FLASH_SIZE);
126+
OK(uc_reg_write(uc, UC_AVR_REG_R24W, &r_func_arg0));
127+
OK(uc_reg_write(uc, UC_AVR_REG_R22W, &r_func_arg1));
128+
129+
const uint64_t code_start = ADDR[ADDR_test_func] + 8;
130+
OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0));
131+
132+
uint32_t r_pc;
133+
OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc));
134+
OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25]));
135+
OK(uc_reg_read(uc, UC_AVR_REG_R24, &r[24]));
136+
OK(uc_reg_read(uc, UC_AVR_REG_R23, &r[23]));
137+
OK(uc_reg_read(uc, UC_AVR_REG_R22, &r[22]));
138+
139+
TEST_CHECK(r_pc == code_start + 4);
140+
TEST_CHECK(r[25] == 0 && r[24] == 3);
141+
TEST_CHECK(r[23] == 0 && r[22] == 2);
142+
143+
OK(uc_reg_read(uc, UC_AVR_REG_R24W, &r_func_ret));
144+
OK(uc_reg_read(uc, UC_AVR_REG_R22W, &r_func_arg1));
145+
146+
TEST_CHECK(r_func_ret == r[24]);
147+
TEST_CHECK(r_func_arg1 == r[22]);
148+
149+
OK(uc_close(uc));
150+
}
151+
152+
typedef struct MEM_HOOK_RESULT_s {
153+
uc_mem_type type;
154+
uint64_t address;
155+
int size;
156+
uint64_t value;
157+
} MEM_HOOK_RESULT;
158+
159+
typedef struct MEM_HOOK_RESULTS_s {
160+
uint64_t count;
161+
MEM_HOOK_RESULT results[16];
162+
} MEM_HOOK_RESULTS;
163+
164+
static bool test_avr_basic_mem_cb_eventmem(uc_engine *uc, uc_mem_type type,
165+
uint64_t address, int size, int64_t value, void *user_data)
166+
{
167+
MEM_HOOK_RESULTS *const r = user_data;
168+
169+
uint64_t count = r->count;
170+
if (count >= ARRAY_ELEMS(r->results)) {
171+
TEST_ASSERT(false);
172+
}
173+
174+
r->results[count].type = type;
175+
r->results[count].address = address;
176+
r->results[count].size = size;
177+
r->results[count].value = value;
178+
r->count++;
179+
return true;
180+
}
181+
182+
static void test_avr_basic_mem(void)
183+
{
184+
uc_engine *uc = NULL;
185+
uc_hook eventmem_hook;
186+
MEM_HOOK_RESULTS eventmem_trace = {0};
187+
188+
uc_common_setup(&uc, 0, FLASH, FLASH_SIZE);
189+
OK(uc_hook_add(uc, &eventmem_hook, UC_HOOK_MEM_VALID,
190+
test_avr_basic_mem_cb_eventmem, &eventmem_trace, 1, 0));
191+
192+
const uint64_t code_start = ADDR[ADDR__init__];
193+
OK(uc_emu_start(uc, code_start, ADDR[ADDR__init__+1], 0, 0));
194+
195+
uint32_t r_pc;
196+
OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc));
197+
TEST_CHECK(r_pc == ADDR[ADDR__init__+1]);
198+
199+
const uint16_t DATA_BASE = ADDR[ADDR__data__];
200+
const uint16_t DATA_SIZE = ADDR[ADDR__data__+1] - DATA_BASE;
201+
const uint8_t *const DATA = &FLASH[ADDR[ADDR__data__]];
202+
203+
// Check SRAM was correctly initialized with data from Flash program memory
204+
uint8_t mem[DATA_SIZE];
205+
OK(uc_mem_read(uc, MEM_BASE, mem, sizeof(mem)));
206+
TEST_CHECK(memcmp(mem, DATA, DATA_SIZE) == 0);
207+
208+
TEST_CHECK(eventmem_trace.count == 2*DATA_SIZE);
209+
for (unsigned i = 0; i < DATA_SIZE; i++) {
210+
const MEM_HOOK_RESULT *const mr = &eventmem_trace.results[2*i];
211+
TEST_CHECK(mr->type == UC_MEM_READ);
212+
TEST_CHECK(mr->address == (UC_AVR_MEM_FLASH|(DATA_BASE+i)));
213+
TEST_CHECK(mr->size == 1);
214+
TEST_CHECK(mr->value == 0);
215+
216+
const MEM_HOOK_RESULT *const mw = &eventmem_trace.results[2*i+1];
217+
TEST_CHECK(mw->type == UC_MEM_WRITE);
218+
TEST_CHECK(mw->address == MEM_BASE+i);
219+
TEST_CHECK(mw->size == 1);
220+
TEST_CHECK(mw->value == DATA[i]);
221+
}
222+
223+
OK(uc_close(uc));
224+
}
225+
226+
static void test_avr_full_exec(void)
227+
{
228+
uc_engine *uc = NULL;
229+
230+
uc_common_setup(&uc, 0, FLASH, FLASH_SIZE);
231+
232+
const uint64_t code_start = ADDR[ADDR__init__];
233+
OK(uc_emu_start(uc, code_start, ADDR[ADDR__init__+1], 0, 0));
234+
235+
uint32_t r_pc;
236+
OK(uc_reg_read(uc, UC_AVR_REG_PC, &r_pc));
237+
TEST_CHECK(r_pc == ADDR[ADDR__init__+1]);
238+
239+
uint32_t r_sp = MEM_BASE + MEM_SIZE - 1;
240+
OK(uc_reg_write(uc, UC_AVR_REG_SP, &r_sp));
241+
242+
const uint64_t exits[] = {
243+
ADDR[ADDR_main],
244+
ADDR[ADDR__stop_program]
245+
};
246+
OK(uc_ctl_exits_enable(uc));
247+
OK(uc_ctl_set_exits(uc, exits, ARRAY_ELEMS(exits)));
248+
249+
const uint64_t code_main = ADDR[ADDR_main];
250+
OK(uc_emu_start(uc, code_main, 0, 0, 0));
251+
252+
uint8_t r[32] = {0,};
253+
OK(uc_reg_read(uc, UC_AVR_REG_R25, &r[25]));
254+
OK(uc_reg_read(uc, UC_AVR_REG_R24, &r[24]));
255+
TEST_CHECK(r[25] == 0 && r[24] == 0);
256+
257+
OK(uc_close(uc));
258+
}
259+
260+
TEST_LIST = {
261+
{"test_avr_basic_alu", test_avr_basic_alu},
262+
{"test_avr_basic_mem", test_avr_basic_mem},
263+
{"test_avr_full_exec", test_avr_full_exec},
264+
{NULL, NULL}
265+
};

0 commit comments

Comments
 (0)