Skip to content

Commit 77d7e28

Browse files
committed
Add AVR code samples.
Signed-off-by: Glenn Baker <[email protected]>
1 parent 155dae5 commit 77d7e28

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,6 +1357,7 @@ endif()
13571357
if (UNICORN_HAS_AVR)
13581358
set(UNICORN_COMPILE_OPTIONS ${UNICORN_COMPILE_OPTIONS} -DUNICORN_HAS_AVR)
13591359
set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} avr-softmmu)
1360+
set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_avr)
13601361
target_link_libraries(avr-softmmu unicorn-common)
13611362
endif()
13621363

samples/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ endif
9393
ifneq (,$(findstring tricore,$(UNICORN_ARCHS)))
9494
SOURCES += sample_tricore.c
9595
endif
96+
ifneq (,$(findstring avr,$(UNICORN_ARCHS)))
97+
SOURCES += sample_avr.c
98+
endif
9699

97100
BINS = $(SOURCES:.c=$(BIN_EXT))
98101
OBJS = $(SOURCES:.c=.o)

samples/sample_avr.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
Created for Unicorn Engine by Glenn Baker <[email protected]>, 2024
3+
*/
4+
5+
/* Sample code to demonstrate how to emulate AVR code */
6+
7+
#include <stdio.h>
8+
#include <string.h>
9+
#include <unicorn/unicorn.h>
10+
11+
// Code to be emulated
12+
static const uint32_t CODE_BASE = 0x0000;
13+
static const uint8_t CODE[] =
14+
"\x86\x0f" // add r24, r22
15+
"\x97\x1f" // adc r25, r23
16+
"\x88\x0f" // add r24, r24
17+
"\x99\x1f" // adc r25, r25
18+
"\x01\x96" // adiw r24, 0x01
19+
"\x08\x95" // ret
20+
;
21+
static const uint32_t CODE_SIZE = sizeof(CODE) - 1;
22+
static const uint32_t CODE_SIZE_ALIGNED = (CODE_SIZE + 0xff) & -0x100;
23+
24+
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size,
25+
void *user_data)
26+
{
27+
printf(">>> Tracing basic block at 0x%" PRIx64 ", block size = 0x%x\n",
28+
address, size);
29+
}
30+
31+
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size,
32+
void *user_data)
33+
{
34+
printf(">>> Tracing instruction at 0x%" PRIx64
35+
", instruction size = 0x%x\n",
36+
address, size);
37+
}
38+
39+
static bool is_error(uc_err err, const char *what)
40+
{
41+
if (err != UC_ERR_OK) {
42+
fprintf(stderr, "error: failed on %s() with error %u: %s\n",
43+
what, err, uc_strerror(err));
44+
return true;
45+
}
46+
return false;
47+
}
48+
49+
static bool test_avr(void)
50+
{
51+
uc_engine *uc = NULL;
52+
uc_hook trace1, trace2;
53+
bool success = false;
54+
55+
printf("Emulate AVR code\n");
56+
do {
57+
// Initialize emulator in AVR mode
58+
uc_err err = uc_open(UC_ARCH_AVR, UC_MODE_LITTLE_ENDIAN, &uc);
59+
if (is_error(err, "uc_open"))
60+
break;
61+
62+
// Map program code
63+
err = uc_mem_map(uc, CODE_BASE, CODE_SIZE_ALIGNED, UC_PROT_READ|UC_PROT_EXEC);
64+
if (is_error(err, "uc_mem_map"))
65+
break;
66+
67+
// Write machine code to be emulated to memory
68+
err = uc_mem_write(uc, CODE_BASE, CODE, CODE_SIZE);
69+
if (is_error(err, "uc_mem_write"))
70+
break;
71+
72+
// Tracing all basic blocks with customized callback
73+
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
74+
if (is_error(err, "uc_hook_add[UC_HOOK_BLOCK]"))
75+
break;
76+
77+
// Tracing one instruction at CODE_BASE with customized callback
78+
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, CODE_BASE,
79+
CODE_BASE + 1);
80+
if (is_error(err, "uc_hook_add[UC_HOOK_CODE]"))
81+
break;
82+
83+
// Initialize registers
84+
uint8_t regs[32];
85+
memset(regs, 0, sizeof(regs));
86+
regs[25] = 0; regs[24] = 1;
87+
regs[23] = 0; regs[22] = 2;
88+
89+
int reg_ids[32];
90+
void *reg_vals[32];
91+
for (unsigned i = 0; i < 4; i++) {
92+
reg_ids[i] = UC_AVR_REG_R0 + 22 + i;
93+
reg_vals[i] = &regs[22 + i];
94+
}
95+
err = uc_reg_write_batch(uc, reg_ids, reg_vals, 4);
96+
if (is_error(err, "uc_reg_write_batch"))
97+
break;
98+
99+
// Emulate machine code in infinite time (last param = 0), or
100+
// when finishing all the code.
101+
err = uc_emu_start(uc, CODE_BASE, CODE_BASE + 4, 0, 0);
102+
if (is_error(err, "uc_emu_start"))
103+
break;
104+
105+
// now print out some registers
106+
printf(">>> Emulation done. Below is the CPU context\n");
107+
108+
uc_reg_read(uc, UC_AVR_REG_R25, &regs[25]);
109+
uc_reg_read(uc, UC_AVR_REG_R24, &regs[24]);
110+
uc_reg_read(uc, UC_AVR_REG_R23, &regs[23]);
111+
uc_reg_read(uc, UC_AVR_REG_R22, &regs[22]);
112+
printf(">>> r25,r24 = 0x%02x%02x\n", regs[25], regs[24]);
113+
if (regs[25] == 0 && regs[24] == 3 && regs[23] == 0 && regs[22] == 2)
114+
success = true;
115+
} while (0);
116+
117+
if (uc)
118+
uc_close(uc);
119+
return success;
120+
}
121+
122+
int main(int argc, char **argv, char **envp)
123+
{
124+
if (!test_avr())
125+
abort();
126+
return 0;
127+
}

0 commit comments

Comments
 (0)