summaryrefslogtreecommitdiff
path: root/msim/sim.c
blob: 9e0d5184301115e6bfcac93cd5e6246a1e2b457c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <merror.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include "sim.h"
#include "melf.h"

void sim_dump_reg(struct simulator *sim)
{
	const char *names[32] = {
		"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1",
		"t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3",
		"s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp",
		"fp", "ra"
	};

	for (uint32_t i = 0; i < 8; i++) {
		for (uint32_t j = 0; j < 4; j++) {
			if (j != 0)
				fputc(' ', stderr);
			int idx = i+j*8;
			fprintf(stderr, "$%s:\t0x%08x", names[idx], sim->reg[idx]);
		}
		fputc('\n', stderr);
	}
}

__attribute__((format(printf, 2, 3)))
_Noreturn void sim_dump(struct simulator *sim, const char *format, ...) {

	va_list list;
	va_start(list, format);

	// header
	fprintf(stderr, "\n\t\t!!! An exception has occurred !!!\n\n");
	fprintf(stderr, "\033[31merror: \033[0m");
	vfprintf(stderr, format, list);
	fputc('\n', stderr);

	// pc
	uint32_t pc = sim->current_pc;
	fprintf(stderr, "pc: 0x%08x\n", pc);

	if (pc >= sim->text_min && pc < sim->text_max)
		fprintf(stderr, "ins: 0x%08x\n", B32(* (uint32_t *) (uintptr_t) pc));

	// registers
	fprintf(stderr, "registers:\n");
	sim_dump_reg(sim);

	exit(1);
}

void sim_step(struct simulator *sim)
{
	if (sim->pc < sim->text_min || sim->pc >= sim->text_max)
		sim_dump(sim, "program counter reached non executable memory");

	uint32_t ins = * (uint32_t *) (uintptr_t) sim->pc;
	sim->pc += 4;
	sim_ins(sim, ins);
	sim->current_pc = sim->pc;
}

_Noreturn void sim_run(struct simulator *sim)
{
	sim->pc = sim->entry;
	sim->current_pc = sim->pc;
	while (1)
		sim_step(sim);
}

int sim_init(struct simulator *sim, struct simulator_args *args) {
	memset(sim->reg, 0, sizeof(uint32_t) * 32);
	sim->data_max = MEM_DATA_ADDR;
	sim->data_min = MEM_DATA_ADDR;
	sim->text_max = MEM_TEXT_ADDR;
	sim->text_min = MEM_TEXT_ADDR;
	sim->args = args;

	// load executable
	if (sim_load_file(sim))
		return M_ERROR;

	// check entry
	if (sim->entry < sim->text_min || sim->entry >= sim->text_max) {
		ERROR("elf entrypoint invalid");
		return M_ERROR;
	}

	return M_SUCCESS;
}