Merge branch 'master' of git.worn.eu:guru/dcpu16
This commit is contained in:
commit
d7302226ea
|
@ -1,5 +1,8 @@
|
||||||
*%
|
*%
|
||||||
*~
|
*~
|
||||||
|
.vscode/
|
||||||
*.o
|
*.o
|
||||||
*.orig
|
*.orig
|
||||||
dsim
|
dsim
|
||||||
|
*.asm
|
||||||
|
*.bin
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -1,10 +1,16 @@
|
||||||
.PHONY: all clean reformat
|
.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
|
REFORMAT=astyle --style=linux
|
||||||
|
DEVICES=$(patsubst %.c,%.o,$(wildcard dev_*.c))
|
||||||
|
|
||||||
all: dsim
|
all: dsim
|
||||||
|
|
||||||
|
dsim: dsim.o device.o $(DEVICES)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) *~ *% *.o *.orig
|
$(RM) *~ *% *.o *.orig
|
||||||
$(RM) dsim
|
$(RM) dsim
|
||||||
|
|
115
asm.py
115
asm.py
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from rply import ParserGenerator, LexerGenerator
|
from rply import ParserGenerator, LexerGenerator
|
||||||
|
import struct
|
||||||
|
|
||||||
OPS = {
|
OPS = {
|
||||||
'ADD': lambda a, b: a + b,
|
'ADD': lambda a, b: a + b,
|
||||||
|
@ -15,8 +16,8 @@ OPCODES = {
|
||||||
'MLI': (0x05, None), 'DIV': (0x06, None), 'DVI': (0x07, None), 'MOD': (0x08, None),
|
'MLI': (0x05, None), 'DIV': (0x06, None), 'DVI': (0x07, None), 'MOD': (0x08, None),
|
||||||
'MDI': (0x09, None), 'AND': (0x0a, None), 'BOR': (0x0b, None), 'XOR': (0x0c, 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),
|
'SHR': (0x0d, None), 'ASR': (0x0e, None), 'SHL': (0x0f, None), 'IFB': (0x10, None),
|
||||||
'IFC': (0x11, None), 'IFE': (0x12, None), 'IFN': (0x13, None), 'ING': (0x14, None),
|
'IFC': (0x11, None), 'IFE': (0x12, None), 'IFN': (0x13, None), 'IFG': (0x14, None),
|
||||||
'INA': (0x15, None), 'INL': (0x16, None), 'INU': (0x17, None), 'ADX': (0x1a, None),
|
'IFA': (0x15, None), 'IFL': (0x16, None), 'IFU': (0x17, None), 'ADX': (0x1a, None),
|
||||||
'SBX': (0x1b, None), 'STI': (0x1e, None), 'STD': (0x1f, None),
|
'SBX': (0x1b, None), 'STI': (0x1e, None), 'STD': (0x1f, None),
|
||||||
|
|
||||||
'JSR': (0x00, 0x01), 'INT': (0x00, 0x08), 'IAG': (0x00, 0x09), 'IAS': (0x00, 0x0a),
|
'JSR': (0x00, 0x01), 'INT': (0x00, 0x08), 'IAG': (0x00, 0x09), 'IAS': (0x00, 0x0a),
|
||||||
|
@ -31,11 +32,13 @@ REGISTERS = {
|
||||||
'I': 0x06, 'J': 0x07, 'SP': 0x1b, 'PC': 0x1c, 'EX': 0x1d
|
'I': 0x06, 'J': 0x07, 'SP': 0x1b, 'PC': 0x1c, 'EX': 0x1d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ASM(SimpleNamespace):
|
class ASM(SimpleNamespace):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def addr(arg, is_a):
|
def addr(arg, is_a):
|
||||||
if type(arg) == Expr:
|
if type(arg) == Expr:
|
||||||
arg = arg.value
|
return (0x1f, arg)
|
||||||
if type(arg) == Register:
|
if type(arg) == Register:
|
||||||
return (REGISTERS[arg.name], None)
|
return (REGISTERS[arg.name], None)
|
||||||
elif type(arg) == int:
|
elif type(arg) == int:
|
||||||
|
@ -44,20 +47,16 @@ class ASM(SimpleNamespace):
|
||||||
else:
|
else:
|
||||||
return (0x1f, arg)
|
return (0x1f, arg)
|
||||||
elif type(arg) == Indirect:
|
elif type(arg) == Indirect:
|
||||||
if type(arg.disp) == Expr:
|
|
||||||
disp = arg.disp.value
|
|
||||||
else:
|
|
||||||
disp = arg.disp
|
|
||||||
if arg.reg is None:
|
if arg.reg is None:
|
||||||
return (0x1e, disp)
|
return (0x1e, arg.disp)
|
||||||
else:
|
else:
|
||||||
if arg.reg == 'SP':
|
if arg.reg == 'SP':
|
||||||
sp = getattr(arg, 'sp', None)
|
sp = getattr(arg, 'sp', None)
|
||||||
if sp is None:
|
if sp is None:
|
||||||
if disp == 0:
|
if arg.disp == 0:
|
||||||
return (0x19, None)
|
return (0x19, None)
|
||||||
else:
|
else:
|
||||||
return (0x1a, disp)
|
return (0x1a, arg.disp)
|
||||||
else:
|
else:
|
||||||
if (sp, is_a) not in (('inc', True), ('dec', False)):
|
if (sp, is_a) not in (('inc', True), ('dec', False)):
|
||||||
raise SyntaxError()
|
raise SyntaxError()
|
||||||
|
@ -66,10 +65,16 @@ class ASM(SimpleNamespace):
|
||||||
elif arg.reg in ('PC', 'EX'):
|
elif arg.reg in ('PC', 'EX'):
|
||||||
raise SyntaxError()
|
raise SyntaxError()
|
||||||
else:
|
else:
|
||||||
if arg.disp == 0:
|
if hasattr(type(arg.reg), "getstr"):
|
||||||
return (0x08+REGISTERS[arg.reg], None)
|
r = arg.reg.getstr()
|
||||||
else:
|
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], arg.disp)
|
||||||
|
|
||||||
def code(self):
|
def code(self):
|
||||||
o, b = OPCODES[self.op]
|
o, b = OPCODES[self.op]
|
||||||
a_bits, a_extra = self.addr(self.a, True)
|
a_bits, a_extra = self.addr(self.a, True)
|
||||||
|
@ -81,24 +86,12 @@ class ASM(SimpleNamespace):
|
||||||
for e in a_extra, b_extra:
|
for e in a_extra, b_extra:
|
||||||
if e is not None:
|
if e is not None:
|
||||||
r.append(e)
|
r.append(e)
|
||||||
|
print("Assembing: %s %r, %r -> %r" % (self.op, self.b, self.a, r))
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def words(self):
|
def words(self):
|
||||||
r = 1
|
return len(self.code())
|
||||||
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
|
|
||||||
|
|
||||||
class Expr(SimpleNamespace):
|
class Expr(SimpleNamespace):
|
||||||
def eval(self, ctx):
|
def eval(self, ctx):
|
||||||
|
@ -205,13 +198,14 @@ def none(p):
|
||||||
@pg.production("line : EOL")
|
@pg.production("line : EOL")
|
||||||
def line(p):
|
def line(p):
|
||||||
label = None
|
label = None
|
||||||
|
instr = Directive(label=None, directive=None, args=None)
|
||||||
for t in p:
|
for t in p:
|
||||||
if type(t) in (ASM, Directive):
|
if type(t) in (ASM, Directive):
|
||||||
t.label = label
|
instr = t
|
||||||
return t
|
|
||||||
elif t.gettokentype() == 'SYMBOL':
|
elif t.gettokentype() == 'SYMBOL':
|
||||||
label = t.getstr()
|
label = t.getstr()
|
||||||
return None
|
instr.label = label
|
||||||
|
return instr
|
||||||
|
|
||||||
@pg.production("op : OP2 arg_b COMMA arg_a")
|
@pg.production("op : OP2 arg_b COMMA arg_a")
|
||||||
def op_op2(p):
|
def op_op2(p):
|
||||||
|
@ -340,60 +334,65 @@ def expr_sym(p):
|
||||||
lexer = lg.build()
|
lexer = lg.build()
|
||||||
parser = pg.build()
|
parser = pg.build()
|
||||||
|
|
||||||
def assemble(ctx, inst, step=1):
|
def assemble(ctx, inst):
|
||||||
if inst.label is not None:
|
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']
|
ctx[inst.label] = ctx['.addr']
|
||||||
if type(inst) == Directive:
|
if type(inst) == Directive:
|
||||||
if inst.directive == ".org":
|
if inst.directive == ".org":
|
||||||
ctx['.addr'] = inst.args.eval(ctx)
|
ctx['.addr'] = inst.args.eval(ctx)
|
||||||
|
return None
|
||||||
elif inst.directive in (".data", ".word", "DAT"):
|
elif inst.directive in (".data", ".word", "DAT"):
|
||||||
al = []
|
al = []
|
||||||
for a in inst.args:
|
for a in inst.args:
|
||||||
if type(a) == str:
|
if type(a) == str:
|
||||||
al.extend([ord(x) for x in a])
|
al.extend([ord(x) for x in a])
|
||||||
else:
|
else:
|
||||||
if step == 1:
|
al.append(a.simplify(ctx))
|
||||||
al.append(a)
|
|
||||||
else:
|
|
||||||
al.append(a.eval(ctx))
|
|
||||||
if step > 1:
|
|
||||||
print(ctx['.addr'], al)
|
|
||||||
ctx['.addr'] += len(al)
|
ctx['.addr'] += len(al)
|
||||||
|
return al
|
||||||
elif type(inst) == ASM:
|
elif type(inst) == ASM:
|
||||||
try:
|
if type(inst.a) == Expr:
|
||||||
if type(inst.a) == Expr:
|
inst.a = inst.a.simplify(ctx)
|
||||||
inst.a = inst.a.eval(ctx)
|
if type(inst.b) == Expr:
|
||||||
if type(inst.b) == Expr:
|
inst.b = inst.b.simplify(ctx)
|
||||||
inst.b = inst.b.eval(ctx)
|
|
||||||
except KeyError as e:
|
|
||||||
if step != 1:
|
|
||||||
raise e
|
|
||||||
if inst.b is not None:
|
if inst.b is not None:
|
||||||
print(f"{ctx['.addr']} {inst.op} {inst.b}, {inst.a} [len={inst.words()}]")
|
print(f"{ctx['.addr']} {inst.op} {inst.b}, {inst.a} [len={inst.words()}]")
|
||||||
else:
|
else:
|
||||||
print(f"{ctx['.addr']} {inst.op} {inst.a} [len={inst.words()}]")
|
print(f"{ctx['.addr']} {inst.op} {inst.a} [len={inst.words()}]")
|
||||||
|
|
||||||
ctx['.addr'] += inst.words()
|
ctx['.addr'] += inst.words()
|
||||||
|
return inst.code()
|
||||||
if step != 1:
|
|
||||||
return inst.code()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
sym = {}
|
sym = {}
|
||||||
sym['.addr'] = 0
|
sym['.addr'] = 0
|
||||||
|
insns = []
|
||||||
for filename in sys.argv[1:]:
|
for filename in sys.argv[1:]:
|
||||||
with open(filename, 'r') as sourcefile:
|
with open(filename, 'r') as sourcefile:
|
||||||
code = parser.parse(lexer.lex(sourcefile.read()))
|
code = parser.parse(lexer.lex(sourcefile.read()))
|
||||||
for inst in code:
|
for inst in code: # pylint: disable=E1133
|
||||||
# print(sym['.addr'], inst)
|
# 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(sym)
|
||||||
|
print(insns)
|
||||||
sym['.addr'] = 0
|
sym['.addr'] = 0
|
||||||
for inst in code:
|
binimage = b''
|
||||||
a = assemble(sym, inst, 2)
|
for a, c in insns: # pylint: disable=E1133
|
||||||
if a is not None:
|
words = []
|
||||||
print(["%04x" % x for x in a])
|
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("<H", w)
|
||||||
|
outfilename = filename[:filename.rfind('.')]+'.bin'
|
||||||
|
with open(outfilename, 'wb') as binfile:
|
||||||
|
binfile.write(binimage)
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 618 B |
|
@ -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 <stdint.h>
|
||||||
|
|
||||||
|
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]):
|
||||||
|
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{h:04x}, 0x{l:04x},\t/* {ch:3d} 0x{ch:02x} {d}*/")
|
||||||
|
ch += 1
|
||||||
|
print("};")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
|
||||||
|
for fn in sys.argv[1:]:
|
||||||
|
convert(fn)
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#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 */
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#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<count; i++) {
|
||||||
|
a = (addr + i) % sizeof(ram);
|
||||||
|
if ((i % 8) == 0)
|
||||||
|
printf("\n%04x: ", a);
|
||||||
|
printf("%04x ", ram[a]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_tick()
|
||||||
|
{
|
||||||
|
if (trace)
|
||||||
|
dumpregs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_irqh()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dev_entry debug_dev = { 0x6d53647c, 0x62e037d3, 0x0000, debug_irqh, NULL, NULL, debug_tick }; /* Debug device */
|
|
@ -0,0 +1,377 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#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<<BPP)
|
||||||
|
|
||||||
|
#define SCREEN_W (TEXT_COLS*CHAR_W)
|
||||||
|
#define SCREEN_H (TEXT_ROWS*CHAR_H)
|
||||||
|
|
||||||
|
#define SURFACE_W (BORDER_L+SCREEN_W+BORDER_R)
|
||||||
|
#define SURFACE_H (BORDER_T+SCREEN_H+BORDER_B)
|
||||||
|
|
||||||
|
#define WINDOW_W (SURFACE_W*ZOOM)
|
||||||
|
#define WINDOW_H (SURFACE_H*ZOOM)
|
||||||
|
|
||||||
|
uint16_t screen_iptr;
|
||||||
|
uint16_t font_iptr;
|
||||||
|
uint16_t palette_iptr;
|
||||||
|
uint16_t border;
|
||||||
|
|
||||||
|
#define PALETTE(x) (palette_iptr ? ram[(palette_iptr+(x))&0xffff] : default_palette[x])
|
||||||
|
#define FONT(x) (font_iptr ? ram[(font_iptr+(x))&0xffff] : default_font[x])
|
||||||
|
#define SCREEN(x) (ram[(screen_iptr+(x))&0xffff])
|
||||||
|
|
||||||
|
#include "font.c"
|
||||||
|
#include "palette.c"
|
||||||
|
|
||||||
|
SDL_Window *window = NULL;
|
||||||
|
SDL_Surface *screenSurface = NULL;
|
||||||
|
SDL_Surface *glyph_shapes = NULL;
|
||||||
|
SDL_Surface *glyph_tiles = NULL;
|
||||||
|
SDL_Palette *palette = NULL;
|
||||||
|
|
||||||
|
struct timeval poweron_time;
|
||||||
|
|
||||||
|
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);
|
||||||
|
SDL_BlitSurface(glyph_shapes, NULL, glyph_tiles, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_font()
|
||||||
|
{
|
||||||
|
int x, y, i, j;
|
||||||
|
uint8_t fg, bg;
|
||||||
|
bool pixel;
|
||||||
|
uint8_t *raster;
|
||||||
|
|
||||||
|
printf("update_font()\n");
|
||||||
|
|
||||||
|
SDL_LockSurface(glyph_shapes);
|
||||||
|
raster = (uint8_t *)(glyph_shapes->pixels);
|
||||||
|
for (i=0; i<sizeof(default_font)/sizeof(default_font[0]); i++) {
|
||||||
|
for (j=0; j<16; j++) {
|
||||||
|
x = i*2+(1-j/8);
|
||||||
|
y = j%8;
|
||||||
|
pixel = ((FONT(i)>>j) & 1) != 0;
|
||||||
|
// raster[x+y*glyph_shapes->w] = (pixel ? 1 : 0);
|
||||||
|
for (fg=0; fg<COLORS; fg++)
|
||||||
|
for (bg=0; bg<COLORS; bg++)
|
||||||
|
raster[x+(y+(fg<<4|bg)*CHAR_H)*glyph_shapes->w] = (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; i<COLORS; i++) {
|
||||||
|
palette->colors[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
khead = klen = 0;
|
||||||
|
kint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lem1802_free()
|
||||||
|
{
|
||||||
|
if (window)
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
window = NULL;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_key(SDL_Event *e)
|
||||||
|
{
|
||||||
|
uint8_t k=0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
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:
|
||||||
|
if (!ignore_modifiers)
|
||||||
|
k = 0x90;
|
||||||
|
break;
|
||||||
|
case SDLK_LCTRL:
|
||||||
|
case SDLK_RCTRL:
|
||||||
|
if (!ignore_modifiers)
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
if (e.type == SDL_TEXTINPUT) {
|
||||||
|
// printf("Text input: %s\n", &e.text.text);
|
||||||
|
process_key(&e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<TEXT_ROWS*TEXT_COLS; i++) {
|
||||||
|
cell = ram[(screen_iptr+i) & 0xffff];
|
||||||
|
ch = cell & 0x7f;
|
||||||
|
bl = (cell & 0x80) != 0;
|
||||||
|
bg = (cell >> 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 */
|
||||||
|
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());
|
||||||
|
} else {
|
||||||
|
screenSurface = SDL_GetWindowSurface(window);
|
||||||
|
SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x80, 0x80, 0x80));
|
||||||
|
SDL_UpdateWindowSurface(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rb == 0) {
|
||||||
|
/* LEM1802 power down */
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
window = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
screen_iptr = rb;
|
||||||
|
break;
|
||||||
|
case 1: /* MEM_MAP_FONT */
|
||||||
|
font_iptr = rb;
|
||||||
|
update_font();
|
||||||
|
break;
|
||||||
|
case 2: /* MEM_MAP_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<sizeof(default_font)/sizeof(default_font[0]); i++)
|
||||||
|
ram[(rb+i)&0xffff] = default_font[i];
|
||||||
|
break;
|
||||||
|
case 5: /* MEM_DUMP_PALETTE */
|
||||||
|
printf("Dumping default palette to 0x%04x\n", rb);
|
||||||
|
for (i=0; i<sizeof(default_palette)/sizeof(default_palette[0]); i++)
|
||||||
|
ram[(rb+i)&0xffff] = default_palette[i];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboard_irqh()
|
||||||
|
{
|
||||||
|
switch (ra) {
|
||||||
|
case 0: /* Clear buffer */
|
||||||
|
khead = klen = 0;
|
||||||
|
break;
|
||||||
|
case 1: /* Get next key */
|
||||||
|
if (klen > 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 */
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#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
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef __DEVICE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
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
|
|
@ -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("<H", b)[0]
|
||||||
|
|
||||||
|
def disassemble(filename):
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
pc = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
w = read_word(f)
|
||||||
|
except EOFError:
|
||||||
|
break
|
||||||
|
ins = [w]
|
||||||
|
op = w & 0x1f
|
||||||
|
b = (w >> 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])
|
265
dsim.c
265
dsim.c
|
@ -3,31 +3,52 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
uint16_t ram[0x10000];
|
uint16_t ram[0x10000];
|
||||||
uint16_t ra, rb, rc, rx, ry, rz, ri, rj;
|
uint16_t ra, rb, rc, rx, ry, rz, ri, rj;
|
||||||
uint16_t rpc, rsp, rex, ria;
|
uint16_t rpc, rsp, rex, ria;
|
||||||
|
uint16_t lit_a, lit_b; /* temporary storage for literal operands */
|
||||||
|
|
||||||
bool skip_next;
|
bool skip_next;
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
bool running;
|
bool running;
|
||||||
|
bool trace;
|
||||||
bool intq_en;
|
bool intq_en;
|
||||||
#define MAX_INTQ_SIZE 256
|
#define MAX_INTQ_SIZE 256
|
||||||
uint16_t intq[MAX_INTQ_SIZE];
|
uint16_t intq[MAX_INTQ_SIZE];
|
||||||
unsigned int intq_size;
|
unsigned int intq_size;
|
||||||
uint8_t intq_head;
|
uint8_t intq_head;
|
||||||
|
uint16_t hwn;
|
||||||
|
struct timeval time;
|
||||||
|
|
||||||
|
extern void dumpregs();
|
||||||
|
|
||||||
void intq_push(uint16_t v)
|
void intq_push(uint16_t v)
|
||||||
{
|
{
|
||||||
|
if (ria == 0)
|
||||||
|
return;
|
||||||
if (intq_size < MAX_INTQ_SIZE) {
|
if (intq_size < MAX_INTQ_SIZE) {
|
||||||
intq[intq_head] = v;
|
intq[intq_head] = v;
|
||||||
intq_head = (intq_head + 1) % MAX_INTQ_SIZE;
|
intq_head = (intq_head + 1) % MAX_INTQ_SIZE;
|
||||||
intq_size++;
|
intq_size++;
|
||||||
|
} else {
|
||||||
|
printf("Halt and catch fire!\n");
|
||||||
|
running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t intq_pop()
|
uint16_t intq_pop()
|
||||||
{
|
{
|
||||||
if (intq_size > 0) {
|
if (intq_size > 0) {
|
||||||
return intq[(intq_head-intq_size--) % MAX_INTQ_SIZE];
|
return intq[(intq_head+MAX_INTQ_SIZE-intq_size--) % MAX_INTQ_SIZE];
|
||||||
} else
|
} else
|
||||||
return 0xffff;
|
return 0xffff;
|
||||||
}
|
}
|
||||||
|
@ -44,34 +65,30 @@ void reset()
|
||||||
skip_next = false;
|
skip_next = false;
|
||||||
ticks = 0;
|
ticks = 0;
|
||||||
|
|
||||||
|
trace = false;
|
||||||
running = true;
|
running = true;
|
||||||
|
|
||||||
|
for (hwn = 0; iodevs[hwn] != NULL; hwn++)
|
||||||
|
if (iodevs[hwn]->init)
|
||||||
|
iodevs[hwn]->init();
|
||||||
|
|
||||||
|
printf("Initialized %d devices\n", hwn);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*dev_t)(void);
|
void shutdown()
|
||||||
|
{
|
||||||
struct dev_entry {
|
int i;
|
||||||
uint32_t vendor;
|
for (i = 0; i < hwn; i++)
|
||||||
uint32_t product;
|
if (iodevs[i]->free)
|
||||||
uint16_t version;
|
iodevs[i]->free();
|
||||||
void (*irqh)();
|
}
|
||||||
void (*init)();
|
|
||||||
void (*free)();
|
|
||||||
void (*tick)();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dev_entry iodevs[] = {
|
|
||||||
{ 0, 0, 0, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
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)
|
uint16_t *val(int operand, bool is_a)
|
||||||
{
|
{
|
||||||
|
uint16_t *lit;
|
||||||
|
|
||||||
|
lit = (is_a ? &lit_a : &lit_b);
|
||||||
|
|
||||||
switch (operand) {
|
switch (operand) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
return &ra;
|
return &ra;
|
||||||
|
@ -107,35 +124,35 @@ uint16_t *val(int operand, bool is_a)
|
||||||
return &ram[rj];
|
return &ram[rj];
|
||||||
case 0x10:
|
case 0x10:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[ra+ram[rpc++]];
|
return &ram[(ra+ram[rpc++])&0xffff];
|
||||||
case 0x11:
|
case 0x11:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[rb+ram[rpc++]];
|
return &ram[(rb+ram[rpc++])&0xffff];
|
||||||
case 0x12:
|
case 0x12:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[rc+ram[rpc++]];
|
return &ram[(rc+ram[rpc++])&0xffff];
|
||||||
case 0x13:
|
case 0x13:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[rx+ram[rpc++]];
|
return &ram[(rx+ram[rpc++])&0xffff];
|
||||||
case 0x14:
|
case 0x14:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[ry+ram[rpc++]];
|
return &ram[(ry+ram[rpc++])&0xffff];
|
||||||
case 0x15:
|
case 0x15:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[rz+ram[rpc++]];
|
return &ram[(rz+ram[rpc++])&0xffff];
|
||||||
case 0x16:
|
case 0x16:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[ri+ram[rpc++]];
|
return &ram[(ri+ram[rpc++])&0xffff];
|
||||||
case 0x17:
|
case 0x17:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[rj+ram[rpc++]];
|
return &ram[(rj+ram[rpc++])&0xffff];
|
||||||
case 0x18:
|
case 0x18:
|
||||||
return (is_a ? &ram[rsp++] : &ram[--rsp]);
|
return (is_a ? &ram[(skip_next?rsp:rsp++)] : &ram[(skip_next?rsp-1:--rsp)]);
|
||||||
case 0x19:
|
case 0x19:
|
||||||
return &ram[rsp];
|
return &ram[rsp];
|
||||||
case 0x1a:
|
case 0x1a:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[rsp+ram[rpc++]];
|
return &ram[(rsp+ram[rpc++])&0xffff];
|
||||||
case 0x1b:
|
case 0x1b:
|
||||||
return &rsp;
|
return &rsp;
|
||||||
case 0x1c:
|
case 0x1c:
|
||||||
|
@ -147,9 +164,11 @@ uint16_t *val(int operand, bool is_a)
|
||||||
return &ram[ram[rpc++]];
|
return &ram[ram[rpc++]];
|
||||||
case 0x1f:
|
case 0x1f:
|
||||||
ticks++;
|
ticks++;
|
||||||
return &ram[rpc++]; /* FIXME: write to literal */
|
*lit = ram[rpc++];
|
||||||
|
return lit;
|
||||||
default:
|
default:
|
||||||
return &lit[operand-0x20];
|
*lit = operand - 0x21;
|
||||||
|
return lit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,10 +192,11 @@ void oADD(uint16_t *a, uint16_t *b)
|
||||||
|
|
||||||
void oSUB(uint16_t *a, uint16_t *b)
|
void oSUB(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
uint16_t pre = *b;
|
uint32_t t;
|
||||||
|
|
||||||
*b -= *a;
|
t = *b - *a;
|
||||||
rex = (pre<*b ? 0xffff : 0x0000);
|
*b = t;
|
||||||
|
rex = t >> 16;
|
||||||
ticks++;
|
ticks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,9 +220,13 @@ void oMLI(uint16_t *a, uint16_t *b)
|
||||||
|
|
||||||
void oDIV(uint16_t *a, uint16_t *b)
|
void oDIV(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
|
uint32_t wb, wt;
|
||||||
|
|
||||||
if (*a) {
|
if (*a) {
|
||||||
rex = ((uint32_t)*b<<16) / *a;
|
wb = *b;
|
||||||
*b /= *a;
|
wt = (wb<<16) / *a;
|
||||||
|
rex = wt&0xffff;
|
||||||
|
*b = wt>>16;
|
||||||
} else {
|
} else {
|
||||||
*b = rex = 0;
|
*b = rex = 0;
|
||||||
}
|
}
|
||||||
|
@ -211,7 +235,7 @@ void oDIV(uint16_t *a, uint16_t *b)
|
||||||
void oDVI(uint16_t *a, uint16_t *b)
|
void oDVI(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
if (*a) {
|
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;
|
*b = (int16_t)*b / (int16_t)*a;
|
||||||
} else {
|
} else {
|
||||||
*b = rex = 0;
|
*b = rex = 0;
|
||||||
|
@ -230,7 +254,7 @@ void oMOD(uint16_t *a, uint16_t *b)
|
||||||
void oMDI(uint16_t *a, uint16_t *b)
|
void oMDI(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
if (*a) {
|
if (*a) {
|
||||||
*b = (int16_t)*b / (int16_t)*a;
|
*b = (int16_t)*b % (int16_t)*a;
|
||||||
} else {
|
} else {
|
||||||
*b = 0;
|
*b = 0;
|
||||||
}
|
}
|
||||||
|
@ -253,32 +277,32 @@ void oXOR(uint16_t *a, uint16_t *b)
|
||||||
|
|
||||||
void oSHR(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;
|
t = (((uint32_t)*b) << 16) >> *a;
|
||||||
rex = ((uint64_t)*b << 16) >> *a;
|
*b = t >> 16;
|
||||||
*b = t;
|
rex = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void oASR(uint16_t *a, uint16_t *b)
|
void oASR(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
uint16_t t;
|
int32_t t;
|
||||||
|
|
||||||
t = *b >> *a;
|
t = (((int32_t)*b) << 16) >> *a;
|
||||||
rex = ((uint32_t)*b << 16) >> *a;
|
*b = t >> 16;
|
||||||
*b = t;
|
rex = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void oSHL(uint16_t *a, uint16_t *b)
|
void oSHL(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
uint16_t t;
|
uint32_t t;
|
||||||
|
|
||||||
t = *b << *a;
|
t = ((uint32_t)*b) << *a;
|
||||||
rex = ((uint64_t)*b << *a) >> 16;
|
rex = t >> 16;
|
||||||
*b = t;
|
*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)
|
void oIFB(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
|
@ -374,6 +398,8 @@ void oIAG(uint16_t *a, uint16_t *b)
|
||||||
void oIAS(uint16_t *a, uint16_t *b)
|
void oIAS(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
ria = *a;
|
ria = *a;
|
||||||
|
if (ria == 0)
|
||||||
|
intq_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void oRFI(uint16_t *a, uint16_t *b)
|
void oRFI(uint16_t *a, uint16_t *b)
|
||||||
|
@ -390,19 +416,19 @@ void oIAQ(uint16_t *a, uint16_t *b)
|
||||||
|
|
||||||
void oHWN(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)
|
void oHWQ(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
uint16_t idx = *a;
|
uint16_t idx = *a;
|
||||||
|
|
||||||
if (idx < sizeof(iodevs) / sizeof(struct dev_entry)) {
|
if (idx < hwn) {
|
||||||
ra = iodevs[idx].product & 0xffff;
|
ra = iodevs[idx]->product & 0xffff;
|
||||||
rb = (iodevs[idx].product >> 16) & 0xffff;
|
rb = (iodevs[idx]->product >> 16) & 0xffff;
|
||||||
rc = iodevs[idx].version;
|
rc = iodevs[idx]->version;
|
||||||
rx = iodevs[idx].vendor & 0xffff;
|
rx = iodevs[idx]->vendor & 0xffff;
|
||||||
ry = (iodevs[idx].vendor >> 16) & 0xffff;
|
ry = (iodevs[idx]->vendor >> 16) & 0xffff;
|
||||||
} else {
|
} else {
|
||||||
ra = rb = rc = rx = ry = 0;
|
ra = rb = rc = rx = ry = 0;
|
||||||
}
|
}
|
||||||
|
@ -412,41 +438,28 @@ void oHWI(uint16_t *a, uint16_t *b)
|
||||||
{
|
{
|
||||||
uint16_t idx = *a;
|
uint16_t idx = *a;
|
||||||
|
|
||||||
if (idx < sizeof(iodevs) / sizeof(struct dev_entry)) {
|
if (idx < hwn) {
|
||||||
if (iodevs[idx].irqh)
|
if (iodevs[idx]->irqh)
|
||||||
iodevs[idx].irqh();
|
iodevs[idx]->irqh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void oHLT(uint16_t *a, uint16_t *b)
|
|
||||||
{
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (*op_t)(uint16_t *, uint16_t *);
|
typedef void (*op_t)(uint16_t *, uint16_t *);
|
||||||
|
|
||||||
const op_t ops[] = {
|
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 */
|
oMOD, oMDI, oAND, oBOR, oXOR, oSHR, oASR, oSHL, /* 08-0f */
|
||||||
oIFB, oIFC, oIFE, oIFN, oIFG, oIFA, oIFL, oIFU, /* 10-17 */
|
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[] = {
|
const op_t sops[] = {
|
||||||
oNOP, oJSR, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, /* 00-07 */
|
NULL, oJSR, NULL, NULL, NULL, NULL, NULL, NULL, /* 00-07 */
|
||||||
oINT, oIAG, oIAS, oRFI, oIAQ, oNOP, oNOP, oNOP, /* 08-0f */
|
oINT, oIAG, oIAS, oRFI, oIAQ, NULL, NULL, NULL, /* 08-0f */
|
||||||
oHWN, oHWQ, oHWI, oNOP, oNOP, oNOP, oNOP, oNOP, /* 10-17 */
|
oHWN, oHWQ, oHWI, NULL, NULL, NULL, NULL, NULL, /* 10-17 */
|
||||||
oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oHLT /* 18-1f */
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* 18-1f */
|
||||||
};
|
};
|
||||||
|
|
||||||
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 next()
|
void next()
|
||||||
{
|
{
|
||||||
uint16_t ir;
|
uint16_t ir;
|
||||||
|
@ -455,9 +468,23 @@ void next()
|
||||||
op_t f;
|
op_t f;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
|
||||||
if ((!intq_en) && (intq_size > 0)) {
|
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();
|
i = intq_pop();
|
||||||
if (ria != 0) {
|
if (ria != 0) {
|
||||||
|
printf("Firing interrupt with message 0x%04x\n", i);
|
||||||
intq_en = true;
|
intq_en = true;
|
||||||
ram[--rsp] = rpc;
|
ram[--rsp] = rpc;
|
||||||
ram[--rsp] = ra;
|
ram[--rsp] = ra;
|
||||||
|
@ -465,14 +492,18 @@ void next()
|
||||||
ra = i;
|
ra = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
dumpregs();
|
if (trace)
|
||||||
|
dumpregs();
|
||||||
|
*/
|
||||||
|
// printf("PC: %04x\n", rpc);
|
||||||
|
// dumpregs();
|
||||||
|
|
||||||
ir = ram[rpc++];
|
ir = ram[rpc++];
|
||||||
|
|
||||||
opcode = ir & 0x001f;
|
opcode = ir & 0x001f;
|
||||||
a = (ir >> 5) & 0x001f;
|
a = (ir >> 10) & 0x003f;
|
||||||
b = (ir >> 10) & 0x003f;
|
b = (ir >> 5) & 0x001f;
|
||||||
|
|
||||||
if (opcode == 0) { /* special instruction */
|
if (opcode == 0) { /* special instruction */
|
||||||
f = sops[b];
|
f = sops[b];
|
||||||
|
@ -484,18 +515,68 @@ void next()
|
||||||
pb = val(b, false);
|
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)
|
if (!skip_next)
|
||||||
f(pa, pb);
|
f(pa, pb);
|
||||||
else
|
else
|
||||||
skip_next = false;
|
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();
|
||||||
|
|
||||||
ticks++;
|
ticks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int load_image(char *filename)
|
||||||
{
|
{
|
||||||
reset();
|
int fd;
|
||||||
while (running) next();
|
ssize_t r;
|
||||||
|
ssize_t pos;
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
printf("Loading %s ...\n", filename);
|
||||||
|
fd = open(filename, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return fd;
|
||||||
|
buf = (uint8_t *)ram;
|
||||||
|
for (pos=0;;) {
|
||||||
|
r = read(fd, &buf[pos], sizeof(ram)-pos);
|
||||||
|
if (r > 0)
|
||||||
|
pos += r;
|
||||||
|
else {
|
||||||
|
close(fd);
|
||||||
|
if (r == 0)
|
||||||
|
return pos;
|
||||||
|
else
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc > 1) {
|
||||||
|
load_image(argv[1]);
|
||||||
|
reset();
|
||||||
|
while (running) next();
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint16_t default_font[] = {
|
||||||
|
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 */
|
||||||
|
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 " " */
|
||||||
|
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 */
|
||||||
|
};
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* CGA-like palette */
|
||||||
|
|
||||||
|
uint16_t default_palette[] = {
|
||||||
|
0x0000,
|
||||||
|
0x000a,
|
||||||
|
0x00a0,
|
||||||
|
0x00aa,
|
||||||
|
0x0a00,
|
||||||
|
0x0a0a,
|
||||||
|
0x0a50,
|
||||||
|
0x0aaa,
|
||||||
|
0x0555,
|
||||||
|
0x055f,
|
||||||
|
0x05f5,
|
||||||
|
0x05ff,
|
||||||
|
0x0f55,
|
||||||
|
0x0f5f,
|
||||||
|
0x0ff5,
|
||||||
|
0x0fff,
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.bin
|
||||||
|
*.dasm16
|
||||||
|
*.xxd
|
||||||
|
*.txt
|
|
@ -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
|
Loading…
Reference in New Issue