Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
package computer;
// Referenced classes of package computer:
// KeyMapping
public class AWTKeyMapping extends KeyMapping
{
public AWTKeyMapping()
{
map(38, 128);
map(40, 129);
map(37, 130);
map(39, 131);
}
}
package computer;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.*;
import java.io.*;
import javax.swing.JFrame;
// Referenced classes of package computer:
// VirtualMonitor, VirtualKeyboard, AWTKeyMapping
public class DCPU {
public DCPU() {
ram = new char[0x10000];
registers = new char[8];
}
public int getAddr(int type) {
if (type >= 32)
return 0x20000 | type & 0x1f;
switch (type & 0xf8) {
case 0: // '\0'
return 0x10000 + (type & 7);
case 8: // '\b'
return registers[type & 7];
case 16: // '\020'
cycles++;
return ram[pc++] + registers[type & 7] & 0xffff;
case 24: // '\030'
switch (type & 7) {
case 0: // '\0'
return sp++ & 0xffff;
case 1: // '\001'
return sp & 0xffff;
case 2: // '\002'
return --sp & 0xffff;
case 3: // '\003'
return 0x10008;
case 4: // '\004'
return 0x10009;
case 5: // '\005'
return 0x10010;
case 6: // '\006'
cycles++;
return ram[pc++];
}
cycles++;
return 0x20000 | ram[pc++];
}
throw new IllegalStateException((new StringBuilder(
"Illegal value type ")).append(type)
.append("! How did you manage that!?").toString());
}
public char get(int addr) {
if (addr < 0x10000)
return ram[addr & 0xffff];
if (addr < 0x10008)
return registers[addr & 7];
if (addr >= 0x20000)
return (char) addr;
if (addr == 0x10008)
return sp;
if (addr == 0x10009)
return pc;
if (addr == 0x10010)
return o;
else
throw new IllegalStateException((new StringBuilder(
"Illegal address ")).append(Integer.toHexString(addr))
.append("! How did you manage that!?").toString());
}
public void set(int addr, char val) {
if (addr < 0x10000)
ram[addr & 0xffff] = val;
else if (addr < 0x10008)
registers[addr & 7] = val;
else if (addr < 0x20000)
if (addr == 0x10008)
sp = val;
else if (addr == 0x10009)
pc = val;
else if (addr == 0x10010)
o = val;
else
throw new IllegalStateException((new StringBuilder(
"Illegal address ")).append(Integer.toHexString(addr))
.append("! How did you manage that!?").toString());
}
public static int getInstructionLength(char opcode) {
int len = 1;
int cmd = opcode & 0xf;
if (cmd == 0) {
cmd = opcode >> 4 & 0xf;
if (cmd > 0) {
int atype = opcode >> 10 & 0x3f;
if ((atype & 0xf8) == 16 || atype == 31 || atype == 30)
len++;
}
} else {
int atype = opcode >> 4 & 0x3f;
int btype = opcode >> 10 & 0x3f;
if ((atype & 0xf8) == 16 || atype == 31 || atype == 30)
len++;
if ((btype & 0xf8) == 16 || btype == 31 || btype == 30)
len++;
}
return len;
}
public void skip() {
cycles++;
pc += getInstructionLength(ram[pc++]);
}
public void tick() {
cycles++;
char opcode = ram[pc++];
int cmd = opcode & 0xf;
if (cmd == 0) {
cmd = opcode >> 4 & 0xf;
if (cmd != 0) {
int atype = opcode >> 10 & 0x3f;
int aaddr = getAddr(atype);
char a = get(aaddr);
switch (cmd) {
case 1: // '\001'
ram[--sp & 0xffff] = (char) ((pc - 2) + getInstructionLength(opcode));
pc = a;
break;
}
}
} else {
int atype = opcode >> 4 & 0x3f;
int btype = opcode >> 10 & 0x3f;
int aaddr = getAddr(atype);
char a = get(aaddr);
int baddr = getAddr(btype);
char b = get(baddr);
switch (cmd) {
default:
break;
case 1: // '\001'
{
a = b;
break;
}
case 2: // '\002'
{
cycles++;
int val = a + b;
a = (char) val;
o = (char) (val >> 16);
break;
}
case 3: // '\003'
{
cycles++;
int val = a - b;
a = (char) val;
o = (char) (val >> 16);
break;
}
case 4: // '\004'
{
cycles++;
int val = a * b;
a = (char) val;
o = (char) (val >> 16);
break;
}
case 5: // '\005'
{
cycles += 2;
if (b == 0) {
a = o = '\0';
} else {
long val = ((long) a << 16) / (long) b;
a = (char) (int) (val >> 16);
o = (char) (int) val;
}
break;
}
case 6: // '\006'
{
cycles += 2;
if (b == 0)
a = '\0';
else
a %= b;
break;
}
case 7: // '\007'
{
cycles++;
long val = (long) a << b;
a = (char) (int) val;
o = (char) (int) (val >> 16);
break;
}
case 8: // '\b'
{
cycles++;
long val = (long) a << 16 - b;
a = (char) (int) (val >> 16);
o = (char) (int) val;
break;
}
case 9: // '\t'
{
a &= b;
break;
}
case 10: // '\n'
{
a |= b;
break;
}
case 11: // '\013'
{
a ^= b;
break;
}
case 12: // '\f'
{
cycles++;
if (a != b)
skip();
return;
}
case 13: // '\r'
{
cycles++;
if (a == b)
skip();
return;
}
case 14: // '\016'
{
cycles++;
if (a <= b)
skip();
return;
}
case 15: // '\017'
{
cycles++;
if ((a & b) == 0)
skip();
return;
}
}
set(aaddr, a);
}
}
private static void testCpus(int cpuCount, char ram[]) {
DCPU cpus[] = new DCPU[cpuCount];
for (int i = 0; i < cpuCount; i++) {
cpus[i] = new DCPU();
for (int j = 0; j < 0x10000; j++)
cpus[i].ram[j] = ram[j];
}
long ops = 0L;
int hz = 0x186a0;
int cyclesPerFrame = hz / 60;
long nsPerFrame = 0xfe502aL;
long nextTime = System.nanoTime();
double tick = 0.0D;
double total = 0.0D;
long startTime = System.currentTimeMillis();
while (!stop) {
long a = System.nanoTime();
while (System.nanoTime() < nextTime)
try {
Thread.sleep(1L);
} catch (InterruptedException e) {
e.printStackTrace();
}
long b = System.nanoTime();
for (int j = 0; j < cpuCount; j++) {
while (cpus[j].cycles < cyclesPerFrame)
cpus[j].tick();
cpus[j].cycles -= cyclesPerFrame;
}
long c = System.nanoTime();
ops += cyclesPerFrame;
nextTime += nsPerFrame;
tick += (double) (c - b) / 1000000000D;
total += (double) (c - a) / 1000000000D;
}
long passedTime = System.currentTimeMillis() - startTime;
System.out.println((new StringBuilder(String.valueOf(cpuCount)))
.append(" DCPU at ").append((double) ops / (double) passedTime)
.append(" khz, ").append((tick * 100D) / total)
.append("% cpu use").toString());
}
private static void attachDisplay(DCPU cpu) {
final VirtualMonitor display = new VirtualMonitor(cpu.ram, 32768);
final VirtualKeyboard keyboard = new VirtualKeyboard(cpu.ram, 36864,
new AWTKeyMapping());
Thread t = new Thread() {
public void run() {
try {
int SCALE = 3;
JFrame frame = new JFrame();
Canvas canvas = new Canvas();
canvas.setPreferredSize(new Dimension(160 * SCALE,
128 * SCALE));
canvas.setMinimumSize(new Dimension(160 * SCALE,
128 * SCALE));
canvas.setMaximumSize(new Dimension(160 * SCALE,
128 * SCALE));
canvas.setFocusable(true);
canvas.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent ke) {
keyboard.keyPressed(ke.getKeyCode());
}
public void keyReleased(KeyEvent ke) {
keyboard.keyReleased(ke.getKeyCode());
}
public void keyTyped(KeyEvent ke) {
keyboard.keyTyped(ke.getKeyChar());
}
});
frame.add(canvas);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(3);
frame.setVisible(true);
BufferedImage img2 = new BufferedImage(160, 128, 2);
BufferedImage img = new BufferedImage(128, 128, 2);
display.setPixels(((DataBufferInt) img.getRaster()
.getDataBuffer()).getData());
canvas.requestFocus();
do {
display.render();
Graphics g = img2.getGraphics();
g.setColor(new Color(display.getBackgroundColor()));
g.fillRect(0, 0, 160, 128);
g.drawImage(img, 16, 16, 128, 128, null);
g.dispose();
g = canvas.getGraphics();
g.drawImage(img2, 0, 0, 160 * SCALE, 128 * SCALE, null);
g.dispose();
Thread.sleep(1L);
} while (true);
} catch (Exception e) {
e.printStackTrace();
}
}
};
t.start();
}
private static void testCpu(char ram[]) {
DCPU cpu = new DCPU();
for (int j = 0; j < 0x10000; j++)
cpu.ram[j] = ram[j];
attachDisplay(cpu);
long ops = 0L;
int hz = 0x186a0;
int cyclesPerFrame = hz / 60;
long nsPerFrame = 0xfe502aL;
long nextTime = System.nanoTime();
double tick = 0.0D;
double total = 0.0D;
long time = System.currentTimeMillis();
while (!stop) {
long a = System.nanoTime();
while (System.nanoTime() < nextTime)
try {
Thread.sleep(1L);
} catch (InterruptedException e) {
e.printStackTrace();
}
long b = System.nanoTime();
while (cpu.cycles < cyclesPerFrame)
cpu.tick();
cpu.cycles -= cyclesPerFrame;
long c = System.nanoTime();
ops += cyclesPerFrame;
nextTime += nsPerFrame;
tick += (double) (c - b) / 1000000000D;
total += (double) (c - a) / 1000000000D;
while (System.currentTimeMillis() > time) {
time += 1000L;
System.out.println((new StringBuilder("1 DCPU at "))
.append((double) ops / 1000D).append(" khz, ")
.append((tick * 100D) / total).append("% cpu use")
.toString());
tick = total = ops = 0L;
}
}
}
public static void main(String args[]) throws Exception {
final DCPU cpu = new DCPU();
DataInputStream dis = new DataInputStream(
DCPU.class.getResourceAsStream("mem.dmp"));
try {
int i = 0;
do {
char ch = dis.readChar();
cpu.ram[i] = ch;
i++;
} while (true);
} catch (EOFException e) {
e.printStackTrace();
}
dis.close();
dump(cpu.ram, 0, 768);
if (args.length == 0) {
testCpu(cpu.ram);
return;
}
int threads = args.length <= 0 ? 1 : Integer.parseInt(args[0]);
final int cpusPerCore = args.length <= 1 ? 100 : Integer
.parseInt(args[1]);
int seconds = args.length <= 2 ? 5 : Integer.parseInt(args[2]);
System.out.println((new StringBuilder("Aiming at 100 khz, with "))
.append(cpusPerCore).append(" DCPUs per thread, on ")
.append(threads).append(" threads.").toString());
System.out.println("");
System.out.println((new StringBuilder("Running test for "))
.append(seconds).append(" seconds..").toString());
for (int i = 0; i < threads; i++) {
(new Thread() {
public void run() {
DCPU.testCpus(cpusPerCore, cpu.ram);
}
}).start();
}
for (int i = seconds; i > 0; i--) {
System.out.println((new StringBuilder(String.valueOf(i))).append(
"..").toString());
Thread.sleep(1000L);
}
stop = true;
}
private static void dump(char ram[], int start, int len) {
for (int i = 0; i < len;) {
String str;
for (str = Integer.toHexString(i); str.length() < 4; str = (new StringBuilder(
"0")).append(str).toString())
;
System.out.print((new StringBuilder(String.valueOf(str))).append(
":").toString());
for (int j = 0; j < 8 && i < len; i++) {
for (str = Integer.toHexString(ram[i]); str.length() < 4; str = (new StringBuilder(
"0")).append(str).toString())
;
System.out.print((new StringBuilder(" ")).append(str)
.toString());
j++;
}
System.out.println();
}
}
public char ram[];
public char pc;
public char sp;
public char o;
public char registers[];
public int cycles;
private static volatile boolean stop = false;
private static final int khz = 100;
}
package computer;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.*;
import java.io.*;
// Referenced classes of package computer:
// DCPU, VirtualMonitor, VirtualKeyboard, AWTKeyMapping
public class DCPUApplet extends Applet
implements Runnable
{
public DCPUApplet()
{
running = false;
}
public void start()
{
running = true;
(new Thread(this)).start();
}
public void paint(Graphics g1)
{
}
public void update(Graphics g1)
{
}
public void stop()
{
running = false;
}
public void run()
{
try
{
DCPU cpu = new DCPU();
DataInputStream dis = new DataInputStream(DCPU.class.getResourceAsStream("mem.dmp"));
try
{
int i = 0;
do
{
char ch = dis.readChar();
cpu.ram[i] = ch;
i++;
} while(true);
}
catch(EOFException eofexception)
{
dis.close();
}
emulate(cpu);
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void emulate(DCPU cpu)
{
display = new VirtualMonitor(cpu.ram, 32768);
keyboard = new VirtualKeyboard(cpu.ram, 36864, new AWTKeyMapping());
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent ke)
{
keyboard.keyPressed(ke.getKeyCode());
}
public void keyReleased(KeyEvent ke)
{
keyboard.keyReleased(ke.getKeyCode());
}
public void keyTyped(KeyEvent ke)
{
keyboard.keyTyped(ke.getKeyChar());
}
});
long ops = 0L;
int hz = 0x186a0;
int cyclesPerFrame = hz / 60;
long nsPerFrame = 0xfe502aL;
long nextTime = System.nanoTime();
double tick = 0.0D;
double total = 0.0D;
long time = System.currentTimeMillis();
while(running)
{
long a = System.nanoTime();
while(System.nanoTime() < nextTime)
try
{
Thread.sleep(1L);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
long b = System.nanoTime();
while(cpu.cycles < cyclesPerFrame)
cpu.tick();
BufferedImage img2 = new BufferedImage(160, 128, 2);
BufferedImage img = new BufferedImage(128, 128, 2);
display.setPixels(((DataBufferInt)img.getRaster().getDataBuffer()).getData());
display.render();
Graphics g = img2.getGraphics();
g.setColor(new Color(display.getBackgroundColor()));
g.fillRect(0, 0, 160, 128);
g.drawImage(img, 16, 16, 128, 128, null);
g.dispose();
g = getGraphics();
g.drawImage(img2, 0, 0, 480, 384, null);
g.dispose();
cpu.cycles -= cyclesPerFrame;
long c = System.nanoTime();
ops += cyclesPerFrame;
nextTime += nsPerFrame;
tick += (double)(c - b) / 1000000000D;
total += (double)(c - a) / 1000000000D;
while(System.currentTimeMillis() > time)
{
time += 1000L;
System.out.println((new StringBuilder("1 DCPU at ")).append((double)ops / 1000D).append(" khz, ").append((tick * 100D) / total).append("% cpu use").toString());
tick = total = ops = 0L;
}
}
}
private static final int khz = 100;
private static final int SCALE = 3;
private boolean running;
private VirtualMonitor display;
private VirtualKeyboard keyboard;
}
package computer;
import java.util.HashMap;
import java.util.Map;
public class KeyMapping
{
public KeyMapping()
{
keyMap = new HashMap();
}
public int getKey(int key)
{
if(keyMap.containsKey(Integer.valueOf(key)))
return ((Integer)keyMap.get(Integer.valueOf(key))).intValue();
else
return -1;
}
protected void map(int key, int c)
{
keyMap.put(Integer.valueOf(key), Integer.valueOf(c));
}
public Map keyMap;
}
package computer;
// Referenced classes of package computer:
// KeyMapping
public class VirtualKeyboard
{
public VirtualKeyboard(char ram[], int offset, KeyMapping keyMapping)
{
pp = 0;
this.ram = ram;
this.offset = offset;
this.keyMapping = keyMapping;
}
public void keyTyped(int i)
{
if(i <= 0 || i > 127)
return;
if(ram[offset + pp] != 0)
{
return;
} else
{
ram[offset + pp] = (char)i;
pp = pp + 1 & 0xf;
return;
}
}
public void keyPressed(int key)
{
int i = keyMapping.getKey(key);
if(i < 80 || i > 255)
return;
if(ram[offset + pp] != 0)
{
return;
} else
{
ram[offset + pp] = (char)i;
pp = pp + 1 & 0xf;
return;
}
}
public void keyReleased(int key)
{
int i = keyMapping.getKey(key);
if(i < 80 || i > 255)
return;
if(ram[offset + pp] != 0)
{
return;
} else
{
ram[offset + pp] = (char)(i | 0x100);
pp = pp + 1 & 0xf;
return;
}
}
public static final int KEY_UP = 128;
public static final int KEY_DOWN = 129;
public static final int KEY_LEFT = 130;
public static final int KEY_RIGHT = 131;
private final char ram[];
private final int offset;
private int pp;
private KeyMapping keyMapping;
}
package computer;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class VirtualMonitor
{
public VirtualMonitor(char ram[], int offset)
{
this.pixels = new int[16384];
this.ram = ram;
this.offset = offset;
charOffset = offset + 384;
miscDataOffset = charOffset + 256;
for(int i = 0; i < 256; i++)
{
int bg = genColor(i % 16);
int fg = genColor(i / 16);
colorBase[i] = bg;
colorOffs[i] = fg - bg;
}
int pixels[] = new int[4096];
try
{
ImageIO.read(getClass().getResource("font.png")).getRGB(0, 0, 128, 32, pixels, 0, 128);
}
catch(IOException e)
{
e.printStackTrace();
}
for(int c = 0; c < 128; c++)
{
int ro = charOffset + c * 2;
int xo = (c % 32) * 4;
int yo = (c / 32) * 8;
ram[ro + 0] = '\0';
ram[ro + 1] = '\0';
for(int xx = 0; xx < 4; xx++)
{
int bb = 0;
for(int yy = 0; yy < 8; yy++)
if((pixels[xo + xx + (yo + yy) * 128] & 0xff) > 128)
bb |= 1 << yy;
ram[ro + xx / 2] |= bb << (xx + 1 & 1) * 8;
}
}
}
private static int genColor(int i)
{
int b = (i >> 0 & 1) * 170;
int g = (i >> 1 & 1) * 170;
int r = (i >> 2 & 1) * 170;
if(i == 6)
b += 85;
else
if(i >= 8)
{
r += 85;
g += 85;
b += 85;
}
return 0xff000000 | r << 16 | g << 8 | b;
}
public void render()
{
long time = System.currentTimeMillis() / 16L;
boolean blink = (time / 20L) % 2L == 0L;
long reds = 0L;
long greens = 0L;
long blues = 0L;
for(int y = 0; y < 12; y++)
{
for(int x = 0; x < 32; x++)
{
char dat = ram[offset + x + y * 32];
int ch = dat & 0x7f;
int colorIndex = dat >> 8 & 0xff;
int co = charOffset + ch * 2;
int color = colorBase[colorIndex];
int colorAdd = colorOffs[colorIndex];
if(blink && (dat & 0x80) > 0)
colorAdd = 0;
int pixelOffs = x * 4 + y * 8 * 128;
for(int xx = 0; xx < 4; xx++)
{
int bits = ram[co + (xx >> 1)] >> (xx + 1 & 1) * 8 & 0xff;
for(int yy = 0; yy < 8; yy++)
{
int col = color + colorAdd * (bits >> yy & 1);
pixels[pixelOffs + xx + yy * 128] = col;
reds += col & 0xff0000;
greens += col & 0xff00;
blues += col & 0xff;
}
}
}
}
int color = colorBase[ram[miscDataOffset] & 0xf];
for(int y = 96; y < 128; y++)
{
for(int x = 0; x < 128; x++)
pixels[x + y * 128] = color;
}
int borderPixels = 100;
reds += (color & 0xff0000) * borderPixels;
greens += (color & 0xff00) * borderPixels;
blues += (color & 0xff) * borderPixels;
reds = reds / (long)(12288 + borderPixels) & 0xff0000L;
greens = greens / (long)(12288 + borderPixels) & 65280L;
blues = blues / (long)(12288 + borderPixels) & 255L;
lightColor = (int)(reds | greens | blues);
}
public int getBackgroundColor()
{
return colorBase[ram[miscDataOffset] & 0xf];
}
public void setPixels(int pixels[])
{
this.pixels = pixels;
}
public int getLightColor()
{
return lightColor;
}
public static final int WIDTH_CHARS = 32;
public static final int HEIGHT_CHARS = 12;
public static final int WIDTH_PIXELS = 128;
public static final int HEIGHT_PIXELS = 96;
private final char ram[];
private final int offset;
private final int charOffset;
private final int miscDataOffset;
private final int colorBase[] = new int[256];
private final int colorOffs[] = new int[256];
private int lightColor;
public int pixels[];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment