commit 4f262166f7c82512a85c987b4f775eb77409f18c Author: ipc Date: Mon Jan 31 16:58:03 2022 +0100 initial commit 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