summaryrefslogblamecommitdiffstats
path: root/src/emu/risci.c
blob: 8c4e30f0955c02d557cbe38ccadb5a7c9b4566bb (plain) (tree)





































































































































                                                                                            
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <readline/readline.h>

#include "asm.h"
#include "cpu.h"
#include "log.h"
#include "opc.h"

bool is_debug = false;
bool is_interactive = false;

/* global program buffer */
uint8_t *P = NULL;

static
void usage(int rc)
{
	fprintf(stderr, "Usage: risci [-dhi] <program>\n");
	exit(rc);
}

static
void signal_handler(int sig)
{
	switch (sig) {
	case SIGILL:
		/* SIGILL is raised by the cpu for an unknown instruction */
		error("ERROR: illegal instruction.");
		if (!is_interactive)
			exit(-1);
		break;
	case SIGSEGV:
		/* SIGSEGV is raised for unaligned memory access */
		error("ERROR: unaligned memory access.");
		if (!is_interactive)
			exit(-1);
		break;
	case SIGFPE:
		/* SIGFPE is raised by devision with zero */
		error("ERROR: division by zero.");
		exit(-1);
		break;
	}
}

static
void read_program(const char *program)
{
	struct stat sb;
	if (lstat(program, &sb) == -1)
		pdie("cannot stat program");

	if (sb.st_size % sizeof(uint32_t))
		die("program does not align to op-code size of %u bytes", sizeof(uint32_t));

	int pfd;
	if ((pfd = open(program, O_RDONLY)) == -1)
		pdie("could not open program");

	P = malloc(sb.st_size + sizeof(uint32_t));
	if (read(pfd, P, sb.st_size) != sb.st_size)
		die("premature end of program");

	memset(P + sb.st_size, 0xFF, sizeof(uint32_t));
}

static
uint32_t next_instruction(void)
{
	if (is_interactive) {
		/* read next instruction from stdin */
		printf("%03d", PC/4);
		return compile(readline("> "));
	}

	uint32_t tmp;
	memcpy(&tmp, &P[PC], sizeof(uint32_t));
	return tmp;
}

int main(int argc, char *argv[])
{
	int ch;

	while ((ch = getopt(argc, argv, "dhi")) != -1) {
		switch (ch) {
		case 'd':
			is_debug = true;
			break;
		case 'h':
			usage(EXIT_SUCCESS);
		case 'i':
			is_interactive = true;
			break;
		case '?':
		default:
			usage(EXIT_FAILURE);
		}
	}

	argc -= optind;
	argv += optind;

	/* catch cpu signal traps */
	signal(SIGILL,  signal_handler);
	signal(SIGFPE,  signal_handler);
	signal(SIGSEGV, signal_handler);

	/* load program from file if we're not in interactive mode */
	if (!is_interactive) {
		if (argc < 1)
			usage(EXIT_FAILURE);

		read_program(argv[0]);
	}

	/* reset program counter to first instruction */
	PC = 0;

	/* start instruction loop */
	while (1) {
		execute(next_instruction());
		PC += 4;
	}

	/* not reached, program is terminated by signal traps from the cpu */
}