draw operations

This commit is contained in:
Jairinho 2022-02-24 17:05:00 -03:00
parent b10d6e6c81
commit a6c9060e8c
No known key found for this signature in database
GPG Key ID: 954589B18A21D5B6
2 changed files with 70 additions and 12 deletions

View File

@ -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

View File

@ -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
}
}
}