One of the great mysteries to me was why calling write on an io port was ineffective.

I wanted to set the Apple II's configuration for the Composite monitor type and it wouldn't work at all.
0 = color
1 = bw
2 = green
3 = amber


Calling manager:machine():ioport().ports[":a2_config"]:write(1) would seemingly have no effect,

I could then print it out and see that there was no change:

Code
[MAME]> print(manager:machine():ioport().ports[":a2_config"]:read())
0
[MAME]> print(manager:machine():ioport().ports[":a2_config"]:write(1))

[MAME]> print(manager:machine():ioport().ports[":a2_config"]:read())
0

and the trying of the field's set_value behaved strangely: only by passing it values of 1 or 0 would
get it to "cycle" through the possible values.

manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"]:set_value(0)
manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"]:set_value(1)

This made no sense to me at all.

But looking at the code to set the ioport_fields in ioport.cpp gave some clues:

Code
void ioport_field::set_value(ioport_value value)
{
        m_digital_value = value != 0;
}


So here the m_digital value is only getting a value of 1 or 0.


So I thought, why not set the live value directly:

Adding a set_value function to the ioport_field_live in ioport.h

Code
// internal live state of an input field
struct ioport_field_live
{
        // construction/destruction
        ioport_field_live(ioport_field &field, analog_field *analog);

        void set_value(ioport_value newvalue) {value = newvalue;};

and adding set_value and value to the ioport_field_live usertype in luaengine.cpp

Code
/* field.live
 */
	sol().registry().new_usertype<ioport_field_live>("ioport_field_live", "new", sol::no_constructor,
                        "set_value", &ioport_field_live::set_value,  // added set_value function
			"name", &ioport_field_live::name,
                        "value", &ioport_field_live::value);     // added access to member value

Now I can set the value directly:


Code
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(0)
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(1)
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(2)
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(3)
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value=2     
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value=0
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value) 
0
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value=3
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value)
3
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(5))

[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value)
5
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(2))

[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value)
2
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Shift key mod"].live.value)
4
[MAME]> print(manager:machine():ioport().ports[":a2_config"]:read())
6
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Shift key mod"].live.value=0 
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Shift key mod"].live.value)
0
[MAME]> print(manager:machine():ioport().ports[":a2_config"]:read())
2


If I set the value "out of bounds" like setting the monitor type to 5 the mame control panel will complain INVALID, but it doesn't seem to hurt anything since it gets masked off.

One thing I realize now is that .live.value=x and .live:set_value(x) are equivalent, so the set_value function probably isn't needed.

Another thing that is a bit perplexing is that you don't want to mix these two accesses:


This is the field set_value:
Code
manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].set_value(1)
and this is the field.live.value or field.live.set_value()
Code
manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value=1
manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.set_value(1)
When you use the field set_value, it causes strange behaviors when you use the live set_value, like inverting the field bits. So use the live one 8-)


[Linked Image from i.imgur.com]

And one last bit: here's a print table function where you pass a lambda function that will print the .live.value for each field in the table:

It's pretty handy to show you all of the values of each field.

Code
[MAME]> function printtf(a,f) for i,j in pairs(a) do print(i,f(j)) end end

[MAME]> printtf(manager:machine():ioport().ports[":a2_config"].fields, function(b) return b.live.value end)
Composite monitor type	2
Shift key mod	0



And if you want to get tricky with lambda functions, this will print all of the values of the ports and fields:
Code
[MAME]> function dopairs(a,f) for i,j in pairs(a) do f(i,j) end end     -- calls f on each pair i,j in the table
[MAME]> dopairs(manager:machine():ioport().ports,function(a,b) print("ports[\""..a.."\"]:read()="..b:read()) dopairs(b.fields,function(i,j) print("ports[\""..a.."\"].".."fields[\""..i.."\"]"..".live.value="..j.live.value) end) end)

ports[":a2_config"]:read()=2
ports[":a2_config"].fields["Composite monitor type"].live.value=2
ports[":a2_config"].fields["Shift key mod"].live.value=0
ports[":sl2:agraphtablet:a2mse_x"]:read()=64608
ports[":sl2:agraphtablet:a2mse_x"].fields["Mouse X 3"].live.value=0
... etc

Last edited by Golden Child; 04/21/19 04:27 PM.