summaryrefslogtreecommitdiffstats
path: root/src/emu/risci.c
blob: 8c4e30f0955c02d557cbe38ccadb5a7c9b4566bb (plain) (blame)
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#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 */
}