initial commit
This commit is contained in:
commit
4f262166f7
|
@ -0,0 +1,22 @@
|
|||
PREFIX := /usr/local
|
||||
LDFLAGS := -lcurses
|
||||
CFLAGS := -Wall -Wmissing-prototypes -O2
|
||||
CC := cc
|
||||
|
||||
all: mcim mcimc
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -I. -c $< -o $@
|
||||
|
||||
mcim: mcim.o cpu.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^
|
||||
|
||||
mcimc: mcimc.o
|
||||
$(CC) -I. -o $@ $^
|
||||
|
||||
install: mcim mcimc
|
||||
mkdir -p $(PREFIX)/bin
|
||||
cp $^ $(PREFIX)/bin
|
||||
|
||||
clean:
|
||||
rm -f mcim mcimc mcim.o cpu.o mcimc.o
|
|
@ -0,0 +1,13 @@
|
|||
mcim
|
||||
|
||||
b: set breakpoint on target process
|
||||
l: switch to process view
|
||||
m: switch to memory view
|
||||
o: open executable
|
||||
p: switch to tty output view
|
||||
s: restart process
|
||||
|
||||
options:
|
||||
|
||||
-n: start without initial process
|
||||
-t: log tty output to file
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2022 ipc
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mcim.h"
|
||||
|
||||
uint
|
||||
lget(uchar *p)
|
||||
{
|
||||
uint n;
|
||||
|
||||
n = *p;
|
||||
n |= *(p+1) << 8;
|
||||
n |= *(p+2) << 16;
|
||||
n |= *(p+3) << 24;
|
||||
return n;
|
||||
}
|
||||
|
||||
#define MEM(p) p->mem
|
||||
|
||||
static uint
|
||||
lcget(struct mcimp *p)
|
||||
{
|
||||
uint n;
|
||||
|
||||
n = lget(&p->MEM(p)[p->pc]);
|
||||
p->pc += 4;
|
||||
return n;
|
||||
}
|
||||
|
||||
static uint
|
||||
rget(struct mcimp *p)
|
||||
{
|
||||
uint n;
|
||||
|
||||
n = p->MEM(p)[p->pc];
|
||||
p->pc += 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
#define R() rget(p)
|
||||
#define L() lcget(p)
|
||||
#define J(n) p->pc = n + p->epc
|
||||
|
||||
static void
|
||||
lw(struct mcimp *p)
|
||||
{
|
||||
uint r;
|
||||
uint l;
|
||||
|
||||
r = R();
|
||||
if ((l = L() + 4) >= p->p->nmem)
|
||||
return;
|
||||
p->r[r] = lget(&p->MEM(p)[l+p->r[8]]);
|
||||
}
|
||||
|
||||
static void
|
||||
lb(struct mcimp *p)
|
||||
{
|
||||
uint r;
|
||||
uint l;
|
||||
|
||||
r = R();
|
||||
if ((l = L()) >= p->p->nmem)
|
||||
return;
|
||||
p->r[r] = p->MEM(p)[l+p->r[8]];
|
||||
}
|
||||
|
||||
static void
|
||||
li(struct mcimp *p)
|
||||
{
|
||||
uint r;
|
||||
|
||||
r = R();
|
||||
p->r[r] = L();
|
||||
}
|
||||
|
||||
static void
|
||||
sw(struct mcimp *p)
|
||||
{
|
||||
uint r;
|
||||
uint l;
|
||||
uint c;
|
||||
|
||||
r = R();
|
||||
l = L();
|
||||
l += p->r[8];
|
||||
if (l > p->p->nmem) {
|
||||
c = (l - p->p->nmem) + 4;
|
||||
allocmem(p->p, c);
|
||||
p->p->nmem += c;
|
||||
}
|
||||
p->MEM(p)[l] = p->r[r];
|
||||
p->MEM(p)[l+1] = p->r[r] >> 8;
|
||||
p->MEM(p)[l+2] = p->r[r] >> 16;
|
||||
p->MEM(p)[l+3] = p->r[r] >> 24;
|
||||
}
|
||||
|
||||
static void
|
||||
sb(struct mcimp *p)
|
||||
{
|
||||
uint r;
|
||||
uint l;
|
||||
uint c;
|
||||
|
||||
r = R();
|
||||
l = L();
|
||||
l += p->r[8];
|
||||
if (l >= p->p->nmem) {
|
||||
c = l - p->p->nmem;
|
||||
allocmem(p->p, c+128);
|
||||
p->p->nmem += c+128;
|
||||
}
|
||||
p->MEM(p)[l] = p->r[r];
|
||||
}
|
||||
|
||||
static void
|
||||
add(struct mcimp *p)
|
||||
{
|
||||
uint r[3];
|
||||
|
||||
r[0] = R();
|
||||
r[1] = R();
|
||||
r[2] = R();
|
||||
p->r[r[2]] = p->r[r[0]] + p->r[r[1]];
|
||||
}
|
||||
|
||||
static void
|
||||
addi(struct mcimp *p)
|
||||
{
|
||||
uint r[2];
|
||||
uint l;
|
||||
|
||||
r[0] = R();
|
||||
l = L();
|
||||
r[1] = R();
|
||||
p->r[r[1]] = p->r[r[0]] + l;
|
||||
}
|
||||
|
||||
static void
|
||||
ble(struct mcimp *p)
|
||||
{
|
||||
uint r[2];
|
||||
uint l;
|
||||
|
||||
r[0] = R();
|
||||
r[1] = R();
|
||||
l = L();
|
||||
if (p->r[r[0]] < p->r[r[1]])
|
||||
J(l);
|
||||
}
|
||||
|
||||
static void
|
||||
bgt(struct mcimp *p)
|
||||
{
|
||||
uint r[2];
|
||||
uint l;
|
||||
|
||||
r[0] = R();
|
||||
r[1] = R();
|
||||
l = L();
|
||||
if (p->r[r[0]] > p->r[r[1]])
|
||||
J(l);
|
||||
}
|
||||
|
||||
static void
|
||||
beq(struct mcimp *p)
|
||||
{
|
||||
uint r[2];
|
||||
uint l;
|
||||
|
||||
r[0] = R();
|
||||
r[1] = R();
|
||||
l = L();
|
||||
if (p->r[r[0]] == p->r[r[1]])
|
||||
J(l);
|
||||
}
|
||||
|
||||
static void
|
||||
bne(struct mcimp *p)
|
||||
{
|
||||
uint r[2];
|
||||
uint l;
|
||||
|
||||
r[0] = R();
|
||||
r[1] = R();
|
||||
l = L();
|
||||
if (p->r[r[0]] != p->r[r[1]])
|
||||
J(l);
|
||||
}
|
||||
|
||||
static void
|
||||
j(struct mcimp *p)
|
||||
{
|
||||
J(L());
|
||||
}
|
||||
|
||||
static void
|
||||
jr(struct mcimp *p)
|
||||
{
|
||||
p->pc = p->r[R()];
|
||||
}
|
||||
|
||||
static void
|
||||
jal(struct mcimp *p)
|
||||
{
|
||||
uint pc;
|
||||
|
||||
pc = L();
|
||||
p->r[3] = p->pc;
|
||||
J(pc);
|
||||
}
|
||||
|
||||
static void
|
||||
sys(struct mcimp *p)
|
||||
{
|
||||
uint r;
|
||||
|
||||
r = p->r[R()];
|
||||
switch (r) {
|
||||
case SYSE:
|
||||
p->stat |= STATEXIT;
|
||||
break;
|
||||
case SYSW:
|
||||
if (p->p->ntty >= sizeof p->p->tty)
|
||||
p->p->ntty = 0;
|
||||
p->p->tty[p->p->ntty++] = p->r[1];
|
||||
break;
|
||||
default:
|
||||
err(1, "fatal: illegal syscall (%08x)\n", r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void (*op[]) (struct mcimp *) = {
|
||||
&lw, NULL, &lb, &li, &sw, NULL, &sb, NULL,
|
||||
&add, &addi, NULL, NULL, NULL, &ble, &bgt, &beq,
|
||||
&bne, &j, &jr, &jal, &sys
|
||||
};
|
||||
|
||||
#define brk(p) (p->stat & STATEXIT || p->stat & STATBRK)
|
||||
|
||||
void
|
||||
step(struct mcim *p)
|
||||
{
|
||||
int n;
|
||||
uint i;
|
||||
struct mcimp *c;
|
||||
|
||||
for (i = 0; i < p->nproc; i++) {
|
||||
n = SCHCNT;
|
||||
c = &p->proc[i];
|
||||
while (n-- && !brk(c))
|
||||
op[p->mem[c->pc++]](c);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2022 ipc
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <curses.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mcim.h"
|
||||
|
||||
static char *progname;
|
||||
static int dispc;
|
||||
|
||||
void
|
||||
err(int f, char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
vfprintf(stderr, fmt, arg);
|
||||
va_end(arg);
|
||||
if (f) {
|
||||
endwin();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
err(1, "usage: %s [-n] [-t file] file\n", progname);
|
||||
}
|
||||
|
||||
int
|
||||
allocmem(struct mcim *p, uint n)
|
||||
{
|
||||
if ((p->mem = realloc(p->mem, p->nmem+n)) == NULL)
|
||||
return -1;
|
||||
memset(p->mem+p->nmem, 0, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
loadproc(struct mcim *p, struct mcimp *c, FILE *f)
|
||||
{
|
||||
uchar hdr[4];
|
||||
uint n;
|
||||
|
||||
if (fread(hdr, 1, sizeof hdr, f) < 4)
|
||||
return -1;
|
||||
if ((n = lget(hdr)) > MEMLIM)
|
||||
return -1;
|
||||
allocmem(p, n);
|
||||
if (fread(p->mem+p->nmem, 1, n, f) < n)
|
||||
return -1;
|
||||
c->p = p;
|
||||
c->epc = p->nmem;
|
||||
c->pc = c->epc;
|
||||
c->stat = 0;
|
||||
memset(c->r, 0, sizeof c->r);
|
||||
p->nmem += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MOVCLR(y) \
|
||||
move(y, 0); \
|
||||
clrtoeol()
|
||||
#define MOVINFO() \
|
||||
MOVCLR(p->nproc)
|
||||
|
||||
static void
|
||||
brkp(struct mcim *p, int cmd)
|
||||
{
|
||||
struct mcimp *c;
|
||||
int i;
|
||||
|
||||
nocbreak();
|
||||
echo();
|
||||
MOVINFO();
|
||||
scanw("%4d", &i);
|
||||
if (i >= 0 && i < p->nproc) {
|
||||
c = &p->proc[i];
|
||||
c->stat ^= STATBRK;
|
||||
}
|
||||
noecho();
|
||||
cbreak();
|
||||
}
|
||||
|
||||
static void
|
||||
view(struct mcim *p, int cmd)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = "lmp";
|
||||
dispc = strchr(s, cmd) - s;
|
||||
clear();
|
||||
}
|
||||
|
||||
static void
|
||||
exec(struct mcim *p, int cmd)
|
||||
{
|
||||
char s[256];
|
||||
FILE *f;
|
||||
int n;
|
||||
|
||||
nocbreak();
|
||||
echo();
|
||||
MOVINFO();
|
||||
scanw("%255s", s);
|
||||
if ((f = fopen(s, "r")) == NULL) {
|
||||
MOVINFO();
|
||||
printw("%s: couldn't open file", s);
|
||||
goto enable;
|
||||
}
|
||||
n = loadproc(p, &p->proc[p->nproc], f);
|
||||
fclose(f);
|
||||
if (n == -1) {
|
||||
MOVINFO();
|
||||
printw("%s: invalid process", s);
|
||||
} else
|
||||
p->nproc++;
|
||||
enable:
|
||||
cbreak();
|
||||
noecho();
|
||||
}
|
||||
|
||||
static void
|
||||
start(struct mcim *p, int cmd)
|
||||
{
|
||||
struct mcimp *c;
|
||||
int i;
|
||||
|
||||
i = -1;
|
||||
nocbreak();
|
||||
echo();
|
||||
MOVINFO();
|
||||
scanw("%4d", &i);
|
||||
cbreak();
|
||||
noecho();
|
||||
if (i < 0 || i > p->nproc - 1) {
|
||||
MOVINFO();
|
||||
printw("%s", i<0?"bad input":"out of range");
|
||||
return;
|
||||
}
|
||||
c = &p->proc[i];
|
||||
memset(c->r, 0, sizeof c->r);
|
||||
c->pc = c->epc;
|
||||
c->stat = 0;
|
||||
}
|
||||
|
||||
void (*comtab[]) (struct mcim *, int) = {
|
||||
&brkp,
|
||||
&view,
|
||||
&view,
|
||||
&exec,
|
||||
&view,
|
||||
&start,
|
||||
};
|
||||
|
||||
static int
|
||||
get(struct mcim *p)
|
||||
{
|
||||
int c;
|
||||
char *cmd;
|
||||
char *cp;
|
||||
|
||||
c = 0;
|
||||
cmd = "blmops";
|
||||
read(STDIN_FILENO, &c, 1);
|
||||
if (c == 'q')
|
||||
return -1;
|
||||
if ((cp = strchr(cmd, c)) == NULL) {
|
||||
MOVINFO();
|
||||
printw("invalid command");
|
||||
return 0;
|
||||
}
|
||||
comtab[cp - cmd](p, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pdisp(struct mcim *p)
|
||||
{
|
||||
int i, j;
|
||||
struct mcimp *c;
|
||||
|
||||
for (i = 0; i < p->nproc; i++) {
|
||||
c = &p->proc[i];
|
||||
MOVCLR(i);
|
||||
mvprintw(i, 0, "%d %08x %08x %x ", i, c->epc, c->pc, c->stat);
|
||||
for (j = 0; j < 16; j++)
|
||||
printw("%x%s", c->r[j], j == 15 ? "" : ":");
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
||||
static void
|
||||
mdisp(struct mcim *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
move(0, 0);
|
||||
clrtoeol();
|
||||
for (i = 0; i < p->nmem; i++)
|
||||
printw("%02x%s", p->mem[i],
|
||||
i == p->nmem-1 || (i+1)%12 == 0 ? "\n" : " ");
|
||||
refresh();
|
||||
}
|
||||
|
||||
static void
|
||||
tdisp(struct mcim *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
move(0, 0);
|
||||
for (i = 0; i < p->ntty; i++)
|
||||
printw("%c", p->tty[i]);
|
||||
printw("\n");
|
||||
refresh();
|
||||
}
|
||||
|
||||
void (*disptab[]) (struct mcim *) = {
|
||||
&pdisp, &mdisp, &tdisp
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int iproc;
|
||||
char *s;
|
||||
char *ttyout;
|
||||
FILE *f;
|
||||
int n;
|
||||
int log;
|
||||
struct mcim c;
|
||||
struct pollfd pfd[1];
|
||||
|
||||
iproc = 1;
|
||||
ttyout = NULL;
|
||||
f = NULL;
|
||||
progname = *argv[0]!='\0'?argv[0]:"mcim";
|
||||
while (--argc > 0 && (*++argv)[0] == '-')
|
||||
for (s = argv[0]+1; *s != '\0'; s++)
|
||||
switch (*s) {
|
||||
case 'n':
|
||||
iproc = 0;
|
||||
break;
|
||||
case 't':
|
||||
if (argc < 2)
|
||||
usage();
|
||||
ttyout = argv[1];
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
memset(&c, 0, sizeof c);
|
||||
if (iproc) {
|
||||
if (argc < 1)
|
||||
usage();
|
||||
if ((f = fopen(argv[0], "rb")) == NULL)
|
||||
err(1, "%s: couldn't open '%s'\n", progname, argv[0]);
|
||||
c.nproc++;
|
||||
n = loadproc(&c, &c.proc[0], f);
|
||||
fclose(f);
|
||||
if (n == -1)
|
||||
err(1, "%s: bad executable\n", progname);
|
||||
}
|
||||
if (ttyout != NULL)
|
||||
if ((f = fopen(ttyout, "w")) == NULL)
|
||||
err(1, "%s: couldn't open '%s'\n", progname, ttyout);
|
||||
n = 0;
|
||||
log = LOGCNT;
|
||||
pfd[0].fd = STDIN_FILENO;
|
||||
pfd[0].events = POLLIN;
|
||||
initscr();
|
||||
cbreak();
|
||||
noecho();
|
||||
while ((n = poll(pfd, 1, 10)) != -1) {
|
||||
if (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))
|
||||
break;
|
||||
if (n > 0 && get(&c) == -1)
|
||||
break;
|
||||
disptab[dispc](&c);
|
||||
step(&c);
|
||||
if (c.ntty > 0 && ttyout != NULL && !--log) {
|
||||
log = LOGCNT;
|
||||
fseek(f, 0L, SEEK_SET);
|
||||
fwrite(c.tty, 1, c.ntty, f);
|
||||
}
|
||||
}
|
||||
free(c.mem);
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2022 ipc
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
enum {
|
||||
SYSE,
|
||||
SYSP,
|
||||
SYSW
|
||||
};
|
||||
|
||||
#define MEMLIM 0xff000
|
||||
#define SCHCNT 300
|
||||
#define LOGCNT 50
|
||||
|
||||
#define STATEXIT 1 << 1
|
||||
#define STATBRK 1 << 2
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char uchar;
|
||||
|
||||
struct mcimp {
|
||||
struct mcim *p;
|
||||
uint r[16];
|
||||
uint epc;
|
||||
uint pc;
|
||||
uint stat;
|
||||
};
|
||||
|
||||
struct mcim {
|
||||
struct mcimp proc[4096];
|
||||
uchar *mem;
|
||||
uchar tty[8192];
|
||||
uint ntty;
|
||||
uint nproc;
|
||||
uint nmem;
|
||||
};
|
||||
|
||||
void err(int f, char *fmt, ...);
|
||||
int allocmem(struct mcim *p, uint n);
|
||||
uint lget(uchar *p);
|
||||
void step(struct mcim *p);
|
|
@ -0,0 +1,586 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2022 ipc
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "mcimc.h"
|
||||
|
||||
enum {
|
||||
IDNT,
|
||||
LBL,
|
||||
REG,
|
||||
ADDR,
|
||||
PROC
|
||||
};
|
||||
|
||||
#define SYMLEN 1024
|
||||
#define SYMALLOC 8192
|
||||
|
||||
#define MAXLBL 8192
|
||||
#define MAXREG 16
|
||||
|
||||
struct sym {
|
||||
int t;
|
||||
int l;
|
||||
char s[SYMLEN];
|
||||
};
|
||||
|
||||
struct ins {
|
||||
char s[SYMLEN];
|
||||
char fmt[4];
|
||||
};
|
||||
|
||||
struct lbl {
|
||||
char s[SYMLEN];
|
||||
uint addr;
|
||||
int l;
|
||||
struct lbl *next;
|
||||
};
|
||||
|
||||
static struct sym *tab;
|
||||
static struct sym *sp;
|
||||
static struct lbl *lab[MAXLBL];
|
||||
static struct lbl *lbp;
|
||||
static int nsym;
|
||||
static int asym;
|
||||
static int errc;
|
||||
static uchar *buf;
|
||||
static int abuf;
|
||||
static uint pc;
|
||||
struct ins instab[];
|
||||
|
||||
static FILE *f;
|
||||
static char in[1024];
|
||||
static char *progname;
|
||||
|
||||
static void mfree(void);
|
||||
|
||||
static void
|
||||
err(int f, char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
vfprintf(stderr, fmt, arg);
|
||||
va_end(arg);
|
||||
errc++;
|
||||
if (f) {
|
||||
mfree();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
err(1, "usage: %s [-o out] file\n", progname);
|
||||
}
|
||||
|
||||
static void
|
||||
mfree(void)
|
||||
{
|
||||
int i;
|
||||
struct lbl *p, *t;
|
||||
|
||||
free(tab);
|
||||
free(buf);
|
||||
for (i = 0; i < MAXLBL; i++) {
|
||||
p = lab[i];
|
||||
while (p != NULL) {
|
||||
t = p;
|
||||
p = p->next;
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
allocsym(long n)
|
||||
{
|
||||
asym += n;
|
||||
if ((tab = realloc(tab, asym*sizeof(struct sym))) == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sym *
|
||||
makesym(int t, int l, char *s)
|
||||
{
|
||||
struct sym *p;
|
||||
|
||||
if ((p = malloc(sizeof(struct sym))) == NULL)
|
||||
return NULL;
|
||||
p->t = t;
|
||||
p->l = l;
|
||||
strcpy(p->s, s);
|
||||
return p;
|
||||
}
|
||||
|
||||
static struct sym *
|
||||
pushsym(struct sym *p)
|
||||
{
|
||||
if (nsym >= asym)
|
||||
if (allocsym(SYMALLOC) == -1)
|
||||
return NULL;
|
||||
tab[nsym++] = *p;
|
||||
return p;
|
||||
}
|
||||
|
||||
static struct lbl *
|
||||
makelbp(char *s, uint n, uint l)
|
||||
{
|
||||
struct lbl *p;
|
||||
|
||||
if ((p = malloc(sizeof(struct lbl))) == NULL)
|
||||
return NULL;
|
||||
strcpy(p->s, s);
|
||||
p->addr = n;
|
||||
p->l = l;
|
||||
p->next = lbp;
|
||||
lbp = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
static int l = 1;
|
||||
|
||||
static int
|
||||
cget(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = getc(f);
|
||||
l += c == '\n';
|
||||
return c;
|
||||
}
|
||||
|
||||
static int
|
||||
get(struct sym **p)
|
||||
{
|
||||
char s[SYMLEN];
|
||||
int n;
|
||||
int c;
|
||||
int t;
|
||||
int lp;
|
||||
|
||||
n = 0;
|
||||
t = -1;
|
||||
while ((c = cget()) != EOF && isspace(c))
|
||||
;
|
||||
switch (c) {
|
||||
case '%':
|
||||
t = REG;
|
||||
break;
|
||||
case '$':
|
||||
t = ADDR;
|
||||
break;
|
||||
case '.':
|
||||
t = PROC;
|
||||
while ((c = cget()) != EOF && c != '\n') {
|
||||
if (n >= SYMLEN-1)
|
||||
break;
|
||||
s[n++] = c;
|
||||
}
|
||||
s[n] = '\0';
|
||||
lp = c == '\n' ? l-1 : l;
|
||||
*p = makesym(t, lp, s);
|
||||
return 1;
|
||||
case ';':
|
||||
while ((c = cget()) != EOF && c != '\n')
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
if (t == -1 && isalpha(c)) {
|
||||
t = IDNT;
|
||||
ungetc(c, f);
|
||||
while ((c = cget()) != EOF) {
|
||||
if (c == ':')
|
||||
t = LBL;
|
||||
if (!isalnum(c))
|
||||
break;
|
||||
if (n >= SYMLEN-1)
|
||||
break;
|
||||
s[n++] = c;
|
||||
}
|
||||
s[n] = '\0';
|
||||
lp = c == '\n' ? l-1 : l;
|
||||
*p = makesym(t, lp, s);
|
||||
return 1;
|
||||
}
|
||||
if (t == REG || t == ADDR) {
|
||||
while ((c = cget()) != EOF) {
|
||||
if (!isxdigit(c) && !isspace(c)) {
|
||||
err(0, "%s:%d: bad address\n", in, l);
|
||||
break;
|
||||
} else if (!isxdigit(c))
|
||||
break;
|
||||
if (n >= SYMLEN-1)
|
||||
break;
|
||||
s[n++] = c;
|
||||
}
|
||||
s[n] = '\0';
|
||||
lp = c == '\n' ? l-1 : l;
|
||||
*p = makesym(t, lp, s);
|
||||
return 1;
|
||||
}
|
||||
if (c != EOF) {
|
||||
err(0, "%s:%d: unknown symbol\n", in, l);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
com(char *s)
|
||||
{
|
||||
uint n;
|
||||
uchar *p;
|
||||
|
||||
n = 0;
|
||||
for (p = (uchar*) s; *p != '\0'; p++)
|
||||
n = n * 31 + *p;
|
||||
return n % MAXLBL;
|
||||
}
|
||||
|
||||
static struct lbl *
|
||||
lookup(char *s, int c)
|
||||
{
|
||||
int n;
|
||||
struct lbl *p;
|
||||
|
||||
n = com(s);
|
||||
for (p = lab[n]; p != NULL; p = p->next)
|
||||
if (strcmp(s, p->s) == 0)
|
||||
return p;
|
||||
if (c) {
|
||||
if ((p = malloc(sizeof(struct lbl))) == NULL)
|
||||
return NULL;
|
||||
strcpy(p->s, s);
|
||||
p->addr = pc;
|
||||
p->next = lab[n];
|
||||
lab[n] = p;
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
lp(uchar *p, uint l)
|
||||
{
|
||||
*p = l;
|
||||
*(p+1) = l >> 8;
|
||||
*(p+2) = l >> 16;
|
||||
*(p+3) = l >> 24;
|
||||
}
|
||||
|
||||
static int
|
||||
allocb(void)
|
||||
{
|
||||
abuf += 8192;
|
||||
buf = realloc(buf, abuf);
|
||||
return buf == NULL ? -1 : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cput(uchar c)
|
||||
{
|
||||
if (pc+1 >= abuf)
|
||||
allocb();
|
||||
buf[pc++] = c;
|
||||
}
|
||||
|
||||
static void
|
||||
lput(uint l)
|
||||
{
|
||||
if (pc+4 >= abuf)
|
||||
allocb();
|
||||
lp(buf+pc, l);
|
||||
pc += 4;
|
||||
}
|
||||
|
||||
static void
|
||||
reg(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (sp->t != REG)
|
||||
err(0, "%s:%d: expected register\n", in, sp->l);
|
||||
else if ((n = strtol(sp->s, NULL, 16)) >= MAXREG)
|
||||
err(0, "%s:%d: bad register %02x\n", in, sp->l, n);
|
||||
else
|
||||
cput(n);
|
||||
sp++;
|
||||
}
|
||||
|
||||
static void
|
||||
addr(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
if (sp->t == ADDR)
|
||||
n = strtol(sp->s, NULL, 16);
|
||||
else if (sp->t == IDNT)
|
||||
makelbp(sp->s, pc, sp->l);
|
||||
else {
|
||||
err(0, "%s:%d: expected immediate\n", in, sp->l);
|
||||
sp++;
|
||||
return;
|
||||
}
|
||||
lput(n);
|
||||
sp++;
|
||||
}
|
||||
|
||||
static int gen(void);
|
||||
|
||||
static int
|
||||
pget(char *p, char *s)
|
||||
{
|
||||
if (*p != '\'')
|
||||
return -1;
|
||||
for (p++; *p != '\0' && *p != '\''; p++)
|
||||
*s++ = *p;
|
||||
if (*p != '\'')
|
||||
return -1;
|
||||
*s = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
inc(struct sym *sp, char *p)
|
||||
{
|
||||
char path[1024];
|
||||
char mpath[1024];
|
||||
FILE *fp;
|
||||
int lp;
|
||||
|
||||
if (pget(p, path) == -1) {
|
||||
err(0, "%s:%d: expected value in include\n", in, sp->l);
|
||||
return;
|
||||
}
|
||||
fp = f;
|
||||
if ((f = fopen(path, "r")) == NULL) {
|
||||
err(0, "%s:%d: couldn't open '%s'\n", in, sp->l, path);
|
||||
f = fp;
|
||||
return;
|
||||
}
|
||||
strcpy(mpath, in);
|
||||
strcpy(in, path);
|
||||
lp = l;
|
||||
gen();
|
||||
f = fp;
|
||||
l = lp;
|
||||
strcpy(in, mpath);
|
||||
}
|
||||
|
||||
struct proc {
|
||||
char *s;
|
||||
void (*fn) (struct sym *, char *);
|
||||
};
|
||||
|
||||
static struct proc proctab[] = {
|
||||
{ "include", &inc },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
proc(struct sym *sp)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
char *s;
|
||||
char com[1024];
|
||||
|
||||
p = sp->s;
|
||||
s = com;
|
||||
while (*p != '\0' && !isspace(*p))
|
||||
*s++ = *p++;
|
||||
*s = '\0';
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
for (i = 0; proctab[i].s != NULL; i++)
|
||||
if (strcmp(com, proctab[i].s) == 0) {
|
||||
proctab[i].fn(sp, p);
|
||||
return;
|
||||
}
|
||||
err(0, "%s:%d: unknown directive '%s'\n", in, sp->l, com);
|
||||
}
|
||||
|
||||
static void
|
||||
ins(void)
|
||||
{
|
||||
char *p;
|
||||
struct ins *ip;
|
||||
int i;
|
||||
|
||||
if (sp->t == LBL) {
|
||||
if (lookup(sp->s, 1) != NULL)
|
||||
err(0, "%s:%d: redefining label '%s'\n", in, sp->l,
|
||||
sp->s);
|
||||
sp++;
|
||||
return;
|
||||
}
|
||||
if (sp->t != IDNT) {
|
||||
err(0, "%s:%d: expected instruction\n", in, sp->l);
|
||||
sp++;
|
||||
return;
|
||||
}
|
||||
for (ip = NULL, i = 0; i < AINS; i++)
|
||||
if (strcmp(sp->s, instab[i].s) == 0) {
|
||||
ip = &instab[i];
|
||||
break;
|
||||
}
|
||||
if (ip == NULL) {
|
||||
err(0, "%s:%d: invalid instruction '%s'\n", in, sp->l, sp->s);
|
||||
sp++;
|
||||
return;
|
||||
}
|
||||
cput(i);
|
||||
sp++;
|
||||
for (p = ip->fmt; *p != '\0'; p++)
|
||||
switch (*p) {
|
||||
case 'r':
|
||||
reg();
|
||||
break;
|
||||
case 'i':
|
||||
addr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lbl(void)
|
||||
{
|
||||
struct lbl *p;
|
||||
|
||||
while (lbp != NULL) {
|
||||
if ((p = lookup(lbp->s, 0)) == NULL)
|
||||
err(0, "%s:%d: no such label '%s'\n", in, lbp->l,
|
||||
lbp->s);
|
||||
else
|
||||
lp(buf+lbp->addr, p->addr);
|
||||
p = lbp;
|
||||
lbp = lbp->next;
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
gen(void)
|
||||
{
|
||||
struct sym *s;
|
||||
struct sym n;
|
||||
int c;
|
||||
|
||||
while ((c = get(&s)) != -1)
|
||||
if (c != 0) {
|
||||
if (s->t == PROC)
|
||||
proc(s);
|
||||
else
|
||||
pushsym(s);
|
||||
}
|
||||
fclose(f);
|
||||
n.t = -1;
|
||||
pushsym(&n);
|
||||
while (sp->t != -1)
|
||||
ins();
|
||||
sp++;
|
||||
if (errc > 0) {
|
||||
err(0, "%s: %d error%s\n", in, errc, errc>1?"s":"");
|
||||
errc--;
|
||||
return -1;
|
||||
}
|
||||
errc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *out;
|
||||
char *s;
|
||||
int n;
|
||||
uchar hd[4];
|
||||
|
||||
progname = *argv[0]!='\0'?argv[0]:"mcimc";
|
||||
out = "a";
|
||||
while (--argc > 0 && (*++argv)[0] == '-')
|
||||
for (s = argv[0]+1; *s != '\0'; s++)
|
||||
switch (*s) {
|
||||
case 'o':
|
||||
if (argc < 2)
|
||||
usage();
|
||||
out = argv[1];
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
if (argc < 1)
|
||||
usage();
|
||||
strcpy(in, argv[0]);
|
||||
if ((f = fopen(in, "r")) == NULL)
|
||||
err(1, "%s: couldn't open '%s'\n", progname, in);
|
||||
if (allocsym(SYMALLOC) == -1) {
|
||||
fclose(f);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
sp = tab;
|
||||
allocb();
|
||||
n = gen();
|
||||
if (n == -1) {
|
||||
mfree();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
lbl();
|
||||
if ((f = fopen(out, "wb")) == NULL)
|
||||
err(1, "%s: couldn't open '%s'\n", progname, out);
|
||||
lp(hd, pc);
|
||||
fwrite(hd, 1, sizeof hd, f);
|
||||
fwrite(buf, 1, pc, f);
|
||||
fclose(f);
|
||||
mfree();
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ins instab[AINS] = {
|
||||
{ "lw", "ri" },
|
||||
{ "lwu", "ri" },
|
||||
{ "lb", "ri" },
|
||||
{ "li", "ri" },
|
||||
{ "sw", "ri" },
|
||||
{ "swu", "ri" },
|
||||
{ "sb", "ri" },
|
||||
{ "sr", "ri" },
|
||||
{ "add", "rrr" },
|
||||
{ "addi", "rir" },
|
||||
{ "sub", "rrr" },
|
||||
{ "mul", "rrr" },
|
||||
{ "div", "rrr" },
|
||||
{ "ble", "rri" },
|
||||
{ "bgt", "rri" },
|
||||
{ "beq", "rri" },
|
||||
{ "bne", "rri" },
|
||||
{ "j", "i" },
|
||||
{ "jr", "r" },
|
||||
{ "jal", "i" },
|
||||
{ "sys", "r" }
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
enum {
|
||||
ALW,
|
||||
ALWU,
|
||||
ALB,
|
||||
ALI,
|
||||
ASW,
|
||||
ASWU,
|
||||
ASB,
|
||||
ASR,
|
||||
AADD,
|
||||
AADDI,
|
||||
ASUB,
|
||||
AMUL,
|
||||
ADIV,
|
||||
ABLE,
|
||||
ABGT,
|
||||
ABEQ,
|
||||
ABNE,
|
||||
AJ,
|
||||
AJR,
|
||||
AJAL,
|
||||
ASYS,
|
||||
AINS
|
||||
};
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char uchar;
|
|
@ -0,0 +1,5 @@
|
|||
li %0 $0
|
||||
li %0 $1
|
||||
add %0 %1 %0
|
||||
li %2 $0
|
||||
sys %2
|
|
@ -0,0 +1,12 @@
|
|||
.include 'sys.s'
|
||||
|
||||
start:
|
||||
jal write
|
||||
li %1 $41
|
||||
li %2 $7e
|
||||
li %3 $1
|
||||
loop:
|
||||
sys %0
|
||||
add %1 %3 %1
|
||||
bne %1 %2 loop
|
||||
jal exit
|
|
@ -0,0 +1,4 @@
|
|||
li %0 $020002
|
||||
sw %0 $100
|
||||
sw %0 $200
|
||||
sys %0
|
|
@ -0,0 +1,6 @@
|
|||
j start
|
||||
|
||||
; SYSE ($0)
|
||||
exit: li %0 $0 sys %0 jr %3
|
||||
; SYSW ($2)
|
||||
write: li %0 $2 jr %3
|
|
@ -0,0 +1,21 @@
|
|||
; memory test
|
||||
li %0 $41
|
||||
sb %0 $100
|
||||
li %0 $42
|
||||
sb %0 $101
|
||||
li %0 $43
|
||||
sb %0 $102
|
||||
li %0 $0
|
||||
sb %0 $103
|
||||
li %2 $0
|
||||
li %3 $2
|
||||
li %8 $100
|
||||
print:
|
||||
lb %1 $0
|
||||
beq %1 %2 end
|
||||
sys %3
|
||||
addi %8 $1 %8
|
||||
j print
|
||||
end:
|
||||
li %0 $0
|
||||
sys %0
|
Loading…
Reference in New Issue