Previous Thread
Next Thread
Print Thread
Page 12 of 80 1 2 10 11 12 13 14 79 80
Joined: Jan 2012
Posts: 891
Likes: 17
C
Senior Member
Senior Member
C Offline
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
G
Very Senior Member
Very Senior Member
G Offline
Joined: Feb 2014
Posts: 1,135
Likes: 198
Cool, field:set_value seems to work for buttons.

Code
[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.

Code
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
C
Senior Member
Senior Member
C Offline
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
G
Very Senior Member
Very Senior Member
G Offline
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

Code
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:

Code
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.

Code

-- ===========================================================================
-- 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
G
Very Senior Member
Very Senior Member
G Offline
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:

Code
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.

Code
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

Code
wpset c030,1,r 

and then typed g in the debug window.

Once the boot beep hit c030 I went to the lua console and typed:

Code
a = emu.time()
then hit g again in the debugger, and then got the time at that point:

Code
b = emu.time()

so how long did that take?

Code
print(b-a)

0.00053435114503789

so let's convert that to hertz:

Code
print(1/(b-a))
1871.4285714295

oh but wait, it should be half that since we've only counted half a tone cycle

Code
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.



Code
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
G
Very Senior Member
Very Senior Member
G Offline
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:

Code
>print totalcycles
3

so how to get that value into a variable in lua?

Code
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:

Code
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:

Code
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:

Code
a = emu.time(); cyclesa = getcycles()

so let's get the next click:

Code
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:


Code
[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

Code
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:


Code
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).

Code

#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
C
Senior Member
Senior Member
C Offline
Joined: Jan 2012
Posts: 891
Likes: 17
dbg.consolelog:__len() == #dbg.consolelog

Joined: Feb 2014
Posts: 1,135
Likes: 198
G
Very Senior Member
Very Senior Member
G Offline
Joined: Feb 2014
Posts: 1,135
Likes: 198
Originally Posted by crazyc
dbg.consolelog:__len() == #dbg.consolelog

I didn't think anyone would see that. Post edited 8-)

Joined: Feb 2014
Posts: 1,135
Likes: 198
G
Very Senior Member
Very Senior Member
G Offline
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?

Code
#define SOL_CHECK_ARGUMENTS
#include "sol2/sol.hpp"

I inevitably type . instead of : and get a segfault.

For example:

Code
print((manager:machine():debugger().consolelog:__len()))
2

but if I change the : to a ., then kaboom.

Code
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.

Code
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/408

Quote
ThePhD 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
C
Senior Member
Senior Member
C Offline
Joined: Jan 2012
Posts: 891
Likes: 17
There shouldn't be any issues enabling that.

Page 12 of 80 1 2 10 11 12 13 14 79 80

Link Copied to Clipboard
Who's Online Now
0 members (), 58 guests, and 5 robots.
Key: Admin, Global Mod, Mod
ShoutChat
Comment Guidelines: Do post respectful and insightful comments. Don't flame, hate, spam.
Forum Statistics
Forums9
Topics9,331
Posts122,197
Members5,077
Most Online1,283
Dec 21st, 2022
Our Sponsor
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!

Superior Solitaire
Powered by UBB.threads™ PHP Forum Software 8.0.0