8 #include "yams/src/cpu.h"
9 #include "yams/src/cpu_defs.h"
10 #include "yams/src/cpuregs.h"
11 #include "yams/src/memory.h"
12 #include "yams/src/simulator.h"
20 #define MEM_SIZE 0x800000
21 #if __BYTE_ORDER == __LITTLE_ENDIAN
22 #define MEM_SIZE_M1 (MEM_SIZE - 1)
23 #define MEM_SIZE_M2 (MEM_SIZE - 2)
24 #define MEM_SIZE_M4 (MEM_SIZE - 4)
32 uint16_t hw[MEM_SIZE >> 1];
33 uint32_t w[MEM_SIZE >> 2];
36 int load_ihx(char *name) {
37 FILE *fp = fopen(name, "r");
43 int base = 0, entry_point = 0;
46 while (fgets(line, 0x100, fp)) {
47 for (char *p = line; *p; ++p)
54 fprintf(stderr, "garbage after EOF record: %s\n", line);
59 fprintf(stderr, "require colon: %s\n", line);
65 for (len = 0; len < 0x7f; ++len) {
66 char *p = line + 1 + len * 2;
77 buf[len] = (uint8_t)strtol(p, &q, 16);
80 fprintf(stderr, "not hex byte: %s\n", p);
86 fprintf(stderr, "empty line: %s\n", line);
91 for (int i = 0; i < len; ++i)
94 checksum -= buf[len - 1];
97 "checksum %02x, should be %02x\n",
106 fprintf(stderr, "incorrect length: %s\n", line);
110 int addr = (buf[1] << 8) | buf[2], end_addr;
114 end_addr = addr + len;
115 if (end_addr < addr || end_addr > MEM_SIZE) {
116 fprintf(stderr, "invalid load range: [0x%x, 0x%x)\n", addr, end_addr);
119 for (int i = 0; i < len; ++i)
120 mem.b[(addr + i) ^ MEM_SIZE_M1] = buf[4 + i];
128 fprintf(stderr, "invalid start address record: %s\n", line);
131 entry_point = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
136 fprintf(stderr, "invalid extended linear address record: %s\n", line);
139 base = (buf[4] << 24) | (buf[5] << 16);
143 fprintf(stderr, "invalid start linear address record: %s\n", line);
146 entry_point = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
149 fprintf(stderr, "unknown record type: 0x%x\n", buf[3]);
154 fprintf(stderr, "no EOF record\n");
162 int read_byte(void *context, int addr) {
163 if (addr < 0 || addr >= MEM_SIZE) {
164 fprintf(stderr, "invalid read byte: %08x\n", addr);
167 int data = mem.b[addr ^ MEM_SIZE_M1];
169 fprintf(stderr, "addr=%08x rd=%02x\n", addr, data);
174 int read_halfword(void *context, int addr) {
175 if (addr < 0 || addr >= MEM_SIZE || (addr & 1)) {
176 fprintf(stderr, "invalid read halfword: %08x\n", addr);
179 int data = mem.hw[(addr ^ MEM_SIZE_M2) >> 1];
181 fprintf(stderr, "addr=%08x rd=%04x\n", addr, data);
186 int read_word(void *context, int addr) {
187 if (addr < 0 || addr >= MEM_SIZE || (addr & 3)) {
188 fprintf(stderr, "invalid read word: %08x\n", addr);
191 int data = mem.w[(addr ^ MEM_SIZE_M4) >> 2];
193 fprintf(stderr, "addr=%08x rd=%08x\n", addr, data);
198 void write_byte(void *context, int addr, int data) {
200 fprintf(stderr, "addr=%08x wr=%02x\n", addr, data);
202 if (addr < 0 || addr >= MEM_SIZE) {
203 fprintf(stderr, "invalid write byte: %08x\n", addr);
206 mem.b[addr ^ MEM_SIZE_M1] = data;
209 void write_halfword(void *context, int addr, int data) {
211 fprintf(stderr, "addr=%08x wr=%04x\n", addr, data);
213 if (addr < 0 || addr >= MEM_SIZE || (addr & 1)) {
214 fprintf(stderr, "invalid write halfword: %08x\n", addr);
217 mem.hw[(addr ^ MEM_SIZE_M2) >> 1] = data;
220 void write_word(void *context, int addr, int data) {
222 fprintf(stderr, "addr=%08x wr=%08x\n", addr, data);
224 if (addr < 0 || addr >= MEM_SIZE || (addr & 3)) {
225 fprintf(stderr, "invalid write word: %08x\n", addr);
228 mem.w[(addr ^ MEM_SIZE_M4) >> 2] = data;
231 void _syscall(uint32_t *v0, uint32_t *a0, uint32_t *a1) {
233 case 1: /* print int */
236 case 4: /* print string */
237 for (int p = *a0, c; (c = mem.b[p ^ MEM_SIZE_M1]) != 0; ++p)
240 case 5: /* read int */
245 if (fgets(buf, 0x100, stdin) == NULL) {
252 case 8: /* read string */
256 char *buf = malloc(*a1);
261 if (fgets(buf, *a1, stdin) == NULL) {
267 while ((mem.b[q++ ^ MEM_SIZE_M1] = *p++) != 0)
272 case 10: /* end program */
274 case 11: /* print char */
277 case 12: /* read char */
282 fprintf(stderr, "unimplemented syscall %d\n", *v0);
288 int simulator_bigendian = 1;
290 /* Translates a virtual address to a physical address
291 * does not check TLB exceptions so make sure they do not
292 * occur when calling this ;) (e.g. by doing memory load/store _before_)
294 uint32_t phys_addr(uint32_t vaddr, cpu_t *cpu) {
298 /* Read a byte, halfword or word from memory. Return exception number. */
299 exception_t mem_read(memory_t *mem, uint32_t addr, void *buf,
300 int size, cpu_t *cpu) {
301 //addr = phys_addr(addr, NULL);
304 *(uint8_t *)buf = read_byte(NULL, addr);
307 *(uint16_t *)buf = read_halfword(NULL, addr);
310 *(uint32_t *)buf = read_word(NULL, addr);
318 /* Write a byte, halfword or word to memory. Return exception number. */
319 exception_t mem_write(memory_t *mem, uint32_t addr, void *buf,
320 int size, cpu_t *cpu) {
321 //addr = phys_addr(addr, NULL);
324 write_byte(NULL, addr, *(uint8_t *)buf);
327 write_halfword(NULL, addr, *(uint16_t *)buf);
330 write_word(NULL, addr, *(uint32_t *)buf);
339 int main(int argc, char **argv) {
341 printf("usage: %s image.ihx\n", argv[0]);
344 int entry_point = load_ihx(argv[1]);
346 // place exit trampoline above the stack so program can return into it
347 mem.w[((MEM_SIZE - 8) ^ MEM_SIZE_M4) >> 2] = 0x2402000a; // li $v0, 10
348 mem.w[((MEM_SIZE - 4) ^ MEM_SIZE_M4) >> 2] = 0x0000000c; // syscall
351 cpu_t *cpu = cpu_init(0);
353 cpu->registers[PC] = entry_point;
354 cpu->next_pc = entry_point + 4;
355 cpu->registers[R29] = MEM_SIZE - 0xc; // sp
356 cpu->registers[R31] = MEM_SIZE - 8; // ra
362 "pc=%08x zero=%08x at=%08x v0=%08x v1=%08x a0=%08x a1=%08x a2=%08x a3=%08x t0=%08x t1=%08x t2=%08x t3=%08x t4=%08x t5=%08x t6=%08x t7=%08x s0=%08x s1=%08x s2=%08x s3=%08x s4=%08x s5=%08x s6=%08x s7=%08x t8=%08x t9=%08x k0=%08x k1=%08x gp=%08x sp=%08x fp=%08x ra=%08x hi=%08x lo=%08x\n",
402 if (cpu->exception_pending == Syscall) {
404 cpu->registers + R2, // v0
405 cpu->registers + R4, // a0
406 cpu->registers + R5 // a1
408 cpu->exception_pending = NoException;
409 cpu->registers[PC] = cpu->next_pc;
415 cpu_mips_init(&cpu, read_byte, NULL, write_byte, NULL);
416 cpu_mips_reset(&cpu);
422 "pc=%04x a=%02x b=%02x s=%04x x=%04x p=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
438 cpu_mips_execute(&cpu);