diff --git a/src/chip8Emulator.ts b/src/chip8Emulator.ts index 93f01c2..29dedc1 100644 --- a/src/chip8Emulator.ts +++ b/src/chip8Emulator.ts @@ -3,16 +3,14 @@ import Keyboard from './keyboard' import RNG from './RNG' class Chip8Emulator { - cpu: CPU; keyboard: Keyboard; - rom: Uint8Array; constructor() { - - this.cpu = new CPU(); this.keyboard = new Keyboard(); + this.cpu = new CPU(this.keyboard); + this.rom = new Uint8Array(); } diff --git a/src/cpu.ts b/src/cpu.ts index a2b5721..a887f8c 100644 --- a/src/cpu.ts +++ b/src/cpu.ts @@ -1,4 +1,5 @@ import RNG from './RNG' +import Keyboard from './keyboard'; const SCREEN_WIDTH = 64; const SCREEN_HEIGHT = 32; @@ -22,9 +23,12 @@ class CPU { memory: Uint8Array; displayMemory: Uint8Array; - rng: RNG; + keyboard: Keyboard; - constructor() { + rng: RNG; + + + constructor(keyboard: Keyboard) { this.memory = new Uint8Array(MEMORY_SIZE); this.displayMemory = new Uint8Array(SCREEN_WIDTH*SCREEN_HEIGHT); this.pc = 0x200; @@ -34,6 +38,7 @@ class CPU { this.delayTimer = 0; this.soundTimer = 0; this.regs = new Uint8Array(REGISTERS); + this.keyboard = keyboard; this.rng = new RNG(0); @@ -268,29 +273,128 @@ class CPU { case 0xD: { // DXYN // draw(Vx, Vy, N) - this.regs[0xF] = 0; + this.regs[0xF] = 0; // Reset register VF let regX = this.regs[nib2]; let regY = this.regs[nib3]; - let y = 0; - while(y < nib4) { + for(let y = 0; y < nib4; y++) { // A sprite is always 8 bits horizontal - let pixel = this.memory[this.indexReg + y]; - let x = 0; - while(x < 8) { - const msb = 0x80; + let pixel = this.memory[this.indexReg + y]; // Fetch pixel from memory starting at I reg + + for(let x = 0; x < 8; x++) { + const MSB = 0x80; // 0b10000000 - - x++; + if((pixel & (MSB >> x)) != 0) { + let mem = x + regX + ((y + regY) * SCREEN_WIDTH); + if(this.displayMemory[mem] == 1) { + this.regs[0xF] = 1; + } + this.displayMemory[mem] ^= 1; + } } - - y++; } this.incrementPC(); } break; + case 0xE: { + if(secondOpcode == 0x9E) { + // EX9E + // if (key() == Vx) + // Skips the next instruction if the key stored at VX is pressed + if(this.keyboard.keys[this.regs[nib2]] == 1) { + this.incrementPC(); + } + }else if(secondOpcode == 0xA1) { + // EXA1 + // if (key() != Vx) + // Skips the next instruction if the key stored at VX is NOT pressed + if(this.keyboard.keys[this.regs[nib2]] != 1) { + this.incrementPC(); + } + } + this.incrementPC(); + } + break; + case 0xF: { + if(secondOpcode == 0x07) { + // FX07 + // Vx = delayTimer + this.regs[nib2] = this.delayTimer; + this.incrementPC(); + }else if(secondOpcode == 0x0A) { + // FX0A + // A key pressed is awaited and then stored at VX. + // [BLOCKING OPERATION], all instructions are halted until next key event + // Vx = get_key() + let keyPressed = false; + + for(let i = 0; i < this.keyboard.keys.length; i++) { + if(this.keyboard.keys[i] != 0) { + keyPressed = true; + this.regs[nib2] = i; + break; + } + } + + if(!keyPressed) + return; // NOT INCREMENT PC SO WE ARE STUCK IN THIS WAITING + + this.incrementPC(); + }else if(secondOpcode == 0x15) { + // FX15 + // delayTimer = Vx + this.delayTimer = this.regs[nib2]; + this.incrementPC(); + }else if(secondOpcode == 0x18) { + // FX18 + // soundTimer = Vx + this.soundTimer = this.regs[nib2]; + this.incrementPC(); + }else if(secondOpcode == 0x1E) { + // FX1E + // I += Vx + // Adds VX to I. VF is not affected + this.indexReg += this.regs[nib2]; + this.incrementPC(); + }else if(secondOpcode == 0x29) { + // FX29 + // I = sprite_addr[Vx] + // Sets I to the location of the sprite for the character in VX + this.indexReg = this.regs[nib2] * 0x5; // ?? + this.incrementPC(); + }else if(secondOpcode == 0x33) { + // FX33 + // set_BCD(Vx) + // *(I+0) = BCD(3); + // *(I+1) = BCD(2); + // *(I+2) = BCD(1); + // Stores the binary-coded decimal representation of Vx, with the hundreds digit memory at location in I, + // + this.memory[this.indexReg] = this.regs[nib2] / 100; + this.memory[this.indexReg + 1] = (this.regs[nib2] / 10) % 10; + this.memory[this.indexReg + 2] = this.regs[nib2] % 10; + this.incrementPC(); + }else if(secondOpcode == 0x55) { + // FX55 + // reg_dump(Vx, &I) + // Stores from V0 to VX in memory starting at address I. + for(let i = 0; i < nib2; i++) { + this.memory[this.indexReg + i] = this.regs[i]; + } + this.incrementPC(); + }else if(secondOpcode == 0x65) { + // 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++) { + this.regs[i] = this.memory[this.indexReg + i]; + } + this.incrementPC(); + } + } + break; } }