~apreiml/octachip

2339a8079bf5feffd115d32ca14f9b97602d91bc — Armin Preiml 3 years ago 322d29c
print F
4 files changed, 213 insertions(+), 25 deletions(-)

M main.go
A mem.go
A roms/f.ch8
M vm.go
M main.go => main.go +17 -2
@@ 1,7 1,22 @@
package main

import (
	"io"
	"log"
	"os"
)

func main() {
	vm := &Chip8{}
	romFile, err := os.Open("roms/f.ch8")
	if err != nil {
		log.Fatal(err)
	}

	rom, err := io.ReadAll(romFile)
	if err != nil {
		log.Fatal(err)
	}

	vm.Run()
	VM.LoadRom(rom)
	Run()
}

A mem.go => mem.go +99 -0
@@ 0,0 1,99 @@
package main

var reservedMem []byte = []byte{
	0b11110000,
	0b10010000,
	0b10010000,
	0b10010000,
	0b11110000,

	0b00100000,
	0b01100000,
	0b00100000,
	0b00100000,
	0b01110000,

	0b11110000,
	0b00010000,
	0b11110000,
	0b10000000,
	0b11110000,

	0b11110000,
	0b00010000,
	0b11110000,
	0b00010000,
	0b11110000,

	0b10010000,
	0b10010000,
	0b11110000,
	0b00010000,
	0b00010000,

	0b11110000,
	0b10000000,
	0b11110000,
	0b00010000,
	0b11110000,

	0b11110000,
	0b10000000,
	0b11110000,
	0b10010000,
	0b11110000,

	0b11110000,
	0b00010000,
	0b00100000,
	0b01000000,
	0b01000000,

	0b11110000,
	0b10010000,
	0b11110000,
	0b10010000,
	0b11110000,

	0b11110000,
	0b10010000,
	0b11110000,
	0b00010000,
	0b11110000,

	0b11110000,
	0b10010000,
	0b11110000,
	0b10010000,
	0b10010000,

	0b11100000,
	0b10010000,
	0b11100000,
	0b10010000,
	0b11100000,

	0b11110000,
	0b10000000,
	0b10000000,
	0b10000000,
	0b11110000,

	0b11100000,
	0b10010000,
	0b10010000,
	0b10010000,
	0b11100000,

	0b11110000,
	0b10000000,
	0b11110000,
	0b10000000,
	0b11110000,

	0b11110000,
	0b10000000,
	0b11110000,
	0b10000000,
	0b10000000,
}

A roms/f.ch8 => roms/f.ch8 +0 -0
M vm.go => vm.go +97 -23
@@ 1,9 1,8 @@
package main

import (
	"fmt"
	"encoding/binary"
	"math"
	"time"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/pixelgl"


@@ 24,10 23,19 @@ type Chip8 struct {
	st  byte
	pc  uint16
	sp  byte

	display *Display
}

func (c *Chip8) initMem() {
	copy(c.mem[:], reservedMem)
}

func (c *Chip8) LoadRom(rom []byte) error {
	c.initMem()
	copy(c.mem[romStart:], rom)

	c.pc = romStart
	return nil
}



@@ 39,13 47,7 @@ func run() {
		VSync:  true,
	}

	d.buffer[0] = 1
	d.buffer[2] = 1

	d.buffer[64] = 1
	d.buffer[64+4] = 1

	d.buffer[31*64] = 1
	VM.display = d

	win, err := pixelgl.NewWindow(cfg)
	if err != nil {


@@ 55,26 57,79 @@ func run() {
	win.Clear(colornames.Black)

	go func() {
		i := 10
		ticker := time.NewTicker(time.Second)
		for {
			select {
			case <-ticker.C:
				d.buffer[i] = 1
				i += 2
				fmt.Println(i)
		/*
			i := 10
			ticker := time.NewTicker(time.Second)
			for {
				select {
				case <-ticker.C:
					d.buffer[i] = 1
					i += 2
					fmt.Println(i)
				}
			}
		*/
		for {
			VM.fetchExecute()
		}
	}()

	for !win.Closed() {
		if d.clear {
			win.Clear(colornames.Black)
			d.clear = false
		}

		sprite := pixel.NewSprite(d, d.Bounds())
		sprite.Draw(win, pixel.IM.Moved(win.Bounds().Center()))

		// JustPressed, JustReleased
		if win.Pressed(pixelgl.KeyQ) {
			//
		}
		win.Update()
	}
}

func (c *Chip8) Run() {
func (c *Chip8) fetchExecute() {
	cmd := binary.BigEndian.Uint16(c.mem[c.pc : c.pc+2])

	nextPc := c.pc + 2
	switch {
	case cmd>>12 == 0x1:
		nextPc = cmd & 0x0FFF
	case cmd>>12 == 0x6:
		reg := (cmd & 0x0F00) >> 8
		c.v[reg] = byte(cmd & 0x00FF)
	case cmd>>12 == 0xA:
		c.i = cmd & 0x0FFF
	case cmd>>12 == 0xD:
		vx := byte((cmd & 0x0F00) >> 8)
		vy := byte((cmd & 0x00F0) >> 4)
		n := byte((cmd & 0x000F) >> 0)
		c.drawSprite(c.v[vx], c.v[vy], n)
	}

	c.pc = nextPc
}

func (c *Chip8) drawSprite(x, y, n byte) {
	for dy := byte(0); dy < n; dy++ {
		row := c.mem[c.i+uint16(dy)]

		for dx := byte(0); dx < 8; dx++ {
			pixel := (row >> (7 - dx)) & 0x1
			erased := c.display.Put(x+dx, y+dy, pixel)
			if erased != 0 {
				c.v[0xF] = 1
			}
		}
	}
}

var VM *Chip8 = &Chip8{}

func Run() {
	pixelgl.Run(run)
}



@@ 82,7 137,8 @@ type Display struct {
	bounds       pixel.Rect
	xm, ym       float64
	buffer       []byte
	modeX, modeY int
	modeX, modeY byte
	clear        bool
}

func NewDisplay(w, h float64) *Display {


@@ 93,9 149,10 @@ func NewDisplay(w, h float64) *Display {
		bounds: pixel.R(0, 0, w, h),
		xm:     w / float64(modeX),
		ym:     h / float64(modeY),
		modeX:  modeX,
		modeY:  modeY,
		modeX:  byte(modeX),
		modeY:  byte(modeY),
		buffer: make([]byte, modeX*modeY),
		clear:  true,
	}
}



@@ 107,12 164,29 @@ func (d Display) Color(at pixel.Vec) pixel.RGBA {
	x := int(math.Floor(at.X / d.xm))
	y := int(math.Floor(at.Y / d.ym))

	y = d.modeY - y - 1
	y = int(d.modeY) - y - 1

	idx := y*d.modeX + x
	idx := y*int(d.modeX) + x
	set := d.buffer[idx]
	if set == 1 {
		return pixel.RGB(1, 1, 1)
	}
	return pixel.RGB(255, 255, 255)
}

func (d *Display) Put(x, y, v byte) (erased byte) {
	x = x % d.modeX
	y = y % d.modeY

	idx := int(y)*int(d.modeX) + int(x)

	if d.buffer[idx] == v {
		erased = 1
	}
	d.buffer[idx] = d.buffer[idx] ^ v
	return
}

func (d *Display) Clear() {
	d.clear = true
}