AlchemicRaker / alchemy65

A vscode debugger extension for NES projects using cc65 and ca65.
MIT License
17 stars 4 forks source link

Getting Alchemy65 to work with Mesen 2 #11

Open DoctorMikeReddy opened 9 months ago

DoctorMikeReddy commented 9 months ago

Trying to update Alchemy65 (for VS Code) to debug with Mesen 2. I have enabled "Allow access to I/O and OS functions" and "Allow network access" (which is required for sockets), thanks to a tip on NesDev, but now getting the following error:

adapter.lua:247: attempt to index a nil value (field 'cpu')

The adapter.lua file is stored in c:\Users/XXX.vscode\extensions\alchemic-raker-alchemy65-1.0.8\lua and so is clearly Alchemy65 code that is run from within Mesen. This works with Mesen-X, of course, but this code:

    if command == "getcpuvars" then
      local state = emu.getState()
      local pc_prg = emu.getPrgRomOffset(state.cpu.pc) <- *** HERE
      connection:send("cpuvars " .. tostring(state.cpu.status) .. " " .. tostring(state.cpu.a) .. " " .. tostring(state.cpu.x) .. " " .. tostring(state.cpu.y) .. " " .. tostring(state.cpu.pc) .. " " .. tostring(state.cpu.sp) .. " " .. tostring(pc_prg) .. "\n")
      --log("cpuvars")
      return true -- keep processing messages
    end

doesn't seem to like the 'cpu' bit

Any thoughts?

DoctorMikeReddy commented 9 months ago

It appears that state.anything.anything does not work with Mesen2. state.region is fine, but state.cpu.pc returns 'nil' as does any other nested table item

DoctorMikeReddy commented 9 months ago

It looks like various elements from https://www.mesen.ca/docs/apireference/emulation.html#getstate have not been implemented in Mesen2, so closing this now

DoctorMikeReddy commented 9 months ago

Ok, it appears I was wrong, and it was just a different way of accessing: Instead of state.cpu.pc we need state["cpu.pc"] in the code

DoctorMikeReddy commented 9 months ago

So, I am looking at altering the adapter.lua script to work with Mesen2 with the revised syntax. emu.getPrgRomOffset doesn't appear to be implemented in Mesen2, so it may need extending, like Mesen-X was UPDATE: dumping the value of the PrgRomOffset for a test rom gave back -1 (the default, as the test rom I am using doesn't have a mapper), so for now we can just send this. I think that ConvertAddress is what replaced it, but it is a bit more complex, doing more than the old one

DoctorMikeReddy commented 9 months ago

Right, cpu.status isn't available in Mesen2 yet, and is not implemented. Have gone back to the author of Mesen2 to see if we can get these. Doing some digging, cpu.status is cpu.ps in the new emulator

DoctorMikeReddy commented 9 months ago

StepOver StepInto and StepOut in VSCode cause errors in Mesen2. The execute command in Mesen-X has been replaced by a Step function; I think this is the StepInto that is missing. Mesen 2 also doesn't have Lua calls for StepOver and StepOut. Break has been renamed BreakExecution, but uses the same local call, so isn't an issue.

JeffAlyanak commented 3 months ago

@DoctorMikeReddy You may have already found this, but Mesen2 has the following document on the new Lua implementation: LuaDocumentation.json

Looks like the step function now takes a stepType param:

{
    "name": "step",
    "description": "Breaks the emulation's execution when the step conditions are reached.",
    "parameters": [
        { "name": "count", "type": "Int", "description": "Number of cycles/frames/etc." },
        { "name": "stepType", "type": "Enum", "enumName": "stepType", "description": "Step type" },
        { "name": "cpuType", "type": "Enum", "enumName": "cpuType", "description": "CPU type", "defaultValue": "main CPU" }
    ]
}

And that stepType enum includes stepOver and StepOut:

