From 4f262166f7c82512a85c987b4f775eb77409f18c Mon Sep 17 00:00:00 2001 From: ipc Date: Mon, 31 Jan 2022 16:58:03 +0100 Subject: [PATCH] initial commit --- Makefile | 22 ++ README | 13 ++ cpu.c | 271 +++++++++++++++++++++++ mcim.c | 313 ++++++++++++++++++++++++++ mcim.h | 53 +++++ mcimc.c | 586 +++++++++++++++++++++++++++++++++++++++++++++++++ mcimc.h | 27 +++ sample/init.s | 5 + sample/l1.s | 12 + sample/mem.s | 4 + sample/sys.s | 6 + sample/write.s | 21 ++ 12 files changed, 1333 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 cpu.c create mode 100644 mcim.c create mode 100644 mcim.h create mode 100644 mcimc.c create mode 100644 mcimc.h create mode 100644 sample/init.s create mode 100644 sample/l1.s create mode 100644 sample/mem.s create mode 100644 sample/sys.s create mode 100644 sample/write.s diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bd18a41 --- /dev/null +++ b/Makefile @@ -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 diff --git a/README b/README new file mode 100644 index 0000000..99bcd8f --- /dev/null +++ b/README @@ -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 diff --git a/cpu.c b/cpu.c new file mode 100644 index 0000000..8373670 --- /dev/null +++ b/cpu.c @@ -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 +#include + +#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); + } +} diff --git a/mcim.c b/mcim.c new file mode 100644 index 0000000..610385a --- /dev/null +++ b/mcim.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 +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/mcim.h b/mcim.h new file mode 100644 index 0000000..8ee256c --- /dev/null +++ b/mcim.h @@ -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); diff --git a/mcimc.c b/mcimc.c new file mode 100644 index 0000000..ab9e5ac --- /dev/null +++ b/mcimc.c @@ -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 +#include +#include +#include +#include + +#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" } +}; diff --git a/mcimc.h b/mcimc.h new file mode 100644 index 0000000..7e53277 --- /dev/null +++ b/mcimc.h @@ -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; diff --git a/sample/init.s b/sample/init.s new file mode 100644 index 0000000..d6481d2 --- /dev/null +++ b/sample/init.s @@ -0,0 +1,5 @@ +li %0 $0 +li %0 $1 +add %0 %1 %0 +li %2 $0 +sys %2 diff --git a/sample/l1.s b/sample/l1.s new file mode 100644 index 0000000..c18b693 --- /dev/null +++ b/sample/l1.s @@ -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 diff --git a/sample/mem.s b/sample/mem.s new file mode 100644 index 0000000..0a2a448 --- /dev/null +++ b/sample/mem.s @@ -0,0 +1,4 @@ +li %0 $020002 +sw %0 $100 +sw %0 $200 +sys %0 diff --git a/sample/sys.s b/sample/sys.s new file mode 100644 index 0000000..484db7b --- /dev/null +++ b/sample/sys.s @@ -0,0 +1,6 @@ +j start + +; SYSE ($0) +exit: li %0 $0 sys %0 jr %3 +; SYSW ($2) +write: li %0 $2 jr %3 diff --git a/sample/write.s b/sample/write.s new file mode 100644 index 0000000..c979dc6 --- /dev/null +++ b/sample/write.s @@ -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