import javax.microedition.lcdui.*; import java.util.Random; import java.io.InputStream; import java.io.DataInputStream; import java.io.IOException; public class Emulator extends Canvas { byte[][] screen = new byte[64][32]; byte[] key = new byte[16]; byte[] mem = new byte[4096]; byte[] V = new byte[16]; short I; byte delay_timer; byte sound_timer; short[] stack = new short[16]; short opcode; short PC; byte SP; int w; int h; /** * constructor */ public Emulator() { super(); setFullScreenMode(true); w = getWidth(); h = getHeight(); PC = 0x200; SP = 0; delay_timer = 0; sound_timer = 0; for(int a = 0; a<32; a++){ for(int b = 0; b<64; b++){ screen[a][b] = 0; } } for(int i = 0; i<16; i++){ key[i] = 0; } for(int i = 0; i<4096; i++){ mem[i] = 0; } for(int i = 0; i<16; i++){ V[i] = 0; } for(int i = 0; i<16; i++){ stack[i] = 0; } byte[] font = { 0xF0, 0x90, 0x90, 0x90, 0xF0, //0 0x20, 0x60, 0x20, 0x20, 0x70, //1 0xF0, 0x10, 0xF0, 0x80, 0xF0, //2 0xF0, 0x10, 0xF0, 0x10, 0xF0, //3 0x90, 0x90, 0xF0, 0x10, 0x10, //4 0xF0, 0x80, 0xF0, 0x10, 0xF0, //5 0xF0, 0x80, 0xF0, 0x90, 0xF0, //6 0xF0, 0x10, 0x20, 0x40, 0x40, //7 0xF0, 0x90, 0xF0, 0x90, 0xF0, //8 0xF0, 0x90, 0xF0, 0x10, 0xF0, //9 0xF0, 0x90, 0xF0, 0x90, 0x90, //A 0xE0, 0x90, 0xE0, 0x90, 0xE0, //B 0xF0, 0x80, 0x80, 0x80, 0xF0, //C 0xE0, 0x90, 0x90, 0x90, 0xE0, //D 0xF0, 0x80, 0xF0, 0x80, 0xF0, //E 0xF0, 0x80, 0xF0, 0x80, 0x80 //F }; for(int i = 0; i<80; i++){ mem[i] = font[i]; } } public void loadGame(){ try{ InputStream is = getClass().getResourceAsStream("/game.c8"); DataInputStream dis = new DataInputStream(is); dis.readFully(mem, 0x200, dis.available()); dis.close(); is.close(); }catch(IOException ioe){ System.out.println("File not found"); } } public void drawSprite(byte X, byte Y, byte N){ V[0xF] = 0; if(N == 0) N = 16; for(int yline = 0; yline> xpix))!=0){ if((V[X] + xpix)<64&&(V[Y] + yline)<32&&(V[X] + xpix)>=0&&(V[Y] + yline)>=0){ if(screen[(V[X] + xpix)*2][(V[Y] + yline)*2] == 1){ V[0xF] = 1; screen[(V[X] + xpix)*2][(V[Y] + yline)*2]^=1; screen[(V[X] + xpix)*2 + 1][(V[Y] + yline)*2]^=1; screen[(V[X] + xpix)*2][(V[Y] + yline)*2 + 1]^=1; screen[(V[X] + xpix)*2+1][(V[Y] + yline)*2+1]^=1; } } } } } } public void executeNextOpcode(){ opcode = (short)((mem[PC]<<8) + mem[PC+1]); PC+=2; int x = (int)((opcode&0x0F00)>>8); int y = (int)((opcode&0x00F0)>>4); byte kk = (byte)(opcode&0x00FF); switch((opcode&0xF000)>>12){ case 0x0: switch(opcode&0x00FF){ case 0xE0: for(int a = 0; a<32; a++){ for(int b = 0; b<64; b++){ screen[a][b] = 0; } } break; case 0xEE: PC = stack[--SP]; break; default: System.err.println("Unknown opcode"); break; } break; case 0x1: PC = (short)(opcode&0x0FFF); break; case 0x2: stack[SP++] = PC; PC = (short)(opcode&0x0FFF); break; case 0x3: if(V[x] == kk) PC+=2; break; case 0x4: if(V[x]!=kk) PC+=2; break; case 0x5: switch(opcode&0x000F){ case 0x0: if(V[x] == V[y]) PC+=2; break; default: System.err.println("Unknown opcode"); break; } break; case 0x6: V[x] = kk; break; case 0x7: V[x]+=kk; break; case 0x8: switch(opcode&0x000F){ case 0x0: V[x] = V[y]; break; case 0x1: V[x]=(byte)(V[x]|V[y]); break; case 0x2: V[x] = (byte)(V[x]&V[y]); break; case 0x3: V[x] = (byte)(V[x]^V[y]); break; case 0x4: if((V[x] + V[y])>0xF) V[0xF] = 1; else V[0xF] = 0; break; case 0x5: if(V[x]>=V[y]) V[0xF] = 1; else V[0xF] = 0; V[x]-=V[y]; break; case 0x6: if((V[x]&0x000F) == 1) V[0xF] = 1; else V[0xF] = 0; V[x] = (byte)(V[x] >> 1); break; case 0x7: if(V[y]>=V[x]) V[0xF] = 1; else V[0xF] = 0; V[x] = (byte)(V[y] - V[x]); break; case 0xE: if((V[x]&0x000F)==1) V[0xF] = 1; else V[0xF] = 0; V[x] = (byte)(V[x] << 1); break; default: System.err.println("Unknown opcode"); break; } break; case 0x9: switch(opcode&0x000F){ case 0x0: if(V[x]!=V[y]) PC+=2; break; default: System.err.println("Uncnown opcode"); break; } break; case 0xA: I = (short)(opcode&0x0FFF); break; case 0xB: PC = (short)(opcode&0x0FFF + V[0x0]); break; case 0xC: Random rnd = new Random(); V[x] = (byte)(((rnd.nextInt()>>>1)%255)&kk); break; case 0xD: byte x = (byte)((opcode&0x0F00)>>8); byte y = (byte)((opcode&0x00F0)>>4); byte n = (byte)(opcode&0x000F); drawSprite(x, y, n); break; case 0xE: switch(opcode&0x00FF){ case 0x9E: if(key[(int)(V[x])] == 1) PC+=2; break; case 0xA1: if(key[(int)(V[x])]==0) PC+=2; break; default: System.err.println("Unknown opcode"); break; } break; case 0xF: switch(opcode&0x00FF){ case 0x07: V[x] = delay_timer; break; case 0x0A: for(int i = 0; i<16; i++){ if(key[i] == 1){ V[x] = (byte)i; break; } } break; case 0x15: delay_timer = V[x]; break; case 0x18: sound_timer = V[x]; break; case 0x1E: I = (short)(I + V[x]); break; case 0x29: I = (short)((V[x]-1)*5+1); break; case 0x33: byte a = (byte)(V[x]/100); byte b = (byte)((V[x] - 100*a)/10); byte c = (byte)(V[x] - 100*a - 10*b); mem[I] = (byte)(a&0xF); mem[I+1] = (byte)(b&0xF); mem[I+2] = (byte)(c&0xF); break; case 0x55: for(int i = 0; i<16; i++){ mem[I+i] = V[i]; } break; case 0x65: for(int i = 0; i<16; i++){ V[i] = mem[I+i]; } break; default: System.err.println("Unknown opcode"); break; } break; } } public void decreaseTimers(){ if(delay_timer > 0){ delay_timer--; } if(sound_timer > 0){ sound_timer--; } } /** * paint */ public void paint(Graphics g) { Image i = Image.createImage(w, h); Graphics G = i.getGraphics(); G.setColor(0xFFFFFF); G.fillRect(0, 0, w, h); G.translate(w/2 + 32, h/2 + 64); G.setColor(0x000000); G.fillRect(0, 0, 32, 64); for(int a = 0; a<32; a++){ for(int b = 0; b<64;b++){ if(screen[a][b]==1){ G.setColor(0xFFFFFF); G.drawLine(a, b, a, b); repaint(); } } } g.drawImage(i, w/2, h/2, 3); while(true){ executeNextOpcode(); decreaseTimers(); repaint(); } } /** * Called when a key is pressed. */ protected void keyPressed(int keyCode) { int ga = getGameAction(keyCode); switch(keyCode){ case KEY_NUM1: key[0x1] = 1; break; case KEY_NUM2: key[0x2] = 1; break; case KEY_NUM3: key[0x3] = 1; break; case KEY_NUM4: key[0x4] = 1; break; case KEY_NUM5: key[0x5] = 1; break; case KEY_NUM6: key[0x6] = 1; break; case KEY_NUM7: key[0x7] = 1; break; case KEY_NUM8: key[0x8] = 1; break; case KEY_NUM9: key[0x9] = 1; break; case KEY_NUM0: key[0x0] = 1; break; case KEY_STAR: key[0xF] = 1; break; } if(ga==UP&&keyCode!=KEY_NUM2){ key[0xA] = 1; } if(ga==DOWN&&keyCode!=KEY_NUM8){ key[0xB] = 1; } if(ga==LEFT&&keyCode!=KEY_NUM4){ key[0xC] = 1; } if(ga==RIGHT&&keyCode!=KEY_NUM6){ key[0xD] = 1; } if(ga == FIRE&&keyCode!=KEY_NUM5){ key[0xE] = 1; } } }