rvemu

RISC-V RV32I execution engine
git clone git://mcdim.xyz/rvemu.git
Log | Files | Refs | README

main.c (4622B)


      1 #include <stdint.h>
      2 #include <inttypes.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 
      7 #ifdef HAVE_READLINE
      8 #include <readline/history.h>
      9 #include <readline/readline.h>
     10 #endif
     11 
     12 //#include "disasm.h"
     13 #include "exec.h"
     14 #include "mem.h"
     15 #include "disasm.h"
     16 
     17 typedef enum {
     18 	MODE_RUN,
     19 	MODE_STEP
     20 } emu_mode_t;
     21 
     22 static void
     23 load_program(uint8_t *mem)
     24 {
     25 	/* PROGRAM */
     26 	uint32_t arr[] = {
     27 		0x10000593,	//li      a1,256
     28 		0xfff00513,	//li      a0,-1
     29 		0x00a58023,	//sb      a0,0(a1)
     30 		0x0005c503,	//lbu     a0,0(a1)
     31 		0x00150513,	//addi    a0,a0,1
     32 		0x00a59123,	//sh      a0,2(a1)
     33 		0x00259503,	//lh      a0,2(a1)
     34 		0xeff50513,	//addi    a0,a0,-257
     35 		0x00a58223,	//sb      a0,4(a1)
     36 		0x00458503,	//lb      a0,4(a1)
     37 		0x00a59323,	//sh      a0,6(a1)
     38 		0x00659503,	//lh      a0,6(a1)
     39 		0x0065d503,	//lhu     a0,6(a1)
     40 		0x00150513,	//addi    a0,a0,1
     41 		0x00a5a423,	//sw      a0,8(a1)
     42 		0x00000513,	//li      a0,0
     43 		0x0085a503,	//lw      a0,8(a1)
     44 		0x00000593,	//li      a1,0
     45 		0x00100073	//ebreak
     46 /*
     47 		0x20400093,     // addi x1,x0,0x204
     48 		0x12300113,     // addi x2,x0,0x123
     49 		0xfe20ae23,     // sw   x2,-4(x1) -> address 0x200
     50 		0xffc0a183,     // lw   x3,-4(x1)
     51 		0x00100073,     // ebreak
     52 */
     53 	};
     54 
     55 	size_t len = sizeof(arr) / sizeof(arr[0]);
     56 
     57 	int b = 0; /*byte*/
     58 	for (size_t i=0; i<len; i++) {
     59 		
     60 		mem[b+0] = (uint8_t)(arr[i] >> 0);
     61 		mem[b+1] = (uint8_t)(arr[i] >> 8);
     62 		mem[b+2] = (uint8_t)(arr[i] >> 16);
     63 		mem[b+3] = (uint8_t)(arr[i] >> 24);
     64 
     65 		b+=4;
     66 	}
     67 }
     68 
     69 static emu_mode_t
     70 trap_handler(cpu_state_t *cpu)
     71 {
     72 	if (cpu->status == CPU_TRAPPED) {
     73 		printf("CPU trapped\n");
     74 		switch(cpu->trap.cause) {
     75 		case TRAP_EBREAK:
     76 			printf("Code reached breakpoint\n");
     77 			break;
     78 		case TRAP_ECALL:
     79 			printf("Code ECALL\n");
     80 			break;
     81 		case TRAP_ILLEGAL_INSTRUCTION:
     82 			printf("Illegal instruction\n");
     83 			break;
     84 		case TRAP_INSTRUCTION_MISALIGNED: 
     85 			printf("Instruction misaligned\n");
     86 			break;
     87 		case TRAP_INSTRUCTION_ACCESS_FAULT: 
     88 			printf("Instruction access fault\n");
     89 			break;
     90 		case TRAP_LOAD_MISALIGNED:
     91 			printf("Load misaligned\n");
     92 			break;
     93 		case TRAP_LOAD_ACCESS_FAULT:
     94 			printf("Load access fault\n");
     95 			break;
     96 		case TRAP_STORE_MISALIGNED:
     97 			printf("Store misaligned\n");
     98 			break;
     99 		case TRAP_STORE_ACCESS_FAULT:
    100 			printf("Store access fault\n");
    101 			break;
    102 		case TRAP_NONE:
    103 			printf("No trap cause\n");
    104 			break;
    105 		}
    106 		return MODE_STEP;
    107 	}
    108 	return MODE_RUN;
    109 }
    110 
    111 static emu_mode_t
    112 debugger(cpu_state_t *cpu, uint8_t *mem)
    113 {
    114 #ifdef HAVE_READLINE
    115 	char prompt[10];
    116 	snprintf(prompt, 10, "PC 0x%x>", cpu->pc);
    117 	char *line;
    118 	line = readline(prompt);
    119 	rl_bind_key('\t', rl_complete);
    120 
    121 	if (!line) {
    122 		free(line);
    123 		return MODE_STEP;
    124 	}
    125 	
    126 	add_history(line);
    127 #else
    128 	printf("PC 0x%x>", cpu->pc);
    129 	char line[256];
    130 	if (!fgets(line, sizeof(line), stdin)) {
    131 		fprintf(stderr, "Error reading"
    132 			"interactive input\n");
    133 	}
    134 #endif
    135 
    136 	if (strncmp(line, "s", 1) == 0 ||
    137 	    strncmp(line, "step", 4) == 0  ||
    138 	    strncmp(line, "n", 1) == 0 ||
    139 	    strncmp(line, "next", 4) == 0) {
    140 
    141 		uint32_t inst = load_u32_le(mem, cpu->pc); /* load little endian */
    142 		disassemble_instruction(inst);
    143 		cpu_step(cpu, mem);
    144 
    145 		trap_handler(cpu);
    146 
    147 	} else if (strncmp(line, "r", 1) == 0 ||
    148 		   strncmp(line, "registers", 9) == 0) {
    149 		printf("Registers:\n");
    150 		for (int i=0; i<32; i++) {
    151 			printf("x%d: 0x%x\n", i, cpu->x[i]);
    152 		}
    153 	} else if (strncmp(line, "x", 1) == 0) {
    154 		uint32_t from_addr = 0;
    155 		uint32_t count = 1;
    156 		sscanf(line, "x/%" SCNu32 " %" SCNx32, &count, &from_addr);
    157 
    158 		uint32_t xtarget = count*4 + from_addr;
    159 		/* TODO: probably some kind or helper or something */
    160 /*		if (xtarget+3 > MEMSIZE) {
    161 			printf("Out of bounds\n");
    162 #ifdef HAVE_READLINE
    163 			free(line);
    164 #endif
    165 			return MODE_RUN;
    166 		}
    167 */
    168 		
    169 		for (uint32_t i=from_addr; i<xtarget; i+=4) {
    170 			if (cpu->pc == i) {
    171 				printf("-> ");
    172 			} else {
    173 				printf("   ");
    174 			}
    175 			printf("0x%.8x: 0x%.2x 0x%.2x 0x%.2x 0x%.2x     ",
    176 			       i, mem[i], mem[i+1], mem[i+2], mem[i+3]);
    177 			disassemble_instruction(load_u32_le(mem,i));
    178 		}
    179 	} else if (strncmp(line, "ip", 2) == 0 ||
    180 		   strncmp(line, "pc", 2) == 0) {
    181 		printf("Instruction poiter:\n");
    182 		printf("PC: %" PRIu32 "\n", cpu->pc);
    183 	} else if (strncmp(line, "e", 1) == 0) {
    184 #ifdef HAVE_READLINE
    185 		free(line);
    186 #endif
    187 		return MODE_RUN;
    188 	}
    189 
    190 #ifdef HAVE_READLINE
    191 	free(line);
    192 #endif
    193 	return MODE_STEP;
    194 }
    195 
    196 int
    197 main()
    198 {
    199 	cpu_state_t cpu = {0};
    200 
    201 	uint8_t mem[MEMSIZE] = {0};
    202 
    203 	load_program(mem);
    204 	
    205 	/* fetch & run */
    206 	emu_mode_t mode = MODE_STEP;	
    207 
    208 	while (1) {
    209 		if (mode == MODE_RUN) {
    210 			cpu_step(&cpu, mem);
    211 			mode = trap_handler(&cpu);
    212 		} else {
    213 			mode = debugger(&cpu, mem);
    214 		}
    215 	}
    216 
    217 	return 0;
    218 }