mirror of
https://github.com/holub/mame
synced 2025-04-20 23:42:22 +03:00
plugins/cheatfind: run same operation over a batch of data (nw)
This commit is contained in:
parent
2a6e17c438
commit
6dcb009816
@ -23,12 +23,16 @@
|
||||
-- },
|
||||
-- "screen": {
|
||||
-- "varname": "tag"
|
||||
-- },
|
||||
-- },
|
||||
-- ...
|
||||
-- "region": {
|
||||
-- "varname": "tag",
|
||||
-- ...
|
||||
-- },
|
||||
-- "ram": {
|
||||
-- "varname": "tag",
|
||||
-- ...
|
||||
-- },
|
||||
-- "script": {
|
||||
-- "on|off|run|change": "script",
|
||||
-- ...
|
||||
@ -159,7 +163,7 @@ function cheat.startplugin()
|
||||
script = load(script, cheat.desc .. name, "t", cheat.cheat_env)
|
||||
if not script then
|
||||
print("error loading cheat script: " .. cheat.desc)
|
||||
cheat = { desc = cheat.desc .. "error" }
|
||||
cheat = { desc = cheat.desc .. " error" }
|
||||
return
|
||||
end
|
||||
cheat.script[name] = script
|
||||
@ -174,7 +178,7 @@ function cheat.startplugin()
|
||||
cpu = manager:machine().devices[space.tag]
|
||||
if not cpu then
|
||||
print("error loading cheat script: " .. cheat.desc)
|
||||
cheat = { desc = cheat.desc .. "error" }
|
||||
cheat = { desc = cheat.desc .. " error" }
|
||||
return
|
||||
end
|
||||
if space.type then
|
||||
@ -184,7 +188,7 @@ function cheat.startplugin()
|
||||
end
|
||||
if not mem then
|
||||
print("error loading cheat script: " .. cheat.desc)
|
||||
cheat = { desc = cheat.desc .. "error" }
|
||||
cheat = { desc = cheat.desc .. " error" }
|
||||
return
|
||||
end
|
||||
cheat.cheat_env[name] = mem
|
||||
@ -207,12 +211,24 @@ function cheat.startplugin()
|
||||
mem = manager:machine():memory().regions[region]
|
||||
if not mem then
|
||||
print("error loading cheat script: " .. cheat.desc)
|
||||
cheat = nil
|
||||
cheat = { desc = cheat.desc .. " error" }
|
||||
return
|
||||
end
|
||||
cheat.cheat_env[name] = mem
|
||||
end
|
||||
end
|
||||
if cheat.ram then
|
||||
for name, ram in pairs(cheat.ram) do
|
||||
local ram
|
||||
ram = manager:machine().devices[ram]
|
||||
if not ram then
|
||||
print("error loading cheat script: " .. cheat.desc)
|
||||
cheat = { desc = cheat.desc .. " error" }
|
||||
return
|
||||
end
|
||||
cheat.cheat_env[name] = emu.item(ram.items["0/pointer"])
|
||||
end
|
||||
end
|
||||
local param = cheat.parameter
|
||||
if not param then
|
||||
return
|
||||
|
@ -63,6 +63,7 @@ function cheatfind.startplugin()
|
||||
-- compare two data blocks
|
||||
function cheat.comp(olddata, newdata, oper, val, signed, width, endian)
|
||||
local ret = {}
|
||||
local ref = {} -- this is a helper for comparing two match lists
|
||||
local format = ""
|
||||
local size = olddata.size
|
||||
|
||||
@ -73,27 +74,27 @@ function cheatfind.startplugin()
|
||||
end
|
||||
if width == 16 then
|
||||
size = size & 0xfffe
|
||||
if signed == "signed" then
|
||||
if signed == 1 then
|
||||
format = format .. "h"
|
||||
else
|
||||
format = format .. "H"
|
||||
end
|
||||
elseif width == 32 then
|
||||
size = size & 0xfffc
|
||||
if signed == "signed" then
|
||||
if signed == 1 then
|
||||
format = format .. "l"
|
||||
else
|
||||
format = format .. "L"
|
||||
end
|
||||
elseif width == 64 then
|
||||
size = size & 0xfff8
|
||||
if signed == "signed" then
|
||||
if signed == 1 then
|
||||
format = format .. "j"
|
||||
else
|
||||
format = format .. "J"
|
||||
end
|
||||
else
|
||||
if signed == "signed" then
|
||||
if signed == 1 then
|
||||
format = format .. "b"
|
||||
else
|
||||
format = format .. "B"
|
||||
@ -115,6 +116,7 @@ function cheatfind.startplugin()
|
||||
ret[#ret + 1] = { addr = olddata.start + i - 1,
|
||||
oldval = old,
|
||||
newval = new}
|
||||
ref[ret[#ret].addr] = #ret
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -127,6 +129,7 @@ function cheatfind.startplugin()
|
||||
ret[#ret + 1] = { addr = olddata.start + i - 1,
|
||||
oldval = old,
|
||||
newval = new}
|
||||
ref[ret[#ret].addr] = #ret
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -138,12 +141,66 @@ function cheatfind.startplugin()
|
||||
ret[#ret + 1] = { addr = olddata.start + i - 1,
|
||||
oldval = old,
|
||||
newval = new}
|
||||
ref[ret[#ret].addr] = #ret
|
||||
end
|
||||
end
|
||||
elseif oper == "!" or oper == "ne" then
|
||||
for i = 1, size do
|
||||
local old = string.unpack(format, olddata.block, i)
|
||||
local new = string.unpack(format, newdata.block, i)
|
||||
if old ~= new then
|
||||
ret[#ret + 1] = { addr = olddata.start + i - 1,
|
||||
oldval = old,
|
||||
newval = new}
|
||||
ref[ret[#ret].addr] = #ret
|
||||
end
|
||||
end
|
||||
elseif oper == "^" or oper == "xor" then
|
||||
if val >= width then
|
||||
return {}
|
||||
end
|
||||
for i = 1, size do
|
||||
local old = string.unpack(format, olddata.block, i)
|
||||
local new = string.unpack(format, newdata.block, i)
|
||||
if ((old ~ new) & (1 << val)) ~= 0 then
|
||||
ret[#ret + 1] = { addr = olddata.start + i - 1,
|
||||
oldval = old,
|
||||
newval = new}
|
||||
ref[ret[#ret].addr] = #ret
|
||||
end
|
||||
end
|
||||
end
|
||||
return ret
|
||||
return ret, ref
|
||||
end
|
||||
|
||||
-- compare successive pairs of blocks from a table returning only addresses that match every comparison
|
||||
function cheat.compall(dattable, oper, val, signed, width, endian)
|
||||
if #dattable < 2 then
|
||||
return {}
|
||||
end
|
||||
local matches, refs = cheat.comp(dattable[1], dattable[2], oper, val, signed, width, endian)
|
||||
local nonmatch = {}
|
||||
for i = 2, #dattable - 1 do
|
||||
local matchnext, refsnext = cheat.comp(dattable[i], dattable[i+1], oper, val, signed, width, endian)
|
||||
for addr, ref in pairs(refs) do
|
||||
if not refsnext[addr] then
|
||||
nonmatch[ref] = true
|
||||
refs[addr] = nil
|
||||
else
|
||||
matches[ref].newval = matchnext[refsnext[addr]].newval
|
||||
end
|
||||
end
|
||||
end
|
||||
local resort = {}
|
||||
for num, match in pairs(matches) do
|
||||
if not nonmatch[num] then
|
||||
resort[#resort + 1] = match
|
||||
end
|
||||
end
|
||||
return resort
|
||||
end
|
||||
|
||||
|
||||
-- compare a data block to the current state
|
||||
function cheat.compcur(olddata, oper, val, signed, width, endian)
|
||||
local newdata = cheat.save(olddata.space, olddata.start, olddata.size, olddata.space)
|
||||
@ -154,11 +211,13 @@ function cheatfind.startplugin()
|
||||
|
||||
local devtable = {}
|
||||
local devsel = 1
|
||||
local devcur = 1
|
||||
local bitwidth = 3
|
||||
local signed = 0
|
||||
local endian = 0
|
||||
local optable = { "<", ">", "=" }
|
||||
local optable = { "<", ">", "=", "!", "^" }
|
||||
local opsel = 1
|
||||
local bit = 0
|
||||
local value = 0
|
||||
local leftop = 1
|
||||
local rightop = 0
|
||||
@ -166,19 +225,20 @@ function cheatfind.startplugin()
|
||||
local matchsel = 1
|
||||
local menu_blocks = {}
|
||||
local midx = { region = 1, init = 2, save = 3, width = 5, signed = 6, endian = 7, op = 8, val = 9,
|
||||
lop = 10, rop = 11, comp = 12, match = 14 }
|
||||
lop = 10, rop = 11, comp = 12, match = 14 }
|
||||
|
||||
local function start()
|
||||
devtable = {}
|
||||
devsel = 1
|
||||
devsel = 1
|
||||
devcur = 1
|
||||
bitwidth = 3
|
||||
signed = 0
|
||||
endian = 0
|
||||
opsel = 1
|
||||
bit = 0
|
||||
value = 0
|
||||
leftop = 1
|
||||
rightop = 0
|
||||
rightop = 1
|
||||
matches = {}
|
||||
matchsel = 1
|
||||
menu_blocks = {}
|
||||
@ -218,14 +278,14 @@ function cheatfind.startplugin()
|
||||
end
|
||||
end
|
||||
|
||||
menu[midx.region] = { "CPU or RAM", devtable[devsel].tag, "" }
|
||||
menu[midx.region] = { "CPU or RAM", devtable[devsel].tag, 0 }
|
||||
if #devtable == 1 then
|
||||
menu[midx.region][3] = 0
|
||||
else
|
||||
menu_lim(devsel, 1, #devtable, menu[midx.region])
|
||||
end
|
||||
menu[midx.init] = { "Init", "", 0 }
|
||||
if next(menu_blocks) then
|
||||
if #menu_blocks ~= 0 then
|
||||
menu[midx.save] = { "Save current", "", 0 }
|
||||
menu[midx.save + 1] = { "---", "", "off" }
|
||||
menu[midx.width] = { "Bit Width", 1 << bitwidth , 0 }
|
||||
@ -242,24 +302,28 @@ function cheatfind.startplugin()
|
||||
end
|
||||
menu[midx.op] = { "Operator", optable[opsel], "" }
|
||||
menu_lim(opsel, 1, #optable, menu[midx.op])
|
||||
menu[midx.val] = { "Value", value, "" }
|
||||
menu_lim(value, 0, 100, menu[midx.val]) -- max value?
|
||||
if value == 0 then
|
||||
menu[midx.val][2] = "Any"
|
||||
if optable[opsel] == "^" then
|
||||
menu[midx.val] = { "Bit", bit, "" }
|
||||
menu_lim(bit, 0, (1 << bitwidth), menu[midx.val])
|
||||
else
|
||||
menu[midx.val] = { "Value", value, "" }
|
||||
menu_lim(value, 0, 100, menu[midx.val]) -- max value?
|
||||
if value == 0 then
|
||||
menu[midx.val][2] = "Any"
|
||||
end
|
||||
end
|
||||
menu[midx.lop] = { "Left operand", leftop, "" }
|
||||
if #menu_blocks == 1 then
|
||||
menu[midx.lop][3] = 0
|
||||
else
|
||||
menu_lim(leftop, 1, #menu_blocks, menu[midx.lop])
|
||||
menu_lim(leftop, 1, #menu_blocks[1] + 1, menu[midx.lop])
|
||||
if leftop == #menu_blocks[1] + 1 then
|
||||
menu[midx.lop][2] = "All"
|
||||
end
|
||||
menu[midx.rop] = { "Right operand", rightop, "" }
|
||||
menu_lim(rightop, 0, #menu_blocks, menu[midx.rop])
|
||||
if rightop == 0 then
|
||||
menu_lim(rightop, 1, #menu_blocks[1] + 1, menu[midx.rop])
|
||||
if rightop == #menu_blocks[1] + 1 then
|
||||
menu[midx.rop][2] = "Current"
|
||||
end
|
||||
menu[midx.comp] = { "Compare", "", 0 }
|
||||
if next(matches) then
|
||||
if #matches ~= 0 then
|
||||
menu[midx.comp + 1] = { "---", "", "off" }
|
||||
menu[midx.match] = { "Match block", matchsel, "" }
|
||||
if #matches == 1 then
|
||||
@ -304,70 +368,87 @@ function cheatfind.startplugin()
|
||||
end
|
||||
|
||||
if index == midx.region then
|
||||
if (event == "left" or event == "right") and #menu_blocks ~= 0 then
|
||||
manager:machine():popmessage("Changes to this only take effect when Init is selected")
|
||||
end
|
||||
devsel = incdec(devsel, 1, #devtable)
|
||||
return true
|
||||
elseif index == midx.init then
|
||||
if event == "select" then
|
||||
menu_blocks = {{}}
|
||||
menu_blocks = {}
|
||||
matches = {}
|
||||
for num, region in ipairs(devtable[devsel].ram) do
|
||||
menu_blocks[1][num] = cheat.save(devtable[devsel].space, region.offset, region.size)
|
||||
end
|
||||
manager:machine():popmessage("Data cleared and current state saved")
|
||||
ret = true
|
||||
end
|
||||
elseif index == midx.init then
|
||||
if event == "select" then
|
||||
menu_blocks = {{}}
|
||||
matches = {}
|
||||
for num, region in ipairs(devtable[devsel].ram) do
|
||||
menu_blocks[1][num] = cheat.save(devtable[devsel].space, region.offset, region.size)
|
||||
for num, region in ipairs(devtable[devcur].ram) do
|
||||
menu_blocks[num] = {}
|
||||
menu_blocks[num][1] = cheat.save(devtable[devcur].space, region.offset, region.size)
|
||||
end
|
||||
manager:machine():popmessage("Data cleared and current state saved")
|
||||
ret = true
|
||||
end
|
||||
devcur = devsel
|
||||
elseif index == midx.save then
|
||||
if event == "select" then
|
||||
menu_blocks[#menu_blocks + 1] = {}
|
||||
for num, region in ipairs(devtable[devsel].ram) do
|
||||
menu_blocks[#menu_blocks][num] = cheat.save(devtable[devsel].space, region.offset, region.size)
|
||||
for num, region in ipairs(devtable[devcur].ram) do
|
||||
menu_blocks[num][#menu_blocks[num] + 1] = cheat.save(devtable[devcur].space, region.offset, region.size)
|
||||
end
|
||||
manager:machine():popmessage("Current state saved")
|
||||
ret = true
|
||||
end
|
||||
elseif index == midx.width then
|
||||
bitwidth = incdec(bitwidth, 3, 6)
|
||||
if event == "left" or event == "right" then
|
||||
bit = 0
|
||||
end
|
||||
elseif index == midx.signed then
|
||||
signed = incdec(signed, 0, 1)
|
||||
elseif index == midx.endian then
|
||||
endian = incdec(endian, 0, 1)
|
||||
elseif index == midx.op then
|
||||
if event == "up" or event == "down" or event == "comment" then
|
||||
if event == "left" or event == "right" or event == "comment" then
|
||||
if optable[opsel] == "<" then
|
||||
manager:machine():popmessage("Left less than right, value is difference")
|
||||
elseif optable[opsel] == ">" then
|
||||
manager:machine():popmessage("Left greater than right, value is difference")
|
||||
elseif optable[opsel] == "=" then
|
||||
manager:machine():popmessage("Left equal to right, value is ignored")
|
||||
elseif optable[opsel] == "!" then
|
||||
manager:machine():popmessage("Left not equal to right, value is ignored")
|
||||
elseif optable[opsel] == "^" then
|
||||
manager:machine():popmessage("Left bit different than right")
|
||||
end
|
||||
else
|
||||
opsel = incdec(opsel, 1, #optable)
|
||||
end
|
||||
opsel = incdec(opsel, 1, #optable)
|
||||
elseif index == midx.val then
|
||||
value = incdec(value, 0, 100)
|
||||
if optable[opsel] == "^" then
|
||||
bit = incdec(bit, 0, (1 << bitwidth))
|
||||
else
|
||||
value = incdec(value, 0, 100)
|
||||
end
|
||||
elseif index == midx.lop then
|
||||
leftop = incdec(leftop, 1, #menu_blocks)
|
||||
leftop = incdec(leftop, 1, #menu_blocks[1] + 1)
|
||||
if (event == "left" or event == "right" or event == "comment") and leftop == #menu_blocks[1] + 1 then
|
||||
manager:machine():popmessage("Any compares every saved data pair and returns only matches that are true for all. Right operand is ignored.")
|
||||
end
|
||||
elseif index == midx.rop then
|
||||
rightop = incdec(rightop, 0, #menu_blocks)
|
||||
rightop = incdec(rightop, 1, #menu_blocks[1] + 1)
|
||||
elseif index == midx.comp then
|
||||
if event == "select" then
|
||||
matches = {}
|
||||
for num = 1, #menu_blocks[1] do
|
||||
if rightop == 0 then
|
||||
matches[#matches + 1] = cheat.compcur(menu_blocks[leftop][num], optable[opsel], value,
|
||||
signed, 1 << bitwidth, endian)
|
||||
local val
|
||||
if optable[opsel] == "^" then
|
||||
val = bit
|
||||
else
|
||||
val = value
|
||||
end
|
||||
for num = 1, #menu_blocks do
|
||||
if leftop == #menu_blocks[1] + 1 then
|
||||
matches[#matches + 1] = cheat.compall(menu_blocks[num], optable[opsel], val, signed,
|
||||
1 << bitwidth, endian)
|
||||
elseif rightop == #menu_blocks[1] + 1 then
|
||||
matches[#matches + 1] = cheat.compcur(menu_blocks[num][leftop], optable[opsel], val,
|
||||
signed, 1 << bitwidth, endian)
|
||||
else
|
||||
matches[#matches + 1] = cheat.comp(menu_blocks[leftop][num], menu_blocks[rightop][num],
|
||||
optable[opsel], value, signed, 1 << bitwidth, endian)
|
||||
matches[#matches + 1] = cheat.comp(menu_blocks[num][leftop], menu_blocks[num][rightop],
|
||||
optable[opsel], val, signed, 1 << bitwidth, endian)
|
||||
end
|
||||
end
|
||||
ret = true
|
||||
@ -379,6 +460,7 @@ function cheatfind.startplugin()
|
||||
-- write out a script?
|
||||
end
|
||||
end
|
||||
devsel = devcur
|
||||
return ret
|
||||
end
|
||||
emu.register_menu(menu_callback, menu_populate, "Cheat Finder")
|
||||
|
Loading…
Reference in New Issue
Block a user