Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
d6e1b989e2 | |||
1f526b5331 | |||
edac661d26 | |||
97a4855bea | |||
35c01939a0 | |||
b0797ff4af | |||
ec8fb167e7 |
@ -1,8 +1,8 @@
|
|||||||
package chip8
|
package chip8
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
const graphicsBufferSize = 64 * 32
|
const graphicsBufferSize = 64 * 32
|
||||||
@ -10,6 +10,7 @@ const graphicsBufferSize = 64 * 32
|
|||||||
type Chip8 struct {
|
type Chip8 struct {
|
||||||
addressRegister uint16
|
addressRegister uint16
|
||||||
beepTimer byte
|
beepTimer byte
|
||||||
|
beepRequired bool
|
||||||
drawRequired bool
|
drawRequired bool
|
||||||
delayTimer byte
|
delayTimer byte
|
||||||
graphics [graphicsBufferSize]byte
|
graphics [graphicsBufferSize]byte
|
||||||
@ -48,7 +49,6 @@ func NewCHIP8(prog []byte) *Chip8 {
|
|||||||
memory_slice := cpu.memory[:80]
|
memory_slice := cpu.memory[:80]
|
||||||
copy(memory_slice, getLetters())
|
copy(memory_slice, getLetters())
|
||||||
memory_slice = cpu.memory[0x200:]
|
memory_slice = cpu.memory[0x200:]
|
||||||
fmt.Printf("%d\n", prog[0])
|
|
||||||
copy(memory_slice, prog)
|
copy(memory_slice, prog)
|
||||||
|
|
||||||
// Do some extra checking to ensure the right
|
// Do some extra checking to ensure the right
|
||||||
@ -70,11 +70,22 @@ func (cpu *Chip8) TickTimers() {
|
|||||||
if cpu.delayTimer > 0 {
|
if cpu.delayTimer > 0 {
|
||||||
cpu.delayTimer--
|
cpu.delayTimer--
|
||||||
}
|
}
|
||||||
if cpu.beepTimer > 0 {
|
if cpu.beepTimer == 1 {
|
||||||
|
cpu.beepRequired = true
|
||||||
|
cpu.beepTimer--
|
||||||
|
} else if cpu.beepTimer > 1 {
|
||||||
cpu.beepTimer--
|
cpu.beepTimer--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cpu *Chip8) BeepNeeded() bool {
|
||||||
|
if cpu.beepRequired == true {
|
||||||
|
cpu.beepRequired = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (cpu *Chip8) zeroIndexOpcodes() {
|
func (cpu *Chip8) zeroIndexOpcodes() {
|
||||||
if cpu.opcode == 0x00E0 {
|
if cpu.opcode == 0x00E0 {
|
||||||
// fuck it the gc can do the hard work for us
|
// fuck it the gc can do the hard work for us
|
||||||
@ -164,38 +175,43 @@ func (cpu *Chip8) bitOpsAndMath() {
|
|||||||
case 4:
|
case 4:
|
||||||
// 8XY4
|
// 8XY4
|
||||||
// Set register x to X+=Y (Set VF to 1 when there's a carry and 0 if not)
|
// Set register x to X+=Y (Set VF to 1 when there's a carry and 0 if not)
|
||||||
res := cpu.registers[regX] + cpu.registers[regY]
|
if cpu.registers[regX] > 0xFF-cpu.registers[regY] {
|
||||||
if res > 0xFF {
|
|
||||||
cpu.registers[0x0F] = 1
|
cpu.registers[0x0F] = 1
|
||||||
} else {
|
} else {
|
||||||
cpu.registers[0x0F] = 0
|
cpu.registers[0x0F] = 0
|
||||||
}
|
}
|
||||||
cpu.registers[regX] = res & 0xFF
|
cpu.registers[regX] += +cpu.registers[regY]
|
||||||
case 5:
|
case 5:
|
||||||
// 8XY5
|
// 8XY5
|
||||||
// Set register x to X-=Y (Set VF to 1 when there's a carry and 0 if not)
|
// Set register x to X-=Y (Set VF to 1 when there's a carry and 0 if not)
|
||||||
res := cpu.registers[regX] - cpu.registers[regY]
|
if cpu.registers[regY] < 0xFF-cpu.registers[regX] {
|
||||||
if res > 0xFF {
|
|
||||||
cpu.registers[0x0F] = 1
|
cpu.registers[0x0F] = 1
|
||||||
} else {
|
} else {
|
||||||
cpu.registers[0x0F] = 0
|
cpu.registers[0x0F] = 0
|
||||||
}
|
}
|
||||||
cpu.registers[regX] = res & 0xFF
|
cpu.registers[regX] -= cpu.registers[regY]
|
||||||
case 6:
|
case 6:
|
||||||
// BXY6
|
// BXY6
|
||||||
// Store lsb of reg X in reg F and then shift reg X >> 1
|
// Store lsb of reg X in reg F and then shift reg X >> 1
|
||||||
cpu.registers[0x0F] = cpu.registers[regX] & 0x01
|
// Need to account for quirks - look how that js one does it
|
||||||
cpu.registers[regX] >>= 1
|
cpu.registers[0x0F] = cpu.registers[regY] & 0x01
|
||||||
|
cpu.registers[regX] = cpu.registers[regY] >> 1
|
||||||
case 7:
|
case 7:
|
||||||
// 8XY57
|
// 8XY7
|
||||||
// Set register x to X=Y-X (Set VF to 1 when there's a carry and 0 if not)
|
// Set register x to X=Y-X (Set VF to 1 when there's a carry and 0 if not)
|
||||||
res := cpu.registers[regY] - cpu.registers[regX]
|
if cpu.registers[regX] < 0xFF-cpu.registers[regY] {
|
||||||
if res < 0 {
|
cpu.registers[0x0F] = 1
|
||||||
cpu.registers[0x0F] = 0
|
|
||||||
} else {
|
} else {
|
||||||
cpu.registers[0x0f] = 1
|
cpu.registers[0x0f] = 0
|
||||||
}
|
}
|
||||||
cpu.registers[regX] = res & 0xFF
|
cpu.registers[regX] = cpu.registers[regY] - cpu.registers[regX]
|
||||||
|
case 0xE:
|
||||||
|
// BXYE
|
||||||
|
// Store msb of reg X in reg F and then shift reg X >> 1
|
||||||
|
// Need to account for quirks - look how that js one does it
|
||||||
|
// Need to account for quircks - look how that js one does it
|
||||||
|
cpu.registers[0x0F] = (cpu.registers[regY] >> 7) & 0x01
|
||||||
|
cpu.registers[regX] = cpu.registers[regY] << 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +226,9 @@ func (cpu *Chip8) setAddressRegister() {
|
|||||||
// ANNN
|
// ANNN
|
||||||
// Sets the address register to NNN
|
// Sets the address register to NNN
|
||||||
cpu.addressRegister = cpu.opcode & 0x0FFF
|
cpu.addressRegister = cpu.opcode & 0x0FFF
|
||||||
|
fmt.Printf("---set----\n")
|
||||||
|
fmt.Printf("%x\n", cpu.opcode)
|
||||||
|
fmt.Printf("addr set to %d\n", cpu.addressRegister)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cpu *Chip8) jumpToV0PlusAddress() {
|
func (cpu *Chip8) jumpToV0PlusAddress() {
|
||||||
@ -231,12 +250,20 @@ func (cpu *Chip8) displaySprite() {
|
|||||||
cpu.registers[0x0F] = 0
|
cpu.registers[0x0F] = 0
|
||||||
x := int(cpu.registers[(cpu.opcode>>8)&0x0F])
|
x := int(cpu.registers[(cpu.opcode>>8)&0x0F])
|
||||||
y := int(cpu.registers[(cpu.opcode>>4)&0x0F])
|
y := int(cpu.registers[(cpu.opcode>>4)&0x0F])
|
||||||
|
|
||||||
for row := 0; row < int(cpu.opcode&0xF); row++ {
|
for row := 0; row < int(cpu.opcode&0xF); row++ {
|
||||||
pixel := cpu.memory[int(cpu.addressRegister)+row]
|
pixel := cpu.memory[int(cpu.addressRegister)+row]
|
||||||
for column := 0; column < 8; column++ {
|
for column := 0; column < 8; column++ {
|
||||||
if pixel&(0x80>>column) != 0 {
|
if pixel&(0x80>>column) != 0 {
|
||||||
graphicsPosition := x + column + ((y + row) * 64)
|
graphicsPosition := x + column + ((y + row) * 64)
|
||||||
|
if graphicsPosition > 2048 {
|
||||||
|
fmt.Printf("OH FUCK\n")
|
||||||
|
fmt.Printf("graphpos: %d\n", graphicsPosition)
|
||||||
|
fmt.Printf("x: %d\n", x)
|
||||||
|
fmt.Printf("y: %d\n", y)
|
||||||
|
fmt.Printf("row: %d\n", row)
|
||||||
|
fmt.Printf("addreg: %d\n", cpu.addressRegister)
|
||||||
|
graphicsPosition = graphicsPosition % 64 * 32
|
||||||
|
}
|
||||||
if cpu.graphics[graphicsPosition] == 1 {
|
if cpu.graphics[graphicsPosition] == 1 {
|
||||||
cpu.registers[0xF] = 1
|
cpu.registers[0xF] = 1
|
||||||
}
|
}
|
||||||
@ -306,10 +333,16 @@ func (cpu *Chip8) fifteenIndexOpcodes() {
|
|||||||
cpu.registers[0x0F] = 0
|
cpu.registers[0x0F] = 0
|
||||||
}
|
}
|
||||||
cpu.addressRegister = uint16((int(cpu.addressRegister) + int(cpu.registers[reg])) & 0xFFF)
|
cpu.addressRegister = uint16((int(cpu.addressRegister) + int(cpu.registers[reg])) & 0xFFF)
|
||||||
|
fmt.Printf("---set----\n")
|
||||||
|
fmt.Printf("%x\n", cpu.opcode)
|
||||||
|
fmt.Printf("addr set to %d\n", cpu.addressRegister)
|
||||||
case 0x29:
|
case 0x29:
|
||||||
// FX29
|
// FX29
|
||||||
// Sets address register to location of char stored in VX
|
// Sets address register to location of char stored in VX
|
||||||
cpu.addressRegister = uint16(cpu.registers[reg]) * 5
|
cpu.addressRegister = uint16(cpu.registers[reg]) * 5
|
||||||
|
fmt.Printf("---set----\n")
|
||||||
|
fmt.Printf("%x\n", cpu.opcode)
|
||||||
|
fmt.Printf("addr set to %d\n", cpu.addressRegister)
|
||||||
case 0x33:
|
case 0x33:
|
||||||
// FX33
|
// FX33
|
||||||
// Stores BCD representation of VX
|
// Stores BCD representation of VX
|
||||||
@ -332,9 +365,14 @@ func (cpu *Chip8) fifteenIndexOpcodes() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cpu *Chip8) UpdateKeys(newKeys [16]byte) {
|
||||||
|
cpu.keys = newKeys
|
||||||
|
}
|
||||||
|
|
||||||
func (cpu *Chip8) PerformCycle() {
|
func (cpu *Chip8) PerformCycle() {
|
||||||
cpu.opcode = (uint16(cpu.memory[cpu.pc]) << 8) + uint16(cpu.memory[cpu.pc + 1])
|
cpu.opcode = (uint16(cpu.memory[cpu.pc]) << 8) + uint16(cpu.memory[cpu.pc+1])
|
||||||
cpu.pc += 2
|
cpu.pc += 2
|
||||||
|
fmt.Printf("%x\n", cpu.opcode)
|
||||||
switch cpu.opcode >> 12 {
|
switch cpu.opcode >> 12 {
|
||||||
case 0:
|
case 0:
|
||||||
cpu.zeroIndexOpcodes()
|
cpu.zeroIndexOpcodes()
|
||||||
@ -370,4 +408,3 @@ func (cpu *Chip8) PerformCycle() {
|
|||||||
cpu.fifteenIndexOpcodes()
|
cpu.fifteenIndexOpcodes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ func TestCreateCPU(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x00E0
|
||||||
func TestClearDisplay(t *testing.T) {
|
func TestClearDisplay(t *testing.T) {
|
||||||
cpu := Chip8{opcode: 0x00E0}
|
cpu := Chip8{opcode: 0x00E0}
|
||||||
for i := range cpu.graphics {
|
for i := range cpu.graphics {
|
||||||
@ -41,6 +42,7 @@ func TestClearDisplay(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x00EE
|
||||||
func TestLeaveFunction(t *testing.T) {
|
func TestLeaveFunction(t *testing.T) {
|
||||||
cpu := Chip8{pc: 50, opcode: 0x00EE}
|
cpu := Chip8{pc: 50, opcode: 0x00EE}
|
||||||
cpu.stack = append(cpu.stack, 1, 2, 3, 4, 5)
|
cpu.stack = append(cpu.stack, 1, 2, 3, 4, 5)
|
||||||
@ -50,6 +52,7 @@ func TestLeaveFunction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x1NNN
|
||||||
func TestGoTo(t *testing.T) {
|
func TestGoTo(t *testing.T) {
|
||||||
cpu := Chip8{opcode: 0x3420}
|
cpu := Chip8{opcode: 0x3420}
|
||||||
cpu.goTo()
|
cpu.goTo()
|
||||||
@ -58,6 +61,7 @@ func TestGoTo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x2NNN
|
||||||
func TestCallSubroutine(t *testing.T) {
|
func TestCallSubroutine(t *testing.T) {
|
||||||
cpu := Chip8{opcode: 0x3420, pc: 43}
|
cpu := Chip8{opcode: 0x3420, pc: 43}
|
||||||
cpu.callSubroutine()
|
cpu.callSubroutine()
|
||||||
@ -66,6 +70,7 @@ func TestCallSubroutine(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x3XNN
|
||||||
func TestSkipIfRegisterEqual(t *testing.T) {
|
func TestSkipIfRegisterEqual(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
register, regValue byte
|
register, regValue byte
|
||||||
@ -90,6 +95,7 @@ func TestSkipIfRegisterEqual(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x4XNN
|
||||||
func TestSkipIfRegisterNotEqual(t *testing.T) {
|
func TestSkipIfRegisterNotEqual(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
register, regValue byte
|
register, regValue byte
|
||||||
@ -114,6 +120,7 @@ func TestSkipIfRegisterNotEqual(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x5XY0
|
||||||
func TestSkipIfRegistersEqual(t *testing.T) {
|
func TestSkipIfRegistersEqual(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
reg1, reg2, val1, val2 byte
|
reg1, reg2, val1, val2 byte
|
||||||
@ -140,6 +147,7 @@ func TestSkipIfRegistersEqual(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x6XNN
|
||||||
func TestSetRegisterTo(t *testing.T) {
|
func TestSetRegisterTo(t *testing.T) {
|
||||||
cpu := Chip8{opcode: 0x0824}
|
cpu := Chip8{opcode: 0x0824}
|
||||||
cpu.setRegisterTo()
|
cpu.setRegisterTo()
|
||||||
@ -148,6 +156,7 @@ func TestSetRegisterTo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//0x7XNN
|
||||||
func TestRegisterPlusEqualsNN(t *testing.T) {
|
func TestRegisterPlusEqualsNN(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
register, initalVal, toAdd, expected byte
|
register, initalVal, toAdd, expected byte
|
||||||
@ -169,3 +178,455 @@ func TestRegisterPlusEqualsNN(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0x8000
|
||||||
|
func TestLoadVxVy(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal byte
|
||||||
|
}{
|
||||||
|
{0, 2, 2, 4},
|
||||||
|
{0, 15, 3, 1},
|
||||||
|
{15, 2, 0, 2},
|
||||||
|
{15, 3, 6, 0},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d", tt.regX, tt.regY, tt.xVal, tt.yVal)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x8000 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.yVal)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x8001
|
||||||
|
func TestOrVxVy(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, result byte
|
||||||
|
}{
|
||||||
|
{0, 2, 0xBB, 0xCC, 0xFF},
|
||||||
|
{0, 2, 0x00, 0x00, 0x00},
|
||||||
|
{0, 2, 0x0F, 0xF0, 0xFF},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,expected:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.result)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x8001 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.result {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.result)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0x8002
|
||||||
|
func TestAndVxVy(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, result byte
|
||||||
|
}{
|
||||||
|
{0, 2, 0xCC, 0xDD, 0xCC},
|
||||||
|
{0, 2, 0x00, 0x00, 0x00},
|
||||||
|
{0, 2, 0x0F, 0xF0, 0x00},
|
||||||
|
{0, 2, 0x0F, 0xF1, 0x01},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,expected:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.result)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x8002 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.result {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.result)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0x8003
|
||||||
|
func TestXORVxVy(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, result byte
|
||||||
|
}{
|
||||||
|
{0, 2, 0xDD, 0xEE, 0x33},
|
||||||
|
{0, 2, 0x00, 0x00, 0x00},
|
||||||
|
{0, 4, 0x0F, 0xF0, 0xFF},
|
||||||
|
{0, 2, 0xFF, 0xFF, 0x00},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,expected:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.result)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x8003 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.result {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.result)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0x8004
|
||||||
|
func TestAddVxVyCarry(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, result, carry byte
|
||||||
|
}{
|
||||||
|
{0, 2, 0x44, 0xAA, 0xEE, 0},
|
||||||
|
{0, 2, 0xAA, 0xAA, 0x54, 1},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,expected:%d,carry:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.result, tt.carry)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x8004 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.result {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.result)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
if cpu.registers[0x0F] != tt.carry {
|
||||||
|
t.Errorf("Carry register is %d, wanted %d", cpu.registers[0x0F], tt.carry)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0x8005
|
||||||
|
func TestSubVxVyCarry(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, result, carry byte
|
||||||
|
}{
|
||||||
|
{0, 2, 0xAA, 0x22, 0x88, 1},
|
||||||
|
{0, 2, 0x22, 0xDD, 0x45, 0},
|
||||||
|
{0, 2, 0x22, 0x22, 0x00, 1},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,expected:%d,carry:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.result, tt.carry)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x8005 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.result {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.result)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
if cpu.registers[0x0F] != tt.carry {
|
||||||
|
t.Errorf("Carry register is %d, wanted %d", cpu.registers[0x0F], tt.carry)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0x8006
|
||||||
|
func TestSHRVxVyCarry(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, expX, expY, regF byte
|
||||||
|
}{
|
||||||
|
{0, 2, 0x11, 0x44, 0x22, 0x44, 0},
|
||||||
|
{0, 2, 0x11, 0x45, 0x22, 0x45, 1},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,expX:%d,expY:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.expX, tt.expY)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x8006 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.expX {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.expX)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
if cpu.registers[0x0F] != tt.regF {
|
||||||
|
t.Errorf("Carry register is %d, wanted %d", cpu.registers[0x0F], tt.regF)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0x8007
|
||||||
|
func TestSUBNVxVyCarry(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, result, carry byte
|
||||||
|
}{
|
||||||
|
{0, 2, 0x22, 0xAA, 0x88, 1},
|
||||||
|
{0, 2, 0xDD, 0x22, 0x45, 0},
|
||||||
|
{0, 2, 0x22, 0x22, 0x00, 1},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,expected:%d,carry:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.result, tt.carry)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x8007 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.result {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.result)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
if cpu.registers[0x0F] != tt.carry {
|
||||||
|
t.Errorf("Carry register is %d, wanted %d", cpu.registers[0x0F], tt.carry)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0x800E
|
||||||
|
func TestSHLVxVyCarry(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, expX, expY, regF byte
|
||||||
|
}{
|
||||||
|
{7, 8, 0x22, 0x44, 0x88, 0x44, 0},
|
||||||
|
{7, 8, 0x22, 0x45, 0x8A, 0x45, 0},
|
||||||
|
{7, 8, 0x22, 0xff, 0xFE, 0xFF, 1},
|
||||||
|
{7, 8, 0x22, 0x7F, 0xFE, 0x7F, 0},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,expX:%d,expY:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.expX, tt.expY)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x800E | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.bitOpsAndMath()
|
||||||
|
if cpu.registers[tt.regX] != tt.expX {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.expX)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
if cpu.registers[0x0F] != tt.regF {
|
||||||
|
t.Errorf("Carry register is %d, wanted %d", cpu.registers[0x0F], tt.regF)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0x9XY0
|
||||||
|
func TestSkipNotEqual(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal byte
|
||||||
|
pc_val uint16
|
||||||
|
}{
|
||||||
|
{7, 8, 0x10, 0x10, 0},
|
||||||
|
{7, 8, 0x10, 0x20, 2},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("RegisterX:%d,RegisterY:%d,Xval:%d,Yval:%d,pc_val:%d", tt.regX, tt.regY, tt.xVal, tt.yVal, tt.pc_val)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0x9000 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4}
|
||||||
|
cpu.pc = 0
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.skipIfRegistersNotEqual()
|
||||||
|
if cpu.registers[tt.regX] != tt.xVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regX], tt.xVal)
|
||||||
|
}
|
||||||
|
if cpu.registers[tt.regY] != tt.yVal {
|
||||||
|
t.Errorf("Register is %d, wanted %d", cpu.registers[tt.regY], tt.yVal)
|
||||||
|
}
|
||||||
|
if cpu.pc != tt.pc_val {
|
||||||
|
t.Errorf("pc is %d, wanted %d", cpu.registers[0x0F], tt.pc_val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xANNN
|
||||||
|
func TestSetAddressRegister(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xA420}
|
||||||
|
cpu.setAddressRegister()
|
||||||
|
if cpu.addressRegister != 0x420 {
|
||||||
|
t.Errorf("Expected address register to be: %d, actual value %d", 0x420, cpu.addressRegister)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xBnnn
|
||||||
|
func TestJumpV0PlusNNN(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regVal byte
|
||||||
|
addr, expPc uint16
|
||||||
|
}{
|
||||||
|
{0x44, 0x555, 0x599},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("TestJmpv0PlusNNN,regVal:%d,addr:%d,expected:%d", tt.regVal, tt.addr, tt.expPc)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xB000 | tt.addr}
|
||||||
|
cpu.registers[0] = tt.regVal
|
||||||
|
cpu.jumpToV0PlusAddress()
|
||||||
|
if cpu.pc != tt.expPc {
|
||||||
|
t.Errorf("Expected pc to be: %d, actual value %d", tt.expPc, cpu.pc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xCXNN
|
||||||
|
// do something for rand but this one's probably fine idk
|
||||||
|
|
||||||
|
//0xfx07
|
||||||
|
func TestSetRegisterToDelayTimer(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xF007 | uint16(7)<<8, delayTimer: 81}
|
||||||
|
cpu.registers[7] = 17
|
||||||
|
cpu.fifteenIndexOpcodes()
|
||||||
|
if cpu.registers[7] != 81 {
|
||||||
|
t.Errorf("Expected register 7 to be %d, actually %d", 81, cpu.registers[7])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xfx15
|
||||||
|
func TestSetDelayTimer(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xF015 | uint16(7)<<8}
|
||||||
|
cpu.registers[7] = 161
|
||||||
|
cpu.fifteenIndexOpcodes()
|
||||||
|
if cpu.delayTimer != 161 {
|
||||||
|
t.Errorf("Expected delay timer to be %d, actually %d", 161, cpu.delayTimer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xfx18
|
||||||
|
func TestSetSoundTimer(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xF018 | uint16(7)<<8}
|
||||||
|
cpu.registers[7] = 161
|
||||||
|
cpu.fifteenIndexOpcodes()
|
||||||
|
if cpu.beepTimer != 161 {
|
||||||
|
t.Errorf("Expected delay timer to be %d, actually %d", 161, cpu.beepTimer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xFx1E
|
||||||
|
func TestAddIVx(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, xVal byte
|
||||||
|
iVal, res uint16
|
||||||
|
}{
|
||||||
|
{0xB, 0x33, 0x22, 0x55},
|
||||||
|
{0xA, 0xFF, 0x1, 0x100},
|
||||||
|
{0xC, 0x01, 0xFFF, 0},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("TestAddIVX,regX:%d,xVal:%d,iVal:%d,res:%d", tt.regX, tt.xVal, tt.iVal, tt.res)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xF01E | uint16(tt.regX)<<8, addressRegister: tt.iVal}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.fifteenIndexOpcodes()
|
||||||
|
if cpu.addressRegister != tt.res {
|
||||||
|
t.Errorf("Expected address register to be %d actually %d", tt.res, cpu.addressRegister)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xFx29
|
||||||
|
func TestLoadSprite(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, xVal byte
|
||||||
|
iVal uint16
|
||||||
|
}{
|
||||||
|
{0xB, 0x0, 0x0},
|
||||||
|
{0xA, 0x1, 0x5},
|
||||||
|
{0xC, 0x2, 0xA},
|
||||||
|
{0xC, 0xf, 0x4B},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("TestLoadSprite,regX:%d,xVal:%d,iVal:%d", tt.regX, tt.xVal, tt.iVal)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xF029 | uint16(tt.regX)<<8}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.fifteenIndexOpcodes()
|
||||||
|
if cpu.addressRegister != tt.iVal {
|
||||||
|
t.Errorf("Expected address register to be %d actually %d", tt.iVal, cpu.addressRegister)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xFx33
|
||||||
|
func TestStoreBCD(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xFA33, addressRegister: 0x0AAA}
|
||||||
|
cpu.registers[0xA] = 123
|
||||||
|
cpu.fifteenIndexOpcodes()
|
||||||
|
if cpu.memory[0x0AAA] != 1 {
|
||||||
|
t.Errorf("Store BCD Failed")
|
||||||
|
}
|
||||||
|
if cpu.memory[0x0AAA+1] != 2 {
|
||||||
|
t.Errorf("Store BCD Failed")
|
||||||
|
}
|
||||||
|
if cpu.memory[0x0AAA+2] != 3 {
|
||||||
|
t.Errorf("Store BCD Failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0xfx55
|
||||||
|
//0xfx65
|
||||||
|
// do the load store ones idk
|
||||||
|
|
||||||
|
//0xdxyn
|
||||||
|
func TestDraw(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
regX, regY, xVal, yVal, n, collision byte
|
||||||
|
addressRegister uint16
|
||||||
|
sprite []byte
|
||||||
|
set_bits [][]byte
|
||||||
|
}{
|
||||||
|
{0xA, 0xB, 10, 10, 2, 0, 0x0BBB,
|
||||||
|
[]byte{0x3C, 0xC3},
|
||||||
|
[][]byte{[]byte{12, 10}, []byte{13, 10}, []byte{14, 10}, []byte{15, 10}, []byte{10, 11}, []byte{11, 11}, []byte{16, 11}, []byte{17, 11}}},
|
||||||
|
{0xA, 0xB, 10, 10, 2, 1, 0x0BBB,
|
||||||
|
[]byte{0x20},
|
||||||
|
[][]byte{}},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
testname := fmt.Sprintf("DrawTest%d", i)
|
||||||
|
t.Run(testname, func(t *testing.T) {
|
||||||
|
cpu := Chip8{opcode: 0xD000 | uint16(tt.regX)<<8 | uint16(tt.regY)<<4 | uint16(tt.n)}
|
||||||
|
cpu.registers[tt.regX] = tt.xVal
|
||||||
|
cpu.registers[tt.regY] = tt.yVal
|
||||||
|
cpu.addressRegister = tt.addressRegister
|
||||||
|
for j, val := range tt.sprite {
|
||||||
|
cpu.memory[cpu.addressRegister+uint16(j)] = val
|
||||||
|
}
|
||||||
|
cpu.displaySprite()
|
||||||
|
if tt.collision == 1 {
|
||||||
|
cpu.displaySprite() // this is pretty fucking horrible but at this point i'm satisfied this function is correct so whatevs
|
||||||
|
}
|
||||||
|
if cpu.addressRegister != tt.addressRegister {
|
||||||
|
t.Errorf("Expected address register to be %d actually %d", tt.addressRegister, cpu.addressRegister)
|
||||||
|
}
|
||||||
|
if cpu.registers[0xF] != tt.collision {
|
||||||
|
t.Errorf("Expected reg[0xF] to be %d, %d", cpu.registers[0xF], tt.collision)
|
||||||
|
}
|
||||||
|
for _, val := range tt.set_bits {
|
||||||
|
if cpu.graphics[int(val[0])+(int(val[1])*64)] != 1 {
|
||||||
|
t.Errorf("Expected value at %d,%d to be set", val[0], val[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"git.jacknet.io/S.D/Chip-8_Go/chip8"
|
"git.jacknet.io/S.D/Chip-8_Go/chip8"
|
||||||
"fmt"
|
)
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
prog := make([]byte, 6)
|
prog := make([]byte, 6)
|
||||||
|
@ -44,6 +44,11 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<select name="game" id="game-select">
|
||||||
|
<option value="pong" selected>Pong</option>
|
||||||
|
<option value="spaceinv">Space Invaders</option>
|
||||||
|
<option value="tetris">Tetris</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
159
cmd/web/main.go
159
cmd/web/main.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall/js"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/llgcode/draw2d/draw2dimg"
|
"github.com/llgcode/draw2d/draw2dimg"
|
||||||
@ -20,9 +21,139 @@ var sizeMultiplier = 8
|
|||||||
var drawBuf = [64 * 32]byte{}
|
var drawBuf = [64 * 32]byte{}
|
||||||
var drawNeeded = false
|
var drawNeeded = false
|
||||||
var graphicsLock sync.Mutex
|
var graphicsLock sync.Mutex
|
||||||
|
var keysLock sync.Mutex
|
||||||
|
var window, beep js.Value
|
||||||
|
var keys [16]byte
|
||||||
|
var gameRunning = true
|
||||||
|
|
||||||
|
var keyMap = map[int]int{
|
||||||
|
88: 0, // x
|
||||||
|
49: 1, // 1
|
||||||
|
50: 2, // 2
|
||||||
|
51: 3, // 3
|
||||||
|
81: 4, // q
|
||||||
|
87: 5, // w
|
||||||
|
69: 6, // e
|
||||||
|
65: 7, // a
|
||||||
|
83: 8, // s
|
||||||
|
68: 9, // d
|
||||||
|
90: 10, // z
|
||||||
|
67: 11, // c
|
||||||
|
52: 12, // 4
|
||||||
|
82: 13, // r
|
||||||
|
70: 14, // f
|
||||||
|
86: 15, // v
|
||||||
|
}
|
||||||
|
|
||||||
|
var gameMap = map[string]func() []byte{
|
||||||
|
"pong": getPong,
|
||||||
|
"spaceinv": getSpaceInvaders,
|
||||||
|
"tetris": getTetris,
|
||||||
|
}
|
||||||
|
|
||||||
|
func keyEventHandle(event js.Value) {
|
||||||
|
//println(event.Get("type").String())
|
||||||
|
//println(event.Get("keyCode").Int())
|
||||||
|
elem, ok := keyMap[event.Get("keyCode").Int()]
|
||||||
|
if ok {
|
||||||
|
keysLock.Lock()
|
||||||
|
defer keysLock.Unlock()
|
||||||
|
if event.Get("type").String() == "keydown" {
|
||||||
|
keys[elem] = 1
|
||||||
|
} else if event.Get("type").String() == "keyup" {
|
||||||
|
keys[elem] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cpuCycle(cpu *chip8.Chip8, c chan int, i int) {
|
||||||
|
cpu.PerformCycle()
|
||||||
|
if cpu.DrawIsNeeded() {
|
||||||
|
drawNeeded = true
|
||||||
|
graphicsLock.Lock()
|
||||||
|
drawBuf = cpu.GetGraphicsBuffer()
|
||||||
|
graphicsLock.Unlock()
|
||||||
|
keysLock.Lock()
|
||||||
|
cpu.UpdateKeys(keys)
|
||||||
|
keysLock.Unlock()
|
||||||
|
}
|
||||||
|
if i > 7 {
|
||||||
|
cpu.TickTimers()
|
||||||
|
//println("here!")
|
||||||
|
}
|
||||||
|
if cpu.BeepNeeded() {
|
||||||
|
go playSound()
|
||||||
|
}
|
||||||
|
|
||||||
|
c <- 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeCycle(c chan int) {
|
||||||
|
time.Sleep(2000 * time.Microsecond)
|
||||||
|
c <- 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGame(game []byte) {
|
||||||
|
cpu := chip8.NewCHIP8(game)
|
||||||
|
i := 0
|
||||||
|
for gameRunning {
|
||||||
|
c := make(chan int)
|
||||||
|
go timeCycle(c)
|
||||||
|
i++
|
||||||
|
go cpuCycle(cpu, c, i)
|
||||||
|
if i > 7 {
|
||||||
|
i = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
x, y := <-c, <-c
|
||||||
|
if x == 0 {
|
||||||
|
println("CPU RUNNING SLOW")
|
||||||
|
println(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeGame(event js.Value) {
|
||||||
|
//println(event.Get("target").Get("value").String())
|
||||||
|
println(event.Get("target").Get("value").String())
|
||||||
|
elem, ok := gameMap[event.Get("target").Get("value").String()]
|
||||||
|
if ok {
|
||||||
|
println("change event!!!!")
|
||||||
|
gameRunning = false
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
//println("changing games!!")
|
||||||
|
gameRunning = true
|
||||||
|
go runGame(elem())
|
||||||
|
} else {
|
||||||
|
panic("value not found!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func playSound() {
|
||||||
|
beep.Call("play")
|
||||||
|
//window.Get("navigator").Call("vibrate", 300)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
println("CHIP8 IS HERE!")
|
println("CHIP8 IS HERE!")
|
||||||
|
window = js.Global()
|
||||||
|
|
||||||
|
beep = window.Get("Audio").New("data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU2LjI1LjEwMQAAAAAAAAAAAAAA/+NAwAAAAAAAAAAAAFhpbmcAAAAPAAAAAwAAA3YAlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaW8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw////////////////////////////////////////////AAAAAExhdmYAAAAAAAAAAAAAAAAAAAAAACQAAAAAAAAAAAN2UrY2LgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/jYMQAEvgiwl9DAAAAO1ALSi19XgYG7wIAAAJOD5R0HygIAmD5+sEHLB94gBAEP8vKAgGP/BwMf+D4Pgh/DAPg+D5//y4f///8QBhMQBgEAfB8HwfAgIAgAHAGCFAj1fYUCZyIbThYFExkefOCo8Y7JxiQ0mGVaHKwwGCtGCUkY9OCugoFQwDKqmHQiUCxRAKOh4MjJFAnTkq6QqFGavRpYUCmMxpZnGXJa0xiJcTGZb1gJjwOJDJgoUJG5QQuDAsypiumkp5TUjrOobR2liwoGBf/X1nChmipnKVtSmMNQDGitG1fT/JhR+gYdCvy36lTrxCVV8Paaz1otLndT2fZuOMp3VpatmVR3LePP/8bSQpmhQZECqWsFeJxoepX9dbfHS13/////aysppUblm//8t7p2Ez7xKD/42DE4E5z9pr/nNkRw6bhdiCAZVVSktxunhxhH//4xF+bn4//6//3jEvylMM2K9XmWSn3ah1L2MqVIjmNlJtpQux1n3ajA0ZnFSu5EpX////uGatn///////1r/pYabq0mKT//TRyTEFNRTMuOTkuNaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq/+MQxNIAAANIAcAAAKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==")
|
||||||
|
|
||||||
|
window.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
keyEventHandle(args[0])
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
window.Call("addEventListener", "keyup", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
keyEventHandle(args[0])
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
window.Call("addEventListener", "change", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
|
changeGame(args[0])
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
cvs, _ = canvas.NewCanvas2d(false)
|
cvs, _ = canvas.NewCanvas2d(false)
|
||||||
cvs.Create(int(width)*sizeMultiplier, int(height)*sizeMultiplier)
|
cvs.Create(int(width)*sizeMultiplier, int(height)*sizeMultiplier)
|
||||||
@ -30,33 +161,11 @@ func main() {
|
|||||||
height = float64(cvs.Height())
|
height = float64(cvs.Height())
|
||||||
width = float64(cvs.Width())
|
width = float64(cvs.Width())
|
||||||
|
|
||||||
cpu := chip8.NewCHIP8(getPong())
|
|
||||||
|
|
||||||
cvs.Start(60, Render)
|
cvs.Start(60, Render)
|
||||||
i := 0
|
|
||||||
for {
|
|
||||||
c := make(chan int)
|
|
||||||
go timeCycle(c)
|
|
||||||
cpu.PerformCycle()
|
|
||||||
if cpu.DrawIsNeeded() {
|
|
||||||
drawNeeded = true
|
|
||||||
graphicsLock.Lock()
|
|
||||||
drawBuf = cpu.GetGraphicsBuffer()
|
|
||||||
graphicsLock.Unlock()
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
if i > 7 {
|
|
||||||
cpu.TickTimers()
|
|
||||||
i = 0
|
|
||||||
//println("here!")
|
|
||||||
}
|
|
||||||
<-c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func timeCycle(c chan int) {
|
go runGame(getPong())
|
||||||
time.Sleep(2000 * time.Microsecond)
|
never_returns := make(chan int)
|
||||||
c <- 0
|
<-never_returns
|
||||||
}
|
}
|
||||||
|
|
||||||
func Render(gc *draw2dimg.GraphicContext) bool {
|
func Render(gc *draw2dimg.GraphicContext) bool {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user