{
    "name": "stepType",
    "description": "Used by emu.step()",
    "enumValues": [
        { "name": "step", "description": "Steps the specified number of instructions" },
        { "name": "stepOut", "description": "Steps out of the current subroutine (not available for all CPUs)" },
        { "name": "stepOver", "description": "Steps over the current subroutine call (not available for all CPUs)" },
        { "name": "cpuCycleStep", "description": "Steps the specified number of CPU cycles (not available for all CPUs)" },
        { "name": "ppuStep", "description": "Steps the specified number of scanline cycles" },
        { "name": "ppuScanline", "description": "Steps the specified number of scanlines" },
        { "name": "ppuFrame", "description": "Steps the specified number of video frames" },
        { "name": "specificScanline", "description": "Breaks on the specified scanline number" },
        { "name": "runToNmi", "description": "Breaks on the next NMI event" },
        { "name": "runToIrq", "description": "Breaks on the next IRQ event" }
    ]
}
DoctorMikeReddy commented 3 months ago

Excellent. This had been in the back burner, but will be using this next academic year, so thank you

AlchemicRaker commented 3 months ago

Wanted to know that while I'm not in a position to implement and test these updates currently, if someone is able to create the necessary PR for this, I will get it approved quickly. I appreciate the contributions!

JeffAlyanak commented 3 months ago

@AlchemicRaker I'll look at it over the next few days and see if I can put together a PR.

JeffAlyanak commented 3 months ago

Starting work on the PR over here: https://github.com/AlchemicRaker/alchemy65/pull/12

JeffAlyanak commented 3 months ago

I'm still filling this table out, but in case anyone is working on this in parallel or wants to contribute to this PR, I've put together the documentation below on the table returned by emu.getState.

From what I can tell, the only function missing that was used in @AlchemicRaker 's original script is a lack emu.eventType.whilePaused of used in the emu.addEventCallback on line 316.

The main hurdle now is just the lack of a callback or state value for isPaused. For now I've added that in a fork for testing purposes.

