diff --git a/etc/usm.sublime-syntax b/etc/usm.sublime-syntax index b84e2ea..e273a32 100644 --- a/etc/usm.sublime-syntax +++ b/etc/usm.sublime-syntax @@ -30,7 +30,7 @@ contexts: # Special - match: '\&(\S+)\s?' - scope: string.control + scope: entity.name.type pop: true - match: '\=(\S+)\s?' scope: entity.name.type @@ -38,14 +38,10 @@ contexts: # Pushing to stack - - match: '\^(\S+)\s?' - scope: keyword.control - pop: true - match: '\#(\S+)\s?' scope: keyword.control pop: true - # Addressing - match: '\.(\S+)\s?' # zero-page scope: variable.control @@ -73,10 +69,3 @@ contexts: - meta_scope: comment.line - match: '\)' pop: true - - - match: '\[' - scope: keyword - push: - - meta_scope: keyword.line - - match: '\]' - pop: true diff --git a/projects/examples/dev.controller.buttons.usm b/projects/examples/dev.controller.buttons.usm index 4c3df01..0b3d05a 100644 --- a/projects/examples/dev.controller.buttons.usm +++ b/projects/examples/dev.controller.buttons.usm @@ -9,26 +9,26 @@ ( devices ) -|0100 @System &vector $2 &pad $6 &r $2 &g $2 &b $2 -|0110 @Console &pad $8 &char $1 &byte $1 &short $2 &string $2 -|0120 @Screen &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 -|0140 @Controller &vector $2 &button $1 &key $1 +|0100 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ] +|0110 @Console [ &pad $8 &char $1 &byte $1 &short $2 &string $2 ] +|0120 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ] +|0140 @Controller [ &vector $2 &button $1 &key $1 ] |0200 ( theme ) - #0daf ;System/r STR2 - #02ff ;System/g STR2 - #035f ;System/b STR2 + #0daf .System/r IOW2 + #02ff .System/g IOW2 + #035f .System/b IOW2 ( vectors ) - ;on-frame ;Screen/vector STR2 + ;on-frame .Screen/vector IOW2 ( set origin ) - ;Screen/width LDR2 2/ ;Screen/x STR2 - ;Screen/height LDR2 2/ ;Screen/y STR2 - ;default_icn ;Screen/addr STR2 - #31 ;Screen/color POK2 + .Screen/width IOR2 2/ .Screen/x IOW2 + .Screen/height IOR2 2/ .Screen/y IOW2 + ;default_icn .Screen/addr IOW2 + #31 .Screen/color IOW #2a .slime POK BRK @@ -36,43 +36,42 @@ BRK @on-frame #2a .slime POK - ;default_icn ;Screen/addr STR2 + ;default_icn .Screen/addr IOW2 ( hold ctrl key to change slime color ) - - ;Controller/button PEK2 #0f AND + .Controller/button IOR #0f AND DUP #01 NEQ ,&no-ctrl JNZ #25 .slime POK &no-ctrl DUP #02 NEQ ,&no-alt JNZ #2f .slime POK &no-alt POP - ( clear ) #30 ;Screen/color POK2 + ( clear ) #30 .Screen/color IOW ( detect movement ) - ;Controller/button PEK2 #f0 AND + .Controller/button IOR #f0 AND DUP #04 SFT #01 AND #01 NEQ ,&no-up JNZ ( move ) - ;Screen/y LDR2 -- ;Screen/y STR2 - ;up_icn ;Screen/addr STR2 &no-up + .Screen/y IOR2 -- .Screen/y IOW2 + ;up_icn .Screen/addr IOW2 &no-up DUP #05 SFT #01 AND #01 NEQ ,&no-down JNZ ( move ) - ;Screen/y LDR2 ++ ;Screen/y STR2 - ;down_icn ;Screen/addr STR2 &no-down + .Screen/y IOR2 ++ .Screen/y IOW2 + ;down_icn .Screen/addr IOW2 &no-down DUP #06 SFT #01 AND #01 NEQ ,&no-left JNZ ( move ) - ;Screen/x LDR2 -- ;Screen/x STR2 - ;left_icn ;Screen/addr STR2 &no-left + .Screen/x IOR2 -- .Screen/x IOW2 + ;left_icn .Screen/addr IOW2 &no-left DUP #07 SFT #01 AND #01 NEQ ,&no-right JNZ ( move ) - ;Screen/x LDR2 ++ ;Screen/x STR2 - ;right_icn ;Screen/addr STR2 &no-right + .Screen/x IOR2 ++ .Screen/x IOW2 + ;right_icn .Screen/addr IOW2 &no-right POP ( draw face ) - #31 ;Screen/color POK2 + #31 .Screen/color IOW ( draw slime ) - ;slime_icn ;Screen/addr STR2 - .slime PEK ;Screen/color POK2 + ;slime_icn .Screen/addr IOW2 + .slime PEK .Screen/color IOW BRK diff --git a/src/assembler.c b/src/assembler.c index 8bc0657..693d552 100644 --- a/src/assembler.c +++ b/src/assembler.c @@ -11,22 +11,19 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ -#define WORDLENMAX 32 -#define MACROMAX 64 -#define OFFSET 0x0200 +#define TRIM 0x0200 typedef unsigned char Uint8; typedef signed char Sint8; typedef unsigned short Uint16; -typedef signed short Sint16; typedef struct { - char name[WORDLENMAX], items[MACROMAX][WORDLENMAX]; + char name[64], items[64][64]; Uint8 len, refs; } Macro; typedef struct { - char name[WORDLENMAX]; + char name[64]; Uint8 refs; Uint16 addr; } Label; @@ -44,7 +41,7 @@ Program p; char ops[][4] = { "BRK", "LIT", "NOP", "POP", "DUP", "SWP", "OVR", "ROT", - "EQU", "NEQ", "GTH", "LTH", "GTS", "LTS", "---", "---", + "EQU", "NEQ", "GTH", "LTH", "GTS", "LTS", "IOR", "IOW", "PEK", "POK", "LDR", "STR", "JMP", "JNZ", "JSR", "STH", "ADD", "SUB", "MUL", "DIV", "AND", "ORA", "EOR", "SFT" }; @@ -163,9 +160,9 @@ makemacro(char *name, FILE *f) while(fscanf(f, "%s", word)) { if(word[0] == '{') continue; if(word[0] == '}') break; - if(m->len > MACROMAX) + if(m->len > 64) return error("Macro too large", name); - if(slen(word) >= WORDLENMAX) + if(slen(word) >= 64) return error("Word too long", name); scpy(word, m->items[m->len++], 64); } @@ -210,10 +207,13 @@ walktoken(char *w) if(findopcode(w) || scmp(w, "BRK", 4)) return 1; switch(w[0]) { + case '[': return 0; + case ']': return 0; case '.': return 2; /* zero-page: LIT addr-lb */ - case ';': return 3; /* absolute: LIT addr-hb addr-lb */ - case ',': return 2; /* Relative jump: lit addr-offset */ - case '#': return (slen(w + 1) == 4 ? 3 : 2); + case ',': return 2; /* relative: LIT addr-rel */ + case ';': return 3; /* absolute: LIT addr-hb addr-lb */ + case '$': return shex(w + 1); + case '#': return slen(w + 1) == 4 ? 3 : 2; } if((m = findmacro(w))) { int i, res = 0; @@ -227,10 +227,8 @@ walktoken(char *w) int parsetoken(char *w) { - Uint8 op = 0; Label *l; Macro *m; - if(w[0] == '.' && (l = findlabel(w + 1))) { /* zero-page */ pushbyte(l->addr, 1); return ++l->refs; @@ -243,8 +241,8 @@ parsetoken(char *w) } else if(w[0] == ';' && (l = findlabel(w + 1))) { /* absolute */ pushshort(l->addr, 1); return ++l->refs; - } else if((op = findopcode(w)) || scmp(w, "BRK", 4)) { - pushbyte(op, 0); + } else if(findopcode(w) || scmp(w, "BRK", 4)) { + pushbyte(findopcode(w), 0); return 1; } else if(w[0] == '#') { if(slen(w + 1) == 1) @@ -263,6 +261,12 @@ parsetoken(char *w) if(!parsetoken(m->items[i])) return 0; return 1; + } else if(sihx(w)) { + if(slen(w) == 2) + pushbyte(shex(w), 0); + else if(slen(w) == 4) + pushshort(shex(w), 0); + return 1; } return 0; } @@ -270,38 +274,28 @@ parsetoken(char *w) int pass1(FILE *f) { - int ccmnt = 0, cbits = 0; + int ccmnt = 0; Uint16 addr = 0; char w[64], scope[64], subw[64]; printf("Pass 1\n"); while(fscanf(f, "%s", w) == 1) { if(skipblock(w, &ccmnt, '(', ')')) continue; - if(w[0] == '&') { - if(!makelabel(sublabel(subw, scope, w + 1), addr)) - return error("Pass1 failed", w); - } else if(skipblock(w, &cbits, '[', ']')) { - if(w[0] == '[' || w[0] == ']') - continue; - if(slen(w) == 4 && sihx(w)) - addr += 2; - else if(slen(w) == 2 && sihx(w)) - addr += 1; - else - addr += slen(w); + if(w[0] == '|') { + if(shex(w + 1) < addr) + return error("Memory Overwrite", w); + addr = shex(w + 1); } else if(w[0] == '%') { if(!makemacro(w + 1, f)) return error("Pass1 failed", w); - scpy(w + 1, scope, 64); } else if(w[0] == '@') { if(!makelabel(w + 1, addr)) return error("Pass1 failed", w); scpy(w + 1, scope, 64); - } else if(w[0] == '|') { - if(shex(w + 1) < addr) - return error("Memory Overwrite", w); - addr = shex(w + 1); - } else if(w[0] == '$') - addr += shex(w + 1); + } else if(w[0] == '&') { + if(!makelabel(sublabel(subw, scope, w + 1), addr)) + return error("Pass1 failed", w); + } else if(sihx(w)) + addr += slen(w) / 2; else addr += walktoken(w); } @@ -312,37 +306,29 @@ pass1(FILE *f) int pass2(FILE *f) { - int ccmnt = 0, cbits = 0, ctemplate = 0; + int ccmnt = 0, ctemplate = 0; char w[64], scope[64], subw[64]; printf("Pass 2\n"); while(fscanf(f, "%s", w) == 1) { if(w[0] == '%') continue; if(w[0] == '&') continue; + if(w[0] == '[') continue; + if(w[0] == ']') continue; if(skipblock(w, &ccmnt, '(', ')')) continue; if(skipblock(w, &ctemplate, '{', '}')) continue; if(w[0] == '|') { p.ptr = shex(w + 1); continue; - } - else if(w[0] == '$') { + } else if(w[0] == '$') { p.ptr += shex(w + 1); continue; - } - else if(w[0] == '@') { + } else if(w[0] == '@') { scpy(w + 1, scope, 64); continue; } if(w[1] == '&') scpy(sublabel(subw, scope, w + 2), w + 1, 64); - if(skipblock(w, &cbits, '[', ']')) { - if(w[0] == '[' || w[0] == ']') { continue; } - if(slen(w) == 4 && sihx(w)) - pushshort(shex(w), 0); - else if(slen(w) == 2 && sihx(w)) - pushbyte(shex(w), 0); - else - pushtext(w, 0); - } else if(!parsetoken(w)) + if(!parsetoken(w)) return error("Unknown label in second pass", w); } return 1; @@ -352,7 +338,7 @@ void cleanup(char *filename) { int i; - printf("Assembled %s(%0.2fkb), %d labels, %d macros.\n\n", filename, (p.ptr - OFFSET) / 1000.0, p.llen, p.mlen); + printf("Assembled %s(%0.2fkb), %d labels, %d macros.\n\n", filename, (p.ptr - TRIM) / 1000.0, p.llen, p.mlen); for(i = 0; i < p.llen; ++i) if(!p.labels[i].refs) printf("--- Unused label: %s\n", p.labels[i].name); @@ -371,7 +357,7 @@ main(int argc, char *argv[]) return !error("Open", "Failed"); if(!pass1(f) || !pass2(f)) return !error("Assembly", "Failed"); - fwrite(p.data + OFFSET, p.ptr - OFFSET, 1, fopen(argv[2], "wb")); + fwrite(p.data + TRIM, p.ptr - TRIM, 1, fopen(argv[2], "wb")); fclose(f); cleanup(argv[2]); return 0; diff --git a/src/emulator.c b/src/emulator.c index 4a7e59f..5c0b1cf 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -181,6 +181,15 @@ doctrl(Uxn *u, SDL_Event *event, int z) #pragma mark - Devices +Uint8 +system_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) +{ + getcolors(&ppu, &u->ram.dat[ptr + 0x0008]); + reqdraw = 1; + (void)b0; + return b1; +} + Uint8 console_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) { @@ -199,9 +208,9 @@ Uint8 screen_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) { if(b0 == 0x0e) { - Uint16 x = mempeek16(u, ptr + 8); - Uint16 y = mempeek16(u, ptr + 10); - Uint8 *addr = &u->ram.dat[mempeek16(u, ptr + 12)]; + Uint16 x = mempeek16(u, devscreen->addr + 0x08); + Uint16 y = mempeek16(u, devscreen->addr + 0x0a); + Uint8 *addr = &u->ram.dat[mempeek16(u, devscreen->addr + 0x0c)]; Uint8 *layer = b1 >> 4 & 0x1 ? ppu.fg : ppu.bg; switch(b1 >> 5) { case 0: putpixel(&ppu, layer, x, y, b1 & 0x3); break; @@ -210,6 +219,7 @@ screen_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) } reqdraw = 1; } + (void)ptr; return b1; } @@ -286,16 +296,6 @@ datetime_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) return b1; } -Uint8 -system_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) -{ - u->ram.dat[ptr + b0] = b1; - getcolors(&ppu, &u->ram.dat[ptr + 0x0008]); - reqdraw = 1; - (void)ptr; - return b1; -} - Uint8 ppnil(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) { diff --git a/src/uxn.c b/src/uxn.c index fd7288d..2e7b512 100644 --- a/src/uxn.c +++ b/src/uxn.c @@ -16,11 +16,10 @@ WITH REGARD TO THIS SOFTWARE. #pragma mark - Operations /* clang-format off */ -Uint8 devpoke8(Uxn *u, Uint8 id, Uint8 b0, Uint8 b1){ return id < 0x10 ? u->dev[id].poke(u, PAGE_DEVICE + id * 0x10, b0, b1) : b1; } void push8(Stack *s, Uint8 a) { if (s->ptr == 0xff) { s->error = 2; return; } s->dat[s->ptr++] = a; } Uint8 pop8(Stack *s) { if (s->ptr == 0) { s->error = 1; return 0; } return s->dat[--s->ptr]; } Uint8 peek8(Stack *s, Uint8 a) { if (s->ptr < a + 1) s->error = 1; return s->dat[s->ptr - a - 1]; } -void mempoke8(Uxn *u, Uint16 a, Uint8 b) { u->ram.dat[a] = (a & 0xff00) == PAGE_DEVICE ? devpoke8(u, (a & 0xff) >> 4, a & 0xf, b) : b; } +void mempoke8(Uxn *u, Uint16 a, Uint8 b) { u->ram.dat[a] = b; } Uint8 mempeek8(Uxn *u, Uint16 a) { return u->ram.dat[a]; } void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); } Uint16 pop16(Stack *s) { return pop8(s) + (pop8(s) << 8); } @@ -43,6 +42,8 @@ void op_gth(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b void op_lth(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b < a); } void op_gts(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, (Sint8)b > (Sint8)a); } void op_lts(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, (Sint8)b < (Sint8)a); } +void op_ior(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, mempeek8(u, PAGE_DEVICE + a)); } +void op_iow(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); mempoke8(u, PAGE_DEVICE + a, b); u->dev[(a & 0xf0) >> 4].poke(u, PAGE_DEVICE + (a & 0xf0), a & 0x0f, b); } /* Memory */ void op_pek(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, mempeek8(u, a)); } void op_pok(Uxn *u) { Uint8 a = pop8(u->src); Uint8 b = pop8(u->src); mempoke8(u, a, b); } @@ -75,6 +76,8 @@ void op_gth16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->sr void op_lth16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b < a); } void op_gts16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, (Sint16)b > (Sint16)a); } void op_lts16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, (Sint16)b < (Sint16)a); } +void op_ior16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, mempeek16(u, PAGE_DEVICE + a)); } +void op_iow16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); mempoke16(u, PAGE_DEVICE + a, b); u->dev[(a & 0xf0) >> 4].poke(u, PAGE_DEVICE + (a & 0xf0), (a & 0x0f)+1, b); } /* Memory(16-bits) */ void op_pek16(Uxn *u) { Uint16 a = pop16(u->src); push8(u->src, mempeek8(u, a)); } void op_pok16(Uxn *u) { Uint16 a = pop16(u->src); Uint8 b = pop8(u->src); mempoke8(u, a, b); } @@ -96,12 +99,12 @@ void op_sft16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->s void (*ops[])(Uxn *u) = { op_brk, op_lit, op_nop, op_pop, op_dup, op_swp, op_ovr, op_rot, - op_equ, op_neq, op_gth, op_lth, op_gts, op_lts, op_nop, op_nop, + op_equ, op_neq, op_gth, op_lth, op_gts, op_lts, op_ior, op_iow, op_pek, op_pok, op_ldr, op_str, op_jmp, op_jnz, op_jsr, op_sth, op_add, op_sub, op_mul, op_div, op_and, op_ora, op_eor, op_sft, /* 16-bit */ - op_brk, op_lit16, op_nop, op_pop16, op_dup16, op_swp16, op_ovr16, op_rot16, - op_equ16, op_neq16, op_gth16, op_lth16, op_gts16, op_lts16, op_nop, op_nop, + op_brk, op_lit16, op_nop, op_pop16, op_dup16, op_swp16, op_ovr16, op_rot16, + op_equ16, op_neq16, op_gth16, op_lth16, op_gts16, op_lts16, op_ior16, op_iow16, op_pek16, op_pok16, op_ldr16, op_str16, op_jmp16, op_jnz16, op_jsr16, op_sth16, op_add16, op_sub16, op_mul16, op_div16, op_and16, op_ora16, op_eor16, op_sft16 };