Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cpu table optmization #21

Merged
merged 3 commits into from
Nov 27, 2018
Merged

Cpu table optmization #21

merged 3 commits into from
Nov 27, 2018

Conversation

ear7h
Copy link
Contributor

@ear7h ear7h commented Nov 23, 2018

See #20

Implemented a static array for storing operations where the functions are indexed by their opcode. Also removed byte casts from the cbInstruction function as the compiler will already remove the bounds checks from the array. At least based on the assembly output from a similar function:
https://godbolt.org/z/t7uSt1

@codecov
Copy link

codecov bot commented Nov 23, 2018

Codecov Report

Merging #21 into master will increase coverage by 4.04%.
The diff coverage is 99.67%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #21      +/-   ##
==========================================
+ Coverage   65.07%   69.11%   +4.04%     
==========================================
  Files          20       20              
  Lines        2265     2461     +196     
==========================================
+ Hits         1474     1701     +227     
+ Misses        762      730      -32     
- Partials       29       30       +1
Impacted Files Coverage Δ
pkg/gb/gameboy.go 80.89% <100%> (+11.86%) ⬆️
pkg/gb/instructions_cb.go 100% <100%> (ø) ⬆️
pkg/gb/instructions.go 99.66% <99.65%> (+0.11%) ⬆️
pkg/gbio/iopixel/pixels.go 0% <0%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f9f78a9...44458e2. Read the comment docs.

@Humpheh
Copy link
Owner

Humpheh commented Nov 25, 2018

This is great, thanks @ear7h - I'm going to have a review of it soon, but I thought it would be good to benchmark it first just to check.

I added in the new instruction table alongside the old one and then ran this benchmark to run some random instructions:

package gb

import (
	"math/rand"
	"testing"
	"time"

	"github.com/Humpheh/goboy/pkg/cart"
)

func randomBytes(num int) (out []byte) {
	rand.Seed(time.Now().Unix())
	for i := 0; i < num; i++ {
		out = append(out, byte(rand.Intn(0x100)))
	}
	out[0x147] = 0
	return
}

var randomRom = randomBytes(0x10000)

func testGB() *Gameboy {
	gameboy := Gameboy{}
	gameboy.mainInst = gameboy.mainInstructions()
	gameboy.setup()
	gameboy.Memory.Cart = cart.NewCart(randomRom, "")
	return &gameboy
}

func BenchmarkGameboy_ExecuteNextOpcode(b *testing.B) {
	gameboy := testGB()
	for n := 0; n < b.N; n++ {
		gameboy.ExecuteOpcode(byte(rand.Intn(0x100)))
	}
}

func BenchmarkGameboy_ExecuteNextOpcode2(b *testing.B) {
	gameboy := testGB()
	for n := 0; n < b.N; n++ {
		gameboy.mainInst[byte(rand.Intn(0x100))]()
	}
}

The results were:

goos: darwin
goarch: amd64
pkg: github.com/Humpheh/goboy/pkg/gb

BenchmarkGameboy_ExecuteNextOpcode-4    	10000000	       117 ns/op
BenchmarkGameboy_ExecuteNextOpcode2-4   	20000000	        90.8 ns/op

So the new version is definitely faster!

Copy link
Owner

@Humpheh Humpheh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks for doing this. Just some code/comment style points :)

InputMask byte

mainInst [0x100]func()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you put the mainInst above the cbInst so that they are grouped together?

@@ -320,6 +322,8 @@ func (gb *Gameboy) setup() error {

gb.cbInst = gb.cbInstructions()

gb.mainInst = gb.mainInstructions()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, could you put this line above the gb.cbInst line?

log.Printf("Unimplemented opcode: %#2x", opcode)
WaitForInput()
}
gb.mainInst[opcode]()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer is the contents of mainInstructions were in this file rather than a separate one. Also it looks like ExecuteOpcode is only called in one place, so it may be better just to replace that line with gb.mainInst[opcode]() and remove this function.

0x06: func() {
// LD B, n
gb.CPU.BC.SetHi(gb.popPC())

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you remove these blank lines before the end of each function?

val := gb.Memory.ReadHighRam(0xFF00 + uint16(gb.popPC()))
gb.CPU.AF.SetHi(val)

// ========== 16-Bit Loads ===========
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is in the wrong place now and should be outside the function.

// POP HL
gb.CPU.HL.Set(gb.popStack())

// ========== 8-Bit ALU ===========
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with this one.

addr := gb.CPU.HL.HiLo()
gb.instDec(func(val byte) { gb.Memory.Write(addr, val) }, gb.Memory.Read(addr))

// ========== 16-Bit ALU ===========
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another misplaced comment.

gb.instDec16(gb.CPU.SP.Set, gb.CPU.SP.HiLo())

},
0x27: func() { /*
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment seems to have formatted badly. Could you replace the /* ... */ with just // lines? I think that makes it more consistent with the rest of the code base.

gb.halted = true

},
0x10: func() { //gb.halted = true
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment can be moved below the // STOP comment

@Humpheh Humpheh mentioned this pull request Nov 25, 2018
Copy link
Owner

@Humpheh Humpheh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, thanks! :)

@Humpheh Humpheh merged commit f876370 into Humpheh:master Nov 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants