|
Joined: Jan 2012
Posts: 891 Likes: 17
Senior Member
|
Senior Member
Joined: Jan 2012
Posts: 891 Likes: 17 |
Note if you want to set the input port value you have to use field:set_value() not port:write().
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Cool, field:set_value seems to work for buttons. [MAME]> function printt(a) local i,j; for i,j in pairs(a) do print(i,j) end end
[MAME]> printt(manager:machine():ioport().ports[":joystick_buttons"].fields)
P1 Button 2 sol.ioport_field*: 0x55c6ff3a0d28
P2 Button 1 sol.ioport_field*: 0x55c6ff3a0d68
P1 Button 1 sol.ioport_field*: 0x55c6ff3a0ce8
[MAME]> print(manager:machine():ioport().ports[":joystick_buttons"]:read())
0
[MAME]> manager:machine():ioport().ports[":joystick_buttons"].fields["P1 Button 2"]:set_value(1)
[MAME]> print(manager:machine():ioport().ports[":joystick_buttons"]:read())
32
[MAME]> manager:machine():ioport().ports[":joystick_buttons"].fields["P1 Button 2"]:set_value(0)
[MAME]> print(manager:machine():ioport().ports[":joystick_buttons"]:read())
0
I thought I'd try it for a joystick axis value but it doesn't seem to have any effect. I removed the bindings to the second joystick too. manager:machine():ioport().ports[":joystick_2_y"].fields["P2 Joystick Y"]:set_value(0)
print(manager:machine():ioport().ports[":joystick_2_y"]:read())
128
Last edited by Golden Child; 11/06/17 01:42 AM.
|
|
|
|
Joined: Jan 2012
Posts: 891 Likes: 17
Senior Member
|
Senior Member
Joined: Jan 2012
Posts: 891 Likes: 17 |
Unfortunately analog fields are only read directly from the source, there isn't currently any way to override it.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
I thought I'd see if I can have the arcade board's AY-3-8912 make some beeps. But I need to have some delays or it doesn't work. Without delays everything happens all at once... so let's fiddle some more with coroutines. The advantage of this is that we can call a delay() function. So for example if you want for i = 1,60 do
sound(7,24)
settonevol(0,175,15)
delay(2) -- delays for 2 frames
settonevol(0,175,0)
delay(2)
end then you call:
add_func_string([[local i; for i=1,30 do sound(7,24); settonevol(0,175,8); delay(2); settonevol(0,175,0); delay(2); end ]])
and what's cool is that you can enter little tests from the command line quite easily with add_func_string.
-- ===========================================================================
-- FRAME DISPATCHER
dispatch_list={}
function frame_dispatcher()
for index,my_func in pairs(dispatch_list) do my_func() end
end
function dispatch_list_remove(a_func)
for my_index,my_func in pairs(dispatch_list) do if my_func == a_func then table.remove(dispatch_list,my_index) end end
end
function print_dispatch_list() for my_index,my_func in pairs(dispatch_list) do print(my_func) end end
print("type cld() and hit enter to stop a runaway dispatch")
if already_registered_frame_dispatcher == nil then
emu.register_frame(frame_dispatcher);
already_registered_frame_dispatcher = 1
end
function cld()
dispatch_list = {}
end
-- ===========================================================================
-- COROUTINE DISPATCHER
coroutine_frame_list = { }
function coroutine_frame_dispatch()
local i,thread
for i,thread in pairs(coroutine_frame_list) do coroutine.resume(thread) end
for i = #coroutine_frame_list,1,-1 do if coroutine.status(coroutine_frame_list[i]) == "dead" then table.remove(coroutine_frame_list,i) end end
end
function delay(frames)
local f
for f = 1,frames do coroutine.yield() end
end
function add_func_exec(myfunc)
local newthread
newthread = coroutine.create(myfunc)
table.insert(coroutine_frame_list,newthread)
end
function add_func_string(func_string)
local newfunc
newfunc = assert(loadstring(func_string))
if newfunc ~= nil then add_func_exec(newfunc) end
end
function addco()
-- once you clear your dispatch list, you must add the coroutine_frame_dispatch
-- to get the coroutine_dispatch to work
table.insert(dispatch_list,coroutine_frame_dispatch)
end
cld()
addco()
function lobyte(x)
return x & 255
end
function hibyte(x)
return (x & (255<<8))>>8
end
function checkrange(x,lo,hi)
if not(x >= lo and x <= hi) then print("checkrange failed ",x,lo,hi); return false
else return true; end
end
aystr = ":sl7:ssprite:ssprite_ay"
aystr = ":sl4:arcbd:arcbd_ay"
function sound(regnum,value)
emu.item(manager:machine().devices[aystr].items["0/m_regs"]):write(regnum,value)
end
function settone(chan,tone)
if checkrange(chan,0,2) then
regnum = chan*2
sound(regnum,lobyte(tone))
sound(regnum+1,hibyte(tone))
end
end
function setvol(chan,vol)
if checkrange(chan,0,2) then
regnum = chan+8
sound(regnum,vol)
end
end
function settonevol(chan,tone,vol)
settone(chan,tone)
setvol(chan,vol)
end
-- two different ways to add a function, pass a function to add_func_exec
-- or pass add_func_string a string and if you use double brackets you don't have to escape the quotes
add_func_exec(function () local i; for i = 1,10 do print("yoyo",i);delay(5);end end)
add_func_string("local i; for i=1,15 do print(\"hello\",i);delay(5); end")
-- sound(7,24) turns on sound ABC and turns off the noise channels
add_func_string([[local d; local i; for d = 1,4 do print("delay="..d) for i=1,30 do sound(7,24); settonevol(0,175,8); delay(d); settonevol(0,175,0); delay(d); end end ]])
Last edited by Golden Child; 11/07/17 09:06 AM.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
I wanted to see if I could reproduce the apple 2 beep sound with the AY-3-8912. It's supposed to be around 1000hz, but that doesn't sound quite right if I'm using the apple2e driver as a reference. Reading some Synetix SuperSprite documentation (Synetix SuperSprite Owners Manual.pdf page 40 of 266) it says that I just have to divide 63920.438 by the desired pitch. Tone Period =1,022,727 / 16 X desired pitch = 63,920.438 / desired pitch so let's make a little function to calculate the tone:
function calctone(freq)
return math.floor (63920.438 / freq)
end
then I can make something that sounds pretty close to the CTRL+G bell. I came up with around 930 hz just by listening to the tone and hunting for a number that was close.
add_func_string([[for i=0,0 do sound(7,24);settonevol(0,calctone (930),15); delay(6); settonevol(0,0,0); delay(1); end print("done")]])
but how close is that actually? I fired up mame with the debugger and set a watchpoint on $c030 with and then typed g in the debug window. Once the boot beep hit c030 I went to the lua console and typed: then hit g again in the debugger, and then got the time at that point: so how long did that take? print(b-a)
0.00053435114503789 so let's convert that to hertz: print(1/(b-a))
1871.4285714295 oh but wait, it should be half that since we've only counted half a tone cycle print(1/(b-a)/2)
935.71428571477
which I got pretty darn close to, 930 vs 936. Not bad for someone who's tone deaf. Now I've got a beep that is pretty much identical.
add_func_string([[for i=0,0 do sound(7,24);settonevol(0,calctone (936),15); delay(6); settonevol(0,0,0); delay(1); end print("done")]])
Last edited by Golden Child; 11/11/17 01:12 PM.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
One of the things I'm terrible at is counting cpu cycles. So let's figure out how many cycles it takes to do the system beep, and while we're at it figure out what the cpu clock is. How can we get the totalcycles? ./mame64 apple2e -plugin console -debug Just ask the debugger to print the totalcycles. Immediately after boot, if we ask the debugger for totalcycles we get: so how to get that value into a variable in lua? function getcycles()
dbg = manager:machine():debugger()
dbg:command("print totalcycles")
lastline = dbg.consolelog[#dbg.consolelog]
cycles = tonumber(lastline,16)
return cycles
end
and a single line version to paste at the lua console: function getcycles() dbg = manager:machine():debugger() dbg:command("print totalcycles") lastline = dbg.consolelog[#dbg.consolelog] cycles = tonumber(lastline,16) return cycles end
so let's set a watchpoint and then go:
dbg = manager:machine():debugger()
dbg:command("wpset c030,1,rw")
dbg:command("g") so we've hit the first click of the speaker so get the time and the cycles: a = emu.time(); cyclesa = getcycles() so let's get the next click: dbg:command("g")
b = emu.time(); cyclesb = getcycles()
print(cyclesb-cyclesa)
546 and remember that it's a half cycle (since the c030 inverts the speaker) so we multiply by 2 and if we do a little math we can get the system clock: [MAME]> print(1/((b-a)/(cyclesb-cyclesa)))
1021800.0000005
[MAME]> print((cyclesb-cyclesa)*2)
1092
[MAME]> print(1021800/1092)
935.71428571429
[MAME]>
and sure enough the cpu clock corresponds exactly to the source code that defines the cpu frequency static MACHINE_CONFIG_DERIVED( apple2ee, apple2e )
MCFG_CPU_REPLACE("maincpu", M65C02, 1021800) /* close to actual CPU frequency of 1.020484 MHz */
MCFG_CPU_PROGRAM_MAP(apple2e_map)
MACHINE_CONFIG_END
One of the things that baffled me for a bit was why the system clock for the Atari 2600 would come up as not matching the source code exactly: MAME debugger version 0.191 (mame0191-183-g346a935839-dirty)
Currently targeting a2600 (Atari 2600 (NTSC))
[MAME]> function getcycles() dbg = manager:machine():debugger() dbg:command("print totalcycles") lastline = dbg.consolelog[#dbg.consolelog] cycles = tonumber(lastline,16) return cycles end
[MAME]> a = emu.time(); acycles=getcycles()
[MAME]>
3
[MAME]> dbg:command("step")
[MAME]> b = emu.time(); bcycles=getcycles()
[MAME]>
5
print((bcycles-acycles)/(b-a))
1193181.0000007
print((bcycles-acycles)/(b-a)*3)
3579543.0000022
print(3579545/3)
1193181.6666667
so why doesn't 3579543 match up with 3579545? Finally I realized that there's some rounding taking place that converts (3579543/3) = 1193181.6666667 into 1193181.0 because the machines take an integer value for the frequency and that accounts for the discrepancy (bye bye fractional part).
#define MASTER_CLOCK_NTSC 3579545
static MACHINE_CONFIG_START( a2600 )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", M6507, MASTER_CLOCK_NTSC / 3)
Last edited by Golden Child; 11/22/17 02:47 PM.
|
|
|
|
Joined: Jan 2012
Posts: 891 Likes: 17
Senior Member
|
Senior Member
Joined: Jan 2012
Posts: 891 Likes: 17 |
dbg.consolelog:__len() == #dbg.consolelog
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
dbg.consolelog:__len() == #dbg.consolelog I didn't think anyone would see that. Post edited 8-)
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Are there any "bad" side-effects to enabling SOL_CHECK_ARGUMENTS in luaengine.h aside from performance reasons? #define SOL_CHECK_ARGUMENTS
#include "sol2/sol.hpp"
I inevitably type . instead of : and get a segfault. For example: print((manager:machine():debugger().consolelog:__len()))
2 but if I change the : to a ., then kaboom. print((manager:machine():debugger().consolelog.__len()))
Segmentation fault (core dumped)
and if I uncomment #define SOL_CHECK_ARGUMENTS it will gracefully give me an error. print((manager:machine():debugger().consolelog.__len()))
error: [string "print((manager:machine():debugger().consolelo..."]:1: stack index 1, expected userdata, received no value
according to: https://github.com/ThePhD/sol2/issues/408ThePhD commented on May 19
Please turn on the safety features. This will crash your code with a specific error message. You can turn on the most important safety feature by definining SOL_CHECK_ARGUMENTS either VIA command line or by putting it before every single <sol.hpp> include.
The segfault is intentional at this level. If you do not turn on safety features we assume that you are doing so for performance reasons and do not want the (small, but sometimes important to people) overhead, or because you expect certain kinds of type punning to happen (e.g., like the many type-puns the MAME engine does in order to fiddle with bits and mess with other low-level things).
Last edited by Golden Child; 11/22/17 03:02 PM.
|
|
|
|
Joined: Jan 2012
Posts: 891 Likes: 17
Senior Member
|
Senior Member
Joined: Jan 2012
Posts: 891 Likes: 17 |
There shouldn't be any issues enabling that.
|
|
|
0 members (),
58
guests, and
5
robots. |
Key:
Admin,
Global Mod,
Mod
|
|
Forums9
Topics9,331
Posts122,197
Members5,077
|
Most Online1,283 Dec 21st, 2022
|
|
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!
|
|
|
|