From aedf6873a788c93d5dcb16ff80cbe0234a59bf29 Mon Sep 17 00:00:00 2001 From: Maurizio Porrato Date: Sat, 19 Oct 2019 09:31:07 +0100 Subject: [PATCH] Initial commit --- .gitignore | 5 + Makefile | 15 ++ data/c64-80x25-font.png | Bin 0 -> 3330 bytes docs/README.md | 39 ++++ docs/clock.txt | 17 ++ docs/dcpu16.txt | 212 +++++++++++++++++ docs/keyboard.txt | 31 +++ docs/lem1802.txt | 106 +++++++++ docs/m35fd.txt | 102 ++++++++ docs/spc2000.txt | 84 +++++++ docs/sped3.txt | 109 +++++++++ dsim.c | 500 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 1220 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 data/c64-80x25-font.png create mode 100644 docs/README.md create mode 100644 docs/clock.txt create mode 100644 docs/dcpu16.txt create mode 100644 docs/keyboard.txt create mode 100644 docs/lem1802.txt create mode 100644 docs/m35fd.txt create mode 100644 docs/spc2000.txt create mode 100644 docs/sped3.txt create mode 100644 dsim.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f031d1e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*% +*~ +*.o +*.orig +dsim diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c12a8bd --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +.PHONY: all clean reformat + +CFLAGS=-Wall -Werror -pedantic -std=c99 -O2 -mtune=native +REFORMAT=astyle --style=linux + +all: dsim + +clean: + $(RM) *~ *% *.o *.orig + $(RM) dsim + +reformat: $(wildcard *.c) + $(REFORMAT) $^ + +# vim:noet:sw=8:sts=8: diff --git a/data/c64-80x25-font.png b/data/c64-80x25-font.png new file mode 100644 index 0000000000000000000000000000000000000000..a09e9ea6cdaae801e180f9350b1a98b0e8799d71 GIT binary patch literal 3330 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 (treats b, + | | | a as unsigned) + 2 | 0x05 | MLI b, a | like MUL, but treat b, a as signed + 3 | 0x06 | DIV b, a | sets b to b/a, sets EX to ((b<<16)/a)&0xffff. if a==0, + | | | sets b and EX to 0 instead. (treats b, a as unsigned) + 3 | 0x07 | DVI b, a | like DIV, but treat b, a as signed. Rounds towards 0 + 3 | 0x08 | MOD b, a | sets b to b%a. if a==0, sets b to 0 instead. + 3 | 0x09 | MDI b, a | like MOD, but treat b, a as signed. (MDI -7, 16 == -7) + 1 | 0x0a | AND b, a | sets b to b&a + 1 | 0x0b | BOR b, a | sets b to b|a + 1 | 0x0c | XOR b, a | sets b to b^a + 1 | 0x0d | SHR b, a | sets b to b>>>a, sets EX to ((b<<16)>>a)&0xffff + | | | (logical shift) + 1 | 0x0e | ASR b, a | sets b to b>>a, sets EX to ((b<<16)>>>a)&0xffff + | | | (arithmetic shift) (treats b as signed) + 1 | 0x0f | SHL b, a | sets b to b<>16)&0xffff + + 2+| 0x10 | IFB b, a | performs next instruction only if (b&a)!=0 + 2+| 0x11 | IFC b, a | performs next instruction only if (b&a)==0 + 2+| 0x12 | IFE b, a | performs next instruction only if b==a + 2+| 0x13 | IFN b, a | performs next instruction only if b!=a + 2+| 0x14 | IFG b, a | performs next instruction only if b>a + 2+| 0x15 | IFA b, a | performs next instruction only if b>a (signed) + 2+| 0x16 | IFL b, a | performs next instruction only if b +#include +#include +#include + +uint16_t ram[0x10000]; +uint16_t ra, rb, rc, rx, ry, rz, ri, rj; +uint16_t rpc, rsp, rex, ria; +bool skip_next; +uint64_t ticks; +bool running; +bool intq_en; +#define MAX_INTQ_SIZE 256 +uint16_t intq[MAX_INTQ_SIZE]; +unsigned int intq_size; +uint8_t intq_head; + +void intq_push(uint16_t v) +{ + if (intq_size < MAX_INTQ_SIZE) { + intq[intq_head] = v; + intq_head = (intq_head + 1) % MAX_INTQ_SIZE; + intq_size++; + } +} + +uint16_t intq_pop() +{ + if (intq_size > 0) { + return intq[(intq_head-intq_size--) % MAX_INTQ_SIZE]; + } else + return 0xffff; +} + +void reset() +{ + ra = rb = rc = rx = ry = rz = ri = rj = 0; + rpc = rsp = rex = ria = 0; + + intq_en = false; + intq_size = 0; + intq_head = 0; + + skip_next = false; + ticks = 0; + + running = true; +} + +typedef void (*dev_t)(void); + +struct dev_entry { + uint32_t vendor; + uint32_t product; + uint16_t version; + 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) +{ + switch (operand) { + case 0x00: + return &ra; + case 0x01: + return &rb; + case 0x02: + return &rc; + case 0x03: + return ℞ + case 0x04: + return &ry; + case 0x05: + return &rz; + case 0x06: + return &ri; + case 0x07: + return &rj; + case 0x08: + return &ram[ra]; + case 0x09: + return &ram[rb]; + case 0x0a: + return &ram[rc]; + case 0x0b: + return &ram[rx]; + case 0x0c: + return &ram[ry]; + case 0x0d: + return &ram[rz]; + case 0x0e: + return &ram[ri]; + case 0x0f: + return &ram[rj]; + case 0x10: + ticks++; + return &ram[ra+ram[rpc++]]; + case 0x11: + ticks++; + return &ram[rb+ram[rpc++]]; + case 0x12: + ticks++; + return &ram[rc+ram[rpc++]]; + case 0x13: + ticks++; + return &ram[rx+ram[rpc++]]; + case 0x14: + ticks++; + return &ram[ry+ram[rpc++]]; + case 0x15: + ticks++; + return &ram[rz+ram[rpc++]]; + case 0x16: + ticks++; + return &ram[ri+ram[rpc++]]; + case 0x17: + ticks++; + return &ram[rj+ram[rpc++]]; + case 0x18: + return (is_a ? &ram[rsp++] : &ram[--rsp]); + case 0x19: + return &ram[rsp]; + case 0x1a: + ticks++; + return &ram[rsp+ram[rpc++]]; + case 0x1b: + return &rsp; + case 0x1c: + return &rpc; + case 0x1d: + return &rex; + case 0x1e: + ticks++; + return &ram[ram[rpc++]]; + case 0x1f: + ticks++; + return &ram[rpc++]; /* FIXME: write to literal */ + default: + return &lit[operand-0x20]; + } +} + +void oNOP(uint16_t *pa, uint16_t *pb) +{ +} + +void oSET(uint16_t *a, uint16_t *b) +{ + *b = *a; +} + +void oADD(uint16_t *a, uint16_t *b) +{ + uint16_t pre = *b; + + *b += *a; + rex = (pre>*b ? 0x0001 : 0x0000); + ticks++; +} + +void oSUB(uint16_t *a, uint16_t *b) +{ + uint16_t pre = *b; + + *b -= *a; + rex = (pre<*b ? 0xffff : 0x0000); + ticks++; +} + +void oMUL(uint16_t *a, uint16_t *b) +{ + uint32_t res = *b * *a; + + *b = res & 0xffff; + rex = (res>>16) & 0xffff; + ticks++; +} + +void oMLI(uint16_t *a, uint16_t *b) +{ + int32_t res = (int16_t)*a * (int16_t)*b; + + *b = (uint32_t)res & 0xffff; + rex = ((uint32_t)res>>16) & 0xffff; + ticks++; +} + +void oDIV(uint16_t *a, uint16_t *b) +{ + if (*a) { + rex = ((uint32_t)*b<<16) / *a; + *b /= *a; + } else { + *b = rex = 0; + } +} + +void oDVI(uint16_t *a, uint16_t *b) +{ + if (*a) { + rex = ((int32_t)*b<<16) / (int16_t)*a; + *b = (int16_t)*b / (int16_t)*a; + } else { + *b = rex = 0; + } +} + +void oMOD(uint16_t *a, uint16_t *b) +{ + if (*a) { + *b %= *a; + } else { + *b = 0; + } +} + +void oMDI(uint16_t *a, uint16_t *b) +{ + if (*a) { + *b = (int16_t)*b / (int16_t)*a; + } else { + *b = 0; + } +} + +void oAND(uint16_t *a, uint16_t *b) +{ + *b &= *a; +} + +void oBOR(uint16_t *a, uint16_t *b) +{ + *b |= *a; +} + +void oXOR(uint16_t *a, uint16_t *b) +{ + *b ^= *a; +} + +void oSHR(uint16_t *a, uint16_t *b) +{ + uint16_t t; + + t = (uint32_t)*b >> *a; + rex = ((uint64_t)*b << 16) >> *a; + *b = t; +} + +void oASR(uint16_t *a, uint16_t *b) +{ + uint16_t t; + + t = *b >> *a; + rex = ((uint32_t)*b << 16) >> *a; + *b = t; +} + +void oSHL(uint16_t *a, uint16_t *b) +{ + uint16_t t; + + t = *b << *a; + rex = ((uint64_t)*b << *a) >> 16; + *b = t; +} + +#define DOIF(c) if (!(c)) skip_next = true + +void oIFB(uint16_t *a, uint16_t *b) +{ + DOIF((*b & *a) != 0); +} + +void oIFC(uint16_t *a, uint16_t *b) +{ + DOIF((*b & *a) == 0); +} + +void oIFE(uint16_t *a, uint16_t *b) +{ + DOIF(*b == *a); +} + +void oIFN(uint16_t *a, uint16_t *b) +{ + DOIF(*b != *a); +} + +void oIFG(uint16_t *a, uint16_t *b) +{ + DOIF(*b > *a); +} + +void oIFA(uint16_t *a, uint16_t *b) +{ + DOIF((int16_t)*b > (int16_t)*a); +} + +void oIFL(uint16_t *a, uint16_t *b) +{ + DOIF(*b < *a); +} + +void oIFU(uint16_t *a, uint16_t *b) +{ + DOIF((int16_t)*b < (int16_t)*a); +} + +void oADX(uint16_t *a, uint16_t *b) +{ + uint16_t t = *b; + + *b += *a + rex; + rex = (t>*b ? 0x0001 : 0x0000); + ticks += 2; +} + +void oSBX(uint16_t *a, uint16_t *b) +{ + uint16_t t = *b; + + *b -= *a - rex; + rex = (t<*b ? 0xffff : 0x0000); + ticks += 2; +} + +void oSTI(uint16_t *a, uint16_t *b) +{ + *b = *a; + ri++; + rj++; + ticks++; +} + +void oSTD(uint16_t *a, uint16_t *b) +{ + *b = *a; + ri--; + rj--; + ticks++; +} + +void oJSR(uint16_t *a, uint16_t *b) +{ + ram[--rsp] = rpc; + rpc = *a; +} + +void oINT(uint16_t *a, uint16_t *b) +{ + intq_push(*a); + ticks += 3; +} + +void oIAG(uint16_t *a, uint16_t *b) +{ + *a = ria; +} + +void oIAS(uint16_t *a, uint16_t *b) +{ + ria = *a; +} + +void oRFI(uint16_t *a, uint16_t *b) +{ + intq_en = false; + ra = ram[rsp++]; + rpc = ram[rsp++]; +} + +void oIAQ(uint16_t *a, uint16_t *b) +{ + intq_en = (*a != 0); +} + +void oHWN(uint16_t *a, uint16_t *b) +{ + *a = sizeof(iodevs) / sizeof(struct dev_entry); +} + +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; + } else { + ra = rb = rc = rx = ry = 0; + } +} + +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(); + } +} + +void oHLT(uint16_t *a, uint16_t *b) +{ + running = false; +} + +typedef void (*op_t)(uint16_t *, uint16_t *); + +const op_t ops[] = { + oNOP, 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 */ +}; + +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 */ +}; + +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() +{ + uint16_t ir; + int opcode, a, b; + uint16_t *pa, *pb; + op_t f; + uint16_t i; + + if ((!intq_en) && (intq_size > 0)) { + i = intq_pop(); + if (ria != 0) { + intq_en = true; + ram[--rsp] = rpc; + ram[--rsp] = ra; + rpc = ria; + ra = i; + } + } + + dumpregs(); + + ir = ram[rpc++]; + + opcode = ir & 0x001f; + a = (ir >> 5) & 0x001f; + b = (ir >> 10) & 0x003f; + + if (opcode == 0) { /* special instruction */ + f = sops[b]; + pa = val(a, true); + pb = NULL; + } else { + f = ops[opcode]; + pa = val(a, true); + pb = val(b, false); + } + + if (!skip_next) + f(pa, pb); + else + skip_next = false; + + ticks++; +} + +int main() +{ + reset(); + while (running) next(); + return EXIT_SUCCESS; +}