Key Lua type Description
General
consoleType string (Nes, Snes, Gameboy, PcEngine, Sms, Gba)
region string (Ntsc, Pal, Dendy, NtscJapan)
clockRate number
frameCount number
masterClock number
paused bool currently only available in my fork
CPU
cpu.cycleCount number
cpu.pc number Program Counter
cpu.ps number Processor Status (flags)
cpu.sp number Stack Pointer
cpu.a number Accumulator
cpu.x number X Register
cpu.y number Y Register
PPU
ppu.cycle number
ppu.control.backgroundPatternAddr number
ppu.control.largeSprites bool
ppu.control.nmiOnVerticalBlank bool
ppu.control.spritePatternAddr number
ppu.control.verticalWrite bool
ppu.frameCount number
ppu.highBitShift number
ppu.intensifyColorBits number
ppu.lowBitShift number
ppu.mask.backgroundEnabled bool
ppu.mask.backgroundMask bool
ppu.mask.grayscale bool
ppu.mask.intensifyBlue bool
ppu.mask.intensifyGreen bool
ppu.mask.intensifyRed bool
ppu.mask.spriteMask bool
ppu.mask.spritesEnabled bool
ppu.masterClock number
ppu.memoryReadBuffer number
ppu.paletteRamMask number
ppu.ppuBusAddress number
ppu.scanline number
ppu.spriteRamAddr number
ppu.statusFlags.sprite0Hit bool
ppu.statusFlags.spriteOverflow bool
ppu.statusFlags.verticalBlank bool
ppu.tmpVideoRamAddr number
ppu.videoRamAddr number
ppu.writeToggle bool
ppu.xScroll number
APU
apu.dmc.bitsRemaining number
apu.dmc.bufferEmpty bool
apu.dmc.bytesRemaining number
apu.dmc.currentAddr number
apu.dmc.irqEnabled bool
apu.dmc.loopFlag bool
apu.dmc.needToRun bool
apu.dmc.outputLevel number
apu.dmc.readBuffer number
apu.dmc.sampleAddr number
apu.dmc.sampleLength number
apu.dmc.shiftRegister number
apu.dmc.silenceFlag bool
apu.dmc.timer.lastOutput number
apu.dmc.timer.period number
apu.dmc.timer.timer number
apu.frameCounter.blockFrameCounterTick number
apu.frameCounter.currentStep number
apu.frameCounter.inhibitIRQ bool
apu.frameCounter.newValue number
apu.frameCounter.previousCycle number
apu.frameCounter.stepMode number
apu.frameCounter.writeDelayCounter number
apu.noise.envelope.constantVolume bool
apu.noise.envelope.counter number
apu.noise.envelope.divider number
apu.noise.envelope.lengthCounter.counter number
apu.noise.envelope.lengthCounter.enabled bool
apu.noise.envelope.lengthCounter.halt bool
apu.noise.envelope.lengthCounter.newHaltValue bool
apu.noise.envelope.lengthCounter.previousValue number
apu.noise.envelope.lengthCounter.reloadValue number
apu.noise.envelope.start bool
apu.noise.envelope.volume number
apu.noise.modeFlag bool
apu.noise.shiftRegister number
apu.noise.timer.lastOutput number
apu.noise.timer.period number
apu.noise.timer.timer number
apu.square1.duty number
apu.square1.dutyPos number
apu.square1.envelope.constantVolume bool
apu.square1.envelope.counter number
apu.square1.envelope.divider number
apu.square1.envelope.lengthCounter.counter number
apu.square1.envelope.lengthCounter.enabled bool
apu.square1.envelope.lengthCounter.halt bool
apu.square1.envelope.lengthCounter.newHaltValue bool
apu.square1.envelope.lengthCounter.previousValue number
apu.square1.envelope.lengthCounter.reloadValue number
apu.square1.envelope.start bool
apu.square1.envelope.volume number
apu.square1.realPeriod number
apu.square1.reloadSweep bool
apu.square1.sweepDivider number
apu.square1.sweepEnabled bool
apu.square1.sweepNegate bool
apu.square1.sweepPeriod number
apu.square1.sweepShift number
apu.square1.sweepTargetPeriod number
apu.square1.timer.lastOutput number
apu.square1.timer.period number
apu.square1.timer.timer number
apu.square2.duty number
apu.square2.dutyPos number
apu.square2.envelope.constantVolume bool
apu.square2.envelope.counter number
apu.square2.envelope.divider number
apu.square2.envelope.lengthCounter.counter number
apu.square2.envelope.lengthCounter.enabled bool
apu.square2.envelope.lengthCounter.halt bool
apu.square2.envelope.lengthCounter.newHaltValue bool
apu.square2.envelope.lengthCounter.previousValue number
apu.square2.envelope.lengthCounter.reloadValue number
apu.square2.envelope.start bool
apu.square2.envelope.volume number
apu.square2.realPeriod number
apu.square2.reloadSweep bool
apu.square2.sweepDivider number
apu.square2.sweepEnabled bool
apu.square2.sweepNegate bool
apu.square2.sweepPeriod number
apu.square2.sweepShift number
apu.square2.sweepTargetPeriod number
apu.square2.timer.lastOutput number
apu.square2.timer.period number
apu.square2.timer.timer number
apu.triangle.lengthCounter.counter number
apu.triangle.lengthCounter.enabled bool
apu.triangle.lengthCounter.halt bool
apu.triangle.lengthCounter.newHaltValue bool
apu.triangle.lengthCounter.previousValue number
apu.triangle.lengthCounter.reloadValue number
apu.triangle.linearControlFlag bool
apu.triangle.linearCounter number
apu.triangle.linearCounterReload number
apu.triangle.linearReloadFlag bool
apu.triangle.sequencePosition number
apu.triangle.timer.lastOutput number
apu.triangle.timer.period number
apu.triangle.timer.timer number
Control Manager
controlManager.controlDevices[0].strobe bool
controlManager.controlDevices[1].microphoneEnabled bool
controlManager.controlDevices[1].stateBuffer number
controlManager.controlDevices[1].strobe bool
controlManager.lagCounter number
controlManager.pollCounter number