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>
<!-- Original screen is 64x32 -->
<canvas id="emulator-screen" width="256" height="128"></canvas>
<canvas id="emulator-screen" width="512" height="256"></canvas>
<script>
// Assuming your library exposes an Emulator class
console.log(Revuelto8ts);
console.log(Revuelto8ts.Chip8Emulator);
const emulator = new Revuelto8ts.Chip8Emulator();
// Load ROM (you'll need to implement this method in your emulator)
fetch('./roms/1-chip8-logo.ch8')
let fullDirRoms = [
'./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(buffer => {
//emulator.loadROM(new Uint8Array(buffer));
// Load and start
emulator.loadRom(buffer);
.then(arrayBufferRom => {
let romData = new Uint8Array(arrayBufferRom);
emulator.loadRom(romData);
});
const emulatorCanvas = document.getElementById('emulator-screen');
// Loop
while(true) {
emulator.emulateCycle();
emulator.drawGraphics();
emulator.drawToCanvas(emulatorCanvas, 4);
}
setInterval(function() {
if(emulator.isRomLoaded()) {
//console.log(emulator.getCPUStatus());
emulator.emulateCycle();
emulator.drawToCanvas(emulatorCanvas, 8);
}
}, 5);
</script>
</body>
</html>

View File

@ -7,27 +7,32 @@ class Chip8Emulator {
keyboard: Keyboard;
rom: Uint8Array;
romLoaded: boolean;
constructor() {
this.keyboard = new Keyboard();
this.cpu = new CPU(this.keyboard);
this.rom = new Uint8Array();
this.romLoaded = false;
}
loadRom(rom: Uint8Array) {
this.rom = rom;
this.cpu.loadRom(this.rom);
this.romLoaded = true;
}
isRomLoaded() {
return this.romLoaded;
}
emulateCycle() {
// Fetch opcode
// Decode opcode
// Execute opcode
// Update timers
this.cpu.cycle();
}
drawGraphics() {
getCPUStatus() : string {
return this.cpu.getCPUStatus();
}
drawToCanvas(canvas: HTMLCanvasElement, size: number) {
@ -43,11 +48,11 @@ class Chip8Emulator {
for(let i = 0; i < this.cpu.displayMemory.length; i++) {
let isOn: number = this.cpu.displayMemory[i];
if(isOn === 1) {
let y = Math.floor(i/width);
let x = i - (y*width);
let y = Math.floor(i/64);
let x = i - (y*64);
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
stackPointer: number; // 16b
stack: Array<number>;
stack: Uint16Array;
memory: Uint8Array;
displayMemory: Uint8Array;
@ -34,7 +34,7 @@ class CPU {
this.pc = 0x200;
this.indexReg = 0;
this.stackPointer = 0;
this.stack = new Array<number>(STACK_SIZE);
this.stack = new Uint16Array(STACK_SIZE);
this.delayTimer = 0;
this.soundTimer = 0;
this.regs = new Uint8Array(REGISTERS);
@ -99,11 +99,40 @@ class CPU {
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() {
this.pc += 2;
}
private cycle() {
public cycle() {
// Fetch opcode
let firstOpcode: number = this.memory[this.pc];
let secondOpcode: number = this.memory[this.pc + 1];
@ -111,38 +140,47 @@ class CPU {
// Decode opcode
let nib1 = firstOpcode >> 4; // X000
let nib2 = firstOpcode & 0xF; // 0X00
let nib2 = firstOpcode & 0x0F; // 0X00
let nib3 = secondOpcode >> 4; // 00X0
let nib4 = secondOpcode & 0xF; // 000X
let nib4 = secondOpcode & 0x0F; // 000X
switch(nib1) {
case 0x0:
if(opcode == 0x00E0) {
// 00E0
// Clear the screen
this.clearDisplay();
this.incrementPC();
}else if(opcode == 0x00EE) {
// 00EE
// Returns from a subroutine
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;
case 0x1:
case 0x1: {
// 1NNN
// goto NNN;
let threeNib = opcode & 0x0FFF;
this.pc = threeNib;
let address = opcode & 0x0FFF;
this.pc = address;
}
break;
case 0x2:
case 0x2: {
// 2NNN
// 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.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;
case 0x3: {
// 3XNN
// Skips the next instruction if VX equals NN
let val = opcode & 0x00FF; //0x00NN
if(this.regs[nib2] == val){
if(this.regs[nib2] == secondOpcode){
this.incrementPC();
}
this.incrementPC();
@ -151,8 +189,7 @@ class CPU {
case 0x4: {
// 4XNN
// Skips the next instruction if VX NOT equals NN
let val = opcode & 0x00FF; //0x00NN
if(this.regs[nib2] != val){
if(this.regs[nib2] != secondOpcode){
this.incrementPC();
}
this.incrementPC();
@ -177,7 +214,7 @@ class CPU {
case 0x7: {
// 7XNN
// Adds NN to VX
this.regs[nib2] = secondOpcode;
this.regs[nib2] += secondOpcode;
this.incrementPC();
}
break;
@ -204,37 +241,40 @@ class CPU {
this.incrementPC();
}else if(nib4 == 0x4) {
// 8XY4
// Vx += Vy
// Vx += Vy, Set VF to carry
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[0xF] = sum > 255 ? 1 : 0; // Set carry flag
this.incrementPC();
}else if(nib4 == 0x5) {
// 8XY5
// Vx -= Vy
this.regs[0xF] = this.regs[nib2] > this.regs[nib3] ? 1 : 0;
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();
}else if(nib4 == 0x6) {
// 8XY6
// Vx >>= 1
this.regs[0xF] = this.regs[0xF] & 1; // ???? // Store the least significant bit of VX prior
this.regs[nib2] >>= 1;
// Stores the least significant bit of VX prior to the shift in VF
// 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();
}else if(nib4 == 0x7) {
// 8XY7
// Vx = Vy - Vx
this.regs[0xF] = this.regs[nib3] > this.regs[nib2] ? 1 : 0;
let subs = this.regs[nib3] - this.regs[nib2];
this.regs[nib2] = subs;
this.regs[0xF] = this.regs[nib3] > this.regs[nib2] ? 1 : 0;
this.incrementPC();
}else if(nib4 == 0xE) {
// 8XYE
// Vx <<= 1
// Set VF to 1 if the most significant bit of VX prior to that shift was set
this.regs[0xF] = this.regs[0xF] >> 3;
this.regs[nib2] <<= 1;
// Set VF to 1 if the most significant bit of VX.
// Then shift to the left Vx
this.regs[0xF] = this.regs[nib2] >> 7;
this.regs[nib2] = (this.regs[nib2] << 1) & 0xFF;
this.incrementPC();
}
@ -253,14 +293,16 @@ class CPU {
case 0xA: {
// ANNN
// Sets I to the address NNN
this.indexReg = opcode & 0x0FFF;
let address = opcode & 0x0FFF;
this.indexReg = address;
this.incrementPC();
}
break;
case 0xB:{
// BNNN
// 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;
case 0xC: {
@ -380,7 +422,7 @@ class CPU {
// FX55
// reg_dump(Vx, &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.incrementPC();
@ -388,7 +430,7 @@ class CPU {
// FX65
// reg_load(Vx, &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.incrementPC();
@ -396,6 +438,9 @@ class CPU {
}
break;
}
if(this.delayTimer > 0)this.delayTimer--;
if(this.soundTimer > 0)this.soundTimer--; // Should I play a sound???
}