draw operations
This commit is contained in:
parent
b10d6e6c81
commit
a6c9060e8c
|
@ -2,6 +2,7 @@ package chip8
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"image"
|
||||
"math"
|
||||
)
|
||||
|
||||
|
@ -24,14 +25,15 @@ const (
|
|||
)
|
||||
|
||||
type Emulator struct {
|
||||
V [16]uint8 // general registers
|
||||
I uint16 // address register
|
||||
SP uint16 // stack pointer
|
||||
PC uint16 // program counter
|
||||
DT uint8 // delay timer
|
||||
ST uint8 // sound timer
|
||||
Memory [MemorySize]uint8 // 4KB of system RAM
|
||||
ROM []uint8 // game rom
|
||||
V [16]uint8 // general registers
|
||||
I uint16 // address register
|
||||
SP uint16 // stack pointer
|
||||
PC uint16 // program counter
|
||||
DT uint8 // delay timer
|
||||
ST uint8 // sound timer
|
||||
Memory [MemorySize]uint8 // 4KB of system RAM
|
||||
ROM []uint8 // game rom
|
||||
Display *image.Gray
|
||||
}
|
||||
|
||||
func NewEmulator() *Emulator {
|
||||
|
@ -49,9 +51,11 @@ func (emulator *Emulator) Reset() {
|
|||
emulator.ST = 0
|
||||
emulator.Memory = [MemorySize]uint8{}
|
||||
copy(emulator.Memory[ProgramAddress:], emulator.ROM)
|
||||
emulator.Display = image.NewGray(image.Rect(0, 0, Width, Height))
|
||||
}
|
||||
|
||||
func (emulator *Emulator) Cycle() {
|
||||
|
||||
pc := emulator.PC
|
||||
|
||||
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:])
|
||||
|
||||
nnn := instruction & 0x0FFF
|
||||
// n := uint8(instruction & 0x000F)
|
||||
n := uint8(instruction & 0x000F)
|
||||
kk := uint8(instruction & 0x00FF)
|
||||
x := uint8(instruction & 0x0F00 >> 8)
|
||||
y := uint8(instruction & 0x00F0 >> 4)
|
||||
|
||||
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
|
||||
emulator.Jump(nnn)
|
||||
case 0x2: // 2nnn - CALL addr
|
||||
|
@ -106,6 +117,7 @@ func (emulator *Emulator) Cycle() {
|
|||
case 0xB: // Bnnn - JP V0, addr
|
||||
case 0xC: // Cxkk - RND Vx, byte
|
||||
case 0xD: // Dxyn - DRW Vx, Vy, nibble
|
||||
emulator.Draw(x, y, n)
|
||||
case 0xE:
|
||||
switch instruction & 0x00FF {
|
||||
case 0x9E: // SKP Vx
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
package chip8
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
// Clear the display.
|
||||
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() {
|
||||
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.
|
||||
// Then Vx is divided by 2.
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
// Then Vx is multiplied by 2.
|
||||
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
|
||||
}
|
||||
|
||||
// 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