Fix some instructions

This commit is contained in:
Miguel Angel 2024-09-04 21:38:54 +02:00
parent 028a21ed7f
commit a56d787878
3 changed files with 117 additions and 60 deletions

View File

@ -23,33 +23,40 @@
<h1>Chip 8 emulator</h1> <h1>Chip 8 emulator</h1>
<!-- Original screen is 64x32 --> <!-- Original screen is 64x32 -->
<canvas id="emulator-screen" width="256" height="128"></canvas> <canvas id="emulator-screen" width="512" height="256"></canvas>
<script> <script>
// Assuming your library exposes an Emulator class
console.log(Revuelto8ts);
console.log(Revuelto8ts.Chip8Emulator);
const emulator = new Revuelto8ts.Chip8Emulator(); const emulator = new Revuelto8ts.Chip8Emulator();
// Load ROM (you'll need to implement this method in your emulator) let fullDirRoms = [
'./roms/1-chip8-logo.ch8',
fetch('./roms/1-chip8-logo.ch8') './roms/2-ibm-logo.ch8',
'./roms/3-corax+.ch8',
'./roms/4-flags.ch8',
'./roms/5-quirks.ch8',
'./roms/6-keypad.ch8',
'./roms/7-beep.ch8',
'./roms/8-scrolling.ch8',
'./roms/Maze[David Winter, 199x].ch8',
];
// Load ROM
fetch(fullDirRoms[3])
.then(response => response.arrayBuffer()) .then(response => response.arrayBuffer())
.then(buffer => { .then(arrayBufferRom => {
//emulator.loadROM(new Uint8Array(buffer)); let romData = new Uint8Array(arrayBufferRom);
// Load and start emulator.loadRom(romData);
emulator.loadRom(buffer);
}); });
const emulatorCanvas = document.getElementById('emulator-screen'); const emulatorCanvas = document.getElementById('emulator-screen');
// Loop setInterval(function() {
while(true) { if(emulator.isRomLoaded()) {
emulator.emulateCycle(); //console.log(emulator.getCPUStatus());
emulator.emulateCycle();
emulator.drawGraphics(); emulator.drawToCanvas(emulatorCanvas, 8);
emulator.drawToCanvas(emulatorCanvas, 4); }
} }, 5);
</script> </script>
</body> </body>
</html> </html>

View File

