From 69bb5a9dab65617d925d97f277cf228c2a7fa9c0 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Tue, 21 Jan 2020 08:42:05 +0000 Subject: [PATCH 01/20] Make pylint happy --- asm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asm.py b/asm.py index 34a2e7d..c271585 100755 --- a/asm.py +++ b/asm.py @@ -388,12 +388,12 @@ if __name__ == '__main__': for filename in sys.argv[1:]: with open(filename, 'r') as sourcefile: code = parser.parse(lexer.lex(sourcefile.read())) - for inst in code: + for inst in code: # pylint: disable=E1133 # print(sym['.addr'], inst) assemble(sym, inst) print(sym) sym['.addr'] = 0 - for inst in code: + for inst in code: # pylint: disable=E1133 a = assemble(sym, inst, 2) if a is not None: print(["%04x" % x for x in a]) From a853e8eaadfb58f3e87626a3ecb3add11eb894b9 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Tue, 21 Jan 2020 23:31:47 +0000 Subject: [PATCH 02/20] Generate flat binary --- asm.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/asm.py b/asm.py index c271585..71ca018 100755 --- a/asm.py +++ b/asm.py @@ -2,6 +2,7 @@ from types import SimpleNamespace from rply import ParserGenerator, LexerGenerator +import struct OPS = { 'ADD': lambda a, b: a + b, @@ -205,13 +206,14 @@ def none(p): @pg.production("line : EOL") def line(p): label = None + instr = Directive(label=None, directive=None, args=None) for t in p: if type(t) in (ASM, Directive): - t.label = label - return t + instr = t elif t.gettokentype() == 'SYMBOL': label = t.getstr() - return None + instr.label = label + return instr @pg.production("op : OP2 arg_b COMMA arg_a") def op_op2(p): @@ -393,7 +395,13 @@ if __name__ == '__main__': assemble(sym, inst) print(sym) sym['.addr'] = 0 + binimage = b'' for inst in code: # pylint: disable=E1133 a = assemble(sym, inst, 2) if a is not None: print(["%04x" % x for x in a]) + for w in a: + binimage += struct.pack(" Date: Wed, 22 Jan 2020 07:34:36 +0000 Subject: [PATCH 03/20] Allow loading binary images in simulator. Fix instruction decoding. --- dsim.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/dsim.c b/dsim.c index ac6fd2e..017ce46 100644 --- a/dsim.c +++ b/dsim.c @@ -3,6 +3,11 @@ #include #include +#include +#include +#include +#include + uint16_t ram[0x10000]; uint16_t ra, rb, rc, rx, ry, rz, ri, rj; uint16_t rpc, rsp, rex, ria; @@ -47,8 +52,6 @@ void reset() running = true; } -typedef void (*dev_t)(void); - struct dev_entry { uint32_t vendor; uint32_t product; @@ -471,8 +474,8 @@ void next() ir = ram[rpc++]; opcode = ir & 0x001f; - a = (ir >> 5) & 0x001f; - b = (ir >> 10) & 0x003f; + a = (ir >> 10) & 0x003f; + b = (ir >> 5) & 0x001f; if (opcode == 0) { /* special instruction */ f = sops[b]; @@ -492,9 +495,49 @@ void next() ticks++; } -int main() +int load_image(char *filename) { - reset(); - while (running) next(); + int fd; + ssize_t r; + ssize_t pos; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return fd; + for (pos=0;;) { + r = read(fd, &ram[pos], sizeof(ram)); + if (r > 0) + pos += r; + else { + close(fd); + if (r == 0) + return pos; + else + return r; + } + } +} + +void dump_ram(uint16_t addr, uint16_t count) +{ + uint16_t i, a; + + for (i=0; i 1) { + load_image(argv[1]); + dump_ram(0, 32); + reset(); + while (running) next(); + } return EXIT_SUCCESS; } From 48867686a6042aa655ee2f5bdde2657e9e5914fb Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Wed, 22 Jan 2020 07:40:31 +0000 Subject: [PATCH 04/20] Add .vscode to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f031d1e..c1df664 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *% *~ +.vscode/ *.o *.orig dsim From 56eae1aca17d9cc91e95f1704c1c3b682729a9b0 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Wed, 22 Jan 2020 08:01:09 +0000 Subject: [PATCH 05/20] Added debug hardware IRQ to replace non standard HLT opcode --- dsim.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dsim.c b/dsim.c index 017ce46..883a0ee 100644 --- a/dsim.c +++ b/dsim.c @@ -62,8 +62,13 @@ struct dev_entry { void (*tick)(); }; +void debug_irqh() +{ + running = false; +} + struct dev_entry iodevs[] = { - { 0, 0, 0, NULL, NULL, NULL, NULL} + { 0x6d53647c, 0x62e037d3, 0x00000000, debug_irqh, NULL, NULL, NULL }, /* Debug device */ }; uint16_t lit[] = { @@ -421,11 +426,6 @@ void oHWI(uint16_t *a, uint16_t *b) } } -void oHLT(uint16_t *a, uint16_t *b) -{ - running = false; -} - typedef void (*op_t)(uint16_t *, uint16_t *); const op_t ops[] = { @@ -439,7 +439,7 @@ const op_t sops[] = { oNOP, oJSR, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, /* 00-07 */ oINT, oIAG, oIAS, oRFI, oIAQ, oNOP, oNOP, oNOP, /* 08-0f */ oHWN, oHWQ, oHWI, oNOP, oNOP, oNOP, oNOP, oNOP, /* 10-17 */ - oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oHLT /* 18-1f */ + oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP /* 18-1f */ }; void dumpregs() From 9ceac9ae5a364f27ae4f9f492046ed379066ee40 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Wed, 22 Jan 2020 08:21:09 +0000 Subject: [PATCH 06/20] Make dumpregs and dump_ram accessible from debug HWI. Add emulator ID to debug irqh --- dsim.c | 64 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/dsim.c b/dsim.c index 883a0ee..1876279 100644 --- a/dsim.c +++ b/dsim.c @@ -8,6 +8,9 @@ #include #include +#define EMU_ID 0xed6f +#define EMU_VER 0x0000 + uint16_t ram[0x10000]; uint16_t ra, rb, rc, rx, ry, rz, ri, rj; uint16_t rpc, rsp, rex, ria; @@ -20,6 +23,27 @@ uint16_t intq[MAX_INTQ_SIZE]; unsigned int intq_size; uint8_t intq_head; +void dumpregs() +{ + printf("%4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n", + "PC","SP","A","B","C","X","Y","Z","I","J","EX","IA"); + printf("%04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx\n", + rpc, rsp, ra, rb, rc, rx, ry, rz, ri, rj, rex, ria); +} + +void dump_ram(uint16_t addr, uint16_t count) +{ + uint16_t i, a; + + for (i=0; i 1) { load_image(argv[1]); - dump_ram(0, 32); reset(); while (running) next(); } From bc55eadb824b0ffe2b0c28ab0c9923a2f2b5f1b5 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Wed, 22 Jan 2020 08:37:17 +0000 Subject: [PATCH 07/20] Use ephemeral variable for literal operands --- dsim.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/dsim.c b/dsim.c index 1876279..0c617b1 100644 --- a/dsim.c +++ b/dsim.c @@ -14,6 +14,8 @@ uint16_t ram[0x10000]; uint16_t ra, rb, rc, rx, ry, rz, ri, rj; uint16_t rpc, rsp, rex, ria; +uint16_t lit; /* temporary storage for literal operands */ + bool skip_next; uint64_t ticks; bool running; @@ -109,13 +111,6 @@ struct dev_entry iodevs[] = { { 0x6d53647c, 0x62e037d3, 0x00000000, debug_irqh, NULL, NULL, NULL }, /* Debug device */ }; -uint16_t lit[] = { - 0xffff, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30 -}; - uint16_t *val(int operand, bool is_a) { switch (operand) { @@ -195,7 +190,8 @@ uint16_t *val(int operand, bool is_a) ticks++; return &ram[rpc++]; /* FIXME: write to literal */ default: - return &lit[operand-0x20]; + lit = operand - 0x21; + return &lit; } } From 98cecd782f586b0db8dd1c34fc1221d7abf93506 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Wed, 22 Jan 2020 09:46:24 +0000 Subject: [PATCH 08/20] Fix handling of long literals --- dsim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dsim.c b/dsim.c index 0c617b1..6c1d889 100644 --- a/dsim.c +++ b/dsim.c @@ -188,7 +188,8 @@ uint16_t *val(int operand, bool is_a) return &ram[ram[rpc++]]; case 0x1f: ticks++; - return &ram[rpc++]; /* FIXME: write to literal */ + lit = ram[rpc++]; + return &lit; default: lit = operand - 0x21; return &lit; From 706ae9238d153ca924c18f3281b0e72798215c50 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Wed, 22 Jan 2020 22:24:28 +0000 Subject: [PATCH 09/20] Fix typos in opcode names --- asm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asm.py b/asm.py index 71ca018..729bcd4 100755 --- a/asm.py +++ b/asm.py @@ -16,8 +16,8 @@ OPCODES = { 'MLI': (0x05, None), 'DIV': (0x06, None), 'DVI': (0x07, None), 'MOD': (0x08, None), 'MDI': (0x09, None), 'AND': (0x0a, None), 'BOR': (0x0b, None), 'XOR': (0x0c, None), 'SHR': (0x0d, None), 'ASR': (0x0e, None), 'SHL': (0x0f, None), 'IFB': (0x10, None), - 'IFC': (0x11, None), 'IFE': (0x12, None), 'IFN': (0x13, None), 'ING': (0x14, None), - 'INA': (0x15, None), 'INL': (0x16, None), 'INU': (0x17, None), 'ADX': (0x1a, None), + 'IFC': (0x11, None), 'IFE': (0x12, None), 'IFN': (0x13, None), 'IFG': (0x14, None), + 'IFA': (0x15, None), 'IFL': (0x16, None), 'IFU': (0x17, None), 'ADX': (0x1a, None), 'SBX': (0x1b, None), 'STI': (0x1e, None), 'STD': (0x1f, None), 'JSR': (0x00, 0x01), 'INT': (0x00, 0x08), 'IAG': (0x00, 0x09), 'IAS': (0x00, 0x0a), From 67904719be6d69dc4c571bafaeaa5e2aca8fd03b Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Thu, 23 Jan 2020 21:58:48 +0000 Subject: [PATCH 10/20] Fix handling of indirect references --- asm.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/asm.py b/asm.py index 729bcd4..04d03df 100755 --- a/asm.py +++ b/asm.py @@ -46,7 +46,7 @@ class ASM(SimpleNamespace): return (0x1f, arg) elif type(arg) == Indirect: if type(arg.disp) == Expr: - disp = arg.disp.value + disp = getattr(arg.disp, "value", 0) else: disp = arg.disp if arg.reg is None: @@ -67,10 +67,15 @@ class ASM(SimpleNamespace): elif arg.reg in ('PC', 'EX'): raise SyntaxError() else: - if arg.disp == 0: - return (0x08+REGISTERS[arg.reg], None) + if hasattr(type(arg.reg), "getstr"): + r = arg.reg.getstr() else: - return (0x10+REGISTERS[arg.reg], disp) + r = arg.reg + print("REG: "+r) + if arg.disp == 0: + return (0x08+REGISTERS[r], None) + else: + return (0x10+REGISTERS[r], disp) def code(self): o, b = OPCODES[self.op] a_bits, a_extra = self.addr(self.a, True) From f8ec7c2bee532f82c21ebe0de435804a3943fe50 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Thu, 23 Jan 2020 22:11:50 +0000 Subject: [PATCH 11/20] Handle chained conditionals --- dsim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsim.c b/dsim.c index 6c1d889..86f23bb 100644 --- a/dsim.c +++ b/dsim.c @@ -485,7 +485,7 @@ void next() op_t f; uint16_t i; - if ((!intq_en) && (intq_size > 0)) { + if ((!intq_en) && (intq_size > 0) && (!skip_next)) { i = intq_pop(); if (ria != 0) { intq_en = true; @@ -515,7 +515,7 @@ void next() if (!skip_next) f(pa, pb); else - skip_next = false; + skip_next = ((opcode & 0x18) == 0x10); /* Skip chained conditionals */ ticks++; } From a785d2eb12487bd48ffc2471af43d2a7f50431ff Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Fri, 24 Jan 2020 00:31:02 +0000 Subject: [PATCH 12/20] Fix buffer overflow loading images --- dsim.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dsim.c b/dsim.c index 86f23bb..f58bf72 100644 --- a/dsim.c +++ b/dsim.c @@ -525,12 +525,14 @@ int load_image(char *filename) int fd; ssize_t r; ssize_t pos; + uint8_t *buf; fd = open(filename, O_RDONLY); if (fd < 0) return fd; + buf = (uint8_t *)ram; for (pos=0;;) { - r = read(fd, &ram[pos], sizeof(ram)); + r = read(fd, &buf[pos], sizeof(ram)-pos); if (r > 0) pos += r; else { From feeae16d5bbabba32c2a311dd2aed70c3687d98f Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Fri, 24 Jan 2020 08:34:28 +0000 Subject: [PATCH 13/20] Add debug trace --- dsim.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dsim.c b/dsim.c index f58bf72..95a037a 100644 --- a/dsim.c +++ b/dsim.c @@ -19,6 +19,7 @@ uint16_t lit; /* temporary storage for literal operands */ bool skip_next; uint64_t ticks; bool running; +bool trace; bool intq_en; #define MAX_INTQ_SIZE 256 uint16_t intq[MAX_INTQ_SIZE]; @@ -75,6 +76,7 @@ void reset() skip_next = false; ticks = 0; + trace = false; running = true; } @@ -100,6 +102,12 @@ void debug_irqh() case 0x0002: dump_ram(ry, rx); break; + case 0x0004: + trace = false; + break; + case 0x0005: + trace = true; + break; case 0xffff: rx = EMU_ID; ry = EMU_VER; @@ -496,6 +504,9 @@ void next() } } + if (trace) + dumpregs(); + ir = ram[rpc++]; opcode = ir & 0x001f; From a75d9c67819e3a26269ce489c83f1978b1297a5e Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Sat, 25 Jan 2020 10:31:08 +0000 Subject: [PATCH 14/20] Added simple disassembler --- disasm.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 disasm.py diff --git a/disasm.py b/disasm.py new file mode 100755 index 0000000..a2adb3f --- /dev/null +++ b/disasm.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +import struct + + +OPCODES = ( + None , 'SET', 'ADD', 'SUB', 'MUL', 'MLI', 'DIV', 'DVI', + 'MOD', 'MDI', 'AND', 'BOR', 'XOR', 'SHR', 'ASR', 'SHL', + 'IFB', 'IFC', 'IFE', 'IFN', 'IFG', 'IFA', 'IFL', 'IFU', + None , None , 'ADX', 'SBX', None , None , 'STI', 'STD' +) + +OPCODES_X = ( + None , 'JSR', None , None , None , None , None , None , + 'INT', 'IAG', 'IAS', 'RFI', 'IAQ', None , None , None , + 'HWN', 'HWQ', 'HWI', None , None , None , None , None , + None , None , None , None , None , None , None , None +) + +ADDRESSING = ( + 'A', 'B', 'C', 'X', 'Y', 'Z', 'I', 'J', + '[A]', '[B]', '[C]', '[X]', '[Y]', '[Z]', '[I]', '[J]', + '[A+n]', '[B+n]', '[C+n]', '[X+n]', '[Y+n]', '[Z+n]', '[I+n]', '[J+n]', + 'POP/PUSH', 'PEEK', 'PEEK n', 'SP', 'PC', 'EX', '[n]', 'n' +) + +def read_word(f): + b = f.read(2) + if len(b) < 2: + raise EOFError() + return struct.unpack("> 5) & 0x1f + a = (w >> 10) & 0x3f + if a < 0x20: + a_str = ADDRESSING[a] + if 'n' in a_str: + w = read_word(f) + ins.append(w) + a_str = a_str.replace('n', str(w)) + else: + a_str = str(int(a) - 0x21) + a_str = a_str.split('/')[0] + if op == 0: + mnemonic = "%s %s" % (OPCODES_X[b], a_str) + else: + b_str = ADDRESSING[b] + if 'n' in b_str: + w = read_word(f) + ins.append(w) + b_str = b_str.replace('n', str(w)) + b_str = b_str.split('/')[-1] + mnemonic = "%s %s, %s" % (OPCODES[op], b_str, a_str) + print("%5d:\t%-20s; %s" % (pc, mnemonic, ' '.join(["%04x" % x for x in ins]))) + pc += len(ins) + + +if __name__ == '__main__': + import sys + + if len(sys.argv) > 1: + disassemble(sys.argv[1]) From d13d72ce8b3436fd3991fd5332d726d9978aaba2 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Sat, 18 Apr 2020 16:23:30 +0100 Subject: [PATCH 15/20] asm.py: improve literal handling; parse source file only once --- asm.py | 86 ++++++++++++++++++++++++---------------------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/asm.py b/asm.py index 04d03df..8f39388 100755 --- a/asm.py +++ b/asm.py @@ -32,11 +32,13 @@ REGISTERS = { 'I': 0x06, 'J': 0x07, 'SP': 0x1b, 'PC': 0x1c, 'EX': 0x1d } + class ASM(SimpleNamespace): + @staticmethod def addr(arg, is_a): if type(arg) == Expr: - arg = arg.value + return (0x1f, arg) if type(arg) == Register: return (REGISTERS[arg.name], None) elif type(arg) == int: @@ -45,12 +47,8 @@ class ASM(SimpleNamespace): else: return (0x1f, arg) elif type(arg) == Indirect: - if type(arg.disp) == Expr: - disp = getattr(arg.disp, "value", 0) - else: - disp = arg.disp if arg.reg is None: - return (0x1e, disp) + return (0x1e, arg.disp) else: if arg.reg == 'SP': sp = getattr(arg, 'sp', None) @@ -75,7 +73,8 @@ class ASM(SimpleNamespace): if arg.disp == 0: return (0x08+REGISTERS[r], None) else: - return (0x10+REGISTERS[r], disp) + return (0x10+REGISTERS[r], arg.disp) + def code(self): o, b = OPCODES[self.op] a_bits, a_extra = self.addr(self.a, True) @@ -84,27 +83,15 @@ class ASM(SimpleNamespace): else: b_bits, b_extra = self.addr(self.b, False) r = [o | (a_bits << 10) | (b_bits << 5)] - for e in a_extra, b_extra: + for e in b_extra, a_extra: if e is not None: r.append(e) + print("Assembing: %s %r, %r -> %r" % (self.op, self.b, self.a, r)) return r + def words(self): - r = 1 - if type(self.a) in (Expr, int): # literal (FIXME: optimize short literals) - if type(self.a) == int: - if not (-1 <= self.a <= 30): - r += 1 - else: - r += 1 - elif type(self.a) == Indirect: - if self.a.disp != 0: - r += 1 - if type(self.b) in (Expr, int): # literal - r += 1 - elif type(self.b) == Indirect: - if self.b.disp != 0: - r += 1 - return r + return len(self.code()) + class Expr(SimpleNamespace): def eval(self, ctx): @@ -347,65 +334,64 @@ def expr_sym(p): lexer = lg.build() parser = pg.build() -def assemble(ctx, inst, step=1): +def assemble(ctx, inst): if inst.label is not None: - if step == 1 and inst.label in ctx: - print(f"Redefining symbol {inst.label}") ctx[inst.label] = ctx['.addr'] if type(inst) == Directive: if inst.directive == ".org": ctx['.addr'] = inst.args.eval(ctx) + return None elif inst.directive in (".data", ".word", "DAT"): al = [] for a in inst.args: if type(a) == str: al.extend([ord(x) for x in a]) else: - if step == 1: - al.append(a) - else: - al.append(a.eval(ctx)) - if step > 1: - print(ctx['.addr'], al) + al.append(a.simplify(ctx)) ctx['.addr'] += len(al) + return al elif type(inst) == ASM: - try: - if type(inst.a) == Expr: - inst.a = inst.a.eval(ctx) - if type(inst.b) == Expr: - inst.b = inst.b.eval(ctx) - except KeyError as e: - if step != 1: - raise e + if type(inst.a) == Expr: + inst.a = inst.a.simplify(ctx) + if type(inst.b) == Expr: + inst.b = inst.b.simplify(ctx) if inst.b is not None: print(f"{ctx['.addr']} {inst.op} {inst.b}, {inst.a} [len={inst.words()}]") else: print(f"{ctx['.addr']} {inst.op} {inst.a} [len={inst.words()}]") ctx['.addr'] += inst.words() - - if step != 1: - return inst.code() + return inst.code() if __name__ == '__main__': import sys sym = {} sym['.addr'] = 0 + insns = [] for filename in sys.argv[1:]: with open(filename, 'r') as sourcefile: code = parser.parse(lexer.lex(sourcefile.read())) for inst in code: # pylint: disable=E1133 # print(sym['.addr'], inst) - assemble(sym, inst) + a = sym['.addr'] + c = assemble(sym, inst) + if c is not None: + insns.append((a, c)) print(sym) + print(insns) sym['.addr'] = 0 binimage = b'' - for inst in code: # pylint: disable=E1133 - a = assemble(sym, inst, 2) - if a is not None: - print(["%04x" % x for x in a]) - for w in a: + for a, c in insns: # pylint: disable=E1133 + words = [] + for w in c: + if type(w) == int: + words.append(w) + else: + words.append(w.eval(sym)) + if words: + print(["%04x" % x for x in words]) + for w in words: binimage += struct.pack(" Date: Thu, 23 Apr 2020 08:41:15 +0100 Subject: [PATCH 16/20] Add LEM1802, keyboard and clock. Fix indirect argument encoding in assembler. --- Makefile | 8 +++- asm.py | 6 +-- dsim.c | 114 +++++++++++++++++++------------------------------------ 3 files changed, 50 insertions(+), 78 deletions(-) diff --git a/Makefile b/Makefile index 3d9853d..10ce296 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,16 @@ .PHONY: all clean reformat -CFLAGS=-Wall -Werror -pedantic -std=c99 -O2 -mtune=native +CFLAGS=-Wall -Werror -pedantic -std=c99 -g3 # -O2 -mtune=native +CFLAGS+=-DDEV_DEBUG -DDEV_LEM1802 -DDEV_CLOCK +CFLAGS+=$(shell pkg-config --cflags sdl2) +LDLIBS+=$(shell pkg-config --libs sdl2) REFORMAT=astyle --style=linux +DEVICES=$(patsubst %.c,%.o,$(wildcard dev_*.c)) all: dsim +dsim: dsim.o device.o $(DEVICES) + clean: $(RM) *~ *% *.o *.orig $(RM) dsim diff --git a/asm.py b/asm.py index 8f39388..75aeba9 100755 --- a/asm.py +++ b/asm.py @@ -53,10 +53,10 @@ class ASM(SimpleNamespace): if arg.reg == 'SP': sp = getattr(arg, 'sp', None) if sp is None: - if disp == 0: + if arg.disp == 0: return (0x19, None) else: - return (0x1a, disp) + return (0x1a, arg.disp) else: if (sp, is_a) not in (('inc', True), ('dec', False)): raise SyntaxError() @@ -83,7 +83,7 @@ class ASM(SimpleNamespace): else: b_bits, b_extra = self.addr(self.b, False) r = [o | (a_bits << 10) | (b_bits << 5)] - for e in b_extra, a_extra: + for e in a_extra, b_extra: if e is not None: r.append(e) print("Assembing: %s %r, %r -> %r" % (self.op, self.b, self.a, r)) diff --git a/dsim.c b/dsim.c index 95a037a..335b9f0 100644 --- a/dsim.c +++ b/dsim.c @@ -8,8 +8,9 @@ #include #include -#define EMU_ID 0xed6f -#define EMU_VER 0x0000 +#include + +#include "device.h" uint16_t ram[0x10000]; uint16_t ra, rb, rc, rx, ry, rz, ri, rj; @@ -25,27 +26,8 @@ bool intq_en; uint16_t intq[MAX_INTQ_SIZE]; unsigned int intq_size; uint8_t intq_head; - -void dumpregs() -{ - printf("%4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n", - "PC","SP","A","B","C","X","Y","Z","I","J","EX","IA"); - printf("%04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx\n", - rpc, rsp, ra, rb, rc, rx, ry, rz, ri, rj, rex, ria); -} - -void dump_ram(uint16_t addr, uint16_t count) -{ - uint16_t i, a; - - for (i=0; i 0) { - return intq[(intq_head-intq_size--) % MAX_INTQ_SIZE]; + return intq[(intq_head+MAX_INTQ_SIZE-intq_size--) % MAX_INTQ_SIZE]; } else return 0xffff; } @@ -78,47 +60,22 @@ void reset() trace = false; running = true; + + for (hwn = 0; iodevs[hwn] != NULL; hwn++) + if (iodevs[hwn]->init) + iodevs[hwn]->init(); + + printf("Initialized %d devices\n", hwn); } -struct dev_entry { - uint32_t vendor; - uint32_t product; - uint16_t version; - void (*irqh)(); - void (*init)(); - void (*free)(); - void (*tick)(); -}; - -void debug_irqh() +void shutdown() { - switch (ra) { - case 0x0000: - running = false; - break; - case 0x0001: - dumpregs(); - break; - case 0x0002: - dump_ram(ry, rx); - break; - case 0x0004: - trace = false; - break; - case 0x0005: - trace = true; - break; - case 0xffff: - rx = EMU_ID; - ry = EMU_VER; - break; - } + int i; + for (i = 0; i < hwn; i++) + if (iodevs[i]->free) + iodevs[i]->free(); } -struct dev_entry iodevs[] = { - { 0x6d53647c, 0x62e037d3, 0x00000000, debug_irqh, NULL, NULL, NULL }, /* Debug device */ -}; - uint16_t *val(int operand, bool is_a) { switch (operand) { @@ -441,19 +398,19 @@ void oIAQ(uint16_t *a, uint16_t *b) void oHWN(uint16_t *a, uint16_t *b) { - *a = sizeof(iodevs) / sizeof(struct dev_entry); + *a = hwn; } void oHWQ(uint16_t *a, uint16_t *b) { uint16_t idx = *a; - if (idx < sizeof(iodevs) / sizeof(struct dev_entry)) { - ra = iodevs[idx].product & 0xffff; - rb = (iodevs[idx].product >> 16) & 0xffff; - rc = iodevs[idx].version; - rx = iodevs[idx].vendor & 0xffff; - ry = (iodevs[idx].vendor >> 16) & 0xffff; + if (idx < hwn) { + ra = iodevs[idx]->product & 0xffff; + rb = (iodevs[idx]->product >> 16) & 0xffff; + rc = iodevs[idx]->version; + rx = iodevs[idx]->vendor & 0xffff; + ry = (iodevs[idx]->vendor >> 16) & 0xffff; } else { ra = rb = rc = rx = ry = 0; } @@ -463,9 +420,9 @@ void oHWI(uint16_t *a, uint16_t *b) { uint16_t idx = *a; - if (idx < sizeof(iodevs) / sizeof(struct dev_entry)) { - if (iodevs[idx].irqh) - iodevs[idx].irqh(); + if (idx < hwn) { + if (iodevs[idx]->irqh) + iodevs[idx]->irqh(); } } @@ -493,9 +450,12 @@ void next() op_t f; uint16_t i; + gettimeofday(&time, NULL); + if ((!intq_en) && (intq_size > 0) && (!skip_next)) { i = intq_pop(); if (ria != 0) { + printf("Firing interrupt with message 0x%04x\n", i); intq_en = true; ram[--rsp] = rpc; ram[--rsp] = ra; @@ -503,10 +463,10 @@ void next() ra = i; } } - - if (trace) - dumpregs(); - + /* + if (trace) + dumpregs(); + */ ir = ram[rpc++]; opcode = ir & 0x001f; @@ -528,6 +488,10 @@ void next() else skip_next = ((opcode & 0x18) == 0x10); /* Skip chained conditionals */ + for (i = 0; iodevs[i] != NULL; i++) + if (iodevs[i]->tick) + iodevs[i]->tick(); + ticks++; } @@ -538,6 +502,7 @@ int load_image(char *filename) ssize_t pos; uint8_t *buf; + printf("Loading %s ...\n", filename); fd = open(filename, O_RDONLY); if (fd < 0) return fd; @@ -562,6 +527,7 @@ int main(int argc, char *argv[]) load_image(argv[1]); reset(); while (running) next(); + shutdown(); } return EXIT_SUCCESS; } From 4127d9bde8659feb32df697c420e73e0b80179b9 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Thu, 23 Apr 2020 08:44:13 +0100 Subject: [PATCH 17/20] Add missing files --- .gitignore | 2 + data/c64-80x25-font.png | Bin 3330 -> 0 bytes data/font.png | Bin 0 -> 618 bytes data/png2c.py | 40 +++++ dev_clock.c | 62 +++++++ dev_debug.c | 62 +++++++ dev_lem1802.c | 361 ++++++++++++++++++++++++++++++++++++++++ device.c | 28 ++++ device.h | 27 +++ font.c | 132 +++++++++++++++ palette.c | 22 +++ 11 files changed, 736 insertions(+) delete mode 100644 data/c64-80x25-font.png create mode 100644 data/font.png create mode 100755 data/png2c.py create mode 100644 dev_clock.c create mode 100644 dev_debug.c create mode 100644 dev_lem1802.c create mode 100644 device.c create mode 100644 device.h create mode 100644 font.c create mode 100644 palette.c diff --git a/.gitignore b/.gitignore index c1df664..cb41444 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ *.o *.orig dsim +*.asm +*.bin diff --git a/data/c64-80x25-font.png b/data/c64-80x25-font.png deleted file mode 100644 index a09e9ea6cdaae801e180f9350b1a98b0e8799d71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3330 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 literal 0 HcmV?d00001 diff --git a/data/png2c.py b/data/png2c.py new file mode 100755 index 0000000..d34cc3d --- /dev/null +++ b/data/png2c.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +from PIL import Image + +FONT_SIZE = (4, 8) + + +def convert(filename, subset=range(0,128)): + img = Image.open(filename) + print("""#include + +uint16_t font[] = {""") + grid = (img.size[0] // FONT_SIZE[0], img.size[1] // FONT_SIZE[1]) + ch = 0 + for r in range(grid[1]): + for c in range(grid[0]): + v = 0 + for x in range(FONT_SIZE[0]-1, -1, -1): + for y in range(FONT_SIZE[1]-1, -1, -1): + v <<= 1 + if img.getpixel((c*FONT_SIZE[0]+x,r*FONT_SIZE[1]+y)): + v |= 1 + h = (v >> 16) & 0xffff + l = v & 0xffff + if 32 <= ch < 127: + d = f'"{ch:c}" ' + else: + d = '' + if ch in subset: + print(f"\t0x{l:04x}, 0x{h:04x},\t/* {ch:3d} 0x{ch:02x} {d}*/") + ch += 1 + print("};") + + +if __name__ == '__main__': + import sys + + for fn in sys.argv[1:]: + convert(fn) + diff --git a/dev_clock.c b/dev_clock.c new file mode 100644 index 0000000..9138531 --- /dev/null +++ b/dev_clock.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include "device.h" + +struct timeval boot_time, last_jiffy; + +uint16_t clockdiv; +uint16_t intmsg; +uint64_t jiffies; +uint16_t clock_ticks; + +void clock_init() { + gettimeofday(&boot_time, NULL); + clockdiv = intmsg = clock_ticks = 0; + last_jiffy.tv_sec = last_jiffy.tv_usec = 0; + jiffies = 0; +} + +void clock_tick() +{ + // struct timeval now; + uint64_t delta; + + if (clockdiv != 0) { + // gettimeofday(&now, NULL); + delta = (time.tv_sec - last_jiffy.tv_sec)*10000 + (time.tv_usec - last_jiffy.tv_usec)/100; + if (delta >= 166) { + jiffies++; + last_jiffy.tv_sec = time.tv_sec; last_jiffy.tv_usec = time.tv_usec; + if (jiffies >= clockdiv) { + jiffies = 0; + clock_ticks++; + printf("Tick!\n"); + if (intmsg != 0) { + intq_push(intmsg); + } + } + } + } +} + +void clock_irqh() +{ + printf("Clock: A=0x%04x B=0x%04x\n", ra, rb); + switch (ra) { + case 0: + clockdiv = rb; + clock_ticks = 0; + break; + case 1: + rc = clock_ticks; + break; + case 2: + intmsg = rb; + break; + } +} + +struct dev_entry clock_dev = { 0x6d53647c, 0x12d0b402, 0x0000, clock_irqh, clock_init, NULL, clock_tick }; /* Clock device */ diff --git a/dev_debug.c b/dev_debug.c new file mode 100644 index 0000000..9c54993 --- /dev/null +++ b/dev_debug.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include "device.h" + +#define EMU_ID 0xed6f +#define EMU_VER 0x0000 + +void dumpregs() +{ + printf("%4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n", + "PC","SP","A","B","C","X","Y","Z","I","J","EX","IA"); + printf("%04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx\n", + rpc, rsp, ra, rb, rc, rx, ry, rz, ri, rj, rex, ria); +} + +void dump_ram(uint16_t addr, uint16_t count) +{ + uint16_t i, a; + + for (i=0; i +#include +#include +#include +#include +#include "device.h" + +#include + +#define BPP 4 + +#define CHAR_W 4 +#define CHAR_H 8 + +#define TEXT_ROWS 12 +#define TEXT_COLS 32 + +#define BORDER_L 16 +#define BORDER_R 16 +#define BORDER_T 16 +#define BORDER_B 16 + +#define ZOOM 8 + +#define KBUF_SIZE 16 + +#define COLORS (1<pixels); + for (i=0; i>j) & 1) != 0; + // raster[x+y*glyph_shapes->w] = (pixel ? 1 : 0); + for (fg=0; fgw] = (pixel ? fg : bg); + } + } + SDL_UnlockSurface(glyph_shapes); + + update_glyph_tiles(); + + printf("update_font() completed\n"); +} + +void update_palette() +{ + int i; + + printf("update_palette()\n"); + + if (palette == NULL) + palette = SDL_AllocPalette(256); + + for (i=0; icolors[i].r = ((PALETTE(i)>>8)&0xf)*0xff/0xf; + palette->colors[i].g = ((PALETTE(i)>>4)&0xf)*0xff/0xf; + palette->colors[i].b = ((PALETTE(i))&0xf)*0xff/0xf; + palette->colors[i].a = 255; + // printf("%2d %02x%02x%02x\n", i, palette->colors[i].r, palette->colors[i].g, palette->colors[i].b); + } + + if (glyph_tiles == NULL) { + glyph_tiles = SDL_CreateRGBSurface(0, glyph_shapes->w, glyph_shapes->h, 32, 0, 0, 0, 0); + } + + update_glyph_tiles(); + + printf("update_palette() completed\n"); +} + +void lem1802_init() +{ + screen_iptr = font_iptr = palette_iptr = border = 0; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); + } +} + +void keyboard_init() +{ + khead = klen = 0; + kint = 0; +} + +void lem1802_free() +{ + if (window) + SDL_DestroyWindow(window); + window = NULL; + if (palette) + SDL_FreePalette(palette); + palette = NULL; +// SDL_Quit(); +} + +void process_key(SDL_KeyboardEvent *ke) +{ + uint8_t k=0; + + if ((ke->keysym.sym >= 0x20) && (ke->keysym.sym <= 0x7f)) { + k = ke->keysym.sym; + } else { + switch (ke->keysym.sym) { + case SDLK_BACKSPACE: + k = 0x10; + break; + case SDLK_RETURN: + case SDLK_RETURN2: + k = 0x11; + break; + case SDLK_INSERT: + k = 0x12; + break; + case SDLK_DELETE: + k = 0x13; + break; + case SDLK_UP: + k = 0x80; + break; + case SDLK_DOWN: + k = 0x81; + break; + case SDLK_LEFT: + k = 0x82; + break; + case SDLK_RIGHT: + k = 0x83; + break; + case SDLK_LSHIFT: + case SDLK_RSHIFT: + k = 0x90; + break; + case SDLK_LCTRL: + case SDLK_RCTRL: + k = 0x91; + break; + default: + break; + } + } + + if (k != 0) { + kbuf[khead] = k; + khead = (khead + 1) % KBUF_SIZE; + if (klen < KBUF_SIZE) { + klen++; + } + if (kint != 0) + intq_push(kint); + } +} + +void lem1802_tick() +{ + uint16_t i; + uint16_t cell; + uint8_t ch, fg, bg; + bool bl; + SDL_Rect src, dst; + SDL_Event e; + static struct timeval last_frame = {0,0}; + + if (screen_iptr != 0) { + // printf("Update\n"); + + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) + running = false; + if (e.type == SDL_KEYDOWN) { + if (e.key.keysym.sym == SDLK_F12) + running = false; + else + process_key(&e.key); + } + } + + // gettimeofday(&t, NULL); + + if ((time.tv_sec - poweron_time.tv_sec)*100 + (time.tv_usec - poweron_time.tv_usec)/10000 < 100) + return; + + if ((time.tv_sec - last_frame.tv_sec)*100 + (time.tv_usec - last_frame.tv_usec)/10000 < 2) + return; + + last_frame.tv_sec = time.tv_sec; + last_frame.tv_usec = time.tv_usec; + + src.x = 0; + src.y = CHAR_H*((border&0xf)<<4|(border&0xf)); + src.w = CHAR_W; + src.h = CHAR_H; + if (SDL_BlitScaled(glyph_tiles, &src, screenSurface, NULL) != 0) + printf("BlitScaled() failed! SDL_Error: %s\n", SDL_GetError()); + + for (i=0; i> 8) & 0xf; + fg = (bl && time.tv_usec>500000 ? bg : (cell >> 12) & 0xf); + src.x = ch*CHAR_W; + src.y = CHAR_H*(fg<<4|bg); + src.w = CHAR_W; + src.h = CHAR_H; + dst.x = (BORDER_L+CHAR_W*(i%TEXT_COLS))*ZOOM; + dst.y = (BORDER_T+CHAR_H*(i/TEXT_COLS))*ZOOM; + dst.w = CHAR_W*ZOOM; + dst.h = CHAR_H*ZOOM; + if (SDL_BlitScaled(glyph_tiles, &src, screenSurface, &dst) != 0) + printf("BlitScaled() failed! SDL_Error: %s\n", SDL_GetError()); + } + SDL_UpdateWindowSurface(window); + } +} + +void lem1802_irqh() +{ + int i; + + switch (ra) { + case 0: /* MEM_MAP_SCREEN */ + if (screen_iptr == 0) { + if (rb != 0) { + /* LEM1802 power up */ + gettimeofday(&poweron_time, NULL); + window = SDL_CreateWindow("LEM1802", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_W, WINDOW_H, SDL_WINDOW_SHOWN); + if(window == NULL) { + printf("Window could not be created! SDL_Error: %s\n", SDL_GetError()); + } else { + screenSurface = SDL_GetWindowSurface(window); + SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x80, 0x80, 0x80)); + SDL_UpdateWindowSurface(window); + update_font(); + update_palette(); + } + } + } else { + if (rb == 0) { + /* LEM1802 power down */ + SDL_DestroyWindow(window); + window = NULL; + } + } + screen_iptr = rb; + break; + case 1: /* MEM_MAP_FONT */ + if (rb != font_iptr) { + font_iptr = rb; + update_font(); + } + break; + case 2: /* MEM_MAP_PALETTE */ + if (rb != palette_iptr) { + palette_iptr = rb; + update_palette(); + } + break; + case 3: /* SET_BORDER_COLOR */ + border = rb; + break; + case 4: /* MEM_DUMP_FONT */ + for (i=0; i 0) { + rc = kbuf[(khead+KBUF_SIZE-klen)%KBUF_SIZE]; + klen--; + } else + rc = 0; + break; + case 2: /* Check key */ + printf("Check if key 0x%04x is pressed\n", rb); + rc = 0; + break; + case 3: /* Set interrupt message */ + printf("Keyboard interrupt message: 0x%04x\n", rb); + kint = rb; + break; + default: + break; + } +} + +struct dev_entry lem1802_dev = { 0x1c6c8b36, 0x7349f615, 0x1802, lem1802_irqh, lem1802_init, lem1802_free, lem1802_tick }; /* LEM1802 */ +struct dev_entry keyboard_dev = { 0x6d53647c, 0x30cf7406, 1, keyboard_irqh, keyboard_init, NULL, NULL }; /* Generic keyboard */ diff --git a/device.c b/device.c new file mode 100644 index 0000000..63c33fe --- /dev/null +++ b/device.c @@ -0,0 +1,28 @@ +#include +#include +#include "device.h" + +#ifdef DEV_DEBUG +extern struct dev_entry debug_dev; +#endif +#ifdef DEV_LEM1802 +extern struct dev_entry lem1802_dev; +extern struct dev_entry keyboard_dev; +#endif +#ifdef DEV_CLOCK +extern struct dev_entry clock_dev; +#endif + +struct dev_entry *iodevs[] = { +#ifdef DEV_DEBUG + &debug_dev, +#endif +#ifdef DEV_LEM1802 + &lem1802_dev, + &keyboard_dev, +#endif +#ifdef DEV_CLOCK + &clock_dev, +#endif + NULL +}; diff --git a/device.h b/device.h new file mode 100644 index 0000000..87c8259 --- /dev/null +++ b/device.h @@ -0,0 +1,27 @@ +#ifndef __DEVICE_H__ + +#include +#include +#include + +struct dev_entry { + uint32_t vendor; + uint32_t product; + uint16_t version; + void (*irqh)(); + void (*init)(); + void (*free)(); + void (*tick)(); +}; + +extern struct dev_entry *iodevs[]; + +extern bool running, trace; +extern uint16_t ram[0x10000]; +extern uint16_t ra, rb, rc, rx, ry, rz, ri, rj; +extern uint16_t rpc, rsp, rex, ria; +extern struct timeval time; + +extern void intq_push(uint16_t v); + +#endif diff --git a/font.c b/font.c new file mode 100644 index 0000000..c694018 --- /dev/null +++ b/font.c @@ -0,0 +1,132 @@ +#include + +uint16_t default_font[] = { + 0x9eb7, 0x8e38, /* 0 0x00 */ + 0x2c72, 0xf475, /* 1 0x01 */ + 0xbb19, 0x8f7f, /* 2 0x02 */ + 0xf985, 0x58b1, /* 3 0x03 */ + 0x2e24, 0x0024, /* 4 0x04 */ + 0x2a08, 0x0008, /* 5 0x05 */ + 0x0800, 0x0000, /* 6 0x06 */ + 0x0808, 0x0808, /* 7 0x07 */ + 0xff00, 0x0000, /* 8 0x08 */ + 0xf800, 0x0808, /* 9 0x09 */ + 0xf808, 0x0000, /* 10 0x0a */ + 0x0f08, 0x0000, /* 11 0x0b */ + 0x0f00, 0x0808, /* 12 0x0c */ + 0xff00, 0x0808, /* 13 0x0d */ + 0xf808, 0x0808, /* 14 0x0e */ + 0xff08, 0x0000, /* 15 0x0f */ + 0x0f08, 0x0808, /* 16 0x10 */ + 0xff08, 0x0808, /* 17 0x11 */ + 0x3366, 0xcc99, /* 18 0x12 */ + 0x3399, 0xcc66, /* 19 0x13 */ + 0xf8fe, 0x80e0, /* 20 0x14 */ + 0x1f7f, 0x0107, /* 21 0x15 */ + 0x0701, 0x7f1f, /* 22 0x16 */ + 0xe080, 0xfef8, /* 23 0x17 */ + 0x0055, 0x00aa, /* 24 0x18 */ + 0xaa55, 0xaa55, /* 25 0x19 */ + 0xaaff, 0x55ff, /* 26 0x1a */ + 0x0f0f, 0x0f0f, /* 27 0x1b */ + 0xf0f0, 0xf0f0, /* 28 0x1c */ + 0x0000, 0xffff, /* 29 0x1d */ + 0xffff, 0x0000, /* 30 0x1e */ + 0xffff, 0xffff, /* 31 0x1f */ + 0x0000, 0x0000, /* 32 0x20 " " */ + 0x5f00, 0x0000, /* 33 0x21 "!" */ + 0x0003, 0x0003, /* 34 0x22 """ */ + 0x143e, 0x003e, /* 35 0x23 "#" */ + 0x6b26, 0x0032, /* 36 0x24 "$" */ + 0x1c61, 0x0043, /* 37 0x25 "%" */ + 0x2936, 0x5076, /* 38 0x26 "&" */ + 0x0200, 0x0001, /* 39 0x27 "'" */ + 0x221c, 0x0041, /* 40 0x28 "(" */ + 0x2241, 0x001c, /* 41 0x29 ")" */ + 0x0814, 0x0014, /* 42 0x2a "*" */ + 0x1c08, 0x0008, /* 43 0x2b "+" */ + 0x2040, 0x0000, /* 44 0x2c "," */ + 0x0808, 0x0008, /* 45 0x2d "-" */ + 0x4000, 0x0000, /* 46 0x2e "." */ + 0x1c60, 0x0003, /* 47 0x2f "/" */ + 0x493e, 0x003e, /* 48 0x30 "0" */ + 0x7f42, 0x0040, /* 49 0x31 "1" */ + 0x5962, 0x0046, /* 50 0x32 "2" */ + 0x4922, 0x0036, /* 51 0x33 "3" */ + 0x080f, 0x007f, /* 52 0x34 "4" */ + 0x4527, 0x0039, /* 53 0x35 "5" */ + 0x493e, 0x0032, /* 54 0x36 "6" */ + 0x1961, 0x0007, /* 55 0x37 "7" */ + 0x4936, 0x0036, /* 56 0x38 "8" */ + 0x4926, 0x003e, /* 57 0x39 "9" */ + 0x2400, 0x0000, /* 58 0x3a ":" */ + 0x2440, 0x0000, /* 59 0x3b ";" */ + 0x1408, 0x0022, /* 60 0x3c "<" */ + 0x1414, 0x0014, /* 61 0x3d "=" */ + 0x1422, 0x0008, /* 62 0x3e ">" */ + 0x5902, 0x0006, /* 63 0x3f "?" */ + 0x593e, 0x005e, /* 64 0x40 "@" */ + 0x097e, 0x007e, /* 65 0x41 "A" */ + 0x497f, 0x0036, /* 66 0x42 "B" */ + 0x413e, 0x0022, /* 67 0x43 "C" */ + 0x417f, 0x003e, /* 68 0x44 "D" */ + 0x497f, 0x0041, /* 69 0x45 "E" */ + 0x097f, 0x0001, /* 70 0x46 "F" */ + 0x413e, 0x007a, /* 71 0x47 "G" */ + 0x087f, 0x007f, /* 72 0x48 "H" */ + 0x7f41, 0x0041, /* 73 0x49 "I" */ + 0x4020, 0x003f, /* 74 0x4a "J" */ + 0x087f, 0x0077, /* 75 0x4b "K" */ + 0x407f, 0x0040, /* 76 0x4c "L" */ + 0x067f, 0x007f, /* 77 0x4d "M" */ + 0x017f, 0x007e, /* 78 0x4e "N" */ + 0x413e, 0x003e, /* 79 0x4f "O" */ + 0x097f, 0x0006, /* 80 0x50 "P" */ + 0x613e, 0x007e, /* 81 0x51 "Q" */ + 0x097f, 0x0076, /* 82 0x52 "R" */ + 0x4926, 0x0032, /* 83 0x53 "S" */ + 0x7f01, 0x0001, /* 84 0x54 "T" */ + 0x403f, 0x007f, /* 85 0x55 "U" */ + 0x601f, 0x001f, /* 86 0x56 "V" */ + 0x307f, 0x007f, /* 87 0x57 "W" */ + 0x0877, 0x0077, /* 88 0x58 "X" */ + 0x7807, 0x0007, /* 89 0x59 "Y" */ + 0x4971, 0x0047, /* 90 0x5a "Z" */ + 0x7f00, 0x0041, /* 91 0x5b "[" */ + 0x1c03, 0x0060, /* 92 0x5c "\" */ + 0x7f41, 0x0000, /* 93 0x5d "]" */ + 0x0102, 0x0002, /* 94 0x5e "^" */ + 0x8080, 0x0080, /* 95 0x5f "_" */ + 0x0100, 0x0002, /* 96 0x60 "`" */ + 0x5424, 0x0078, /* 97 0x61 "a" */ + 0x447f, 0x0038, /* 98 0x62 "b" */ + 0x4438, 0x0028, /* 99 0x63 "c" */ + 0x4438, 0x007f, /* 100 0x64 "d" */ + 0x5438, 0x0058, /* 101 0x65 "e" */ + 0x7e08, 0x0009, /* 102 0x66 "f" */ + 0x5448, 0x003c, /* 103 0x67 "g" */ + 0x047f, 0x0078, /* 104 0x68 "h" */ + 0x7d04, 0x0000, /* 105 0x69 "i" */ + 0x4020, 0x003d, /* 106 0x6a "j" */ + 0x107f, 0x006c, /* 107 0x6b "k" */ + 0x7f01, 0x0000, /* 108 0x6c "l" */ + 0x187c, 0x007c, /* 109 0x6d "m" */ + 0x047c, 0x0078, /* 110 0x6e "n" */ + 0x4438, 0x0038, /* 111 0x6f "o" */ + 0x147c, 0x0008, /* 112 0x70 "p" */ + 0x1408, 0x007c, /* 113 0x71 "q" */ + 0x047c, 0x0008, /* 114 0x72 "r" */ + 0x5448, 0x0024, /* 115 0x73 "s" */ + 0x3e04, 0x0044, /* 116 0x74 "t" */ + 0x403c, 0x007c, /* 117 0x75 "u" */ + 0x601c, 0x001c, /* 118 0x76 "v" */ + 0x307c, 0x007c, /* 119 0x77 "w" */ + 0x106c, 0x006c, /* 120 0x78 "x" */ + 0x504c, 0x003c, /* 121 0x79 "y" */ + 0x5464, 0x004c, /* 122 0x7a "z" */ + 0x3608, 0x0041, /* 123 0x7b "{" */ + 0x7700, 0x0000, /* 124 0x7c "|" */ + 0x3641, 0x0008, /* 125 0x7d "}" */ + 0x0102, 0x0102, /* 126 0x7e "~" */ + 0x0502, 0x0002, /* 127 0x7f */ +}; diff --git a/palette.c b/palette.c new file mode 100644 index 0000000..c95b665 --- /dev/null +++ b/palette.c @@ -0,0 +1,22 @@ +#include + +/* CGA-like palette */ + +uint16_t default_palette[] = { + 0x0000, + 0x000a, + 0x00a0, + 0x00aa, + 0x0a00, + 0x0a0a, + 0x0a50, + 0x0aaa, + 0x0555, + 0x055f, + 0x05f5, + 0x05ff, + 0x0f55, + 0x0f5f, + 0x0ff5, + 0x0fff, +}; From 9cb338f83e5e1ccd4cf597538d1592ea21881e96 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Fri, 24 Apr 2020 07:41:14 +0100 Subject: [PATCH 18/20] Fix execution of instructions with two literals --- dsim.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dsim.c b/dsim.c index 335b9f0..c8333f1 100644 --- a/dsim.c +++ b/dsim.c @@ -15,7 +15,7 @@ uint16_t ram[0x10000]; uint16_t ra, rb, rc, rx, ry, rz, ri, rj; uint16_t rpc, rsp, rex, ria; -uint16_t lit; /* temporary storage for literal operands */ +uint16_t lit_a, lit_b; /* temporary storage for literal operands */ bool skip_next; uint64_t ticks; @@ -78,6 +78,10 @@ void shutdown() uint16_t *val(int operand, bool is_a) { + uint16_t *lit; + + lit = (is_a ? &lit_a : &lit_b); + switch (operand) { case 0x00: return &ra; @@ -153,11 +157,11 @@ uint16_t *val(int operand, bool is_a) return &ram[ram[rpc++]]; case 0x1f: ticks++; - lit = ram[rpc++]; - return &lit; + *lit = ram[rpc++]; + return lit; default: - lit = operand - 0x21; - return &lit; + *lit = operand - 0x21; + return lit; } } From 07b5b504ae6e3e583b94d5f5c707bd5857da74bc Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Mon, 27 Apr 2020 07:41:02 +0100 Subject: [PATCH 19/20] Added test suite. Fixed bugs in opcodes. Fixed font encoding. --- data/png2c.py | 6 +- dev_clock.c | 4 +- dev_lem1802.c | 59 +++++++----- dsim.c | 114 +++++++++++++++------- font.c | 242 +++++++++++++++++++++++------------------------ tests/.gitignore | 4 + tests/fetch.sh | 33 +++++++ 7 files changed, 275 insertions(+), 187 deletions(-) create mode 100644 tests/.gitignore create mode 100755 tests/fetch.sh diff --git a/data/png2c.py b/data/png2c.py index d34cc3d..3a597ef 100755 --- a/data/png2c.py +++ b/data/png2c.py @@ -9,13 +9,13 @@ def convert(filename, subset=range(0,128)): img = Image.open(filename) print("""#include -uint16_t font[] = {""") +uint16_t default_font[] = {""") grid = (img.size[0] // FONT_SIZE[0], img.size[1] // FONT_SIZE[1]) ch = 0 for r in range(grid[1]): for c in range(grid[0]): v = 0 - for x in range(FONT_SIZE[0]-1, -1, -1): + for x in range(FONT_SIZE[0]): for y in range(FONT_SIZE[1]-1, -1, -1): v <<= 1 if img.getpixel((c*FONT_SIZE[0]+x,r*FONT_SIZE[1]+y)): @@ -27,7 +27,7 @@ uint16_t font[] = {""") else: d = '' if ch in subset: - print(f"\t0x{l:04x}, 0x{h:04x},\t/* {ch:3d} 0x{ch:02x} {d}*/") + print(f"\t0x{h:04x}, 0x{l:04x},\t/* {ch:3d} 0x{ch:02x} {d}*/") ch += 1 print("};") diff --git a/dev_clock.c b/dev_clock.c index 9138531..034c76f 100644 --- a/dev_clock.c +++ b/dev_clock.c @@ -33,7 +33,7 @@ void clock_tick() if (jiffies >= clockdiv) { jiffies = 0; clock_ticks++; - printf("Tick!\n"); + // printf("Tick!\n"); if (intmsg != 0) { intq_push(intmsg); } @@ -44,7 +44,7 @@ void clock_tick() void clock_irqh() { - printf("Clock: A=0x%04x B=0x%04x\n", ra, rb); + // printf("Clock: A=0x%04x B=0x%04x\n", ra, rb); switch (ra) { case 0: clockdiv = rb; diff --git a/dev_lem1802.c b/dev_lem1802.c index eed07fa..a55a3a3 100644 --- a/dev_lem1802.c +++ b/dev_lem1802.c @@ -74,18 +74,11 @@ void update_font() printf("update_font()\n"); - if (glyph_shapes == NULL) { - glyph_shapes = SDL_CreateRGBSurface(0, CHAR_W*128, CHAR_H*COLORS*COLORS, 8, 0, 0, 0, 0); - if (glyph_shapes == NULL) { - SDL_Log("SDL_CreateRGBSurface() failed: %s", SDL_GetError()); - } - } - SDL_LockSurface(glyph_shapes); raster = (uint8_t *)(glyph_shapes->pixels); for (i=0; i>j) & 1) != 0; // raster[x+y*glyph_shapes->w] = (pixel ? 1 : 0); @@ -107,8 +100,8 @@ void update_palette() printf("update_palette()\n"); - if (palette == NULL) - palette = SDL_AllocPalette(256); + // if (palette == NULL) + // palette = SDL_AllocPalette(256); for (i=0; icolors[i].r = ((PALETTE(i)>>8)&0xf)*0xff/0xf; @@ -118,10 +111,6 @@ void update_palette() // printf("%2d %02x%02x%02x\n", i, palette->colors[i].r, palette->colors[i].g, palette->colors[i].b); } - if (glyph_tiles == NULL) { - glyph_tiles = SDL_CreateRGBSurface(0, glyph_shapes->w, glyph_shapes->h, 32, 0, 0, 0, 0); - } - update_glyph_tiles(); printf("update_palette() completed\n"); @@ -134,6 +123,18 @@ void lem1802_init() if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); } + palette = SDL_AllocPalette(256); + glyph_shapes = SDL_CreateRGBSurface(0, CHAR_W*128, CHAR_H*COLORS*COLORS, 8, 0, 0, 0, 0); + if (glyph_shapes == NULL) { + SDL_Log("SDL_CreateRGBSurface() failed: %s", SDL_GetError()); + } + // SDL_SetSurfacePalette(glyph_shapes, palette); + glyph_tiles = SDL_CreateRGBSurface(0, glyph_shapes->w, glyph_shapes->h, 32, 0, 0, 0, 0); + if (glyph_tiles == NULL) { + SDL_Log("SDL_CreateRGBSurface() failed: %s", SDL_GetError()); + } + update_font(); + update_palette(); } void keyboard_init() @@ -150,6 +151,12 @@ void lem1802_free() if (palette) SDL_FreePalette(palette); palette = NULL; + if (glyph_tiles) + SDL_FreeSurface(glyph_tiles); + glyph_tiles = NULL; + if (glyph_shapes) + SDL_FreeSurface(glyph_shapes); + glyph_shapes = NULL; // SDL_Quit(); } @@ -159,6 +166,7 @@ void process_key(SDL_KeyboardEvent *ke) if ((ke->keysym.sym >= 0x20) && (ke->keysym.sym <= 0x7f)) { k = ke->keysym.sym; + // printf("sym=%d mod=%d\n", k, ke->keysym.mod); } else { switch (ke->keysym.sym) { case SDLK_BACKSPACE: @@ -229,7 +237,10 @@ void lem1802_tick() if (e.type == SDL_KEYDOWN) { if (e.key.keysym.sym == SDLK_F12) running = false; - else + else if (e.key.keysym.sym == SDLK_F11) { + update_font(); + update_palette(); + } else process_key(&e.key); } } @@ -282,7 +293,7 @@ void lem1802_irqh() if (screen_iptr == 0) { if (rb != 0) { /* LEM1802 power up */ - gettimeofday(&poweron_time, NULL); + poweron_time.tv_sec = time.tv_sec; poweron_time.tv_usec = time.tv_usec; window = SDL_CreateWindow("LEM1802", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_W, WINDOW_H, SDL_WINDOW_SHOWN); if(window == NULL) { printf("Window could not be created! SDL_Error: %s\n", SDL_GetError()); @@ -290,8 +301,6 @@ void lem1802_irqh() screenSurface = SDL_GetWindowSurface(window); SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x80, 0x80, 0x80)); SDL_UpdateWindowSurface(window); - update_font(); - update_palette(); } } } else { @@ -304,25 +313,23 @@ void lem1802_irqh() screen_iptr = rb; break; case 1: /* MEM_MAP_FONT */ - if (rb != font_iptr) { - font_iptr = rb; - update_font(); - } + font_iptr = rb; + update_font(); break; case 2: /* MEM_MAP_PALETTE */ - if (rb != palette_iptr) { - palette_iptr = rb; - update_palette(); - } + palette_iptr = rb; + update_palette(); break; case 3: /* SET_BORDER_COLOR */ border = rb; break; case 4: /* MEM_DUMP_FONT */ + printf("Dumping default font to 0x%04x\n", rb); for (i=0; i> 16; ticks++; } @@ -212,9 +220,13 @@ void oMLI(uint16_t *a, uint16_t *b) void oDIV(uint16_t *a, uint16_t *b) { + uint32_t wb, wt; + if (*a) { - rex = ((uint32_t)*b<<16) / *a; - *b /= *a; + wb = *b; + wt = (wb<<16) / *a; + rex = wt&0xffff; + *b = wt>>16; } else { *b = rex = 0; } @@ -223,7 +235,7 @@ void oDIV(uint16_t *a, uint16_t *b) void oDVI(uint16_t *a, uint16_t *b) { if (*a) { - rex = ((int32_t)*b<<16) / (int16_t)*a; + rex = ((int16_t)*b<<16) / (int16_t)*a; *b = (int16_t)*b / (int16_t)*a; } else { *b = rex = 0; @@ -242,7 +254,7 @@ void oMOD(uint16_t *a, uint16_t *b) void oMDI(uint16_t *a, uint16_t *b) { if (*a) { - *b = (int16_t)*b / (int16_t)*a; + *b = (int16_t)*b % (int16_t)*a; } else { *b = 0; } @@ -265,32 +277,32 @@ void oXOR(uint16_t *a, uint16_t *b) void oSHR(uint16_t *a, uint16_t *b) { - uint16_t t; + uint32_t t; - t = (uint32_t)*b >> *a; - rex = ((uint64_t)*b << 16) >> *a; - *b = t; + t = (((uint32_t)*b) << 16) >> *a; + *b = t >> 16; + rex = t; } void oASR(uint16_t *a, uint16_t *b) { - uint16_t t; + int32_t t; - t = *b >> *a; - rex = ((uint32_t)*b << 16) >> *a; - *b = t; + t = (((int32_t)*b) << 16) >> *a; + *b = t >> 16; + rex = t; } void oSHL(uint16_t *a, uint16_t *b) { - uint16_t t; + uint32_t t; - t = *b << *a; - rex = ((uint64_t)*b << *a) >> 16; + t = ((uint32_t)*b) << *a; + rex = t >> 16; *b = t; } -#define DOIF(c) if (!(c)) skip_next = true +#define DOIF(c) if (!(c)) { skip_next = true; ticks++; } void oIFB(uint16_t *a, uint16_t *b) { @@ -386,6 +398,8 @@ void oIAG(uint16_t *a, uint16_t *b) void oIAS(uint16_t *a, uint16_t *b) { ria = *a; + if (ria == 0) + intq_size = 0; } void oRFI(uint16_t *a, uint16_t *b) @@ -433,17 +447,17 @@ void oHWI(uint16_t *a, uint16_t *b) typedef void (*op_t)(uint16_t *, uint16_t *); const op_t ops[] = { - oNOP, oSET, oADD, oSUB, oMUL, oMLI, oDIV, oDVI, /* 00-07 */ + NULL, oSET, oADD, oSUB, oMUL, oMLI, oDIV, oDVI, /* 00-07 */ oMOD, oMDI, oAND, oBOR, oXOR, oSHR, oASR, oSHL, /* 08-0f */ oIFB, oIFC, oIFE, oIFN, oIFG, oIFA, oIFL, oIFU, /* 10-17 */ - oNOP, oNOP, oADX, oSBX, oNOP, oNOP, oSTI, oSTD /* 18-1f */ + NULL, NULL, oADX, oSBX, NULL, NULL, oSTI, oSTD /* 18-1f */ }; const op_t sops[] = { - oNOP, oJSR, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, /* 00-07 */ - oINT, oIAG, oIAS, oRFI, oIAQ, oNOP, oNOP, oNOP, /* 08-0f */ - oHWN, oHWQ, oHWI, oNOP, oNOP, oNOP, oNOP, oNOP, /* 10-17 */ - oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP /* 18-1f */ + NULL, oJSR, NULL, NULL, NULL, NULL, NULL, NULL, /* 00-07 */ + oINT, oIAG, oIAS, oRFI, oIAQ, NULL, NULL, NULL, /* 08-0f */ + oHWN, oHWQ, oHWI, NULL, NULL, NULL, NULL, NULL, /* 10-17 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* 18-1f */ }; void next() @@ -456,6 +470,17 @@ void next() gettimeofday(&time, NULL); + // if ((!intq_en) && (intq_size > 0) && (!skip_next)) { + // i = intq_pop(); + // if (ria != 0) { + // printf("Firing interrupt with message 0x%04x\n", i); + // intq_en = true; + // ram[--rsp] = rpc; + // ram[--rsp] = ra; + // rpc = ria; + // ra = i; + // } + // } if ((!intq_en) && (intq_size > 0) && (!skip_next)) { i = intq_pop(); if (ria != 0) { @@ -471,6 +496,9 @@ void next() if (trace) dumpregs(); */ + // printf("PC: %04x\n", rpc); + // dumpregs(); + ir = ram[rpc++]; opcode = ir & 0x001f; @@ -487,11 +515,27 @@ void next() pb = val(b, false); } + if (f == NULL) { + printf("Invalid opcode 0x%04x at 0x%04x (o=%02x, a=%02x, b=%02x)\n", ir, rpc-1, opcode, a, b); + running = false; + sleep(5); + return; + } + + if (rpc == 0) { + printf("CRASH!\n"); + } + if (!skip_next) f(pa, pb); else skip_next = ((opcode & 0x18) == 0x10); /* Skip chained conditionals */ + if (rpc == 0) { + sleep(5); + running = false; + } + for (i = 0; iodevs[i] != NULL; i++) if (iodevs[i]->tick) iodevs[i]->tick(); diff --git a/font.c b/font.c index c694018..affbbc4 100644 --- a/font.c +++ b/font.c @@ -1,132 +1,132 @@ #include uint16_t default_font[] = { - 0x9eb7, 0x8e38, /* 0 0x00 */ - 0x2c72, 0xf475, /* 1 0x01 */ - 0xbb19, 0x8f7f, /* 2 0x02 */ - 0xf985, 0x58b1, /* 3 0x03 */ - 0x2e24, 0x0024, /* 4 0x04 */ - 0x2a08, 0x0008, /* 5 0x05 */ - 0x0800, 0x0000, /* 6 0x06 */ + 0xb79e, 0x388e, /* 0 0x00 */ + 0x722c, 0x75f4, /* 1 0x01 */ + 0x19bb, 0x7f8f, /* 2 0x02 */ + 0x85f9, 0xb158, /* 3 0x03 */ + 0x242e, 0x2400, /* 4 0x04 */ + 0x082a, 0x0800, /* 5 0x05 */ + 0x0008, 0x0000, /* 6 0x06 */ 0x0808, 0x0808, /* 7 0x07 */ - 0xff00, 0x0000, /* 8 0x08 */ - 0xf800, 0x0808, /* 9 0x09 */ - 0xf808, 0x0000, /* 10 0x0a */ - 0x0f08, 0x0000, /* 11 0x0b */ - 0x0f00, 0x0808, /* 12 0x0c */ - 0xff00, 0x0808, /* 13 0x0d */ - 0xf808, 0x0808, /* 14 0x0e */ - 0xff08, 0x0000, /* 15 0x0f */ - 0x0f08, 0x0808, /* 16 0x10 */ - 0xff08, 0x0808, /* 17 0x11 */ - 0x3366, 0xcc99, /* 18 0x12 */ - 0x3399, 0xcc66, /* 19 0x13 */ - 0xf8fe, 0x80e0, /* 20 0x14 */ - 0x1f7f, 0x0107, /* 21 0x15 */ - 0x0701, 0x7f1f, /* 22 0x16 */ - 0xe080, 0xfef8, /* 23 0x17 */ - 0x0055, 0x00aa, /* 24 0x18 */ - 0xaa55, 0xaa55, /* 25 0x19 */ - 0xaaff, 0x55ff, /* 26 0x1a */ + 0x00ff, 0x0000, /* 8 0x08 */ + 0x00f8, 0x0808, /* 9 0x09 */ + 0x08f8, 0x0000, /* 10 0x0a */ + 0x080f, 0x0000, /* 11 0x0b */ + 0x000f, 0x0808, /* 12 0x0c */ + 0x00ff, 0x0808, /* 13 0x0d */ + 0x08f8, 0x0808, /* 14 0x0e */ + 0x08ff, 0x0000, /* 15 0x0f */ + 0x080f, 0x0808, /* 16 0x10 */ + 0x08ff, 0x0808, /* 17 0x11 */ + 0x6633, 0x99cc, /* 18 0x12 */ + 0x9933, 0x66cc, /* 19 0x13 */ + 0xfef8, 0xe080, /* 20 0x14 */ + 0x7f1f, 0x0701, /* 21 0x15 */ + 0x0107, 0x1f7f, /* 22 0x16 */ + 0x80e0, 0xf8fe, /* 23 0x17 */ + 0x5500, 0xaa00, /* 24 0x18 */ + 0x55aa, 0x55aa, /* 25 0x19 */ + 0xffaa, 0xff55, /* 26 0x1a */ 0x0f0f, 0x0f0f, /* 27 0x1b */ 0xf0f0, 0xf0f0, /* 28 0x1c */ 0x0000, 0xffff, /* 29 0x1d */ 0xffff, 0x0000, /* 30 0x1e */ 0xffff, 0xffff, /* 31 0x1f */ 0x0000, 0x0000, /* 32 0x20 " " */ - 0x5f00, 0x0000, /* 33 0x21 "!" */ - 0x0003, 0x0003, /* 34 0x22 """ */ - 0x143e, 0x003e, /* 35 0x23 "#" */ - 0x6b26, 0x0032, /* 36 0x24 "$" */ - 0x1c61, 0x0043, /* 37 0x25 "%" */ - 0x2936, 0x5076, /* 38 0x26 "&" */ - 0x0200, 0x0001, /* 39 0x27 "'" */ - 0x221c, 0x0041, /* 40 0x28 "(" */ - 0x2241, 0x001c, /* 41 0x29 ")" */ - 0x0814, 0x0014, /* 42 0x2a "*" */ - 0x1c08, 0x0008, /* 43 0x2b "+" */ - 0x2040, 0x0000, /* 44 0x2c "," */ - 0x0808, 0x0008, /* 45 0x2d "-" */ - 0x4000, 0x0000, /* 46 0x2e "." */ - 0x1c60, 0x0003, /* 47 0x2f "/" */ - 0x493e, 0x003e, /* 48 0x30 "0" */ - 0x7f42, 0x0040, /* 49 0x31 "1" */ - 0x5962, 0x0046, /* 50 0x32 "2" */ - 0x4922, 0x0036, /* 51 0x33 "3" */ - 0x080f, 0x007f, /* 52 0x34 "4" */ - 0x4527, 0x0039, /* 53 0x35 "5" */ - 0x493e, 0x0032, /* 54 0x36 "6" */ - 0x1961, 0x0007, /* 55 0x37 "7" */ - 0x4936, 0x0036, /* 56 0x38 "8" */ - 0x4926, 0x003e, /* 57 0x39 "9" */ - 0x2400, 0x0000, /* 58 0x3a ":" */ - 0x2440, 0x0000, /* 59 0x3b ";" */ - 0x1408, 0x0022, /* 60 0x3c "<" */ - 0x1414, 0x0014, /* 61 0x3d "=" */ - 0x1422, 0x0008, /* 62 0x3e ">" */ - 0x5902, 0x0006, /* 63 0x3f "?" */ - 0x593e, 0x005e, /* 64 0x40 "@" */ - 0x097e, 0x007e, /* 65 0x41 "A" */ - 0x497f, 0x0036, /* 66 0x42 "B" */ - 0x413e, 0x0022, /* 67 0x43 "C" */ - 0x417f, 0x003e, /* 68 0x44 "D" */ - 0x497f, 0x0041, /* 69 0x45 "E" */ - 0x097f, 0x0001, /* 70 0x46 "F" */ - 0x413e, 0x007a, /* 71 0x47 "G" */ - 0x087f, 0x007f, /* 72 0x48 "H" */ - 0x7f41, 0x0041, /* 73 0x49 "I" */ - 0x4020, 0x003f, /* 74 0x4a "J" */ - 0x087f, 0x0077, /* 75 0x4b "K" */ - 0x407f, 0x0040, /* 76 0x4c "L" */ - 0x067f, 0x007f, /* 77 0x4d "M" */ - 0x017f, 0x007e, /* 78 0x4e "N" */ - 0x413e, 0x003e, /* 79 0x4f "O" */ - 0x097f, 0x0006, /* 80 0x50 "P" */ - 0x613e, 0x007e, /* 81 0x51 "Q" */ - 0x097f, 0x0076, /* 82 0x52 "R" */ - 0x4926, 0x0032, /* 83 0x53 "S" */ - 0x7f01, 0x0001, /* 84 0x54 "T" */ - 0x403f, 0x007f, /* 85 0x55 "U" */ - 0x601f, 0x001f, /* 86 0x56 "V" */ - 0x307f, 0x007f, /* 87 0x57 "W" */ - 0x0877, 0x0077, /* 88 0x58 "X" */ - 0x7807, 0x0007, /* 89 0x59 "Y" */ - 0x4971, 0x0047, /* 90 0x5a "Z" */ - 0x7f00, 0x0041, /* 91 0x5b "[" */ - 0x1c03, 0x0060, /* 92 0x5c "\" */ - 0x7f41, 0x0000, /* 93 0x5d "]" */ - 0x0102, 0x0002, /* 94 0x5e "^" */ - 0x8080, 0x0080, /* 95 0x5f "_" */ - 0x0100, 0x0002, /* 96 0x60 "`" */ - 0x5424, 0x0078, /* 97 0x61 "a" */ - 0x447f, 0x0038, /* 98 0x62 "b" */ - 0x4438, 0x0028, /* 99 0x63 "c" */ - 0x4438, 0x007f, /* 100 0x64 "d" */ - 0x5438, 0x0058, /* 101 0x65 "e" */ - 0x7e08, 0x0009, /* 102 0x66 "f" */ - 0x5448, 0x003c, /* 103 0x67 "g" */ - 0x047f, 0x0078, /* 104 0x68 "h" */ - 0x7d04, 0x0000, /* 105 0x69 "i" */ - 0x4020, 0x003d, /* 106 0x6a "j" */ - 0x107f, 0x006c, /* 107 0x6b "k" */ - 0x7f01, 0x0000, /* 108 0x6c "l" */ - 0x187c, 0x007c, /* 109 0x6d "m" */ - 0x047c, 0x0078, /* 110 0x6e "n" */ - 0x4438, 0x0038, /* 111 0x6f "o" */ - 0x147c, 0x0008, /* 112 0x70 "p" */ - 0x1408, 0x007c, /* 113 0x71 "q" */ - 0x047c, 0x0008, /* 114 0x72 "r" */ - 0x5448, 0x0024, /* 115 0x73 "s" */ - 0x3e04, 0x0044, /* 116 0x74 "t" */ - 0x403c, 0x007c, /* 117 0x75 "u" */ - 0x601c, 0x001c, /* 118 0x76 "v" */ - 0x307c, 0x007c, /* 119 0x77 "w" */ - 0x106c, 0x006c, /* 120 0x78 "x" */ - 0x504c, 0x003c, /* 121 0x79 "y" */ - 0x5464, 0x004c, /* 122 0x7a "z" */ - 0x3608, 0x0041, /* 123 0x7b "{" */ - 0x7700, 0x0000, /* 124 0x7c "|" */ - 0x3641, 0x0008, /* 125 0x7d "}" */ - 0x0102, 0x0102, /* 126 0x7e "~" */ - 0x0502, 0x0002, /* 127 0x7f */ + 0x005f, 0x0000, /* 33 0x21 "!" */ + 0x0300, 0x0300, /* 34 0x22 """ */ + 0x3e14, 0x3e00, /* 35 0x23 "#" */ + 0x266b, 0x3200, /* 36 0x24 "$" */ + 0x611c, 0x4300, /* 37 0x25 "%" */ + 0x3629, 0x7650, /* 38 0x26 "&" */ + 0x0002, 0x0100, /* 39 0x27 "'" */ + 0x1c22, 0x4100, /* 40 0x28 "(" */ + 0x4122, 0x1c00, /* 41 0x29 ")" */ + 0x1408, 0x1400, /* 42 0x2a "*" */ + 0x081c, 0x0800, /* 43 0x2b "+" */ + 0x4020, 0x0000, /* 44 0x2c "," */ + 0x0808, 0x0800, /* 45 0x2d "-" */ + 0x0040, 0x0000, /* 46 0x2e "." */ + 0x601c, 0x0300, /* 47 0x2f "/" */ + 0x3e49, 0x3e00, /* 48 0x30 "0" */ + 0x427f, 0x4000, /* 49 0x31 "1" */ + 0x6259, 0x4600, /* 50 0x32 "2" */ + 0x2249, 0x3600, /* 51 0x33 "3" */ + 0x0f08, 0x7f00, /* 52 0x34 "4" */ + 0x2745, 0x3900, /* 53 0x35 "5" */ + 0x3e49, 0x3200, /* 54 0x36 "6" */ + 0x6119, 0x0700, /* 55 0x37 "7" */ + 0x3649, 0x3600, /* 56 0x38 "8" */ + 0x2649, 0x3e00, /* 57 0x39 "9" */ + 0x0024, 0x0000, /* 58 0x3a ":" */ + 0x4024, 0x0000, /* 59 0x3b ";" */ + 0x0814, 0x2200, /* 60 0x3c "<" */ + 0x1414, 0x1400, /* 61 0x3d "=" */ + 0x2214, 0x0800, /* 62 0x3e ">" */ + 0x0259, 0x0600, /* 63 0x3f "?" */ + 0x3e59, 0x5e00, /* 64 0x40 "@" */ + 0x7e09, 0x7e00, /* 65 0x41 "A" */ + 0x7f49, 0x3600, /* 66 0x42 "B" */ + 0x3e41, 0x2200, /* 67 0x43 "C" */ + 0x7f41, 0x3e00, /* 68 0x44 "D" */ + 0x7f49, 0x4100, /* 69 0x45 "E" */ + 0x7f09, 0x0100, /* 70 0x46 "F" */ + 0x3e41, 0x7a00, /* 71 0x47 "G" */ + 0x7f08, 0x7f00, /* 72 0x48 "H" */ + 0x417f, 0x4100, /* 73 0x49 "I" */ + 0x2040, 0x3f00, /* 74 0x4a "J" */ + 0x7f08, 0x7700, /* 75 0x4b "K" */ + 0x7f40, 0x4000, /* 76 0x4c "L" */ + 0x7f06, 0x7f00, /* 77 0x4d "M" */ + 0x7f01, 0x7e00, /* 78 0x4e "N" */ + 0x3e41, 0x3e00, /* 79 0x4f "O" */ + 0x7f09, 0x0600, /* 80 0x50 "P" */ + 0x3e61, 0x7e00, /* 81 0x51 "Q" */ + 0x7f09, 0x7600, /* 82 0x52 "R" */ + 0x2649, 0x3200, /* 83 0x53 "S" */ + 0x017f, 0x0100, /* 84 0x54 "T" */ + 0x3f40, 0x7f00, /* 85 0x55 "U" */ + 0x1f60, 0x1f00, /* 86 0x56 "V" */ + 0x7f30, 0x7f00, /* 87 0x57 "W" */ + 0x7708, 0x7700, /* 88 0x58 "X" */ + 0x0778, 0x0700, /* 89 0x59 "Y" */ + 0x7149, 0x4700, /* 90 0x5a "Z" */ + 0x007f, 0x4100, /* 91 0x5b "[" */ + 0x031c, 0x6000, /* 92 0x5c "\" */ + 0x417f, 0x0000, /* 93 0x5d "]" */ + 0x0201, 0x0200, /* 94 0x5e "^" */ + 0x8080, 0x8000, /* 95 0x5f "_" */ + 0x0001, 0x0200, /* 96 0x60 "`" */ + 0x2454, 0x7800, /* 97 0x61 "a" */ + 0x7f44, 0x3800, /* 98 0x62 "b" */ + 0x3844, 0x2800, /* 99 0x63 "c" */ + 0x3844, 0x7f00, /* 100 0x64 "d" */ + 0x3854, 0x5800, /* 101 0x65 "e" */ + 0x087e, 0x0900, /* 102 0x66 "f" */ + 0x4854, 0x3c00, /* 103 0x67 "g" */ + 0x7f04, 0x7800, /* 104 0x68 "h" */ + 0x047d, 0x0000, /* 105 0x69 "i" */ + 0x2040, 0x3d00, /* 106 0x6a "j" */ + 0x7f10, 0x6c00, /* 107 0x6b "k" */ + 0x017f, 0x0000, /* 108 0x6c "l" */ + 0x7c18, 0x7c00, /* 109 0x6d "m" */ + 0x7c04, 0x7800, /* 110 0x6e "n" */ + 0x3844, 0x3800, /* 111 0x6f "o" */ + 0x7c14, 0x0800, /* 112 0x70 "p" */ + 0x0814, 0x7c00, /* 113 0x71 "q" */ + 0x7c04, 0x0800, /* 114 0x72 "r" */ + 0x4854, 0x2400, /* 115 0x73 "s" */ + 0x043e, 0x4400, /* 116 0x74 "t" */ + 0x3c40, 0x7c00, /* 117 0x75 "u" */ + 0x1c60, 0x1c00, /* 118 0x76 "v" */ + 0x7c30, 0x7c00, /* 119 0x77 "w" */ + 0x6c10, 0x6c00, /* 120 0x78 "x" */ + 0x4c50, 0x3c00, /* 121 0x79 "y" */ + 0x6454, 0x4c00, /* 122 0x7a "z" */ + 0x0836, 0x4100, /* 123 0x7b "{" */ + 0x0077, 0x0000, /* 124 0x7c "|" */ + 0x4136, 0x0800, /* 125 0x7d "}" */ + 0x0201, 0x0201, /* 126 0x7e "~" */ + 0x0205, 0x0200, /* 127 0x7f */ }; diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..edcc19d --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,4 @@ +*.bin +*.dasm16 +*.xxd +*.txt diff --git a/tests/fetch.sh b/tests/fetch.sh new file mode 100755 index 0000000..5cf96da --- /dev/null +++ b/tests/fetch.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +SITE=https://bisqwit.iki.fi/jutut/kuvat/programming_examples/dcpu16/ +FILES=( + ins_test_v1_dat.dasm16 + ins_test_v2.dasm16 ins_test_v2_dat.dasm16 ins_test_v2_doc.txt + ins_test_v3_dat.dasm16 ins_test_v3_doc.txt + ins_test_v4.dasm16 ins_test_v4_dat.dasm16 ins_test_v4_doc.txt + ins_test_v5.dasm16 ins_test_v5_dat.dasm16 ins_test_v5_doc.txt +) + +for f in ${FILES[*]} ; do + if [ \! -f ${f} ] ; then + echo "Downloading ${f}" + wget -4 --quiet "${SITE}${f}" + fi +done + +for f in *_dat.dasm16 ; do + hd="${f}.xxd" + if [ \! -f ${hd} ] ; then + echo "Creating ${hd}" + awk 'BEGIN {printf("%08d: ", 0)} {printf("%04x ", $2)} NR%8==0 {printf("\n%08x: ", 2*NR)} END {printf("\n")}' <${f} >${hd} + fi +done + +for hd in *_dat.dasm16.xxd ; do + bin=$(echo "${hd}" | sed 's/_dat.dasm16.xxd$/.bin/') + if [ \! -f ${bin} ] ; then + echo "Creating ${bin}" + xxd -r <${hd} | dd if=/dev/stdin of=${bin} bs=2 conv=swab >${bin} + fi +done From 7232d1bf6fc58a8f49786b471730b1d6f460c5bd Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Wed, 29 Apr 2020 22:48:44 +0100 Subject: [PATCH 20/20] Properly handle shifted keys. Allow ignoring keyboard modifiers. --- dev_lem1802.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/dev_lem1802.c b/dev_lem1802.c index a55a3a3..969eedd 100644 --- a/dev_lem1802.c +++ b/dev_lem1802.c @@ -59,6 +59,8 @@ uint8_t kbuf[KBUF_SIZE]; uint8_t khead, klen; uint16_t kint; +bool ignore_modifiers = false; + void update_glyph_tiles() { SDL_SetSurfacePalette(glyph_shapes, palette); @@ -160,15 +162,14 @@ void lem1802_free() // SDL_Quit(); } -void process_key(SDL_KeyboardEvent *ke) +void process_key(SDL_Event *e) { uint8_t k=0; - if ((ke->keysym.sym >= 0x20) && (ke->keysym.sym <= 0x7f)) { - k = ke->keysym.sym; - // printf("sym=%d mod=%d\n", k, ke->keysym.mod); - } else { - switch (ke->keysym.sym) { + if ((e->type == SDL_TEXTINPUT) && (e->text.text[0] >= 0x20) && (e->text.text[0] <= 0x7f)) + k = e->text.text[0]; + else if (e->type == SDL_KEYDOWN) { + switch (e->key.keysym.sym) { case SDLK_BACKSPACE: k = 0x10; break; @@ -196,11 +197,13 @@ void process_key(SDL_KeyboardEvent *ke) break; case SDLK_LSHIFT: case SDLK_RSHIFT: - k = 0x90; + if (!ignore_modifiers) + k = 0x90; break; case SDLK_LCTRL: case SDLK_RCTRL: - k = 0x91; + if (!ignore_modifiers) + k = 0x91; break; default: break; @@ -240,8 +243,14 @@ void lem1802_tick() else if (e.key.keysym.sym == SDLK_F11) { update_font(); update_palette(); + } else if (e.key.keysym.sym == SDLK_F10) { + ignore_modifiers = !ignore_modifiers; } else - process_key(&e.key); + process_key(&e); + } + if (e.type == SDL_TEXTINPUT) { + // printf("Text input: %s\n", &e.text.text); + process_key(&e); } }