mirror of
https://github.com/arnaucube/go-chip8.git
synced 2026-02-06 19:16:46 +01:00
Screen drawing works,add zoom,add keyboard mapping
This commit is contained in:
165
main.go
165
main.go
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
@@ -36,6 +37,7 @@ type chip8 struct {
|
||||
|
||||
// graphics
|
||||
renderer *sdl.Renderer
|
||||
zoom int32
|
||||
}
|
||||
|
||||
// Initialize registers and memory once
|
||||
@@ -44,6 +46,11 @@ func (c *chip8) initialize() {
|
||||
c.opcode = 0
|
||||
c.index = 0
|
||||
c.sp = 0
|
||||
c.zoom = 10
|
||||
|
||||
for i := 0; i < len(fontSet); i++ {
|
||||
c.memory[i] = fontSet[i]
|
||||
}
|
||||
}
|
||||
|
||||
func (c *chip8) emulateCycle() {
|
||||
@@ -53,7 +60,7 @@ func (c *chip8) emulateCycle() {
|
||||
y := byte((c.opcode & 0x00F0) >> 4)
|
||||
nn := byte(c.opcode & 0x00FF)
|
||||
nnn := uint16(c.opcode & 0x0FFF)
|
||||
fmt.Printf("%X\n", c.opcode)
|
||||
// fmt.Printf("%X\n", c.opcode)
|
||||
|
||||
// Decode Opcode
|
||||
// https://en.wikipedia.org/wiki/CHIP-8#Opcode_table
|
||||
@@ -92,7 +99,6 @@ func (c *chip8) emulateCycle() {
|
||||
case 0x3000:
|
||||
// 3XNN Skips the next instruction if VX equals NN. (Usually
|
||||
// the next instruction is a jump to skip a code block)
|
||||
fmt.Println(c.v[x], nn)
|
||||
if c.v[x] == nn {
|
||||
c.pc += 2
|
||||
}
|
||||
@@ -147,12 +153,12 @@ func (c *chip8) emulateCycle() {
|
||||
case 0x0004:
|
||||
// 0x8XY4 Adds VY to VX. VF is set to 1 when there's a
|
||||
// carry, and to 0 when there isn't
|
||||
if c.v[(c.opcode&0x00F0)>>4] > (0xFF - c.v[c.opcode&0x0F00]) {
|
||||
if c.v[y] > (0xFF - c.v[x]) {
|
||||
c.v[0xF] = 1
|
||||
} else {
|
||||
c.v[0xF] = 0
|
||||
}
|
||||
c.v[(c.opcode&0x0F00)>>8] += c.v[(c.opcode&0x00F0)>>4]
|
||||
c.v[x] += c.v[y]
|
||||
c.pc += 2
|
||||
break
|
||||
case 0x0005:
|
||||
@@ -208,7 +214,7 @@ func (c *chip8) emulateCycle() {
|
||||
c.pc += 2
|
||||
case 0xA000:
|
||||
// ANNN set index to NNN position
|
||||
c.index = c.opcode & 0x0FFF
|
||||
c.index = nnn
|
||||
c.pc += 2
|
||||
break
|
||||
case 0xB000:
|
||||
@@ -228,34 +234,25 @@ func (c *chip8) emulateCycle() {
|
||||
// instruction. As described above, VF is set to 1 if any
|
||||
// screen pixels are flipped from set to unset when the sprite
|
||||
// is drawn, and to 0 if that doesn’t happen
|
||||
fmt.Printf("D: %X\n", c.opcode)
|
||||
|
||||
height := c.opcode & 0x000F
|
||||
|
||||
var pixel byte
|
||||
c.v[0xF] = 0
|
||||
|
||||
for yline := uint16(0); yline < height; yline++ {
|
||||
pixel = c.memory[c.index+yline]
|
||||
for xline := uint16(0); xline < 8; xline++ {
|
||||
if (pixel & (0x80 >> xline)) != 0 {
|
||||
if c.gfx[(w*(uint16(y)+yline)+(uint16(x)+xline))] == 1 {
|
||||
if c.gfx[(uint16(c.v[x])+xline)+((uint16(c.v[y])+yline)*w)] == 1 {
|
||||
c.v[0xF] = 1
|
||||
}
|
||||
c.gfx[w*(uint16(y)+yline)+(uint16(x)+xline)] ^= 1
|
||||
c.gfx[(uint16(c.v[x])+xline)+((uint16(c.v[y])+yline)*w)] ^= 1
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// for yline := uint16(0); yline < height; yline++ {
|
||||
// pixel = c.memory[c.index+yline]
|
||||
// for xline := uint16(0); xline < 8; xline++ {
|
||||
// if (pixel & (0x80 >> xline)) != 0 {
|
||||
// if c.gfx[(uint16(x)+xline+((uint16(y)+yline)*64))] == 1 {
|
||||
// c.v[0xF] = 1
|
||||
// }
|
||||
// c.gfx[uint16(x)+xline+((uint16(y)+yline)*64)] ^= 1
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
c.drawFlag = true
|
||||
c.pc += 2
|
||||
break
|
||||
@@ -265,18 +262,21 @@ func (c *chip8) emulateCycle() {
|
||||
// EX9E Skips the next instruction if the key stored in
|
||||
// VX is pressed. (Usually the next instruction is a
|
||||
// jump to skip a code block)
|
||||
if c.key[c.v[(c.opcode&0x0F00)>>8]] != 0 {
|
||||
c.pc += 4
|
||||
} else {
|
||||
if c.key[c.v[x]] != 0 {
|
||||
c.pc += 2
|
||||
}
|
||||
c.pc += 2
|
||||
break
|
||||
case 0x00A1:
|
||||
// EXA1 Skips the next instruction if the key stored in
|
||||
// VX isn't pressed. (Usually the next instruction is a
|
||||
// jump to skip a code block)
|
||||
// TODO
|
||||
if c.key[c.v[x]] != 1 {
|
||||
c.pc += 2
|
||||
}
|
||||
c.pc += 2
|
||||
default:
|
||||
fmt.Printf("Unknown opcode [0xE000]: 0x%X\n", c.opcode)
|
||||
}
|
||||
break
|
||||
case 0xF000:
|
||||
@@ -289,7 +289,16 @@ func (c *chip8) emulateCycle() {
|
||||
// FX0A A key press is awaited, and then stored in VX.
|
||||
// (Blocking Operation. All instruction halted until
|
||||
// next key event)
|
||||
// TODO
|
||||
pressed := false
|
||||
for i := 0; i < 16; i++ {
|
||||
if c.key[i] == 1 {
|
||||
c.v[x] = byte(i)
|
||||
pressed = true
|
||||
}
|
||||
}
|
||||
if !pressed {
|
||||
return
|
||||
}
|
||||
c.pc += 2
|
||||
case 0x0015:
|
||||
// FX15 Sets the delay timer to VX
|
||||
@@ -333,6 +342,8 @@ func (c *chip8) emulateCycle() {
|
||||
}
|
||||
c.pc += 2
|
||||
break
|
||||
default:
|
||||
fmt.Printf("Unknown opcode [0xF000]: 0x%X\n", c.opcode)
|
||||
}
|
||||
break
|
||||
default:
|
||||
@@ -387,8 +398,9 @@ func (c *chip8) setupInput() {
|
||||
}
|
||||
|
||||
func (c *chip8) setupGraphics() {
|
||||
fmt.Println(c.zoom)
|
||||
window, err := sdl.CreateWindow("go-chip8", sdl.WINDOWPOS_UNDEFINED,
|
||||
sdl.WINDOWPOS_UNDEFINED, w, h, sdl.WINDOW_SHOWN)
|
||||
sdl.WINDOWPOS_UNDEFINED, w*c.zoom, h*c.zoom, sdl.WINDOW_SHOWN)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -399,37 +411,114 @@ func (c *chip8) setupGraphics() {
|
||||
}
|
||||
|
||||
func (c *chip8) drawGraphics() {
|
||||
// x := 0
|
||||
// y := 0
|
||||
// for i := 0; i < len(c.gfx); i++ {
|
||||
// if i%w == 0 {
|
||||
// x = 0
|
||||
// y++
|
||||
// fmt.Println("")
|
||||
// }
|
||||
// if c.gfx[i]^1 == 0 {
|
||||
// c.renderer.DrawPoint(int32(x), int32(y))
|
||||
// fmt.Print("x")
|
||||
// } else {
|
||||
// fmt.Print(" ")
|
||||
// }
|
||||
// x++
|
||||
// }
|
||||
|
||||
// for y := 0; y < h; y++ {
|
||||
// for x := 0; x < w; x++ {
|
||||
// pixel := c.gfx[y*w+x]
|
||||
// if pixel != 0 {
|
||||
// c.renderer.DrawPoint(int32(x), int32(y))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
c.renderer.SetDrawColor(0, 0, 0, 1)
|
||||
c.renderer.Clear()
|
||||
c.renderer.SetDrawColor(255, 255, 255, 1)
|
||||
x := 0
|
||||
y := 0
|
||||
for i := 0; i < len(c.gfx); i++ {
|
||||
if i%w == 0 {
|
||||
// jump line
|
||||
x = 0
|
||||
y++
|
||||
}
|
||||
if c.gfx[i]^1 == 1 {
|
||||
c.renderer.DrawPoint(int32(x), int32(y))
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
pixel := c.gfx[y*w+x]
|
||||
if pixel != 0 {
|
||||
c.renderer.FillRect(&sdl.Rect{
|
||||
X: int32(x) * c.zoom,
|
||||
Y: int32(y) * c.zoom,
|
||||
W: c.zoom,
|
||||
H: c.zoom,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.renderer.Present()
|
||||
c.drawFlag = false
|
||||
}
|
||||
|
||||
func (c *chip8) setKeys() {
|
||||
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
||||
switch t := event.(type) {
|
||||
case *sdl.QuitEvent:
|
||||
println("Quit")
|
||||
os.Exit(0)
|
||||
// running = false
|
||||
// break
|
||||
case *sdl.KeyboardEvent:
|
||||
switch t.Type {
|
||||
case sdl.KEYDOWN:
|
||||
if keyHex, ok := validKeys[t.Keysym.Sym]; ok {
|
||||
fmt.Println("down", t.Keysym.Sym)
|
||||
c.key[keyHex] = 1
|
||||
fmt.Println(keyHex, c.key[keyHex])
|
||||
}
|
||||
case sdl.KEYUP:
|
||||
if keyHex, ok := validKeys[t.Keysym.Sym]; ok {
|
||||
fmt.Println("up", t.Keysym.Sym)
|
||||
c.key[keyHex] = 0
|
||||
fmt.Println(keyHex, c.key[keyHex])
|
||||
}
|
||||
if t.Keysym.Sym == sdl.K_ESCAPE {
|
||||
fmt.Println("EXIT")
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var validKeys = map[sdl.Keycode]byte{
|
||||
sdl.K_0: 0x00,
|
||||
sdl.K_1: 0x01,
|
||||
sdl.K_2: 0x02,
|
||||
sdl.K_3: 0x03,
|
||||
sdl.K_4: 0x04,
|
||||
sdl.K_5: 0x05,
|
||||
sdl.K_6: 0x06,
|
||||
sdl.K_7: 0x07,
|
||||
sdl.K_8: 0x08,
|
||||
sdl.K_9: 0x09,
|
||||
sdl.K_a: 0x0a,
|
||||
sdl.K_b: 0x0b,
|
||||
sdl.K_c: 0x0c,
|
||||
sdl.K_d: 0x0d,
|
||||
sdl.K_e: 0x0e,
|
||||
sdl.K_f: 0x0f,
|
||||
}
|
||||
|
||||
func main() {
|
||||
filepath := flag.String("file", "file-path", "file path of the input file")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
var c chip8
|
||||
c.initialize()
|
||||
c.setupGraphics()
|
||||
c.setupInput()
|
||||
|
||||
c.initialize()
|
||||
err := c.loadGame(*filepath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -439,7 +528,7 @@ func main() {
|
||||
c.emulateCycle()
|
||||
if c.drawFlag {
|
||||
c.drawGraphics()
|
||||
c.setKeys()
|
||||
}
|
||||
c.setKeys()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user