Browse Source

Screen drawing works,add zoom,add keyboard mapping

master
arnaucube 4 years ago
parent
commit
e0344cbf06
1 changed files with 127 additions and 38 deletions
  1. +127
    -38
      main.go

+ 127
- 38
main.go

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
"os"
"github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/sdl"
) )
@ -36,6 +37,7 @@ type chip8 struct {
// graphics // graphics
renderer *sdl.Renderer renderer *sdl.Renderer
zoom int32
} }
// Initialize registers and memory once // Initialize registers and memory once
@ -44,6 +46,11 @@ func (c *chip8) initialize() {
c.opcode = 0 c.opcode = 0
c.index = 0 c.index = 0
c.sp = 0 c.sp = 0
c.zoom = 10
for i := 0; i < len(fontSet); i++ {
c.memory[i] = fontSet[i]
}
} }
func (c *chip8) emulateCycle() { func (c *chip8) emulateCycle() {
@ -53,7 +60,7 @@ func (c *chip8) emulateCycle() {
y := byte((c.opcode & 0x00F0) >> 4) y := byte((c.opcode & 0x00F0) >> 4)
nn := byte(c.opcode & 0x00FF) nn := byte(c.opcode & 0x00FF)
nnn := uint16(c.opcode & 0x0FFF) nnn := uint16(c.opcode & 0x0FFF)
fmt.Printf("%X\n", c.opcode)
// fmt.Printf("%X\n", c.opcode)
// Decode Opcode // Decode Opcode
// https://en.wikipedia.org/wiki/CHIP-8#Opcode_table // https://en.wikipedia.org/wiki/CHIP-8#Opcode_table
@ -92,7 +99,6 @@ func (c *chip8) emulateCycle() {
case 0x3000: case 0x3000:
// 3XNN Skips the next instruction if VX equals NN. (Usually // 3XNN Skips the next instruction if VX equals NN. (Usually
// the next instruction is a jump to skip a code block) // the next instruction is a jump to skip a code block)
fmt.Println(c.v[x], nn)
if c.v[x] == nn { if c.v[x] == nn {
c.pc += 2 c.pc += 2
} }
@ -147,12 +153,12 @@ func (c *chip8) emulateCycle() {
case 0x0004: case 0x0004:
// 0x8XY4 Adds VY to VX. VF is set to 1 when there's a // 0x8XY4 Adds VY to VX. VF is set to 1 when there's a
// carry, and to 0 when there isn't // 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 c.v[0xF] = 1
} else { } else {
c.v[0xF] = 0 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 c.pc += 2
break break
case 0x0005: case 0x0005:
@ -208,7 +214,7 @@ func (c *chip8) emulateCycle() {
c.pc += 2 c.pc += 2
case 0xA000: case 0xA000:
// ANNN set index to NNN position // ANNN set index to NNN position
c.index = c>n class="p">.n>opcode & 0x0FFF
c.index = nnn
c.pc += 2 c.pc += 2
break break
case 0xB000: case 0xB000:
@ -228,34 +234,25 @@ func (c *chip8) emulateCycle() {
// instruction. As described above, VF is set to 1 if any // instruction. As described above, VF is set to 1 if any
// screen pixels are flipped from set to unset when the sprite // screen pixels are flipped from set to unset when the sprite
// is drawn, and to 0 if that doesn’t happen // is drawn, and to 0 if that doesn’t happen
fmt.Printf("D: %X\n", c.opcode)
height := c.opcode & 0x000F height := c.opcode & 0x000F
var pixel byte var pixel byte
c.v[0xF] = 0 c.v[0xF] = 0
for yline := uint16(0); yline < height; yline++ { for yline := uint16(0); yline < height; yline++ {
pixel = c.memory[c.index+yline] pixel = c.memory[c.index+yline]
for xline := uint16(0); xline < 8; xline++ { for xline := uint16(0); xline < 8; xline++ {
if (pixel & (0x80 >> xline)) != 0 { 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.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.drawFlag = true
c.pc += 2 c.pc += 2
break break
@ -265,18 +262,21 @@ func (c *chip8) emulateCycle() {
// EX9E Skips the next instruction if the key stored in // EX9E Skips the next instruction if the key stored in
// VX is pressed. (Usually the next instruction is a // VX is pressed. (Usually the next instruction is a
// jump to skip a code block) // 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
} }
c.pc += 2
break break
case 0x00A1: case 0x00A1:
// EXA1 Skips the next instruction if the key stored in // EXA1 Skips the next instruction if the key stored in
// VX isn't pressed. (Usually the next instruction is a // VX isn't pressed. (Usually the next instruction is a
// jump to skip a code block) // jump to skip a code block)
// TODO
if c.key[c.v[x]] != 1 {
c.pc += 2
}
c.pc += 2 c.pc += 2
default:
fmt.Printf("Unknown opcode [0xE000]: 0x%X\n", c.opcode)
} }
break break
case 0xF000: case 0xF000:
@ -289,7 +289,16 @@ func (c *chip8) emulateCycle() {
// FX0A A key press is awaited, and then stored in VX. // FX0A A key press is awaited, and then stored in VX.
// (Blocking Operation. All instruction halted until // (Blocking Operation. All instruction halted until
// next key event) // 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 c.pc += 2
case 0x0015: case 0x0015:
// FX15 Sets the delay timer to VX // FX15 Sets the delay timer to VX
@ -333,6 +342,8 @@ func (c *chip8) emulateCycle() {
} }
c.pc += 2 c.pc += 2
break break
default:
fmt.Printf("Unknown opcode [0xF000]: 0x%X\n", c.opcode)
} }
break break
default: default:
@ -387,8 +398,9 @@ func (c *chip8) setupInput() {
} }
func (c *chip8) setupGraphics() { func (c *chip8) setupGraphics() {
fmt.Println(c.zoom)
window, err := sdl.CreateWindow("go-chip8", sdl.WINDOWPOS_UNDEFINED, 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 { if err != nil {
panic(err) panic(err)
} }
@ -399,37 +411,114 @@ func (c *chip8) setupGraphics() {
} }
func (c *chip8) drawGraphics() { 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) 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.renderer.Present()
c.drawFlag = false c.drawFlag = false
} }
func (c *chip8) setKeys() { 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() { func main() {
filepath := flag.String("file", "file-path", "file path of the input file") filepath := flag.String("file", "file-path", "file path of the input file")
flag.Parse() flag.Parse()
var c chip8 var c chip8
c.initialize()
c.setupGraphics() c.setupGraphics()
c.setupInput() c.setupInput()
c.initialize()
err := c.loadGame(*filepath) err := c.loadGame(*filepath)
if err != nil { if err != nil {
panic(err) panic(err)
@ -439,7 +528,7 @@ func main() {
c.emulateCycle() c.emulateCycle()
if c.drawFlag { if c.drawFlag {
c.drawGraphics() c.drawGraphics()
c.setKeys()
} }
c.setKeys()
} }
} }

Loading…
Cancel
Save