OpenMSX - FPS drops during Serial read/write

Page 1/2
| 2

By S0urceror

Resident (45)

S0urceror's picture

02-02-2020, 18:24

Hi all,

I have made an experimental setup for my MSX USB driver. You can read more about this here

Within OpenMSX I created a CH376s emulator/bridge device that connects via Serial to an Arduino board which has the same hardware as my experimental MSX cartridge. This way I can easily develop and test things on my PC.

Functionally they behave the same but on OpenMSX something weird is happening. When communicating via the serial port the FPS drops to around 2. This makes redraws awfully slow. On my NMS8250 MSX2 everything stays fluid.

The emulated device in OpenMSX:

byte CH376s::readIO(word port, EmuTime::param /*time*/)
{
	byte result=0;
	switch (port & 0xff) {
		case 0x10: // read/write data
			readData (&result);
			break;
		case 0x11: // read status/write command
			readStatus (&result);
			break;
		default: // unreachable, avoid warning
			printf ("readIO error port: %d",port);
			UNREACHABLE; result = 255;
		}
	return result;
}
ssize_t CH376s::readData (uint8_t* new_value)
{
    if (fp<0)
      return 0;

    uint8_t cmd[] = {RD_DATA};
    write (fp,cmd,sizeof(cmd));
    size_t len = read (fp,new_value,1);

    return len;
}

It looks like the Serial port access is blocking the frame redraw routines in OpenMSX. Is it possible to run these things on separate threads?

On the MSX side of things my USB keyboard driver is running on H.CHGE and not blocking interrupts. And like I said on a real MSX everything stays fluid.

Ideas? Let me know!

Login or register to post comments

By wouter_

Champion (424)

wouter_'s picture

03-02-2020, 13:01

Hi,

Indeed, if you make blocking calls in the internal openMSX emulation code, you block the full emulator. If you want asynchronous behavior you'll have to implement that yourself.

Like you said, using threads is one way to implement this. Maybe an alternative is to open the serial device in non-blocking mode? But I don't have much experience with this myself.

By ducasp

Master (220)

ducasp's picture

03-02-2020, 14:57

If this is being done on Windows, you probably wanna use overlapped I/O for that, or, you can have a thread doing it. I would do it through overlapped I/O route. Smile

By S0urceror

Resident (45)

S0urceror's picture

03-02-2020, 19:28

Thanks for clarifying.

In CocoaMSX (bluemsx port for macos) the screen updates are much faster. There screen updates are on another thread.

Don’t know if non-blocking and threading will work because an IO read cannot continue without a result.

By ducasp

Master (220)

ducasp's picture

04-02-2020, 04:47

You can have a different io port to schedule the read and another one to check the read status, it won't be like the real hardware but hey, you are using serial io that is probably much slower than what parallel IO can achieve... On a real hardware the hardware would assert wait until data is ready on the bus, vdp would still run but not the CPU... Let's say you have a one byte command and one byte response, at 1Mbps 8N1 it would take at least 20us if PC doesn't waste time to send and Arduino responds right away... It would take 70 regular z80 clock cycles... If Arduino takes 10us to respond, 105 z80 clock cycles... 2 bytes out and 2 bytes in, 175 z80 clock cycles... Now, let's say you are using 115200 bps, we are talking about 1750 z80 clock cycles wasted for 2 bytes... Not knowing what speed and what amount of data you want to transfer and how much time Arduino+CH376S takes to respond to the serial command it is difficult to paint a general picture, but you will need pretty fast serial io baudrate... In your specific case, you can have a FIFO in your serial interface, bytes send are written to PC FIFO, bytes received go to PC FIFO, you read the fifo status on a io port, so you do not waste time getting the data and just get it when there is (enough) data on the fifo.... So the read will return immediately Wink

By S0urceror

Resident (45)

S0urceror's picture

04-02-2020, 09:13

ducasp wrote:

You can have a different io port to schedule the read and another one to check the read status

You are right this is certainly possible but I wanted to keep my MSX code similar between simulated and real hardware. On the real hardware (cartridge) I made the CH376s is connected in parallel to the Z80. In my test setup it goes from my MSX driver code to OpenMSX to a serial connection running on 115200 bps to an Arduino that is connected in parallel to the same CH376s.

What you are suggesting is changing my MSX driver code based on how the hardware is connected. Direct via cartridge or indirect via emulated/serial/Arduino.

In my initial post I was hoping to find a way to speed up things on the OpenMSX side but I realise now that the main bottleneck is and remains the Serial port.

But there are some strange things I cannot explain. I can for example type 'hello' on my keyboard before the first letter 'h' appears in OpenMSX. But if I type 'hello' followed by RETURN then I see an immediate response. Again on the real MSX everything is buttery smooth.

BTW, I'll make a video that shows the differences between real hardware, simulated and test hardware. Hope this will shed more light on things.

By S0urceror

Resident (45)

S0urceror's picture

04-02-2020, 09:57

Update: I jumped the baudrate from 155200 to 1000000. Since it is serial over USB to the Teensy this is possible.

I would've expected a 10 times increase in responsiveness but OpenMSX stays sluggish updating the screen.

By S0urceror

Resident (45)

S0urceror's picture

04-02-2020, 11:29

Three video's showing the USB HID Keyboard driver in action.

On CocoaMSX, BlueMSX port on Mac.
On OpenMSX, running on the same Mac.
On my Philips NMS8250 MSX2.

By ducasp

Master (220)

ducasp's picture

04-02-2020, 14:37

Well, I do not know a lot of how files/serial communication occurs over MacOS, but perhaps on OpenMSX the way connection has been opened is waiting for CR/LF to send data, and this is getting your receiving function locked as nothing has been sent so no response comes and need to wait the time-out of read or for it to start receiving data. Or read is waiting for a few more bytes....

There is a pretty decent response in here that even tells that some parameters not being set might see failures and hanging on read operations...

https://stackoverflow.com/questions/6947413/how-to-open-read...

Perhaps changing how you open the serial port and set it up might alleviate the issues.

By Manuel

Ascended (16134)

Manuel's picture

04-02-2020, 23:56

Whatever you're doing there, it's still on the same thread as where openMSX is doing its drawing... The only thing that would help is using a separate thread. AFAIK some of the MIDI and serial code use one too.

By S0urceror

Resident (45)

S0urceror's picture

05-02-2020, 21:46

Manuel, is OpenMSX treating CHGET or keyboard buffer in a special way?
Why is the observed display response to RETURN immediate, and other chars need to wait?

Nevertheless, I will put this to bed now, I am pretty satisfied with the result so far. I can debug on OpenMSX and having a slower response allows me to see things happening in 'The Matrix Bullet Time'. LOL!

Page 1/2
| 2