draw operations
This commit is contained in:
parent
b10d6e6c81
commit
a6c9060e8c
|
@ -2,6 +2,7 @@ package chip8
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"image"
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,14 +25,15 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Emulator struct {
|
type Emulator struct {
|
||||||
V [16]uint8 // general registers
|
V [16]uint8 // general registers
|
||||||
I uint16 // address register
|
I uint16 // address register
|
||||||
SP uint16 // stack pointer
|
SP uint16 // stack pointer
|
||||||
PC uint16 // program counter
|
PC uint16 // program counter
|
||||||
DT uint8 // delay timer
|
DT uint8 // delay timer
|
||||||
ST uint8 // sound timer
|
ST uint8 // sound timer
|
||||||
Memory [MemorySize]uint8 // 4KB of system RAM
|
Memory [MemorySize]uint8 // 4KB of system RAM
|
||||||
ROM []uint8 // game rom
|
ROM []uint8 // game rom
|
||||||
|
Display *image.Gray
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEmulator() *Emulator {
|
func NewEmulator() *Emulator {
|
||||||
|
@ -49,9 +51,11 @@ func (emulator *Emulator) Reset() {
|
||||||
emulator.ST = 0
|
emulator.ST = 0
|
||||||
emulator.Memory = [MemorySize]uint8{}
|
emulator.Memory = [MemorySize]uint8{}
|
||||||
copy(emulator.Memory[ProgramAddress:], emulator.ROM)
|
copy(emulator.Memory[ProgramAddress:], emulator.ROM)
|
||||||
|
emulator.Display = image.NewGray(image.Rect(0, 0, Width, Height))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (emulator *Emulator) Cycle() {
|
func (emulator *Emulator) Cycle() {
|
||||||
|
|
||||||
pc := emulator.PC
|
pc := emulator.PC
|
||||||
|
|
||||||
emulator.DT = uint8(math.Max(0, float64(emulator.DT)-1))
|
emulator.DT = uint8(math.Max(0, float64(emulator.DT)-1))
|
||||||
|
@ -60,12 +64,19 @@ func (emulator *Emulator) Cycle() {
|
||||||
instruction := binary.BigEndian.Uint16(emulator.Memory[emulator.PC:])
|
instruction := binary.BigEndian.Uint16(emulator.Memory[emulator.PC:])
|
||||||
|
|
||||||
nnn := instruction & 0x0FFF
|
nnn := instruction & 0x0FFF
|
||||||
// n := uint8(instruction & 0x000F)
|
n := uint8(instruction & 0x000F)
|
||||||
kk := uint8(instruction & 0x00FF)
|
kk := uint8(instruction & 0x00FF)
|
||||||
x := uint8(instruction & 0x0F00 >> 8)
|
x := uint8(instruction & 0x0F00 >> 8)
|
||||||
y := uint8(instruction & 0x00F0 >> 4)
|
y := uint8(instruction & 0x00F0 >> 4)
|
||||||
|
|
||||||
switch instruction & 0xF000 >> 12 {
|
switch instruction & 0xF000 >> 12 {
|
||||||
|
case 0x0:
|
||||||
|
switch instruction & 0x00FF {
|
||||||
|
case 0xE0: // 00E0 - CLS
|
||||||
|
emulator.ClearScreen()
|
||||||
|
case 0xEE: // 00EE - RET
|
||||||
|
emulator.Return()
|
||||||
|
}
|
||||||
case 0x1: // 1nnn - JP addr
|
case 0x1: // 1nnn - JP addr
|
||||||
emulator.Jump(nnn)
|
emulator.Jump(nnn)
|
||||||
case 0x2: // 2nnn - CALL addr
|
case 0x2: // 2nnn - CALL addr
|
||||||
|
@ -106,6 +117,7 @@ func (emulator *Emulator) Cycle() {
|
||||||
case 0xB: // Bnnn - JP V0, addr
|
case 0xB: // Bnnn - JP V0, addr
|
||||||
case 0xC: // Cxkk - RND Vx, byte
|
case 0xC: // Cxkk - RND Vx, byte
|
||||||
case 0xD: // Dxyn - DRW Vx, Vy, nibble
|
case 0xD: // Dxyn - DRW Vx, Vy, nibble
|
||||||
|
emulator.Draw(x, y, n)
|
||||||
case 0xE:
|
case 0xE:
|
||||||
switch instruction & 0x00FF {
|
switch instruction & 0x00FF {
|
||||||
case 0x9E: // SKP Vx
|
case 0x9E: // SKP Vx
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
package chip8
|
package chip8
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/draw"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Clear the display.
|
||||||
func (emulator *Emulator) ClearScreen() {
|
func (emulator *Emulator) ClearScreen() {
|
||||||
// TODO: clear the screen buffer
|
draw.Draw(emulator.Display, emulator.Display.Bounds(), &image.Uniform{color.Black}, image.Point{}, draw.Src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return from a subroutine.
|
||||||
|
//
|
||||||
|
// The interpreter sets the program counter to the address at the top of the stack,
|
||||||
|
// then subtracts 1 from the stack pointer.
|
||||||
func (emulator *Emulator) Return() {
|
func (emulator *Emulator) Return() {
|
||||||
emulator.StackPop()
|
emulator.StackPop()
|
||||||
}
|
}
|
||||||
|
@ -128,7 +139,7 @@ func (emulator *Emulator) Sub(x uint8, y uint8) {
|
||||||
// If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0.
|
// If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0.
|
||||||
// Then Vx is divided by 2.
|
// Then Vx is divided by 2.
|
||||||
func (emulator *Emulator) ShiftRight(x uint8) {
|
func (emulator *Emulator) ShiftRight(x uint8) {
|
||||||
emulator.V[0xF] = emulator.V[x] & 0b00000001
|
emulator.V[0xF] = emulator.V[x] & 0b0000_0001
|
||||||
emulator.V[x] >>= 1
|
emulator.V[x] >>= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +157,41 @@ func (emulator *Emulator) SubN(x uint8, y uint8) {
|
||||||
// If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0.
|
// If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0.
|
||||||
// Then Vx is multiplied by 2.
|
// Then Vx is multiplied by 2.
|
||||||
func (emulator *Emulator) ShiftLeft(x uint8) {
|
func (emulator *Emulator) ShiftLeft(x uint8) {
|
||||||
emulator.V[0xF] = emulator.V[x] & 0b10000000
|
emulator.V[0xF] = emulator.V[x] & 0b1000_0000
|
||||||
emulator.V[x] <<= 1
|
emulator.V[x] <<= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
|
||||||
|
//
|
||||||
|
// The interpreter reads n bytes from memory, starting at the address stored in I.
|
||||||
|
// These bytes are then displayed as sprites on screen at coordinates (Vx, Vy).
|
||||||
|
// Sprites are XORed onto the existing screen. If this causes any pixels to be erased,
|
||||||
|
// VF is set to 1, otherwise it is set to 0. If the sprite is positioned so part of it
|
||||||
|
// is outside the coordinates of the display, it wraps around to the opposite side of the screen.
|
||||||
|
func (emulator *Emulator) Draw(x uint8, y uint8, n uint8) {
|
||||||
|
width := uint8(8)
|
||||||
|
height := n
|
||||||
|
|
||||||
|
emulator.V[0xF] = 0x00 // clean collision flag
|
||||||
|
|
||||||
|
for row := uint8(0); row < height; row += 1 {
|
||||||
|
sprite := emulator.Memory[emulator.I+uint16(row)]
|
||||||
|
|
||||||
|
for col := uint8(0); col < width; col += 1 {
|
||||||
|
if (sprite & 0b1000_0000) == 0x1 {
|
||||||
|
px, py := int(emulator.V[x]+col), int(emulator.V[y]+row)
|
||||||
|
|
||||||
|
// check for pixel collision
|
||||||
|
if emulator.Display.At(px, py) != color.Black {
|
||||||
|
emulator.V[0xF] = 0x01 // set collision flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw pixel
|
||||||
|
emulator.Display.Set(px, py, color.White)
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift the sprite left 1. This will move the next next col/bit of the sprite into the first position.
|
||||||
|
sprite <<= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user