Skip to content

Commit

Permalink
ARM cycle stretching now differntiates between MAM mode 1 and 2
Browse files Browse the repository at this point in the history
ARM MAM mode is set according to cartridge mapper driver

Preferences changed to specify this or whether to override it with a
particular value.

Removed the other MAM control preferences

Removed Flash/SRAM information from the last execution window
  • Loading branch information
JetSetIlly committed Jun 18, 2021
1 parent 90bdaf0 commit 0080144
Show file tree
Hide file tree
Showing 14 changed files with 198 additions and 137 deletions.
2 changes: 2 additions & 0 deletions gui/sdlimgui/colors.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type imguiColors struct {
// additional general colors
True imgui.Vec4
False imgui.Vec4
TrueFalse imgui.Vec4
Transparent imgui.Vec4

// playscreen color
Expand Down Expand Up @@ -148,6 +149,7 @@ func newColors() *imguiColors {
// additional general colors
True: imgui.Vec4{0.3, 0.6, 0.3, 1.0},
False: imgui.Vec4{0.6, 0.3, 0.3, 1.0},
TrueFalse: imgui.Vec4{0.6, 0.6, 0.3, 1.0},
Transparent: imgui.Vec4{0.0, 0.0, 0.0, 0.0},

// ROM selector
Expand Down
35 changes: 10 additions & 25 deletions gui/sdlimgui/win_coproc_lastexecution.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func (win *winCoProcLastExecution) draw() {
if programCycles, ok := itr.Details.Summary.(arm7tdmi.Cycles); ok {
iTotal := programCycles.I + programCycles.Imerged
nTotal := programCycles.Npc + programCycles.Ndata
sTotal := programCycles.Spc + programCycles.Sdata + programCycles.Smerged
sTotal := programCycles.Spc + programCycles.Sdata + programCycles.Spcmerged

if imgui.BeginTableV("cycles", 4, imgui.TableFlagsBordersOuter, imgui.Vec2{}, 0.0) {
imgui.TableNextRow()
Expand All @@ -135,27 +135,6 @@ func (win *winCoProcLastExecution) draw() {
imgui.Text(fmt.Sprintf("S: %-6.0f", sTotal))
imgui.EndTable()
}

imgui.Spacing()

nsTotal := nTotal + sTotal
fp := 100.0 * programCycles.FlashAccess / nsTotal
sp := 100.0 * programCycles.SRAMAccess / nsTotal

if imgui.BeginTableV("ratios", 2, imgui.TableFlagsBordersOuter, imgui.Vec2{}, 0.0) {
imgui.TableNextRow()
imgui.TableNextColumn()
imgui.Text(fmt.Sprintf("Flash: %3.1f%%", fp))
imgui.TableNextColumn()
imgui.Text(fmt.Sprintf("SRAM/MAM: %3.1f%%", sp))
imgui.EndTable()
}

if imgui.IsItemHovered() {
imgui.BeginTooltip()
imgui.Text("The fraction of time spent by N and S cycles accessing flash or SRAM/MAM")
imgui.EndTooltip()
}
} else {
imgui.Text("")
}
Expand Down Expand Up @@ -220,10 +199,16 @@ func (win *winCoProcLastExecution) drawDisasm(itr *coprocessor.Iterate) {
imgui.Spacing()
imgui.Separator()
imgui.Spacing()
if cycles.MAMenabled {
imguiColorLabel("MAM", win.img.cols.True)
} else {
switch cycles.MAMCR {
default:
// this is an invalid value for MAMCR. operate on the assumption the the MAM is off
fallthrough
case 0:
imguiColorLabel("MAM", win.img.cols.False)
case 1:
imguiColorLabel("MAM", win.img.cols.TrueFalse)
case 2:
imguiColorLabel("MAM", win.img.cols.True)
}
}
imgui.EndTooltip()
Expand Down
55 changes: 45 additions & 10 deletions gui/sdlimgui/win_prefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,17 +184,52 @@ func (win *winPrefs) drawARM() {
defer imgui.PopItemFlag()
}

defaultMAM := win.img.vcs.Prefs.ARM.DefaultMAM.Get().(bool)
if imgui.Checkbox("Default MAM Enable for Thumb Programs", &defaultMAM) {
win.img.vcs.Prefs.ARM.DefaultMAM.Set(defaultMAM)
// emulateMAMBug := win.img.vcs.Prefs.ARM.EmulateMAMbug.Get().(bool)
// if imgui.Checkbox("Emulate MAM Bug", &emulateMAMBug) {
// win.img.vcs.Prefs.ARM.EmulateMAMbug.Set(emulateMAMBug)
// }
// win.drawHelp(`A bug in some ARM7TDMI chips used in the Harmony cartridge
// can result in a crash if the MAM is in mode 2. Leave this option unticked for
// more situations but if you need to emulate the buggy behaviour then untick this
// option.`)

var mamState string
switch win.img.vcs.Prefs.ARM.MAM.Get().(int) {
case -1:
mamState = "Driver"
case 0:
mamState = "Disabled"
case 1:
mamState = "Partial"
case 2:
mamState = "Full"
}
win.drawHelp("MAM will be enabled at beginning of every thumb program execution.\nRequired for new games like Gorf Arcade and Turbo")

allowMAMfromThumb := win.img.vcs.Prefs.ARM.AllowMAMfromThumb.Get().(bool)
if imgui.Checkbox("Allow MAM Enable from Thumb", &allowMAMfromThumb) {
win.img.vcs.Prefs.ARM.AllowMAMfromThumb.Set(allowMAMfromThumb)
imgui.PushItemWidth(imguiGetFrameDim("Disabled").X + imgui.FrameHeight())
if imgui.BeginComboV("Default MAM State##mam", mamState, imgui.ComboFlagsNone) {
if imgui.Selectable("Driver") {
win.img.vcs.Prefs.ARM.MAM.Set(-1)
}
if imgui.Selectable("Disabled") {
win.img.vcs.Prefs.ARM.MAM.Set(0)
}
if imgui.Selectable("Partial") {
win.img.vcs.Prefs.ARM.MAM.Set(1)
}
if imgui.Selectable("Full") {
win.img.vcs.Prefs.ARM.MAM.Set(2)
}
imgui.EndCombo()
}
win.drawHelp("MAM can be enabled/disabled by thumb program")
imgui.PopItemWidth()
win.drawHelp(`The MAM state at the start of the Thumb program.
For most purposes, this should be set to 'Driver'. This means that the emulated driver
for the cartridge mapper decides what the value should be.
If the 'Default MAM State' value is not set to 'Driver' then the Thumb program will be
prevented from changing the MAM state.
The MAM should almost never be disabled completely.`)

imgui.Spacing()
if imgui.CollapsingHeader("Timings (advanced)") {
Expand All @@ -208,7 +243,7 @@ func (win *winPrefs) drawARM() {
if imgui.SliderFloatV("Flash Access Time", &flashAccessTime, 1, 60, fmt.Sprintf("%.1f ns", flashAccessTime), imgui.SliderFlagsNone) {
win.img.vcs.Prefs.ARM.FlashAccessTime.Set(flashAccessTime)
}
win.drawHelp("The amount of time required for the ARM to address Flash. Default time of 10ns")
win.drawHelp("The amount of time required for the ARM to address Flash. Default time of 50ns")

sramAccessTime := float32(win.img.vcs.Prefs.ARM.SRAMAccessTime.Get().(float64))
if imgui.SliderFloatV("SRAM Access Time", &sramAccessTime, 1, 60, fmt.Sprintf("%.1f ns", sramAccessTime), imgui.SliderFlagsNone) {
Expand Down
104 changes: 58 additions & 46 deletions hardware/memory/cartridge/harmony/arm7tdmi/arm7.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type ARM struct {

stretchFlash float32
stretchSRAM float32
stretchMAM float32

// the speed at which the arm is running at
clock float32
Expand Down Expand Up @@ -353,18 +354,24 @@ func (arm *ARM) write32bit(addr uint32, val uint32) {
// forever.
//
// Returns the number of ARM cycles and any errors.
func (arm *ARM) Run() (float32, error) {
func (arm *ARM) Run(mamcr uint32) (uint32, float32, error) {
err := arm.reset()
if err != nil {
return 0, err
return arm.mam.mamcr, 0, err
}

// apply preferences to ARM state
// set mamcr on startup
arm.mam.pref = arm.prefs.MAM.Get().(int)
if arm.mam.pref == preferences.MAMDriver {
arm.mam.setMAMCR(mamcr)
} else {
arm.mam.setMAMCR(uint32(arm.mam.pref))
}

// main ARM clock
arm.clock = float32(arm.prefs.Clock.Get().(float64))
arm.mam.allowFromThumb = arm.prefs.AllowMAMfromThumb.Get().(bool)
arm.mam.enable(arm.prefs.DefaultMAM.Get().(bool))

// get current stetch values for N and S cycles
// get current stetch values for SRAM/Flash access
arm.stretchFlash = float32(arm.prefs.Clock.Get().(float64) / (1000 / arm.prefs.FlashAccessTime.Get().(float64)))
arm.stretchSRAM = float32(arm.prefs.Clock.Get().(float64) / (1000 / arm.prefs.SRAMAccessTime.Get().(float64)))
if arm.stretchFlash < 1.0 {
Expand All @@ -374,6 +381,9 @@ func (arm *ARM) Run() (float32, error) {
arm.stretchSRAM = 1.0
}

// stretch value of MAM is always 1.0 (?)
arm.stretchMAM = 1.0

// start of program execution
if arm.disasm != nil {
arm.disasm.Start()
Expand Down Expand Up @@ -428,15 +438,15 @@ func (arm *ARM) Run() (float32, error) {
if err != nil {
// can't find memory so we say the ARM program has finished inadvertently
logger.Logf("ARM7", "PC out of range (%#08x). finishing arm program early", arm.registers[rPC])
return arm.cyclesTotal, nil
return arm.mam.mamcr, arm.cyclesTotal, nil
}

// if it's still out-of-range then give up with an error
idx = pc - arm.programMemoryOffset
if idx+1 >= uint32(len(*arm.programMemory)) {
// can't find memory so we say the ARM program has finished inadvertently
logger.Logf("ARM7", "PC out of range (%#08x). finishing arm program early", arm.registers[rPC])
return arm.cyclesTotal, nil
return arm.mam.mamcr, arm.cyclesTotal, nil
}
}

Expand Down Expand Up @@ -551,37 +561,39 @@ func (arm *ARM) Run() (float32, error) {
}

// the state of MAM and PC at end of instruction execution
arm.cyclesInstruction.MAMenabled = arm.mam.isEnabled()
arm.cyclesInstruction.MAMCR = arm.mam.mamcr
arm.cyclesInstruction.PCinSRAM = !(arm.registers[rPC] >= FlashOrigin && arm.registers[rPC] <= Flash64kMemtop)

// sum cycles. not summing merged cycles
sumCycles := arm.cyclesInstruction.I + arm.cyclesInstruction.C

// PC cycle stretching
pcAccess := arm.cyclesInstruction.Npc + arm.cyclesInstruction.Spc
if arm.cyclesInstruction.MAMenabled {
arm.cyclesInstruction.SRAMAccess += pcAccess
sumCycles += pcAccess * arm.stretchSRAM
} else if arm.cyclesInstruction.PCinSRAM {
arm.cyclesInstruction.SRAMAccess += pcAccess
sumCycles += pcAccess * arm.stretchSRAM
} else {
arm.cyclesInstruction.FlashAccess += pcAccess
sumCycles += pcAccess * arm.stretchFlash
}

// data cycle streching
//
// assumption: all data acces is to SRAM
dataAccess := arm.cyclesInstruction.Ndata + arm.cyclesInstruction.Sdata
arm.cyclesInstruction.SRAMAccess += dataAccess
sumCycles += dataAccess * arm.stretchSRAM

// total number of program cycles
arm.cyclesTotal += sumCycles
// sum and strech cycles. I and C cycles added here. N and S cycles
// added according to MAM settings
stretchedCycles := arm.cyclesInstruction.I + arm.cyclesInstruction.C
// stretchedCycles += arm.cyclesInstruction.Imerged

// MAM resolution. page 19 of UM10161.pdf
switch arm.mam.mamcr {
default:
// this is an invalid value for MAMCR. operate on the assumption the the MAM is off
fallthrough
case 0:
stretchedCycles += (arm.cyclesInstruction.Npc + arm.cyclesInstruction.Spc) * arm.stretchFlash
stretchedCycles += (arm.cyclesInstruction.Spcmerged) * arm.stretchFlash
stretchedCycles += (arm.cyclesInstruction.Ndata + arm.cyclesInstruction.Sdata) * arm.stretchSRAM
case 1:
stretchedCycles += (arm.cyclesInstruction.Npc * arm.stretchFlash)
stretchedCycles += (arm.cyclesInstruction.Spc * arm.stretchMAM)
stretchedCycles += (arm.cyclesInstruction.Spcmerged) * arm.stretchMAM
stretchedCycles += (arm.cyclesInstruction.Ndata + arm.cyclesInstruction.Sdata) * arm.stretchSRAM
case 2:
stretchedCycles += (arm.cyclesInstruction.Npc + arm.cyclesInstruction.Spc) * arm.stretchMAM
stretchedCycles += (arm.cyclesInstruction.Spcmerged) * arm.stretchMAM
stretchedCycles += (arm.cyclesInstruction.Ndata + arm.cyclesInstruction.Sdata) * arm.stretchMAM
}

// increas total number of program cycles by the stretched cycles for this instruction
arm.cyclesTotal += stretchedCycles

// update timer
arm.timer.step(sumCycles)
arm.timer.step(stretchedCycles)

// send disasm information to disassembler
if arm.disasm != nil {
Expand Down Expand Up @@ -632,10 +644,10 @@ func (arm *ARM) Run() (float32, error) {
}

if arm.executionError != nil {
return 0, curated.Errorf("ARM: %v", arm.executionError)
return arm.mam.mamcr, 0, curated.Errorf("ARM: %v", arm.executionError)
}

return arm.cyclesTotal, nil
return arm.mam.mamcr, arm.cyclesTotal, nil
}

func (arm *ARM) executeMoveShiftedRegister(opcode uint16) {
Expand Down Expand Up @@ -1406,7 +1418,7 @@ func (arm *ARM) executePCrelativeLoad(opcode uint16) {
// "During the third cycle, the ARM7TDMI-S processor transfers the data to the
// destination register. (External memory is not used.) Normally, the ARM7TDMI-S
// core merges this third cycle with the next prefetch to form one memory N-cycle."
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// the I cycle is marked "as required"
Expand Down Expand Up @@ -1456,7 +1468,7 @@ func (arm *ARM) executeLoadStoreWithRegisterOffset(opcode uint16) {
// "During the third cycle, the ARM7TDMI-S processor transfers the data to the
// destination register. (External memory is not used.) Normally, the ARM7TDMI-S
// core merges this third cycle with the next prefetch to form one memory N-cycle."
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// the I cycle is marked "as required"
Expand Down Expand Up @@ -1532,7 +1544,7 @@ func (arm *ARM) executeLoadStoreSignExtendedByteHalford(opcode uint16) {
// "During the third cycle, the ARM7TDMI-S processor transfers the data to the
// destination register. (External memory is not used.) Normally, the ARM7TDMI-S
// core merges this third cycle with the next prefetch to form one memory N-cycle."
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// the I cycle is marked "as required"
Expand Down Expand Up @@ -1575,7 +1587,7 @@ func (arm *ARM) executeLoadStoreSignExtendedByteHalford(opcode uint16) {
// "During the third cycle, the ARM7TDMI-S processor transfers the data to the
// destination register. (External memory is not used.) Normally, the ARM7TDMI-S
// core merges this third cycle with the next prefetch to form one memory N-cycle."
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// the I cycle is marked "as required"
Expand Down Expand Up @@ -1643,7 +1655,7 @@ func (arm *ARM) executeLoadStoreWithImmOffset(opcode uint16) {
// "During the third cycle, the ARM7TDMI-S processor transfers the data to the
// destination register. (External memory is not used.) Normally, the ARM7TDMI-S
// core merges this third cycle with the next prefetch to form one memory N-cycle."
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// the I cycle is marked "as required"
Expand Down Expand Up @@ -1723,7 +1735,7 @@ func (arm *ARM) executeLoadStoreHalfword(opcode uint16) {
// "During the third cycle, the ARM7TDMI-S processor transfers the data to the
// destination register. (External memory is not used.) Normally, the ARM7TDMI-S
// core merges this third cycle with the next prefetch to form one memory N-cycle."
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// the I cycle is marked "as required"
Expand Down Expand Up @@ -1782,7 +1794,7 @@ func (arm *ARM) executeSPRelativeLoadStore(opcode uint16) {
// "During the third cycle, the ARM7TDMI-S processor transfers the data to the
// destination register. (External memory is not used.) Normally, the ARM7TDMI-S
// core merges this third cycle with the next prefetch to form one memory N-cycle."
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// the I cycle is marked "as required"
Expand Down Expand Up @@ -1947,7 +1959,7 @@ func (arm *ARM) executePushPopRegisters(opcode uint16) {
// with the next instruction prefetch to form a single memory N-cycle."
if arm.cyclesInstruction.Sdata > 0 {
arm.cyclesInstruction.Sdata--
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// load PC register after all other registers
Expand Down Expand Up @@ -2118,7 +2130,7 @@ func (arm *ARM) executeMultipleLoadStore(opcode uint16) {
// with the next instruction prefetch to form a single memory N-cycle."
if arm.cyclesInstruction.Sdata > 0 {
arm.cyclesInstruction.Sdata--
arm.cyclesInstruction.Smerged++
arm.cyclesInstruction.Spcmerged++
}

// write back the new base address
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ package armclocks

const (
MasterClock = 70 // Mhz
FlashAccessTime = 35 // ns
FlashAccessTime = 50 // ns
SRAMAccessTime = 10 // ns
)
Loading

0 comments on commit 0080144

Please sign in to comment.