diff options
author | mrb0nk500 <b0nk@b0nk.xyz> | 2019-12-14 23:58:01 -0500 |
---|---|---|
committer | mrb0nk500 <b0nk@b0nk.xyz> | 2019-12-14 23:58:01 -0500 |
commit | 0b81224b6ab8cd6da45039525962c6490ed2df56 (patch) | |
tree | a76bfa10ee6ae726efb212442a68c17b253b49ba | |
parent | c6d71bcf0e545a490fdeb0dfcafea2d5a02157c6 (diff) |
We now have keyboard support!!!
I also added the WAI instruction, which puts the thread
that executed it, into a catatonic stat, where it can't
do anything, until an interrupt occurs.
I will be starting work on GFsuX next.
I also might start work on SuBAsm, the
Sux Bootstrapping Assembler.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | asmmon.c | 25 | ||||
-rw-r--r-- | opcode.h | 4 | ||||
-rw-r--r-- | sux.c | 207 | ||||
-rw-r--r-- | test/hello-world.s | 5 | ||||
-rw-r--r-- | test/input.s | 127 |
6 files changed, 335 insertions, 35 deletions
@@ -11,7 +11,7 @@ CFLAGS = $(PCC_CFLAGS) $(CFLAGS_EXTRA) OBJS = asmmon.o sux.o OBJ_NAME = cisc-0.2 all : $(OBJS) - $(CC) $(OBJS) $(CFLAGS) -lpthread -o $(OBJ_NAME) + $(CC) $(OBJS) $(CFLAGS) -lpthread -lcurses -o $(OBJ_NAME) sux.o : $(CC) sux.c -c $(CFLAGS) -o sux.o asmmon.o : @@ -4,7 +4,7 @@ #define debug 1 -#define OPNUM 88 +#define OPNUM 89 #define SETOP(num, _mne, _IMM, _ZM, _ZMX, _ZMY, _ABS, _IMPL) \ {opcodes[num].mnemonic[3] = '\0'; strncpy(opcodes[num].mnemonic, _mne, 3); \ opcodes[num].imm = _IMM; \ @@ -123,7 +123,7 @@ void viewmem(uint64_t address) { printf("\n"); } } -int asmmon() { +int asmmon(const char *fn) { opent opcodes[OPNUM]; /* mne IMM ZM ZMX ZMY ABS IMPL*/ SETOP(0, "CPS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); @@ -210,10 +210,17 @@ int asmmon() { SETOP(81, "DAY", 0x00, 0xF3, 0x00, 0x00, 0xF1, 0xD3); SETOP(82, "DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4); SETOP(83, "DAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5); - SETOP(84, "JSL", 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00); - SETOP(85, "NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8); - SETOP(86, "RTL", 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0); - SETOP(87, "BRK", 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8); + SETOP(84, "WAI", 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8); + SETOP(85, "JSL", 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00); + SETOP(86, "NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8); + SETOP(87, "RTL", 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0); + SETOP(88, "BRK", 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8); + FILE *fp; + if (strcasecmp(fn, "stdin") != 0) { + fp = fopen(fn, "r"); + if (fp == NULL) + return 2; + } uint8_t done = 0; uint64_t address = 0x0000; while (!(done & 1)) { @@ -231,7 +238,11 @@ int asmmon() { char *tmp = malloc(sizeof(char *)*128); size_t size; done &= ~0x1F; - getline(&buf, &size, stdin); + if (!strcasecmp(fn, "stdin")) { + getline(&buf, &size, stdin); + } else { + getline(&buf, &size, fp); + } cmd = strtok_r(buf, "\n", &tmp); if (cmd != NULL) { if (strcasecmp(cmd, "done") == 0) { @@ -77,7 +77,7 @@ #define CPX 0xB4 /* ComPare X register. */ #define CAX 0xB5 /* Compare Accumulator, and X register. */ #define ENT 0xB8 /* ENd Threads. */ -#define RTI 0xC0 /* ReTurn from Interupt. */ +#define RTI 0xC0 /* ReTurn from Interrupt. */ #define INC 0xC1 /* INCrement accumulator. */ #define INY 0xC2 /* INcrement Y register. */ #define IAY 0xC3 /* Increment Accumulator, and Y register. */ @@ -88,6 +88,7 @@ #define DAY 0xD3 /* Decrement Accumulator, and Y register. */ #define DEX 0xD4 /* DEcrement X register. */ #define DAX 0xD5 /* Decrement Accumulator, and X register. */ +#define WAI 0xD8 /* WAit for Interrupt. */ #define JSL 0xE0 /* Jump to Subroutine Long. */ #define NOP 0xE8 /* No OPeration. */ #define RTL 0xF0 /* ReTurn from subroutine Long. */ @@ -265,6 +266,7 @@ static const char *opname[0x100] = { OPNAME(DAY), OPNAME(DEX), OPNAME(DAX), + OPNAME(WAI), OPNAME(JSL), [0xE1] = "INC a", [0xE2] = "CPY a", @@ -1,24 +1,38 @@ #include "opcode.h" #include <assert.h> +#include <curses.h> #include <string.h> #include <pthread.h> #define bench 0 #define debug 0 #define IO 1 +#define en_nc 1 #if bench #include <sys/time.h> #endif #define THREADS 1 #define BENCH_INST 100000000*THREADS -#define DATA_ADDR 0xC001 +#define CTRL_ADDR 0xC000 +#define TX_ADDR 0xC001 +#define RX_ADDR 0xC002 +#define CURSES_BACKSPACE 0x7F + uint64_t clk[THREADS]; /* Per Thread Clock cycles. */ uint64_t tclk; /* Total Clock cycles. */ uint64_t inst[THREADS]; uint64_t inss; uint8_t threads_done = 0; +uint8_t kbd_rdy = 0; +uint8_t wai = 0; +uint8_t irq = 0; +#if en_nc +WINDOW *scr; +#endif pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t main_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_cond_t main_cond = PTHREAD_COND_INITIALIZER; struct suxthr { struct sux sx; uint8_t th; @@ -44,10 +58,36 @@ void *run(void *args) { char *s = malloc(2048); uint8_t lines = (6*thread)+2; uint16_t tv = 0xFF50; /* Starting address of the Thread Vectors. */ + int x = 0, y = 0; #if bench gettimeofday(&str[thread], 0); #endif while (!end) { + #if en_nc + if (wai) { + for (int8_t i = 56; i >= 0; i-=8) { + if (i) + addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = (uint64_t)cpu->pc[thread]-1 >> i; + else + addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = (uint64_t)cpu->pc[thread]-1 & 0xFF; + cpu->sp[thread]--; + } + addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = (uint64_t)cpu->ps >> 8*thread; + cpu->sp[thread]--; + cpu->i[thread] = 1; + (cpu->i[thread]) ? (cpu->ps |= (I << 8*thread)) : (cpu->ps &= ~(I << 8*thread)); + cpu->pc[thread] = (uint64_t)addr[0xFFA0] + | (uint64_t)addr[0xFFA1] << 8 + | (uint64_t)addr[0xFFA2] << 16 + | (uint64_t)addr[0xFFA3] << 24 + | (uint64_t)addr[0xFFA4] << 32 + | (uint64_t)addr[0xFFA5] << 40 + | (uint64_t)addr[0xFFA6] << 48 + | (uint64_t)addr[0xFFA7] << 56; + wai = 0; + kbd_rdy &= (uint8_t)~(1 << thread); + } + #endif prefix = addr[cpu->pc[thread]]; if ((prefix & 0x07) == 0x07) cpu->pc[thread]++; @@ -56,16 +96,21 @@ void *run(void *args) { opcode = addr[cpu->pc[thread]]; #if debug && !bench - sprintf(s, "\033[%uH" + /*sprintf(s, "\033[%uH" "pc: 0x%08llx, a: 0x%016llx, x: 0x%016llx, y: 0x%016llx" ", sp: 0x%04lx, ps: 0x%016llx, prefix: 0x%02x, opcode: 0x%02x, thread: %u, inst: %s \r" , lines , cpu->pc[thread], cpu->a[thread], cpu->x[thread], cpu->y[thread] , cpu->sp[thread], cpu->ps, prefix, opcode, thread, opname[opcode]); - fwrite(s, sizeof(char), strlen(s), stdout); + fwrite(s, sizeof(char), strlen(s), stdout);*/ + mvwprintw(scr, lines, 0, "pc: 0x%08llx, a: 0x%016llx, x: 0x%016llx, y: 0x%016llx" + ", sp: 0x%04lx, ps: 0x%016llx, prefix: 0x%02x, opcode: 0x%02x, thread: %u, inst: %s \r" + , cpu->pc[thread], cpu->a[thread], cpu->x[thread], cpu->y[thread] + , cpu->sp[thread], cpu->ps, prefix, opcode, thread, opname[opcode]); + wrefresh(scr); lines++; - if (lines > 6*(thread+1)) - lines = (6*thread)+2; + if (lines > 24*(thread+1)) + lines = (24*thread)+2; #endif uint8_t rs = (prefix & 0x30) >> 4; @@ -716,14 +761,38 @@ void *run(void *args) { value = cpu->y[thread]; if (opcode == STX || opcode == 0x7E || opcode == 0x9E) value = cpu->x[thread]; - addr[address] = value & 0xFF; #if IO - if (address == DATA_ADDR) { + if (address == TX_ADDR) { + /*if (addr[address] == '\r') { + waddch(context->screen, '\n'); + }*/ + #if en_nc + if (addr[address] == CURSES_BACKSPACE || addr[address] == '\b') { + if (x > 0) { + x--; + wmove(scr, y, x); + } + wdelch(scr); + wrefresh(scr); + } else { + wmove(scr, y, x); + waddch(scr, addr[address]); + wrefresh(scr); + if (addr[address] == '\n') { + x = 0; + y+=1; + } else { + x+=1; + } + /*putchar(addr[address]);*/ + } + #else if (addr[address] == '\b') putchar('\b'); else putchar(addr[address]); + #endif } #endif if (regsize >= 2) @@ -1207,7 +1276,7 @@ void *run(void *args) { if ((value >> i) & 1) cpu->pc[i+1] = cpu->pc[0]+(i+1); break; - case RTI: /* ReTurn from Interupt routine. */ + case RTI: /* ReTurn from Interrupt routine. */ cpu->sp[thread]++; cpu->ps = addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] << 8*thread; for (uint8_t i = 0; i < 64; i+=8) { @@ -1365,12 +1434,7 @@ void *run(void *args) { addr[(cpu->stk_st[thread] << 16)+cpu->sp[thread]] = (uint64_t)cpu->ps >> 8*thread; cpu->sp[thread]--; cpu->i[thread] = 1; - (cpu->c[thread]) ? (cpu->ps |= (C << 8*thread)) : (cpu->ps &= ~(C << 8*thread)); - (cpu->z[thread]) ? (cpu->ps |= (Z << 8*thread)) : (cpu->ps &= ~(Z << 8*thread)); (cpu->i[thread]) ? (cpu->ps |= (I << 8*thread)) : (cpu->ps &= ~(I << 8*thread)); - (cpu->s[thread]) ? (cpu->ps |= (S << 8*thread)) : (cpu->ps &= ~(S << 8*thread)); - (cpu->v[thread]) ? (cpu->ps |= (V << 8*thread)) : (cpu->ps &= ~(V << 8*thread)); - (cpu->n[thread]) ? (cpu->ps |= (N << 8*thread)) : (cpu->ps &= ~(N << 8*thread)); cpu->pc[thread] = (uint64_t)addr[0xFFE0] | (uint64_t)addr[0xFFE1] << 8 | (uint64_t)addr[0xFFE2] << 16 @@ -1380,6 +1444,15 @@ void *run(void *args) { | (uint64_t)addr[0xFFE6] << 48 | (uint64_t)addr[0xFFE7] << 56; break; + case WAI: /* WAit for Interrupt. */ + wai = 1; + pthread_mutex_lock(&main_mutex); + pthread_cond_signal(&main_cond); + pthread_mutex_unlock(&main_mutex); + pthread_mutex_lock(&mutex); + pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + break; default: if(opcode != BRK) { /*printf("Cool, you inputed a non existent opcode, which means\n" @@ -1390,9 +1463,11 @@ void *run(void *args) { } ins++; #if debug && !bench - sprintf(s, "\033[%uHInstructions executed: %llu, Clock cycles: %llu\n", (6*thread)+1, ins, iclk); + /*sprintf(s, "\033[%uHInstructions executed: %llu, Clock cycles: %llu\n", (6*thread)+1, ins, iclk); fwrite(s, sizeof(char), strlen(s), stdout); - fflush(stdout); + fflush(stdout);*/ + mvwprintw(scr, (24*thread)+1, 0, "Instructions executed: %llu, Clock cycles: %llu\r", ins, iclk); + wrefresh(scr); #endif #if bench if (ins >= BENCH_INST) { @@ -1401,7 +1476,7 @@ void *run(void *args) { threads_done++; inst[thread] = ins; clk[thread] = iclk; - pthread_cond_signal(&cond); + pthread_cond_signal(&main_cond); pthread_mutex_unlock(&mutex); gettimeofday(&en[thread], 0); } @@ -1418,8 +1493,33 @@ int main(int argc, char **argv) { inss = 0; int v = 0; - if (asmmon() == 2) - return 0; + if (argc != 2) { + if (asmmon("stdin") == 2) + return 0; + } else { + if (asmmon(argv[1]) == 2) + return 0; + } + sprintf(tmp, "\033[2J\033[H"); + fwrite(tmp, sizeof(char), strlen(tmp), stdout); + fflush(stdout); + #if en_nc + if(!scr) + scr = initscr(); + nodelay(stdscr, 0); + crmode(); + noecho(); + nl(); + curs_set(0); + werase(scr); + scrollok(scr, 1); + wrefresh(scr); + start_color(); + use_default_colors(); + init_pair(1, COLOR_WHITE, -1); + attron(COLOR_PAIR(1) | A_BOLD); + wmove(scr, 0, 0); + #endif for (int i = 0; i < THREADS; i++) { thr[i].sx.sp[i] = 0xFFFF; thr[i].sx.stk_st[i] = i+1; @@ -1450,25 +1550,80 @@ int main(int argc, char **argv) { } thr[i].th = i; } + pthread_t therads[THREADS]; + int result; for (int i = 0; i < THREADS; i++) { inst[i] = 0; } - pthread_t therads[THREADS]; - int result; - sprintf(tmp, "\033[2J\033[H"); - fwrite(tmp, sizeof(char), strlen(tmp), stdout); - fflush(stdout); for (int i = 0; i < THREADS; i++) { result = pthread_create(&therads[i], NULL, run, &thr[i]); assert(!result); } - pthread_mutex_lock(&mutex); + int c = 0; while (threads_done < THREADS) { - pthread_cond_wait(&cond, &mutex); + int x, y, i = 0; + #if !bench + if ((c != EOF && c !=-1)) { + pthread_mutex_lock(&main_mutex); + pthread_cond_wait(&main_cond, &main_mutex); + pthread_mutex_unlock(&main_mutex); + c = 0; + } + #if en_nc + getyx(scr, y, x); + attroff(A_REVERSE); + attron(A_BLINK); + wprintw(scr, "_"); + attroff(A_BLINK); + wmove(scr, y, x); + wrefresh(scr); + + c = wgetch(scr); + + /*wmove(scr, 0, getmaxx(scr) - 1); + attron(A_REVERSE); + wprintw(scr, "!"); + attroff(A_REVERSE); + wmove(scr, y, x); + wrefresh(scr);*/ + switch (c) { + case ERR: + kbd_rdy = 0; + wmove(scr, getmaxy(scr)-1, 0); + wprintw(scr, "c: %i, x: %i, y: %i, i: %i.", c, x, y, i++); + wmove(scr, y, x); + wrefresh(scr); + break; + default: + addr[RX_ADDR] = (uint8_t)c; + kbd_rdy = 1 << 0; + pthread_mutex_lock(&mutex); + pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mutex); + break; + } + #else + c = getchar(); + if (c != EOF) { + sprintf(tmp, "\033[24Hc: %i\r", c); + fwrite(tmp, sizeof(char), strlen(tmp), stdout); + fflush(stdout); + kbd_rdy = 1 << 0; + pthread_mutex_lock(&mutex); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + } + #endif + #else + + #endif } - pthread_mutex_unlock(&mutex); #if bench if (threads_done == THREADS) { + #if en_nc + scr = NULL; + endwin(); + #endif double tm_sec, tm_usec, tm[THREADS], ttm; double clkspd; double mhz; diff --git a/test/hello-world.s b/test/hello-world.s index 465583c..9138bc7 100644 --- a/test/hello-world.s +++ b/test/hello-world.s @@ -6,6 +6,11 @@ string: .byte "Hello, world!\n" +; Text buffer. +.org $2000 +buffer: + + ; Get CPU into a known state. .org $0 reset: diff --git a/test/input.s b/test/input.s new file mode 100644 index 0000000..9e5ef69 --- /dev/null +++ b/test/input.s @@ -0,0 +1,127 @@ +; Testing input. +; +; Writen in Sux assembly by +; mr b0nk 500 <b0nk@b0nk.xyz> + + +; Initalize some variables. +.org $1000 +string: + .byte "Please, type something.\n" +string2: + .byte "You typed, " +end: + .byte $0 + +; Input buffer. +.org $2000 +buffer: + +; Main program +.org $0 +reset: + cps + ldx.w #$FFFF + txs + ldy #$0 +clr_buf: + lda #$0 + cpy.w #$1000 + beq start + sta buffer, y + iny + jmp clr_buf + +start: + ldx.w #$0 ; Reset x. + ldy #$0 ; Reset y. + jmp print + +sleep: + wai ; Sleep until we get a character. + lda end + bne spin ; Are we done with getting input? + jmp sleep ; Loop until we get a newline. + +print: + lda string, x ; Get character at offset x. + beq sleep ; Did we find a null terminator? + sta $C001 ; Print character. + inx ; Increment offset. + jmp print ; Keep printing more characters. + +irq_routine: + lda $C002 ; Get typed character. + cmp #$A + beq nl ; Did the user type a newline? + cmp #$8 + beq bs ; Did the user type a backspace? +echo: + sta $C001 ; Echo typed character. + sta buffer, y ; Store typed character into the input buffer. + iny ; Increment buffer offset. +return: + rti ; End of interrupt routine. + +nl: + sta $C001 + lda #$0 ; Replace newline with a null terminator. + sta buffer, y ; Store said terminator into the input buffer. + ldy.w #$0 ; Reset y, to print the result. + jmp result + +bs: + cpy #$0 + beq return ; Are we at the start of the buffer? + jmp echo ; We are not, so add the backspace to the buffer. + +result: + lda string2, y + beq rset_y ; Reset y, if we hit the null terminator. + sta $C001 ; Print 'You have typed, ' + iny ; Increment offset. + jmp result ; Keep printing. + +rset_y: + ldy.w #$0 + jmp print_buf ; Print the input buffer. + +print_buf: + lda buffer, y ; Get a character from the input buffer. + beq fin ; Are we done with printing the buffer? + sta $C001 ; Print said character. + iny + jmp print_buf ; Keep printing the buffer. + +fin: + lda #$A ; Load a newline. + sta $C001 ; Print the newline. + lda #$1 ; Tell the program that we are done. + sta end ; We are done. + + +spin: + nop + nop + nop + jmp spin + +.org $FFC0 +.qword reset + +.org $FF50 +.qword spin +.qword spin +.qword spin +.qword spin +.qword spin +.qword spin +.qword spin + +.org $FFA0 +.qword irq_routine +;.org $0 +;viewmem +;q +done + |