From be767aaaa3c260b9006a1065036d610068d2effa Mon Sep 17 00:00:00 2001 From: pokemium Date: Thu, 13 May 2021 04:56:56 +0900 Subject: [PATCH] Fix: halt cycle bug --- cmd/main.go | 3 +- pkg/gba/apu.go | 4 +- pkg/gba/arm.go | 274 +++++++++++++---------------------------------- pkg/gba/debug.go | 33 +++--- pkg/gba/dma.go | 4 +- pkg/gba/gba.go | 41 ++++--- pkg/gba/io.go | 2 +- pkg/gba/reg.go | 7 ++ pkg/gba/thumb.go | 186 +++++++++++++------------------- pkg/gba/timer.go | 2 +- pkg/gpu/draw.go | 6 +- pkg/util/util.go | 28 ++++- 12 files changed, 236 insertions(+), 354 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 2c09c26..f6f6949 100755 --- a/cmd/main.go +++ b/cmd/main.go @@ -120,7 +120,7 @@ type Emulator struct { } func (e *Emulator) Update() error { - defer e.gba.PanicHandler(true) + defer e.gba.PanicHandler("core", true) e.gba.Update() if e.gba.DoSav && e.gba.Frame%60 == 0 { e.writeSav() @@ -129,6 +129,7 @@ func (e *Emulator) Update() error { } func (e *Emulator) Draw(screen *ebiten.Image) { + defer e.gba.PanicHandler("gpu", true) screen.ReplacePixels(e.gba.Draw().Pix) } diff --git a/pkg/gba/apu.go b/pkg/gba/apu.go index 5859cf3..0c8b1a8 100644 --- a/pkg/gba/apu.go +++ b/pkg/gba/apu.go @@ -73,7 +73,7 @@ func newAPU() *APU { return &APU{ context: context, player: player, - chans: [4]*SoundChan{&SoundChan{}, &SoundChan{}, &SoundChan{}, &SoundChan{}}, + chans: [4]*SoundChan{{}, {}, {}, {}}, } } @@ -491,7 +491,7 @@ func clip(val int32) int16 { } func (g *GBA) soundClock(cycles uint32) { - defer g.PanicHandler(true) + defer g.PanicHandler("apu", true) sndCycles += cycles sampPcmL, sampPcmR := int16(0), int16(0) diff --git a/pkg/gba/arm.go b/pkg/gba/arm.go index b3b9f6b..5b8b3c9 100644 --- a/pkg/gba/arm.go +++ b/pkg/gba/arm.go @@ -59,15 +59,13 @@ func (g *GBA) armExec(inst uint32) { case isArmMSR(inst): g.armMSR(inst) case isArmSWP(inst): - fmt.Fprintf(os.Stderr, "SWI is unsupported in 0x%08x\n", g.inst.loc) - g.Exit("") + g.Exit(fmt.Sprintf("SWI is unsupported in 0x%08x\n", g.inst.loc)) case isArmMPY(inst): g.armMPY(inst) case isArmALU(inst): g.armALU(inst) default: - fmt.Fprintf(os.Stderr, "invalid ARM opcode(0x%08x) in 0x%08x\n", inst, g.inst.loc) - g.Exit("") + g.Exit(fmt.Sprintf("invalid ARM opcode(0x%08x) in 0x%08x\n", inst, g.inst.loc)) } } } @@ -97,13 +95,8 @@ func (g *GBA) armBL(inst uint32) { func (g *GBA) armBX(inst uint32) { rnval := g.R[inst&0b1111] - if util.Bit(rnval, 0) { - g.SetCPSRFlag(flagT, true) - g.R[15] = rnval - 1 - } else { - g.R[15] = rnval - } - g.pipelining() + g.R[15] = rnval + g.interwork() } func (g *GBA) armLDM(inst uint32) { @@ -444,278 +437,161 @@ func (g *GBA) armALU(inst uint32) { } } -func (g *GBA) armALUChangeOSMode() { +func (g *GBA) armALUChangeOSMode(flush bool) { g.restorePrivMode() - g.pipelining() + if flush { + g.pipelining() + } g.checkIRQ() } -func (g *GBA) armAND(inst uint32) { - rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) - g.R[rd] = rnval & op2 - - s := util.Bit(inst, 20) +// set flag in Logic instruction +func (g *GBA) armLogicSet(rd uint32, s bool, res uint32, isTstTeq bool) { if rd == 15 { if s { - g.armALUChangeOSMode() - } else { + g.armALUChangeOSMode(!isTstTeq) + } else if !isTstTeq { g.pipelining() } } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) + g.SetCPSRFlag(flagZ, res == 0) + g.SetCPSRFlag(flagN, util.Bit(res, 31)) } } -func (g *GBA) armEOR(inst uint32) { - rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) - g.R[rd] = rnval ^ op2 - - s := util.Bit(inst, 20) +func (g *GBA) armArithAddSet(rd uint32, s bool, lhs, rhs uint32, res uint64, isCmn bool) { if rd == 15 { if s { - g.armALUChangeOSMode() - } else { + g.armALUChangeOSMode(!isCmn) + } else if !isCmn { g.pipelining() } } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) + g.SetCPSRFlag(flagZ, uint32(res) == 0) + g.SetCPSRFlag(flagN, util.Bit(uint32(res), 31)) + g.SetCPSRFlag(flagC, util.AddC(res)) + g.SetCPSRFlag(flagV, util.AddV(uint32(lhs), uint32(rhs), uint32(res))) } } -func (g *GBA) armSUB(inst uint32) { - rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) - g.R[rd] = rnval - op2 - - s := util.Bit(inst, 20) +func (g *GBA) armArithSubSet(rd uint32, s bool, lhs, rhs uint32, res uint64, isCmp bool) { if rd == 15 { if s { - g.armALUChangeOSMode() - } else { + g.armALUChangeOSMode(!isCmp) + } else if !isCmp { g.pipelining() } } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - g.SetCPSRFlag(flagC, util.SubC(uint64(rnval)-uint64(op2))) - g.SetCPSRFlag(flagV, util.SubV(rnval, op2, g.R[rd])) + g.SetCPSRFlag(flagZ, uint32(res) == 0) + g.SetCPSRFlag(flagN, util.Bit(uint32(res), 31)) + g.SetCPSRFlag(flagC, util.SubC(res)) + g.SetCPSRFlag(flagV, util.SubV(lhs, rhs, uint32(res))) } } -func (g *GBA) armRSB(inst uint32) { +func (g *GBA) armAND(inst uint32) { rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) - g.R[rd] = op2 - rnval + g.R[rd] = rnval & op2 + g.armLogicSet(rd, util.Bit(inst, 20), g.R[rd], false) +} - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - g.SetCPSRFlag(flagC, util.SubC(uint64(op2)-uint64(rnval))) - g.SetCPSRFlag(flagV, util.SubV(op2, rnval, g.R[rd])) - } +func (g *GBA) armEOR(inst uint32) { + rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) + g.R[rd] = rnval ^ op2 + g.armLogicSet(rd, util.Bit(inst, 20), g.R[rd], false) +} + +func (g *GBA) armSUB(inst uint32) { + rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) + res := uint64(rnval) - uint64(op2) + g.R[rd] = uint32(res) + g.armArithSubSet(rd, util.Bit(inst, 20), rnval, op2, res, false) +} + +func (g *GBA) armRSB(inst uint32) { + rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) + res := uint64(op2) - uint64(rnval) + g.R[rd] = uint32(res) + g.armArithSubSet(rd, util.Bit(inst, 20), op2, rnval, res, false) } func (g *GBA) armADD(inst uint32) { rd, rnval, op2 := (inst>>12)&0b1111, g.armALURn(inst), g.armALUOp2(inst) - g.R[rd] = rnval + op2 - - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - g.SetCPSRFlag(flagC, util.AddC(uint64(rnval)+uint64(op2))) - g.SetCPSRFlag(flagV, util.AddV(rnval, op2, g.R[rd])) - } + res := uint64(rnval) + uint64(op2) + g.R[rd] = uint32(res) + g.armArithAddSet(rd, util.Bit(inst, 20), rnval, op2, res, false) } func (g *GBA) armADC(inst uint32) { - carry := uint32(0) - if g.GetCPSRFlag(flagC) { - carry = 1 - } + carry := g.Carry() rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) - g.R[rd] = rnval + op2 + carry - - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - g.SetCPSRFlag(flagC, util.AddC(uint64(rnval)+uint64(op2)+uint64(carry))) - g.SetCPSRFlag(flagV, util.AddV(rnval, op2, g.R[rd])) - } + res := uint64(rnval) + uint64(op2) + uint64(carry) + g.R[rd] = uint32(res) + g.armArithAddSet(rd, util.Bit(inst, 20), rnval, op2, res, false) } func (g *GBA) armSBC(inst uint32) { - carry := uint32(0) - if g.GetCPSRFlag(flagC) { - carry = 1 - } + carry := g.Carry() rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) - g.R[rd] = rnval - op2 + carry - 1 - - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - g.SetCPSRFlag(flagC, util.SubC(uint64(rnval)-uint64(op2)+uint64(carry)-uint64(1))) - g.SetCPSRFlag(flagV, util.SubV(rnval, op2, g.R[rd])) - } + res := uint64(rnval) - uint64(op2) + (uint64(carry) - 1) + g.R[rd] = uint32(res) + g.armArithSubSet(rd, util.Bit(inst, 20), rnval, op2, res, false) } func (g *GBA) armRSC(inst uint32) { - carry := uint32(0) - if g.GetCPSRFlag(flagC) { - carry = 1 - } + carry := g.Carry() rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) - g.R[rd] = op2 - rnval + carry - 1 - - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - g.SetCPSRFlag(flagC, util.SubC(uint64(op2)-uint64(rnval)+uint64(carry)-uint64(1))) - g.SetCPSRFlag(flagV, util.SubV(op2, rnval, g.R[rd])) - } + res := uint64(op2) - uint64(rnval) + (uint64(carry - 1)) + g.R[rd] = uint32(res) + g.armArithSubSet(rd, util.Bit(inst, 20), op2, rnval, res, false) } func (g *GBA) armTST(inst uint32) { rnval, op2 := g.armALURn(inst), g.armALUOp2(inst) result := rnval & op2 - if s := util.Bit(inst, 20); s { - g.SetCPSRFlag(flagZ, result == 0) - g.SetCPSRFlag(flagN, util.Bit(result, 31)) - } + g.armLogicSet(inst>>12&0b1111, util.Bit(inst, 20), result, true) } func (g *GBA) armTEQ(inst uint32) { rnval, op2 := g.armALURn(inst), g.armALUOp2(inst) result := rnval ^ op2 - if s := util.Bit(inst, 20); s { - g.SetCPSRFlag(flagZ, result == 0) - g.SetCPSRFlag(flagN, util.Bit(result, 31)) - } + g.armLogicSet(inst>>12&0b1111, util.Bit(inst, 20), result, true) } func (g *GBA) armCMP(inst uint32) { rnval, op2 := g.armALURn(inst), g.armALUOp2(inst) - result := rnval - op2 - if s := util.Bit(inst, 20); s { - g.SetCPSRFlag(flagZ, result == 0) - g.SetCPSRFlag(flagN, util.Bit(result, 31)) - g.SetCPSRFlag(flagC, util.SubC(uint64(rnval)-uint64(op2))) - g.SetCPSRFlag(flagV, util.SubV(rnval, op2, result)) - } + res := uint64(rnval) - uint64(op2) + g.armArithSubSet(inst>>12&0b1111, util.Bit(inst, 20), rnval, op2, res, true) } func (g *GBA) armCMN(inst uint32) { rnval, op2 := g.armALURn(inst), g.armALUOp2(inst) - result := rnval + op2 - if s := util.Bit(inst, 20); s { - g.SetCPSRFlag(flagZ, result == 0) - g.SetCPSRFlag(flagN, util.Bit(result, 31)) - g.SetCPSRFlag(flagC, util.AddC(uint64(rnval)+uint64(op2))) - g.SetCPSRFlag(flagV, util.AddV(rnval, op2, result)) - } + res := uint64(rnval) + uint64(op2) + g.armArithAddSet(inst>>12&0b1111, util.Bit(inst, 20), rnval, op2, res, true) } func (g *GBA) armORR(inst uint32) { rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) g.R[rd] = rnval | op2 - - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - } + g.armLogicSet(rd, util.Bit(inst, 20), g.R[rd], false) } func (g *GBA) armMOV(inst uint32) { rd, op2 := (inst>>12)&0b1111, g.armALUOp2(inst) g.R[rd] = op2 - - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - } + g.armLogicSet(rd, util.Bit(inst, 20), g.R[rd], false) } func (g *GBA) armBIC(inst uint32) { rd, rnval, op2 := inst>>12&0b1111, g.armALURn(inst), g.armALUOp2(inst) g.R[rd] = rnval & ^op2 - - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - } + g.armLogicSet(rd, util.Bit(inst, 20), g.R[rd], false) } func (g *GBA) armMVN(inst uint32) { rd, op2 := inst>>12&0b1111, g.armALUOp2(inst) g.R[rd] = ^op2 - - s := util.Bit(inst, 20) - if rd == 15 { - if s { - g.armALUChangeOSMode() - } else { - g.pipelining() - } - } else if s { - g.SetCPSRFlag(flagZ, g.R[rd] == 0) - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - } + g.armLogicSet(rd, util.Bit(inst, 20), g.R[rd], false) } func (g *GBA) armMPY(inst uint32) { diff --git a/pkg/gba/debug.go b/pkg/gba/debug.go index baeb654..f6ea659 100644 --- a/pkg/gba/debug.go +++ b/pkg/gba/debug.go @@ -77,33 +77,33 @@ func (g *GBA) printInst(inst uint32) { func (g *GBA) printIRQExceptions() { flag := uint16(g._getRAM(ram.IE)) & uint16(g._getRAM(ram.IF)) switch { - case util.Bit(flag, irqVBlank): + case util.Bit(flag, int(irqVBlank)): fmt.Println("exception occurred: IRQ VBlank") - case util.Bit(flag, irqHBlank): + case util.Bit(flag, int(irqHBlank)): fmt.Println("exception occurred: IRQ HBlank") - case util.Bit(flag, irqVCount): + case util.Bit(flag, int(irqVCount)): fmt.Println("exception occurred: IRQ VCount") - case util.Bit(flag, irqTimer0): + case util.Bit(flag, int(irqTimer0)): fmt.Println("exception occurred: IRQ Timer0") - case util.Bit(flag, irqTimer1): + case util.Bit(flag, int(irqTimer1)): fmt.Println("exception occurred: IRQ Timer1") - case util.Bit(flag, irqTimer2): + case util.Bit(flag, int(irqTimer2)): fmt.Println("exception occurred: IRQ Timer2") - case util.Bit(flag, irqTimer3): + case util.Bit(flag, int(irqTimer3)): fmt.Println("exception occurred: IRQ Timer3") - case util.Bit(flag, irqSerial): + case util.Bit(flag, int(irqSerial)): fmt.Println("exception occurred: IRQ Serial") - case util.Bit(flag, irqDMA0): + case util.Bit(flag, int(irqDMA0)): fmt.Println("exception occurred: IRQ DMA0") - case util.Bit(flag, irqDMA1): + case util.Bit(flag, int(irqDMA1)): fmt.Println("exception occurred: IRQ DMA1") - case util.Bit(flag, irqDMA2): + case util.Bit(flag, int(irqDMA2)): fmt.Println("exception occurred: IRQ DMA2") - case util.Bit(flag, irqDMA3): + case util.Bit(flag, int(irqDMA3)): fmt.Println("exception occurred: IRQ DMA3") - case util.Bit(flag, irqKEY): + case util.Bit(flag, int(irqKEY)): fmt.Println("exception occurred: IRQ KEY") - case util.Bit(flag, irqGamePak): + case util.Bit(flag, int(irqGamePak)): fmt.Println("exception occurred: IRQ GamePak") } } @@ -294,9 +294,9 @@ func (ih IRQHistory) String() string { return fmt.Sprintf("IRQ(%s): 0x%08x -> 0x%08x on %s", ih.irq, ih.start, ih.returnTo, mode) } -func (g *GBA) PanicHandler(stack bool) { +func (g *GBA) PanicHandler(place string, stack bool) { if err := recover(); err != nil { - fmt.Fprintf(os.Stderr, "crash in emulation: %s in 0x%08x\n", err, g.PC()) + fmt.Fprintf(os.Stderr, "%s emulation error: %s in 0x%08x\n", place, err, g.PC()) for depth := 0; ; depth++ { _, file, line, ok := runtime.Caller(depth) if !ok { @@ -305,6 +305,5 @@ func (g *GBA) PanicHandler(stack bool) { fmt.Printf("======> %d: %v:%d\n", depth, file, line) } g.Exit("") - panic("") } } diff --git a/pkg/gba/dma.go b/pkg/gba/dma.go index 051f31b..78828e1 100644 --- a/pkg/gba/dma.go +++ b/pkg/gba/dma.go @@ -118,7 +118,7 @@ func (g *GBA) dmaTransfer(t dmaTiming) { } if ch.irq() { - g.triggerIRQ(IRQID(irqDMA0 + i)) + g.triggerIRQ(irqDMA0 + IRQID(i)) } if ch.repeat() { @@ -159,6 +159,6 @@ func (g *GBA) dmaTransferFifo(ch int) { } if g.dma[ch].irq() { - g.triggerIRQ(IRQID(irqDMA0 + ch)) + g.triggerIRQ(irqDMA0 + IRQID(ch)) } } diff --git a/pkg/gba/gba.go b/pkg/gba/gba.go index 37bbdb3..bfe391a 100644 --- a/pkg/gba/gba.go +++ b/pkg/gba/gba.go @@ -25,20 +25,20 @@ const ( type IRQID int const ( - irqVBlank = 0x00 - irqHBlank = 0x01 - irqVCount = 0x02 - irqTimer0 = 0x03 - irqTimer1 = 0x04 - irqTimer2 = 0x05 - irqTimer3 = 0x06 - irqSerial = 0x07 - irqDMA0 = 0x08 - irqDMA1 = 0x09 - irqDMA2 = 0x0a - irqDMA3 = 0x0b - irqKEY = 0x0c - irqGamePak = 0x0d + irqVBlank IRQID = 0x00 + irqHBlank IRQID = 0x01 + irqVCount IRQID = 0x02 + irqTimer0 IRQID = 0x03 + irqTimer1 IRQID = 0x04 + irqTimer2 IRQID = 0x05 + irqTimer3 IRQID = 0x06 + irqSerial IRQID = 0x07 + irqDMA0 IRQID = 0x08 + irqDMA1 IRQID = 0x09 + irqDMA2 IRQID = 0x0a + irqDMA3 IRQID = 0x0b + irqKEY IRQID = 0x0c + irqGamePak IRQID = 0x0d ) // GBA is core object @@ -98,7 +98,9 @@ func (g *GBA) Exit(s string) { func (g *GBA) exec(cycles int) { if g.halt { + tmp := g.cycle g.timer(cycles) + g.cycle = tmp return } @@ -343,3 +345,14 @@ func (g *GBA) LoadSav(bs []byte) { func (g *GBA) in(addr, start, end uint32) bool { return addr >= start && addr <= end } + +func (g *GBA) interwork() { + g.SetCPSRFlag(flagT, (g.R[15]&1) > 0) + + if g.GetCPSRFlag(flagT) { + g.R[15] &= ^uint32(1) + } else { + g.R[15] &= ^uint32(3) + } + g.pipelining() +} diff --git a/pkg/gba/io.go b/pkg/gba/io.go index 712c472..2c7a70f 100644 --- a/pkg/gba/io.go +++ b/pkg/gba/io.go @@ -93,7 +93,7 @@ func (g *GBA) _setRAM(addr uint32, val uint32, width int) { defer func() { if err := recover(); err != nil { if strings.Contains(fmt.Sprintln(err), "runtime error: index out of range") { - panic(fmt.Sprintf("access to 0x%08x(%v)", addr, err)) + panic(fmt.Sprintf("ram error: write to 0x%08x(%v)", addr, err)) } panic(err) } diff --git a/pkg/gba/reg.go b/pkg/gba/reg.go index f266b5a..7ff0332 100644 --- a/pkg/gba/reg.go +++ b/pkg/gba/reg.go @@ -73,6 +73,13 @@ func (r *Reg) GetCPSRFlag(idx int) bool { return util.Bit(r.CPSR, idx) } +func (r *Reg) Carry() uint32 { + if r.GetCPSRFlag(flagC) { + return 1 + } + return 0 +} + // getPrivMode get Processor mode func (r *Reg) getPrivMode() Mode { return Mode(r.CPSR & 0b11111) diff --git a/pkg/gba/thumb.go b/pkg/gba/thumb.go index 936d573..1457d86 100644 --- a/pkg/gba/thumb.go +++ b/pkg/gba/thumb.go @@ -3,7 +3,6 @@ package gba import ( "fmt" "magia/pkg/util" - "os" ) func (g *GBA) thumbStep() { @@ -64,8 +63,7 @@ func (g *GBA) thumbExec(inst uint16) { case isThumbLinkBranch2(inst): g.thumbLinkBranch2(inst) default: - fmt.Fprintf(os.Stderr, "invalid THUMB opcode(0x%04x) in 0x%08x\n", inst, g.inst.loc) - g.Exit("") + g.Exit(fmt.Sprintf("invalid THUMB opcode(0x%04x) in 0x%08x\n", inst, g.inst.loc)) } } @@ -89,120 +87,103 @@ func (g *GBA) thumbAddSub(inst uint16) { lhs, rhs := g.R[rs], g.R[delta] switch opcode := (inst >> 9) & 0b11; opcode { case 0: // ADD Rd,Rs,Rn - result := uint64(lhs) + uint64(rhs) - g.R[rd] = lhs + rhs - g.SetCPSRFlag(flagC, util.AddC(result)) - g.SetCPSRFlag(flagV, util.AddV(lhs, rhs, uint32(result))) + res := uint64(lhs) + uint64(rhs) + g.R[rd] = uint32(res) + g.armArithAddSet(uint32(rd), true, lhs, rhs, res, false) case 1: // SUB Rd,Rs,Rn - result := uint64(lhs) - uint64(rhs) - g.R[rd] = lhs - rhs - g.SetCPSRFlag(flagC, util.SubC(result)) - g.SetCPSRFlag(flagV, util.SubV(lhs, rhs, uint32(result))) + res := uint64(lhs) - uint64(rhs) + g.R[rd] = uint32(lhs - rhs) + g.armArithSubSet(uint32(rd), true, lhs, rhs, res, false) case 2: // ADD Rd,Rs,#nn - result := uint64(lhs) + uint64(delta) - g.R[rd] = lhs + uint32(delta) - g.SetCPSRFlag(flagC, util.AddC(result)) - g.SetCPSRFlag(flagV, util.AddV(lhs, uint32(delta), uint32(result))) + rhs = uint32(delta) + res := uint64(lhs) + uint64(rhs) + g.R[rd] = uint32(res) + g.armArithAddSet(uint32(rd), true, lhs, rhs, res, false) case 3: // SUB Rd,Rs,#nn - result := uint64(lhs) - uint64(delta) - g.R[rd] = lhs - uint32(delta) - g.SetCPSRFlag(flagC, util.SubC(result)) - g.SetCPSRFlag(flagV, util.SubV(lhs, uint32(delta), uint32(result))) + rhs := uint32(delta) + res := uint64(lhs) - uint64(rhs) + g.R[rd] = uint32(res) + g.armArithSubSet(uint32(rd), true, lhs, rhs, res, false) } - - g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) - g.SetCPSRFlag(flagZ, g.R[rd] == 0) } func (g *GBA) thumbMovCmpAddSub(inst uint16) { rd, nn := (inst>>8)&0b111, uint32(inst&0b1111_1111) - lhs := g.R[rd] - result := uint64(0) + lhs, rhs := g.R[rd], nn switch opcode := (inst >> 11) & 0b11; opcode { case 0: // MOV Rd, #nn - result = uint64(nn) - g.R[rd] = nn + g.R[rd] = rhs + g.armLogicSet(uint32(rd), true, g.R[rd], false) case 1: // CMP - result = uint64(g.R[rd]) - uint64(nn) - g.SetCPSRFlag(flagC, util.SubC(result)) - g.SetCPSRFlag(flagV, util.SubV(g.R[rd], uint32(nn), uint32(result))) + res := uint64(lhs) - uint64(rhs) + g.armArithSubSet(uint32(rd), true, lhs, rhs, res, true) case 2: // ADD - result = uint64(g.R[rd]) + uint64(nn) - g.R[rd] = g.R[rd] + nn - g.SetCPSRFlag(flagC, util.AddC(result)) - g.SetCPSRFlag(flagV, util.AddV(lhs, uint32(nn), uint32(result))) + res := uint64(lhs) + uint64(rhs) + g.R[rd] = uint32(res) + g.armArithAddSet(uint32(rd), true, lhs, rhs, res, false) case 3: // SUB - result = uint64(g.R[rd]) - uint64(nn) - g.R[rd] = g.R[rd] - nn - g.SetCPSRFlag(flagC, util.SubC(result)) - g.SetCPSRFlag(flagV, util.SubV(lhs, uint32(nn), uint32(result))) + res := uint64(lhs) - uint64(rhs) + g.R[rd] = uint32(res) + g.armArithSubSet(uint32(rd), true, lhs, rhs, res, false) } - - g.SetCPSRFlag(flagN, util.Bit(result, 31)) - g.SetCPSRFlag(flagZ, uint32(result) == 0) } func (g *GBA) thumbALU(inst uint16) { rs, rd := (inst>>3)&0b111, inst&0b111 lhs, rhs := g.R[rd], g.R[rs] - result := uint64(0) switch opcode := (inst >> 6) & 0b1111; opcode { case 0: // AND g.R[rd] = g.R[rd] & g.R[rs] - result = uint64(g.R[rd]) + g.armLogicSet(uint32(rd), true, g.R[rd], false) case 1: // EOR(xor) g.R[rd] = g.R[rd] ^ g.R[rs] - result = uint64(g.R[rd]) + g.armLogicSet(uint32(rd), true, g.R[rd], false) case 2: // LSL is := g.R[rs] & 0xff g.R[rd] = g.armLSL(g.R[rd], is, is > 0, false) // Rd = Rd << (Rs AND 0FFh) - result = uint64(g.R[rd]) g.timer(1) + g.armLogicSet(uint32(rd), true, g.R[rd], false) case 3: // LSR is := g.R[rs] & 0xff g.R[rd] = g.armLSR(g.R[rd], is, is > 0, false) // Rd = Rd >> (Rs AND 0FFh) - result = uint64(g.R[rd]) g.timer(1) + g.armLogicSet(uint32(rd), true, g.R[rd], false) case 4: // ASR is := g.R[rs] & 0xff g.R[rd] = g.armASR(g.R[rd], is, is > 0, false) // Rd = Rd >> (Rs AND 0FFh) - result = uint64(g.R[rd]) g.timer(1) + g.armLogicSet(uint32(rd), true, g.R[rd], false) case 5: // ADC - result = uint64(g.R[rd]) + uint64(g.R[rs]) + uint64(util.BoolToInt(g.GetCPSRFlag(flagC))) - g.R[rd] = g.R[rd] + g.R[rs] + uint32(util.BoolToInt(g.GetCPSRFlag(flagC))) // Rd = Rd + Rs + Carry - g.SetCPSRFlag(flagC, util.AddC(result)) - g.SetCPSRFlag(flagV, util.AddV(lhs, rhs, uint32(result))) + res := uint64(lhs) + uint64(rhs) + uint64(g.Carry()) + g.R[rd] = uint32(res) // Rd = Rd + Rs + Carry + g.armArithAddSet(uint32(rd), true, lhs, rhs, res, false) case 6: // SBC - result = uint64(g.R[rd]) - uint64(g.R[rs]) - uint64(util.BoolToInt(!g.GetCPSRFlag(flagC))) - g.R[rd] = g.R[rd] - g.R[rs] - uint32(util.BoolToInt(!g.GetCPSRFlag(flagC))) // Rd = Rd - Rs - NOT Carry - g.SetCPSRFlag(flagC, util.SubC(result)) - g.SetCPSRFlag(flagV, util.SubV(lhs, rhs, uint32(result))) + res := uint64(lhs) - uint64(rhs) - uint64(util.BoolToInt(!g.GetCPSRFlag(flagC))) + g.R[rd] = uint32(res) // Rd = Rd - Rs - NOT Carry + g.armArithSubSet(uint32(rd), true, lhs, rhs, res, false) case 7: // ROR is := g.R[rs] & 0xff g.R[rd] = g.armROR(g.R[rd], is, is > 0, false) // Rd = Rd ROR (Rs AND 0FFh) - result = uint64(g.R[rd]) g.timer(1) - case 8: - result = uint64(g.R[rd] & g.R[rs]) // TST Rd,Rs - case 9: - rhs := g.R[rs] - result = 0 - uint64(g.R[rs]) - g.R[rd] = -g.R[rs] // Rd = -Rs - g.SetCPSRFlag(flagC, util.SubC(result)) - g.SetCPSRFlag(flagV, util.SubV(0, rhs, g.R[rd])) + g.armLogicSet(uint32(rd), true, g.R[rd], false) + case 8: // TST + g.armLogicSet(uint32(rd), true, g.R[rd]&g.R[rs], true) + case 9: // NEG + lhs = 0 + res := 0 - uint64(rhs) + g.R[rd] = uint32(res) // Rd = -Rs + g.armArithSubSet(uint32(rd), true, lhs, rhs, res, false) case 10: // CMP - result = uint64(g.R[rd]) - uint64(g.R[rs]) // Void = Rd - Rs - g.SetCPSRFlag(flagC, util.SubC(result)) - g.SetCPSRFlag(flagV, util.SubV(g.R[rd], g.R[rs], uint32(result))) - case 11: - result = uint64(g.R[rd]) + uint64(g.R[rs]) // Void = Rd + Rs - g.SetCPSRFlag(flagC, util.AddC(result)) - g.SetCPSRFlag(flagV, util.AddV(g.R[rd], g.R[rs], uint32(result))) - case 12: - g.R[rd] = g.R[rd] | g.R[rs] - result = uint64(g.R[rd]) - case 13: + res := uint64(lhs) - uint64(rhs) // Void = Rd - Rs + g.armArithSubSet(uint32(rd), true, lhs, rhs, res, true) + case 11: // CMN + res := uint64(lhs) + uint64(rhs) // Void = Rd + Rs + g.armArithAddSet(uint32(rd), true, lhs, rhs, res, true) + case 12: // ORR + res := lhs | rhs + g.R[rd] = res + g.armLogicSet(uint32(rd), true, res, false) + case 13: // MUL b1, b2, b3 := (g.R[rd]>>8)&0xff, (g.R[rd]>>16)&0xff, (g.R[rd]>>24)&0xff switch { case b3 > 0: @@ -215,19 +196,19 @@ func (g *GBA) thumbALU(inst uint16) { g.timer(1) } - g.R[rd] = g.R[rd] * g.R[rs] // MUL{S} Rd,Rs - result = uint64(g.R[rd]) + g.R[rd] = lhs * rhs // MUL{S} Rd,Rs g.SetCPSRFlag(flagC, false) - case 14: - g.R[rd] = g.R[rd] & ^g.R[rs] // BIC{S} Rd,Rs - result = uint64(g.R[rd]) - case 15: - g.R[rd] = ^g.R[rs] - result = uint64(g.R[rd]) + g.SetCPSRFlag(flagN, util.Bit(g.R[rd], 31)) + g.SetCPSRFlag(flagZ, g.R[rd] == 0) + case 14: // BIC + res := lhs & ^rhs + g.R[rd] = res + g.armLogicSet(uint32(rd), true, res, false) + case 15: // MVN + res := ^g.R[rs] + g.R[rd] = res + g.armLogicSet(uint32(rd), true, res, false) } - - g.SetCPSRFlag(flagN, util.Bit(result, 31)) - g.SetCPSRFlag(flagZ, uint32(result) == 0) } func (g *GBA) thumbHiRegisterBXOperand(r uint16) uint32 { @@ -252,36 +233,24 @@ func (g *GBA) thumbHiRegisterBX(inst uint16) { case 0: // ADD Rd,Rs(Rd = Rd+Rs) g.R[rd] = rdval + rsval case 1: // CMP Rd,Rs(Void = Rd-Rs) - result := uint64(rdval) - uint64(rsval) - g.SetCPSRFlag(flagN, util.Bit(result, 31)) - g.SetCPSRFlag(flagZ, uint32(result) == 0) - g.SetCPSRFlag(flagC, util.SubC(result)) - g.SetCPSRFlag(flagV, util.SubV(rdval, rsval, uint32(result))) + res := uint64(rdval) - uint64(rsval) + g.armArithSubSet(uint32(rd), true, rdval, rsval, res, true) case 2: // MOV Rd,Rs(Rd=Rs) g.R[rd] = rsval case 3: // BX Rs(PC = Rs) rd = 15 - if util.Bit(rsval, 0) { - g.R[15] = rsval - 1 - } else { - g.SetCPSRFlag(flagT, false) // switch to ARM - if rs == 15 { - g.R[15] = util.Align4(g.inst.loc + 4) - } else { - g.R[15] = rsval - } - } + g.R[rd] = g.R[rs] + g.interwork() } - if opcode != 1 && rd == 15 { + if opcode != 1 && opcode != 3 && rd == 15 { g.pipelining() } } func (g *GBA) thumbLoadPCRel(inst uint16) { - rd, nn := (inst>>8)&0b111, uint32(inst&0b1111_1111)*4 - pc := util.Align4(g.inst.loc + 4) - g.R[rd] = g.getRAM32(pc+nn, false) + rd, nn := (inst>>8)&0b111, uint32((inst<<2)&0x3fc) + g.R[rd] = g.getRAM32((g.R[15]&^uint32(3))+nn, false) g.timer(1) } @@ -503,11 +472,8 @@ func (g *GBA) thumbLinkBranch1(inst uint16) { func (g *GBA) thumbLinkBranch2(inst uint16) { nn := inst & 0b0111_1111_1111 - g.R[15] = g.R[14] + uint32(nn<<1) - g.R[14] = g.inst.loc + 2 // return - if g.R[14]&1 == 0 { - g.R[14]++ - } - + imm := g.R[14] + (uint32(nn) << 1) + g.R[14] = (g.R[15] - 2) | 1 // return + g.R[15] = imm & ^uint32(1) g.pipelining() } diff --git a/pkg/gba/timer.go b/pkg/gba/timer.go index e9601d3..2afe936 100644 --- a/pkg/gba/timer.go +++ b/pkg/gba/timer.go @@ -83,7 +83,7 @@ func (g *GBA) timer(c int) { irqs := g.Tick(c) for i, irq := range irqs { if irq { - g.triggerIRQ(IRQID(i + 3)) + g.triggerIRQ(irqTimer0 + IRQID(i)) } } } diff --git a/pkg/gpu/draw.go b/pkg/gpu/draw.go index 9452e6b..ba007ca 100644 --- a/pkg/gpu/draw.go +++ b/pkg/gpu/draw.go @@ -1,11 +1,9 @@ package gpu import ( - "fmt" "image" "image/color" "magia/pkg/util" - "os" "github.com/anthonynsimon/bild/blend" ) @@ -185,9 +183,7 @@ func (g *GPU) draw4() *image.RGBA { } func (g *GPU) draw5() *image.RGBA { - fmt.Fprintf(os.Stderr, "unsupported BG mode 5\n") - panic("") - + panic("unsupported BG mode 5") result := image.NewRGBA(image.Rect(0, 0, 240, 160)) return result } diff --git a/pkg/util/util.go b/pkg/util/util.go index 2529260..2e80b0d 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -83,19 +83,43 @@ func Bit(val interface{}, idx int) bool { } return (val & (1 << idx)) != 0 + case uint16: + if idx < 0 || idx > 15 { + return false + } + return (val & (1 << idx)) != 0 + + case byte: + if idx < 0 || idx > 7 { + return false + } + return (val & (1 << idx)) != 0 + + case int64: + if idx < 0 || idx > 63 { + return false + } + return (val & (1 << idx)) != 0 + + case int32: + if idx < 0 || idx > 31 { + return false + } + return (val & (1 << idx)) != 0 + case int: if idx < 0 || idx > 31 { return false } return (val & (1 << idx)) != 0 - case uint16: + case int16: if idx < 0 || idx > 15 { return false } return (val & (1 << idx)) != 0 - case byte: + case int8: if idx < 0 || idx > 7 { return false }