Skip to content

Instantly share code, notes, and snippets.

@fogus
Created October 6, 2014 15:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fogus/402c14ed6916e3d0c82b to your computer and use it in GitHub Desktop.
Save fogus/402c14ed6916e3d0c82b to your computer and use it in GitHub Desktop.
<title>CHIP-8 Emulator</title>
<script>
var chip8=null;
var context=null;
var videocard=null;
function printoutGraphicsBuffer()
{
for (var i=0; i<chip8.gfx.length; i++)
{
var nowPixel=chip8.gfx[i];
}
}
function display()
{
chip8.emulateCycle();
if(chip8.drawFlag)
{
chip8.drawFlag = false;
}
printoutGraphicsBuffer();
videocard.drawGraphicsBufferIntoContext(chip8.gfx,context);
}
function loop() {
display();
}
function keyboardDown(event)
{
var key=event.key;
if(key == 27) // esc
exit(0);
if(key == '1') chip8.key[0x1] = 1;
else if(key == '2') chip8.key[0x2] = 1;
else if(key == '3') chip8.key[0x3] = 1;
else if(key == '4') chip8.key[0xC] = 1;
else if(key == 'q') chip8.key[0x4] = 1;
else if(key == 'w') chip8.key[0x5] = 1;
else if(key == 'e') chip8.key[0x6] = 1;
else if(key == 'r') chip8.key[0xD] = 1;
else if(key == 'a') chip8.key[0x7] = 1;
else if(key == 's') chip8.key[0x8] = 1;
else if(key == 'd') chip8.key[0x9] = 1;
else if(key == 'f') chip8.key[0xE] = 1;
else if(key == 'z') chip8.key[0xA] = 1;
else if(key == 'x') chip8.key[0x0] = 1;
else if(key == 'c') chip8.key[0xB] = 1;
else if(key == 'v') chip8.key[0xF] = 1;
}
function keyboardUp(event)
{
var key=event.key;
if(key == '1') chip8.key[0x1] = 0;
else if(key == '2') chip8.key[0x2] = 0;
else if(key == '3') chip8.key[0x3] = 0;
else if(key == '4') chip8.key[0xC] = 0;
else if(key == 'q') chip8.key[0x4] = 0;
else if(key == 'w') chip8.key[0x5] = 0;
else if(key == 'e') chip8.key[0x6] = 0;
else if(key == 'r') chip8.key[0xD] = 0;
else if(key == 'a') chip8.key[0x7] = 0;
else if(key == 's') chip8.key[0x8] = 0;
else if(key == 'd') chip8.key[0x9] = 0;
else if(key == 'f') chip8.key[0xE] = 0;
else if(key == 'z') chip8.key[0xA] = 0;
else if(key == 'x') chip8.key[0x0] = 0;
else if(key == 'c') chip8.key[0xB] = 0;
else if(key == 'v') chip8.key[0xF] = 0;
}
function main(argv) {
var pongApplication=new Array(
0x22, 0xfc, 0x6b, 0x0c, 0x6c, 0x3f, 0x6d, 0x0c, 0xa2, 0xea,
0xda, 0xb6, 0xdc, 0xd6, 0x6e, 0x00, 0x22, 0xd4, 0x66, 0x03,
0x68, 0x02, 0x60, 0x60, 0xf0, 0x15, 0xf0, 0x07, 0x30, 0x00,
0x12, 0x1a, 0xc7, 0x17, 0x77, 0x08, 0x69, 0xff, 0xa2, 0xf0,
0xd6, 0x71, 0xa2, 0xea, 0xda, 0xb6, 0xdc, 0xd6, 0x60, 0x01,
0xe0, 0xa1, 0x7b, 0xfe, 0x60, 0x04, 0xe0, 0xa1, 0x7b, 0x02,
0x60, 0x1f, 0x8b, 0x02, 0xda, 0xb6, 0x60, 0x0c, 0xe0, 0xa1,
0x7d, 0xfe, 0x60, 0x0d, 0xe0, 0xa1, 0x7d, 0x02, 0x60, 0x1f,
0x8d, 0x02, 0xdc, 0xd6, 0xa2, 0xf0, 0xd6, 0x71, 0x86, 0x84,
0x87, 0x94, 0x60, 0x3f, 0x86, 0x02, 0x61, 0x1f, 0x87, 0x12,
0x46, 0x00, 0x12, 0x78, 0x46, 0x3f, 0x12, 0x82, 0x47, 0x1f,
0x69, 0xff, 0x47, 0x00, 0x69, 0x01, 0xd6, 0x71, 0x12, 0x2a,
0x68, 0x02, 0x63, 0x01, 0x80, 0x70, 0x80, 0xb5, 0x12, 0x8a,
0x68, 0xfe, 0x63, 0x0a, 0x80, 0x70, 0x80, 0xd5, 0x3f, 0x01,
0x12, 0xa2, 0x61, 0x02, 0x80, 0x15, 0x3f, 0x01, 0x12, 0xba,
0x80, 0x15, 0x3f, 0x01, 0x12, 0xc8, 0x80, 0x15, 0x3f, 0x01,
0x12, 0xc2, 0x60, 0x20, 0xf0, 0x18, 0x22, 0xd4, 0x8e, 0x34,
0x22, 0xd4, 0x66, 0x3e, 0x33, 0x01, 0x66, 0x03, 0x68, 0xfe,
0x33, 0x01, 0x68, 0x02, 0x12, 0x16, 0x79, 0xff, 0x49, 0xfe,
0x69, 0xff, 0x12, 0xc8, 0x79, 0x01, 0x49, 0x02, 0x69, 0x01,
0x60, 0x04, 0xf0, 0x18, 0x76, 0x01, 0x46, 0x40, 0x76, 0xfe,
0x12, 0x6c, 0xa2, 0xf2, 0xfe, 0x33, 0xf2, 0x65, 0xf1, 0x29,
0x64, 0x14, 0x65, 0x02, 0xd4, 0x55, 0x74, 0x15, 0xf2, 0x29,
0xd4, 0x55, 0x00, 0xee, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0x00,
0xff, 0x00, 0x6b, 0x20, 0x6c, 0x00, 0xa2, 0xf6, 0xdb, 0xc4,
0x7c, 0x04, 0x3c, 0x20, 0x13, 0x02, 0x6a, 0x00, 0x6b, 0x00,
0x6c, 0x1f, 0xa2, 0xfa, 0xda, 0xb1, 0xda, 0xc1, 0x7a, 0x08,
0x3a, 0x40, 0x13, 0x12, 0xa2, 0xf6, 0x6a, 0x00, 0x6b, 0x20,
0xdb, 0xa1, 0x00, 0xee
);
var ufoApplication= new Array(
0xa2, 0xcd, 0x69, 0x38, 0x6a, 0x08, 0xd9, 0xa3, 0xa2, 0xd0,
0x6b, 0x00, 0x6c, 0x03, 0xdb, 0xc3, 0xa2, 0xd6, 0x64, 0x1d,
0x65, 0x1f, 0xd4, 0x51, 0x67, 0x00, 0x68, 0x0f, 0x22, 0xa2,
0x22, 0xac, 0x48, 0x00, 0x12, 0x22, 0x64, 0x1e, 0x65, 0x1c,
0xa2, 0xd3, 0xd4, 0x53, 0x6e, 0x00, 0x66, 0x80, 0x6d, 0x04,
0xed, 0xa1, 0x66, 0xff, 0x6d, 0x05, 0xed, 0xa1, 0x66, 0x00,
0x6d, 0x06, 0xed, 0xa1, 0x66, 0x01, 0x36, 0x80, 0x22, 0xd8,
0xa2, 0xd0, 0xdb, 0xc3, 0xcd, 0x01, 0x8b, 0xd4, 0xdb, 0xc3,
0x3f, 0x00, 0x12, 0x92, 0xa2, 0xcd, 0xd9, 0xa3, 0xcd, 0x01,
0x3d, 0x00, 0x6d, 0xff, 0x79, 0xfe, 0xd9, 0xa3, 0x3f, 0x00,
0x12, 0x8c, 0x4e, 0x00, 0x12, 0x2e, 0xa2, 0xd3, 0xd4, 0x53,
0x45, 0x00, 0x12, 0x86, 0x75, 0xff, 0x84, 0x64, 0xd4, 0x53,
0x3f, 0x01, 0x12, 0x46, 0x6d, 0x08, 0x8d, 0x52, 0x4d, 0x08,
0x12, 0x8c, 0x12, 0x92, 0x22, 0xac, 0x78, 0xff, 0x12, 0x1e,
0x22, 0xa2, 0x77, 0x05, 0x12, 0x96, 0x22, 0xa2, 0x77, 0x0f,
0x22, 0xa2, 0x6d, 0x03, 0xfd, 0x18, 0xa2, 0xd3, 0xd4, 0x53,
0x12, 0x86, 0xa2, 0xf8, 0xf7, 0x33, 0x63, 0x00, 0x22, 0xb6,
0x00, 0xee, 0xa2, 0xf8, 0xf8, 0x33, 0x63, 0x32, 0x22, 0xb6,
0x00, 0xee, 0x6d, 0x1b, 0xf2, 0x65, 0xf0, 0x29, 0xd3, 0xd5,
0x73, 0x05, 0xf1, 0x29, 0xd3, 0xd5, 0x73, 0x05, 0xf2, 0x29,
0xd3, 0xd5, 0x00, 0xee, 0x01, 0x7c, 0xfe, 0x7c, 0x60, 0xf0,
0x60, 0x40, 0xe0, 0xa0, 0xf8, 0xd4, 0x6e, 0x01, 0x6d, 0x10,
0xfd, 0x18, 0x00, 0xee
);
var puzzleApplication=new Array(
0x6a, 0x12, 0x6b, 0x01, 0x61, 0x10, 0x62, 0x00, 0x60, 0x00,
0xa2, 0xb0, 0xd1, 0x27, 0xf0, 0x29, 0x30, 0x00, 0xda, 0xb5,
0x71, 0x08, 0x7a, 0x08, 0x31, 0x30, 0x12, 0x24, 0x61, 0x10,
0x72, 0x08, 0x6a, 0x12, 0x7b, 0x08, 0xa3, 0x00, 0xf0, 0x1e,
0xf0, 0x55, 0x70, 0x01, 0x30, 0x10, 0x12, 0x0a, 0x6a, 0x12,
0x6b, 0x01, 0x6c, 0x00, 0x62, 0xff, 0xc0, 0x06, 0x70, 0x02,
0x22, 0x52, 0x72, 0xff, 0x32, 0x00, 0x12, 0x38, 0x6e, 0x00,
0x6e, 0x00, 0xf0, 0x0a, 0x22, 0x52, 0x7e, 0x01, 0x7e, 0x01,
0x12, 0x48, 0x84, 0xa0, 0x85, 0xb0, 0x86, 0xc0, 0x30, 0x02,
0x12, 0x64, 0x45, 0x01, 0x12, 0x64, 0x75, 0xf8, 0x76, 0xfc,
0x30, 0x08, 0x12, 0x70, 0x45, 0x19, 0x12, 0x70, 0x75, 0x08,
0x76, 0x04, 0x30, 0x06, 0x12, 0x7c, 0x44, 0x12, 0x12, 0x7c,
0x74, 0xf8, 0x76, 0xff, 0x30, 0x04, 0x12, 0x88, 0x44, 0x2a,
0x12, 0x88, 0x74, 0x08, 0x76, 0x01, 0xa3, 0x00, 0xf6, 0x1e,
0xf0, 0x65, 0x81, 0x00, 0x60, 0x00, 0xa3, 0x00, 0xf6, 0x1e,
0xf0, 0x55, 0xa3, 0x00, 0xfc, 0x1e, 0x80, 0x10, 0xf0, 0x55,
0xf1, 0x29, 0xd4, 0x55, 0xda, 0xb5, 0x8a, 0x40, 0x8b, 0x50,
0x8c, 0x60, 0x00, 0xee, 0xee, 0x5e, 0xfe, 0xfe, 0xfe, 0xfe,
0xfe, 0xfe, 0xfe, 0xfe
);
var missileApplication=new Array(
0x12, 0x19, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4c, 0x45, 0x20,
0x62, 0x79, 0x20, 0x44, 0x61, 0x76, 0x69, 0x64, 0x20, 0x57,
0x49, 0x4e, 0x54, 0x45, 0x52, 0x6c, 0x0c, 0x60, 0x00, 0x61,
0x00, 0x65, 0x08, 0x66, 0x0a, 0x67, 0x00, 0x6e, 0x01, 0xa2,
0xad, 0xd0, 0x14, 0x70, 0x08, 0x30, 0x40, 0x12, 0x29, 0x60,
0x00, 0x61, 0x1c, 0xa2, 0xb0, 0xd0, 0x14, 0xa2, 0xb0, 0xd0,
0x14, 0x3e, 0x01, 0x12, 0x49, 0x70, 0x04, 0x40, 0x38, 0x6e,
0x00, 0x12, 0x4f, 0x70, 0xfc, 0x40, 0x00, 0x6e, 0x01, 0xd0,
0x14, 0xfc, 0x15, 0xfb, 0x07, 0x3b, 0x00, 0x12, 0x53, 0x62,
0x08, 0xe2, 0x9e, 0x12, 0x95, 0x3c, 0x00, 0x7c, 0xfe, 0x63,
0x1b, 0x82, 0x00, 0xa2, 0xb0, 0xd2, 0x31, 0x64, 0x00, 0xd2,
0x31, 0x73, 0xff, 0xd2, 0x31, 0x3f, 0x00, 0x64, 0x01, 0x33,
0x03, 0x12, 0x6d, 0xd2, 0x31, 0x34, 0x01, 0x12, 0x91, 0x77,
0x05, 0x75, 0xff, 0x82, 0x00, 0x63, 0x00, 0xa2, 0xad, 0xd2,
0x34, 0x45, 0x00, 0x12, 0x97, 0x76, 0xff, 0x36, 0x00, 0x12,
0x39, 0xa2, 0xb4, 0xf7, 0x33, 0xf2, 0x65, 0x63, 0x1b, 0x64,
0x0d, 0xf1, 0x29, 0xd3, 0x45, 0x73, 0x05, 0xf2, 0x29, 0xd3,
0x45, 0x12, 0xab, 0x10, 0x38, 0x38, 0x10, 0x38, 0x7c, 0xfe
);
var brixApplication=new Array(
0x6e, 0x05, 0x65, 0x00, 0x6b, 0x06, 0x6a, 0x00, 0xa3, 0x0c,
0xda, 0xb1, 0x7a, 0x04, 0x3a, 0x40, 0x12, 0x08, 0x7b, 0x02,
0x3b, 0x12, 0x12, 0x06, 0x6c, 0x20, 0x6d, 0x1f, 0xa3, 0x10,
0xdc, 0xd1, 0x22, 0xf6, 0x60, 0x00, 0x61, 0x00, 0xa3, 0x12,
0xd0, 0x11, 0x70, 0x08, 0xa3, 0x0e, 0xd0, 0x11, 0x60, 0x40,
0xf0, 0x15, 0xf0, 0x07, 0x30, 0x00, 0x12, 0x34, 0xc6, 0x0f,
0x67, 0x1e, 0x68, 0x01, 0x69, 0xff, 0xa3, 0x0e, 0xd6, 0x71,
0xa3, 0x10, 0xdc, 0xd1, 0x60, 0x04, 0xe0, 0xa1, 0x7c, 0xfe,
0x60, 0x06, 0xe0, 0xa1, 0x7c, 0x02, 0x60, 0x3f, 0x8c, 0x02,
0xdc, 0xd1, 0xa3, 0x0e, 0xd6, 0x71, 0x86, 0x84, 0x87, 0x94,
0x60, 0x3f, 0x86, 0x02, 0x61, 0x1f, 0x87, 0x12, 0x47, 0x1f,
0x12, 0xac, 0x46, 0x00, 0x68, 0x01, 0x46, 0x3f, 0x68, 0xff,
0x47, 0x00, 0x69, 0x01, 0xd6, 0x71, 0x3f, 0x01, 0x12, 0xaa,
0x47, 0x1f, 0x12, 0xaa, 0x60, 0x05, 0x80, 0x75, 0x3f, 0x00,
0x12, 0xaa, 0x60, 0x01, 0xf0, 0x18, 0x80, 0x60, 0x61, 0xfc,
0x80, 0x12, 0xa3, 0x0c, 0xd0, 0x71, 0x60, 0xfe, 0x89, 0x03,
0x22, 0xf6, 0x75, 0x01, 0x22, 0xf6, 0x45, 0x60, 0x12, 0xde,
0x12, 0x46, 0x69, 0xff, 0x80, 0x60, 0x80, 0xc5, 0x3f, 0x01,
0x12, 0xca, 0x61, 0x02, 0x80, 0x15, 0x3f, 0x01, 0x12, 0xe0,
0x80, 0x15, 0x3f, 0x01, 0x12, 0xee, 0x80, 0x15, 0x3f, 0x01,
0x12, 0xe8, 0x60, 0x20, 0xf0, 0x18, 0xa3, 0x0e, 0x7e, 0xff,
0x80, 0xe0, 0x80, 0x04, 0x61, 0x00, 0xd0, 0x11, 0x3e, 0x00,
0x12, 0x30, 0x12, 0xde, 0x78, 0xff, 0x48, 0xfe, 0x68, 0xff,
0x12, 0xee, 0x78, 0x01, 0x48, 0x02, 0x68, 0x01, 0x60, 0x04,
0xf0, 0x18, 0x69, 0xff, 0x12, 0x70, 0xa3, 0x14, 0xf5, 0x33,
0xf2, 0x65, 0xf1, 0x29, 0x63, 0x37, 0x64, 0x00, 0xd3, 0x45,
0x73, 0x05, 0xf2, 0x29, 0xd3, 0x45, 0x00, 0xee, 0xe0, 0x00,
0x80, 0x00, 0xfc, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00
);
var tictacApplication=new Array(
0x12, 0x18, 0x54, 0x49, 0x43, 0x54, 0x41, 0x43, 0x20, 0x62,
0x79, 0x20, 0x44, 0x61, 0x76, 0x69, 0x64, 0x20, 0x57, 0x49,
0x4e, 0x54, 0x45, 0x52, 0x6b, 0x00, 0x6c, 0x00, 0x80, 0xb0,
0x81, 0xc0, 0xa3, 0xe6, 0xf1, 0x55, 0xa3, 0xc4, 0xff, 0x65,
0xa3, 0xb4, 0xff, 0x55, 0xa3, 0xe6, 0xf1, 0x65, 0x8b, 0x00,
0x8c, 0x10, 0x00, 0xe0, 0x6e, 0x01, 0x60, 0x13, 0x61, 0x03,
0xa3, 0x9a, 0xd0, 0x11, 0x70, 0x08, 0x30, 0x2b, 0x12, 0x3e,
0x60, 0x13, 0x71, 0x08, 0x31, 0x23, 0x12, 0x3e, 0x60, 0x13,
0x61, 0x03, 0xa3, 0x9b, 0xd0, 0x1f, 0x70, 0x08, 0x30, 0x33,
0x12, 0x54, 0x60, 0x13, 0x71, 0x0f, 0xd0, 0x1a, 0x70, 0x08,
0x30, 0x33, 0x12, 0x60, 0x23, 0x66, 0xf0, 0x0a, 0x81, 0x00,
0xa3, 0xb4, 0xf0, 0x1e, 0xf0, 0x65, 0x40, 0x00, 0x12, 0x8a,
0x22, 0x7c, 0x12, 0x6a, 0x60, 0x10, 0xf0, 0x18, 0xf0, 0x15,
0xf0, 0x07, 0x30, 0x00, 0x12, 0x82, 0x00, 0xee, 0x60, 0x02,
0x8e, 0x03, 0x80, 0xe0, 0xf0, 0x55, 0xa3, 0xd4, 0x80, 0x10,
0x70, 0xff, 0x80, 0x04, 0xf0, 0x1e, 0xf1, 0x65, 0xa3, 0xaa,
0x3e, 0x03, 0xa3, 0xaf, 0xd0, 0x15, 0x22, 0xc8, 0x3a, 0x00,
0x12, 0x1c, 0xa3, 0xb4, 0x61, 0x00, 0x62, 0x00, 0x63, 0x01,
0xf0, 0x65, 0x30, 0x00, 0x71, 0x01, 0xf3, 0x1e, 0x72, 0x01,
0x32, 0x10, 0x12, 0xb4, 0x31, 0x10, 0x12, 0x6a, 0x12, 0x1c,
0x6a, 0x00, 0xa3, 0xb4, 0x60, 0x01, 0xf0, 0x1e, 0xf8, 0x65,
0x69, 0x00, 0x89, 0x04, 0x23, 0x44, 0x89, 0x14, 0x23, 0x44,
0x89, 0x24, 0x23, 0x4a, 0x69, 0x00, 0x89, 0x34, 0x23, 0x44,
0x89, 0x44, 0x23, 0x44, 0x89, 0x54, 0x23, 0x4a, 0x69, 0x00,
0x89, 0x64, 0x23, 0x44, 0x89, 0x74, 0x23, 0x44, 0x89, 0x84,
0x23, 0x4a, 0x69, 0x00, 0x89, 0x64, 0x23, 0x44, 0x89, 0x34,
0x23, 0x44, 0x89, 0x04, 0x23, 0x4a, 0x69, 0x00, 0x89, 0x74,
0x23, 0x44, 0x89, 0x44, 0x23, 0x44, 0x89, 0x14, 0x23, 0x4a,
0x69, 0x00, 0x89, 0x84, 0x23, 0x44, 0x89, 0x54, 0x23, 0x44,
0x89, 0x24, 0x23, 0x4a, 0x69, 0x00, 0x89, 0x84, 0x23, 0x44,
0x89, 0x44, 0x23, 0x44, 0x89, 0x04, 0x23, 0x4a, 0x69, 0x00,
0x89, 0x64, 0x23, 0x44, 0x89, 0x44, 0x23, 0x44, 0x89, 0x24,
0x23, 0x4a, 0x00, 0xee, 0x89, 0x0e, 0x89, 0x0e, 0x00, 0xee,
0x49, 0x15, 0x13, 0x54, 0x49, 0x3f, 0x13, 0x5a, 0x00, 0xee,
0x23, 0x66, 0x7b, 0x01, 0x13, 0x5e, 0x23, 0x66, 0x7c, 0x01,
0x23, 0x66, 0x6a, 0x01, 0xf0, 0x0a, 0x00, 0xee, 0x63, 0x05,
0x64, 0x0a, 0xa3, 0xaf, 0xd3, 0x45, 0x63, 0x02, 0x74, 0x06,
0xa3, 0xe6, 0xfb, 0x33, 0x23, 0x88, 0x63, 0x32, 0x64, 0x0a,
0xa3, 0xaa, 0xd3, 0x45, 0x63, 0x2f, 0x74, 0x06, 0xa3, 0xe6,
0xfc, 0x33, 0xf2, 0x65, 0xf0, 0x29, 0x23, 0x94, 0xf1, 0x29,
0x23, 0x94, 0xf2, 0x29, 0xd3, 0x45, 0x73, 0x05, 0x00, 0xee,
0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1c, 0x22, 0x22, 0x22,
0x1c, 0x22, 0x14, 0x08, 0x14, 0x22, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x13, 0x05,
0x1b, 0x05, 0x23, 0x05, 0x13, 0x0d, 0x1b, 0x0d, 0x23, 0x0d,
0x13, 0x15, 0x1b, 0x15, 0x23, 0x15
);
videocard=new Videocard_class();
chip8=new Chip8_class();
chip8.loadApplication(eval(argv[1]));
var canvas = document.getElementById("screen");
context = canvas.getContext("2d");
window.onkeydown = keyboardDown;
window.onkeyup = keyboardUp;
setInterval(loop, 1);
}
</script>
<script>
function printf(text)
{
console.log(text);
}
</script>
<script>
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
function rand() {
return getRandomArbitrary(0,32767);
}
</script>
<script>
function Videocard_class() {
this.pixelSize=6;
this.drawPixelAtXY=function(nowPixel,x,y)
{
var color=(nowPixel==1)?"#000000":"#FFFFFF";
context.fillStyle = color;
context.fillRect(x,y,this.pixelSize,this.pixelSize);
}
this.drawGraphicsBufferIntoContext=function(graphicsBuffer,context)
{
var gfx=graphicsBuffer;
var outputString="";
// Draw
for(var y = 0; y < 32; ++y)
{
for(var x = 0; x < 64; ++x)
{
var nowPixel=gfx[(y*64) + x];
this.drawPixelAtXY(nowPixel,x*this.pixelSize,y*this.pixelSize);
}
outputString+="\n";
}
outputString+="\n";
return outputString;
}
this.debugRender=function(graphicsBuffer)
{
var gfx=graphicsBuffer;
var outputString="";
// Draw
for(var y = 0; y < 32; ++y)
{
for(var x = 0; x < 64; ++x)
{
if(gfx[(y*64) + x] == 0)
outputString+=" ";
else
outputString+="0";
}
outputString+="\n";
}
outputString+="\n";
return outputString;
}
}
</script>
<script>
///////////////////////////////////////////////////////////////////////////////
// Project description
// ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ
// Name: myChip8
//
// Author: Laurence Muller
// Contact: laurence.muller@gmail.com
// Javascript port: Alex Kudryashkin
// Contact: alex.kudryashkin@gmail.com
//
// License: GNU General Public License (GPL) v2
// ( http://www.gnu.org/licenses/old-licenses/gpl-2.0.html )
//
// Copyright (C) 2011 Laurence Muller / www.multigesture.net
///////////////////////////////////////////////////////////////////////////////
chip8_fontset = new Array
(
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
);
function Chip8_class() {
this.opcode=0;
this.memory=new Array(4096);
this.V=new Array(16);
this.I=0;
this.pc=0;
this.gfx=new Array(64*32);
this.delay_timer=0;
this.sound_timer=0;
this.stack=new Array(16)
this.sp=0;
this.drawFlag=false;
this.key=new Array(16);
this.init=function()
{
this.pc = 0x200; // Program counter starts at 0x200 (Start adress program)
this.opcode = 0; // Reset current opcode
this.I = 0; // Reset index register
this.sp = 0; // Reset stack pointer
// Clear display
for(var i = 0; i < 2048; ++i)
this.gfx[i] = 0;
// Clear stack
for(var i = 0; i < 16; ++i)
this.stack[i] = 0;
for(var i = 0; i < 16; ++i)
this.key[i] = this.V[i] = 0;
// Clear memory
for(var i = 0; i < 4096; ++i)
this.memory[i] = 0;
// Load fontset
for(var i = 0; i < 80; ++i)
this.memory[i] = chip8_fontset[i];
// Reset timers
this.delay_timer = 0;
this.sound_timer = 0;
// Clear screen once
this.drawFlag = true;
//srand (time(NULL));
}
this.emulateCycle=function()
{
// Fetch this.opcode
this.opcode = this.memory[this.pc] << 8 | this.memory[this.pc+ 1];
// Process this.opcode
switch(this.opcode & 0xF000)
{
case 0x0000:
switch(this.opcode & 0x000F)
{
case 0x0000: // 0x00E0: Clears the screen
for(var i = 0; i < 2048; ++i)
this.gfx[i] = 0x0;
drawFlag = true;
this.pc+= 2;
break;
case 0x000E: // 0x00EE: Returns from subroutine
--this.sp; // 16 levels of stack, decrease stack pointer to prevent overwrite
this.pc= this.stack[this.sp]; // Put the stored return address from the stack back into the program counter
this.pc+= 2; // Don't forget to increase the program counter!
break;
default:
printf ("Unknown this.opcode [0x0000]: 0x%X\n", this.opcode);
}
break;
case 0x1000: // 0x1NNN: Jumps to address NNN
this.pc= this.opcode & 0x0FFF;
break;
case 0x2000: // 0x2NNN: Calls subroutine at NNN.
this.stack[this.sp] = this.pc; // Store current address in stack
++this.sp; // Increment stack pointer
this.pc= this.opcode & 0x0FFF; // Set the program counter to the address at NNN
break;
case 0x3000: // 0x3XNN: Skips the next instruction if VX equals NN
if(this.V[(this.opcode & 0x0F00) >> 8] == (this.opcode & 0x00FF))
this.pc+= 4;
else
this.pc+= 2;
break;
case 0x4000: // 0x4XNN: Skips the next instruction if VX doesn't equal NN
if(this.V[(this.opcode & 0x0F00) >> 8] != (this.opcode & 0x00FF))
this.pc+= 4;
else
this.pc+= 2;
break;
case 0x5000: // 0x5XY0: Skips the next instruction if VX equals VY.
if(V[(this.opcode & 0x0F00) >> 8] == V[(this.opcode & 0x00F0) >> 4])
this.pc+= 4;
else
this.pc+= 2;
break;
case 0x6000: // 0x6XNN: Sets VX to NN.
this.V[(this.opcode & 0x0F00) >> 8] = this.opcode & 0x00FF;
this.pc+= 2;
break;
case 0x7000: // 0x7XNN: Adds NN to VX.
this.V[(this.opcode & 0x0F00) >> 8] += this.opcode & 0x00FF;
this.pc+= 2;
break;
case 0x8000:
switch(this.opcode & 0x000F)
{
case 0x0000: // 0x8XY0: Sets VX to the value of VY
this.V[(this.opcode & 0x0F00) >> 8] = this.V[(this.opcode & 0x00F0) >> 4];
this.pc+= 2;
break;
case 0x0001: // 0x8XY1: Sets VX to "VX OR VY"
this.V[(this.opcode & 0x0F00) >> 8] |= this.V[(this.opcode & 0x00F0) >> 4];
this.pc+= 2;
break;
case 0x0002: // 0x8XY2: Sets VX to "VX AND VY"
this.V[(this.opcode & 0x0F00) >> 8] &= this.V[(this.opcode & 0x00F0) >> 4];
this.pc+= 2;
break;
case 0x0003: // 0x8XY3: Sets VX to "VX XOR VY"
this.V[(this.opcode & 0x0F00) >> 8] ^= this.V[(this.opcode & 0x00F0) >> 4];
this.pc+= 2;
break;
case 0x0004: // 0x8XY4: Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't
if(this.V[(this.opcode & 0x00F0) >> 4] > (0xFF - this.V[(this.opcode & 0x0F00) >> 8]))
this.V[0xF] = 1; //carry
else
this.V[0xF] = 0;
this.V[(this.opcode & 0x0F00) >> 8] += this.V[(this.opcode & 0x00F0) >> 4];
this.pc+= 2;
break;
case 0x0005: // 0x8XY5: VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't
if(this.V[(this.opcode & 0x00F0) >> 4] > this.V[(this.opcode & 0x0F00) >> 8])
this.V[0xF] = 0; // there is a borrow
else
this.V[0xF] = 1;
this.V[(this.opcode & 0x0F00) >> 8] -= this.V[(this.opcode & 0x00F0) >> 4];
this.pc+= 2;
break;
case 0x0006: // 0x8XY6: Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift
this.V[0xF] = this.V[(this.opcode & 0x0F00) >> 8] & 0x1;
this.V[(this.opcode & 0x0F00) >> 8] >>= 1;
this.pc+= 2;
break;
case 0x0007: // 0x8XY7: Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't
if(this.V[(this.opcode & 0x0F00) >> 8] > this.V[(this.opcode & 0x00F0) >> 4]) // VY-VX
this.V[0xF] = 0; // there is a borrow
else
this.V[0xF] = 1;
this.V[(this.opcode & 0x0F00) >> 8] = this.V[(this.opcode & 0x00F0) >> 4] - V[(this.opcode & 0x0F00) >> 8];
this.pc+= 2;
break;
case 0x000E: // 0x8XYE: Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift
this.V[0xF] = this.V[(this.opcode & 0x0F00) >> 8] >> 7;
this.V[(this.opcode & 0x0F00) >> 8] <<= 1;
this.pc+= 2;
break;
default:
printf ("Unknown this.opcode [0x8000]: 0x%X\n", this.opcode);
}
break;
case 0x9000: // 0x9XY0: Skips the next instruction if VX doesn't equal VY
if(V[(this.opcode & 0x0F00) >> 8] != V[(this.opcode & 0x00F0) >> 4])
this.pc+= 4;
else
this.pc+= 2;
break;
case 0xA000: // ANNN: Sets I to the address NNN
I = this.opcode & 0x0FFF;
this.pc+= 2;
break;
case 0xB000: // BNNN: Jumps to the address NNN plus V0
this.pc= (this.opcode & 0x0FFF) + V[0];
break;
case 0xC000: // CXNN: Sets VX to a random number and NN
this.V[(this.opcode & 0x0F00) >> 8] = (rand() % 0xFF) & (this.opcode & 0x00FF);
this.pc+= 2;
break;
case 0xD000: // DXYN: Draws a sprite at coordinate (VX, VY) that has a width of 8 pixels and a height of N pixels.
// Each row of 8 pixels is read as bit-coded starting from this.memory location I;
// I value doesn't change after the execution of this instruction.
// VF is set to 1 if any screen pixels are flipped from set to unset when the sprite is drawn,
// and to 0 if that doesn't happen
{
var x = this.V[(this.opcode & 0x0F00) >> 8];
var y = this.V[(this.opcode & 0x00F0) >> 4];
var height = this.opcode & 0x000F;
var pixel;
this.V[0xF] = 0;
for (var yline = 0; yline < height; yline++)
{
pixel = this.memory[I + yline];
for(var xline = 0; xline < 8; xline++)
{
if((pixel & (0x80 >> xline)) != 0)
{
if(this.gfx[(x + xline + ((y + yline) * 64))] == 1)
{
this.V[0xF] = 1;
}
this.gfx[x + xline + ((y + yline) * 64)] ^= 1;
}
}
}
drawFlag = true;
this.pc+= 2;
}
break;
case 0xE000:
switch(this.opcode & 0x00FF)
{
case 0x009E: // EX9E: Skips the next instruction if the key stored in VX is pressed
if(this.key[this.V[(this.opcode & 0x0F00) >> 8]] != 0)
this.pc+= 4;
else
this.pc+= 2;
break;
case 0x00A1: // EXA1: Skips the next instruction if the key stored in VX isn't pressed
if(this.key[this.V[(this.opcode & 0x0F00) >> 8]] == 0)
this.pc+= 4;
else
this.pc+= 2;
break;
default:
printf ("Unknown this.opcode [0xE000]: 0x%X\n", this.opcode);
}
break;
case 0xF000:
switch(this.opcode & 0x00FF)
{
case 0x0007: // FX07: Sets VX to the value of the delay timer
this.V[(this.opcode & 0x0F00) >> 8] = this.delay_timer;
this.pc+= 2;
break;
case 0x000A: // FX0A: A key press is awaited, and then stored in VX
{
var keyPress = false;
for(var i = 0; i < 16; ++i)
{
if(this.key[i] != 0)
{
this.V[(this.opcode & 0x0F00) >> 8] = i;
keyPress = true;
}
}
// If we didn't received a keypress, skip this cycle and try again.
if(!keyPress)
return;
this.pc+= 2;
}
break;
case 0x0015: // FX15: Sets the delay timer to VX
this.delay_timer = this.V[(this.opcode & 0x0F00) >> 8];
this.pc+= 2;
break;
case 0x0018: // FX18: Sets the sound timer to VX
this.sound_timer = this.V[(this.opcode & 0x0F00) >> 8];
this.pc+= 2;
break;
case 0x001E: // FX1E: Adds VX to I
if(I + this.V[(this.opcode & 0x0F00) >> 8] > 0xFFF) // VF is set to 1 when range overflow (I+VX>0xFFF), and 0 when there isn't.
this.V[0xF] = 1;
else
this.V[0xF] = 0;
I += this.V[(this.opcode & 0x0F00) >> 8];
this.pc+= 2;
break;
case 0x0029: // FX29: Sets I to the location of the sprite for the character in VX. Characters 0-F (in hexadecimal) are represented by a 4x5 font
I = this.V[(this.opcode & 0x0F00) >> 8] * 0x5;
this.pc+= 2;
break;
case 0x0033: // FX33: Stores the Binary-coded decimal representation of VX at the addresses I, I plus 1, and I plus 2
this.memory[I] = this.V[(this.opcode & 0x0F00) >> 8] / 100;
this.memory[I + 1] = (this.V[(this.opcode & 0x0F00) >> 8] / 10) % 10;
this.memory[I + 2] = (this.V[(this.opcode & 0x0F00) >> 8] % 100) % 10;
this.pc+= 2;
break;
case 0x0055: // FX55: Stores V0 to VX in this.memory starting at address I
for (var i = 0; i <= ((this.opcode & 0x0F00) >> 8); ++i)
this.memory[I + i] = this.V[i];
// On the original interpreter, when the operation is done, I = I + X + 1.
I += ((this.opcode & 0x0F00) >> 8) + 1;
this.pc+= 2;
break;
case 0x0065: // FX65: Fills V0 to VX with values from this.memory starting at address I
for (var i = 0; i <= ((this.opcode & 0x0F00) >> 8); ++i)
this.V[i] = this.memory[I + i];
// On the original interpreter, when the operation is done, I = I + X + 1.
I += ((this.opcode & 0x0F00) >> 8) + 1;
this.pc+= 2;
break;
default:
printf ("Unknown this.opcode [0xF000]: 0x%X\n", this.opcode);
}
break;
default:
printf ("Unknown this.opcode: 0x%X\n", this.opcode);
}
// Update timers
if(this.delay_timer > 0)
--this.delay_timer;
if(this.sound_timer > 0)
{
if(this.sound_timer == 1)
printf("BEEP!\n");
--this.sound_timer;
}
}
this.loadApplication=function(applicationToLoad)
{
this.init();
if (applicationToLoad.length>512) {
printf("application is too big for memory (512 bytes max)");
}
for (var i=0; i<applicationToLoad.length; i++) {
this.memory[512+i]=applicationToLoad[i];
}
return true;
}
}
</script>
<script>
function changeApplication() {
var newApplicationName=document.getElementById("applicationSelectBox").value;
main(new Array("chip8",newApplicationName));
}
</script>
<body onload='main(new Array("chip8","brixApplication"))'>
<center>
<canvas id="screen" width="390" height="320"></canvas>
<br>
Game:
<select id="applicationSelectBox" onchange="changeApplication()">
<option>pongApplication</option>
<option>ufoApplication</option>
<option>puzzleApplication</option>
<option>missileApplication</option>
<option>brixApplication</option>
<option>tictacApplication</option>
</select>
</center>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment