Files
tinyriscv/src/main.c
2023-10-29 15:37:00 +02:00

235 lines
6.2 KiB
C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#define TINYRISCV_M
#include "tinyriscv.h"
typedef enum{
RESET = 0, DEFAULT = 39,
BLACK = 30, BRIGHT_BLACK = 90,
RED = 31, BRIGHT_RED = 91,
GREEN = 32, BRIGHT_GREEN = 92,
YELLOW = 33, BRIGHT_YELLOW = 93,
BLUE = 34, BRIGHT_BLUE = 94,
MAGENTA = 35, BRIGHT_MAGENTA = 95,
CYAN = 36, BRIGHT_CYAN = 96,
WHITE = 37, BRIGHT_WHITE = 97
}Color;
////////////////////////////////////////////////////////////////////////////////
static inline void set_fg_color(const Color color){
printf("\x1b[%dm", color);
}
////////////////////////////////////////////////////////////////////////////////
static inline void clear_screen(void){
printf("\x1b[H\x1b[J");
}
////////////////////////////////////////////////////////////////////////////////
char getch(void)
{
struct termios old_term, new_term;
tcgetattr(STDIN_FILENO, &old_term);
new_term = old_term;
new_term.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new_term);
char c = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &old_term);
return c;
}
////////////////////////////////////////////////////////////////////////////////
void help(const char* message){
if(message) printf("%s\n\n", message);
printf("Usage: tinyricv [OPTION] [VALUE] ...\n\n");
printf(" --help Display this information.\n");
printf(" --bin <file> Load <file> into memory.\n");
printf(" --mem_size <size> Set memory to have <size> bytes.\n");
printf(" --regdump Dump registers at execution halt.\n");
printf(" --memdump <addr> Dump 256B of memory from <addr>.\n");
printf(" --debug Enable debug mode individual astep.\n");
exit(0);
}
////////////////////////////////////////////////////////////////////////////////
void regdump(const tinyriscv_core* core){
printf("\n");
printf(" ABI Reg Hex │ ABI Reg Hex \n");
printf(" ───────────────────┼───────────────────\n");
const char abi[][6] = {
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
"s0/fp", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
};
for(unsigned int i = 0; i < 32; i++){
printf(" %-5s", abi[i]);
set_fg_color(BRIGHT_YELLOW);
printf(i < 10 ? " x%d " : " x%d", i);
set_fg_color(RESET);
if(core->x[i]) set_fg_color(BRIGHT_GREEN);
printf(" %-8x", core->x[i]);
set_fg_color(RESET);
printf(i % 2 ? " \n" : "");
}
printf(" pc ");
set_fg_color(BRIGHT_YELLOW);
printf(" x32");
if(core->pc) set_fg_color(BRIGHT_GREEN);
printf(" %-8x", core->pc);
set_fg_color(RESET);
printf("\n\n");
}
////////////////////////////////////////////////////////////////////////////////
void memdump(const tinyriscv_core* core, uint32_t addr){
addr -= tinyriscv_MEM_OFFSET;
if(addr + 256 > core->mem_size){
help("memdump: Address out of memory range.");
}
printf("\n");
printf(" Address Memory ASCII\n");
for(unsigned int i = 0; i < 73; i++) printf("");
printf("\n");
for(uint32_t end_addr = addr + 256; addr < end_addr; addr += 16){
set_fg_color(BRIGHT_YELLOW);
printf(" %.8x ", addr + tinyriscv_MEM_OFFSET);
set_fg_color(RESET);
for(uint32_t i = addr; i < addr + 16; i++){
set_fg_color(core->mem[i] ? BRIGHT_WHITE : BRIGHT_BLACK);
printf("%.2x ", core->mem[i]);
}
for(uint32_t i = addr; i < addr + 16; i++){
const char c = core->mem[i];
const unsigned int visible = c > 31 && c < 255 && c != 127;
set_fg_color(visible ? BRIGHT_WHITE : BRIGHT_BLACK);
printf("%c", visible ? c : '.');
}
printf("\n");
}
set_fg_color(RESET);
printf("\n");
}
////////////////////////////////////////////////////////////////////////////////
void load_mem_from_file(tinyriscv_core* core, const char* file_path){
FILE* file = fopen(file_path, "rb");
if(!file){
perror("ERROR: Can't open file");
exit(-1);
}
fseek(file, 0, SEEK_END);
const unsigned int file_size = ftell(file);
rewind(file);
if(file_size > core->mem_size){
printf("ERROR: [file] is bigger than allocated memory.");
fclose(file);
exit(-1);
}
if(fread(core->mem, 1, file_size, file) != file_size){
perror("ERROR: 'fread' count different from expected file size.");
exit(-1);
}
fclose(file);
}
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv){
char file_path[256] = "";
size_t mem_size = 4096;
uint32_t dump_addr = 0;
unsigned int do_regdump = 0, do_memdump = 0, do_debug = 0;
//command line arguments
if(argc < 2) help("Not enough arguments.");
for(unsigned int i = 1; i < argc; i++){
if(!strcmp(argv[i], "--help")) help(NULL);
else if(!strcmp(argv[i], "--bin")){
if(i + 1 >= argc) help("Invalid file path.");
strncpy(file_path, argv[i++ + 1], 256);
file_path[255] = '\0';
}
else if(!strcmp(argv[i], "--mem_size")){
if(i + 1 >= argc) help("Invalid [mem_size] value.");
mem_size = strtol(argv[i++ + 1], NULL, 0);
}
else if(!strcmp(argv[i], "--regdump")) do_regdump = 1;
else if(!strcmp(argv[i], "--memdump")){
if(i + 1 >= argc) help("Invalid [dump_addr] value.");
dump_addr = strtol(argv[i++ + 1], NULL, 0);
do_memdump = 1;
}
else if(!strcmp(argv[i], "--debug")) do_debug = 1;
else{
printf("Invalid option: %s\n", argv[i]);
printf("Try 'tinyriscv --help' for more information.\n");
exit(-1);
}
}
tinyriscv_core core;
core.mem = calloc(core.mem_size = mem_size, 1);
//load program into memory
load_mem_from_file(&core, file_path);
//program execution
tinyriscv_init(&core);
if(do_debug){
while(tinyriscv_valid_step(&core)){
clear_screen();
if(do_regdump) regdump(&core);
if(do_memdump) memdump(&core, dump_addr);
printf("\nPress enter to step.\n");
while(getch() != 10);
tinyriscv_step(&core);
}
}
else while(tinyriscv_valid_step(&core)) tinyriscv_step(&core);
if(do_regdump) regdump(&core);
if(do_memdump) memdump(&core, dump_addr);
//cleanup
free(core.mem);
}
////////////////////////////////////////////////////////////////////////////////