@ -7,27 +7,32 @@ class Chip8Emulator {
keyboard: Keyboard; keyboard: Keyboard;
rom: Uint8Array; rom: Uint8Array;
romLoaded: boolean;
constructor() { constructor() {
this.keyboard = new Keyboard(); this.keyboard = new Keyboard();
this.cpu = new CPU(this.keyboard); this.cpu = new CPU(this.keyboard);
this.rom = new Uint8Array(); this.rom = new Uint8Array();
this.romLoaded = false;
} }
loadRom(rom: Uint8Array) { loadRom(rom: Uint8Array) {
this.rom = rom; this.rom = rom;
this.cpu.loadRom(this.rom);
this.romLoaded = true;
}
isRomLoaded() {
return this.romLoaded;
} }
emulateCycle() { emulateCycle() {
// Fetch opcode this.cpu.cycle();
// Decode opcode
// Execute opcode
// Update timers
} }
drawGraphics() { getCPUStatus() : string {
return this.cpu.getCPUStatus();
} }
drawToCanvas(canvas: HTMLCanvasElement, size: number) { drawToCanvas(canvas: HTMLCanvasElement, size: number) {
@ -43,11 +48,11 @@ class Chip8Emulator {
for(let i = 0; i < this.cpu.displayMemory.length; i++) { for(let i = 0; i < this.cpu.displayMemory.length; i++) {
let isOn: number = this.cpu.displayMemory[i]; let isOn: number = this.cpu.displayMemory[i];
if(isOn === 1) { if(isOn === 1) {
let y = Math.floor(i/width); let y = Math.floor(i/64);
let x = i - (y*width); let x = i - (y*64);
ctx.fillStyle = "WHITE"; ctx.fillStyle = "WHITE";
ctx.fillRect(x, y, 1, 1); ctx.fillRect(x*size, y*size, size, size);
} }
} }
} }

View File

@ -18,7 +18,7 @@ class CPU {
soundTimer: number; // 8b soundTimer: number; // 8b
stackPointer: number; // 16b stackPointer: number; // 16b
stack: Array<number>; stack: Uint16Array;
memory: Uint8Array; memory: Uint8Array;
displayMemory: Uint8Array; displayMemory: Uint8Array;
@ -34,7 +34,7 @@ class CPU {
this.pc = 0x200; this.pc = 0x200;
this.indexReg = 0; this.indexReg = 0;
this.stackPointer = 0; this.stackPointer = 0;
this.stack = new Array<number>(STACK_SIZE); this.stack = new Uint16Array(STACK_SIZE);
this.delayTimer = 0; this.delayTimer = 0;
this.soundTimer = 0; this.soundTimer = 0;
this.regs = new Uint8Array(REGISTERS); this.regs = new Uint8Array(REGISTERS);
@ -99,11 +99,40 @@ class CPU {
this.memory.set(characters, addressFont); this.memory.set(characters, addressFont);
} }
public loadRom(rom: Uint8Array) {
// Loads a ROM into starting PC addres??
console.log(rom);
for(let i = 0; i < rom.length; i++) {
this.memory[this.pc+i] = rom[i];
}
this.memory.set(rom, this.pc);
}
public getCPUStatus() : string{
let status = "";
status += "PC: " + this.pc + "\n";
status += "I: " + this.indexReg.toString(16) + "\n";
for(let i = 0; i < REGISTERS; i++) {
status += "V" + i + ": " + this.regs[i].toString(16).toUpperCase().padStart(2, '0') + "\n";
}
status += "SP: " + this.stackPointer.toString(16) + "\n";
for(let i = 0; i < this.stackPointer; i++) {
status += "ST" + i + ": " + this.stack[i] + "\n";
}
status += "\n";
let firstOpcode: number = this.memory[this.pc];
let secondOpcode: number = this.memory[this.pc + 1];
let opcode: number = firstOpcode << 8 | secondOpcode;
status += "OPCODE FOR PC: " + opcode.toString(16).toUpperCase().padStart(4, '0') + "\n";
return status;
}
private incrementPC() { private incrementPC() {
this.pc += 2; this.pc += 2;
} }
private cycle() { public cycle() {
// Fetch opcode // Fetch opcode
let firstOpcode: number = this.memory[this.pc]; let firstOpcode: number = this.memory[this.pc];
let secondOpcode: number = this.memory[this.pc + 1]; let secondOpcode: number = this.memory[this.pc + 1];
@ -111,38 +140,47 @@ class CPU {
// Decode opcode // Decode opcode
let nib1 = firstOpcode >> 4; // X000 let nib1 = firstOpcode >> 4; // X000
let nib2 = firstOpcode & 0xF; // 0X00 let nib2 = firstOpcode & 0x0F; // 0X00
let nib3 = secondOpcode >> 4; // 00X0 let nib3 = secondOpcode >> 4; // 00X0
let nib4 = secondOpcode & 0xF; // 000X let nib4 = secondOpcode & 0x0F; // 000X
switch(nib1) { switch(nib1) {
case 0x0: case 0x0:
if(opcode == 0x00E0) { if(opcode == 0x00E0) {
// 00E0
// Clear the screen // Clear the screen
this.clearDisplay(); this.clearDisplay();
this.incrementPC();
}else if(opcode == 0x00EE) { }else if(opcode == 0x00EE) {
// 00EE
// Returns from a subroutine // Returns from a subroutine
this.stackPointer--; this.stackPointer--;
this.pc = this.stack[this.pc]; if(this.stackPointer < 0) {
throw new Error("Stack pointer cant go to -1");
}
this.pc = this.stack[this.stackPointer];
} }
this.incrementPC();
break; break;
case 0x1: case 0x1: {
// 1NNN
// goto NNN; // goto NNN;
let threeNib = opcode & 0x0FFF; let address = opcode & 0x0FFF;
this.pc = threeNib; this.pc = address;
}
break; break;
case 0x2: case 0x2: {
// 2NNN
// Calls subroutine at NNN // Calls subroutine at NNN
this.stack[this.stackPointer] = this.pc; // Store PC at stack this.stack[this.stackPointer] = this.pc + 2; // Store PC at stack
this.stackPointer++; // Increment it this.stackPointer++; // Increment it
this.pc = opcode & 0x0FFF; // Go to that address to execute code let address = opcode & 0x0FFF;
this.pc = address; // Go to that address to execute code
}
break; break;
case 0x3: { case 0x3: {
// 3XNN // 3XNN
// Skips the next instruction if VX equals NN // Skips the next instruction if VX equals NN
let val = opcode & 0x00FF; //0x00NN if(this.regs[nib2] == secondOpcode){
if(this.regs[nib2] == val){
this.incrementPC(); this.incrementPC();
} }
this.incrementPC(); this.incrementPC();
@ -151,8 +189,7 @@ class CPU {
case 0x4: { case 0x4: {
// 4XNN // 4XNN
// Skips the next instruction if VX NOT equals NN // Skips the next instruction if VX NOT equals NN
let val = opcode & 0x00FF; //0x00NN if(this.regs[nib2] != secondOpcode){
if(this.regs[nib2] != val){
this.incrementPC(); this.incrementPC();
} }
this.incrementPC(); this.incrementPC();
@ -177,7 +214,7 @@ class CPU {
case 0x7: { case 0x7: {
// 7XNN // 7XNN
// Adds NN to VX // Adds NN to VX
this.regs[nib2] = secondOpcode; this.regs[nib2] += secondOpcode;
this.incrementPC(); this.incrementPC();
} }
break; break;
@ -204,37 +241,40 @@ class CPU {
this.incrementPC(); this.incrementPC();
}else if(nib4 == 0x4) { }else if(nib4 == 0x4) {
// 8XY4 // 8XY4
// Vx += Vy // Vx += Vy, Set VF to carry
let sum = this.regs[nib2] + this.regs[nib3]; let sum = this.regs[nib2] + this.regs[nib3];
this.regs[0xF] = sum > 255 ? 1 : 0; // Set carry flag
this.regs[nib2] = sum & 0xFF; // Get only the first byte this.regs[nib2] = sum & 0xFF; // Get only the first byte
this.regs[0xF] = sum > 255 ? 1 : 0; // Set carry flag
this.incrementPC(); this.incrementPC();
}else if(nib4 == 0x5) { }else if(nib4 == 0x5) {
// 8XY5 // 8XY5
// Vx -= Vy // Vx -= Vy
this.regs[0xF] = this.regs[nib2] > this.regs[nib3] ? 1 : 0;
let subs = this.regs[nib2] - this.regs[nib3]; let subs = this.regs[nib2] - this.regs[nib3];
this.regs[nib2] = subs; this.regs[0xF] = this.regs[nib2] > this.regs[nib3] ? 1 : 0;
this.regs[nib2] = subs & 0xFF;
this.incrementPC(); this.incrementPC();
}else if(nib4 == 0x6) { }else if(nib4 == 0x6) {
// 8XY6 // 8XY6
// Vx >>= 1 // Vx >>= 1
this.regs[0xF] = this.regs[0xF] & 1; // ???? // Store the least significant bit of VX prior // Stores the least significant bit of VX prior to the shift in VF
this.regs[nib2] >>= 1; // Then. Shift Vx by 1 to the right.
this.regs[0xF] = this.regs[nib2] & 1; // Get the least significat bit
this.regs[nib2] = this.regs[nib2] >> 1;
this.incrementPC(); this.incrementPC();
}else if(nib4 == 0x7) { }else if(nib4 == 0x7) {
// 8XY7 // 8XY7
// Vx = Vy - Vx // Vx = Vy - Vx
this.regs[0xF] = this.regs[nib3] > this.regs[nib2] ? 1 : 0;
let subs = this.regs[nib3] - this.regs[nib2]; let subs = this.regs[nib3] - this.regs[nib2];
this.regs[nib2] = subs; this.regs[nib2] = subs;
this.regs[0xF] = this.regs[nib3] > this.regs[nib2] ? 1 : 0;
this.incrementPC(); this.incrementPC();
}else if(nib4 == 0xE) { }else if(nib4 == 0xE) {
// 8XYE // 8XYE
// Vx <<= 1 // Vx <<= 1
// Set VF to 1 if the most significant bit of VX prior to that shift was set // Set VF to 1 if the most significant bit of VX.
this.regs[0xF] = this.regs[0xF] >> 3; // Then shift to the left Vx
this.regs[nib2] <<= 1; this.regs[0xF] = this.regs[nib2] >> 7;
this.regs[nib2] = (this.regs[nib2] << 1) & 0xFF;
this.incrementPC(); this.incrementPC();
} }
@ -253,14 +293,16 @@ class CPU {
case 0xA: { case 0xA: {
// ANNN // ANNN
// Sets I to the address NNN // Sets I to the address NNN
this.indexReg = opcode & 0x0FFF; let address = opcode & 0x0FFF;
this.indexReg = address;
this.incrementPC(); this.incrementPC();
} }
break; break;
case 0xB:{ case 0xB:{
// BNNN // BNNN
// Jumps to the address NNN plus V0 // Jumps to the address NNN plus V0
this.pc = this.regs[0] + opcode & 0x0FFF; let address = opcode & 0x0FFF;
this.pc = this.regs[0] + address;
} }
break; break;
case 0xC: { case 0xC: {
@ -380,7 +422,7 @@ class CPU {
// FX55 // FX55
// reg_dump(Vx, &I) // reg_dump(Vx, &I)
// Stores from V0 to VX in memory starting at address I. // Stores from V0 to VX in memory starting at address I.
for(let i = 0; i < nib2; i++) { for(let i = 0; i <= nib2; i++) {
this.memory[this.indexReg + i] = this.regs[i]; this.memory[this.indexReg + i] = this.regs[i];
} }
this.incrementPC(); this.incrementPC();
@ -388,7 +430,7 @@ class CPU {
// FX65 // FX65
// reg_load(Vx, &I) // reg_load(Vx, &I)
// Fills fomr V0 to VX with values from memory staring at address I. // Fills fomr V0 to VX with values from memory staring at address I.
for(let i = 0; i < nib2; i++) { for(let i = 0; i <= nib2; i++) {
this.regs[i] = this.memory[this.indexReg + i]; this.regs[i] = this.memory[this.indexReg + i];
} }
this.incrementPC(); this.incrementPC();
@ -396,6 +438,9 @@ class CPU {
} }
break; break;
} }
if(this.delayTimer > 0)this.delayTimer--;
if(this.soundTimer > 0)this.soundTimer--; // Should I play a sound???
} }