wwarthen / RomWBW

System Software for Z80/Z180/Z280 Computers
GNU Affero General Public License v3.0
331 stars 96 forks source link

Issue with SIO/2 with the Turbo CPU #405

Open vipoo opened 1 month ago

vipoo commented 1 month ago

Hi Wayne,

I recently had a customer who tried to use my Turbo CPU module on a standard RC2014 kit (with the SIO/2 serial module).

The problem is that on boot up, the serial output initially works fine -- see the standard RomWBW/HBIOS boot output - but within a few seconds serial stop responding to any input.

Not sure how aware you are of my Turbo CPU kit - its a CPU module that runs a standard Z80 CPU at 20Mhz. But for all I/O operations is clocks down to 3.5Mhz (bus clock) - and stays at 3.5Mhz for a number of clock cycles, before returning to 20Mhz. By clocking down the CPU during I/O, it was my expectation and goal that for the most part things continue to work just fine without any software changes.

I understand, for the SIO/2 chip, that the CPU and the clock sent to the SIO/2 chip must be in sync for all operations - and that should be the case - because, as mention, the CPU clock will sync with the bus clock for any I/O operations.

I know this configuration use to work just fine under RomWBW (well I am pretty sure, its been a long time since I last tested in under RomWBW - maybe a year or 2 ago!) Its also works find for my latest MSX rom images - which is where I mainly test it.

I discovered that if I disabled interrupts in the configuration file, then it all works as expected. Can boot into CP/M and BASIC etc. But of course, there is now no interrupt facility for any driver.

My suspicion is some kind of race condition of timing issue in the SIO/2 driver, when the CPU runs a little faster. I wonder, also, if the CPU speed calculation might not be accurate (due to the dual clock speeds) and cause the HBIOS DELAY function to not delay as required?

I have not looked any further at this (been distracted on the eZ80 stuff).

But just wonder if you might have any suggestions of what might have changed, that might have influence this issue? I see some stuff with CTS handling? --- I expect that trying to debug the interrupt/timing will be not fun! 😣

Appreciate any guidance/help you might be able to share.

Cheers Dean

wwarthen commented 1 month ago

Interesting.

It actually makes sense to me that interrupt driven input may be a problem. If I understand correctly, the clock will be running at 20 MHz until there is an I/O operation, then it slows down for a bit to handle the I/O. The problem that I see is that when a character is received, the bits must be decoded before an interrupt is generated. During that time, the clock is likely to be running fast and therefore the baud rate divisor is messed up.

I suspect the reason that non-interrupt driven input is working is because in that scenario, the SIO is being constantly polled (doing I/O) which is keeping the clock running slow during the character reception process.

With interrupt driven input, anytime the system checks for a character, there is no I/O -- it just checks the in-memory ring buffer to see if anything has been received. So, no I/O, fast clock, messed up input.

Is this theory possible?

In general, serial input may be an issue with your turbo circuit. For example, I would expect that if a user typed a character during a long running CPU algorithm (doing no I/O), then that character would be corrupted.

With the official SIO module from Spencer, the baud clock for port A is hard-wired to the primary CLK signal. However, the secondary port baud clock can be routed to the CLK2 signal. It might be interesting to try use that to try and see if it resolves the issues for the secondary port.

Thanks, Wayne

vipoo commented 1 month ago

With interrupt driven input, anytime the system checks for a character, there is no I/O -- it just checks the in-memory ring buffer to see if anything has been received. So, no I/O, fast clock, messed up input.

But that's just normal ROM/RAM operation - no need for I/O? So why would it be a specific problem.

With the interrupt handler, i would suspect that the IN instruction directed at the SIO/2 chip to verify that it was the SIO/2 chip that raised the interrupt, would cause it to clock immediately down. But its certainly an area to explore. The issue certainly seems to be related to the handling of the interrupts.

In general, serial input may be an issue with your turbo circuit. For example, I would expect that if a user typed a character during a long running CPU algorithm (doing no I/O), then that character would be corrupted.

Anything is possible, but i would expect again, as the CPU will always in on the BUS clock when doing any I/O - as soon as the CPU attempt to read/write to the SIO/2 chip - the cpu will be running in the slower clock. The idea is, that for from the perspective of any/all hardware devices, the CPU appears to be running at the slower bus clock. The main issue this introduced for me was the delay between various I/O operations may arrive quicker - but as mention, the CPU will stay in the slower clock for many cycles (forget the exact number)

With the official SIO module from Spencer, the baud clock for port A is hard-wired to the primary CLK signal. However, the secondary port baud clock can be routed to the CLK2 signal. It might be interesting to try use that to try and see if it resolves the issues for the secondary port.

Hmm that is a very good point... interesting - that's what I did when I ran the SIO/2 module in the MSX configuration. The MSX BIOS has a lot of overhead - so I needed to run at a slower baud rate.

One thing I was thinking, would it be possible to add a new configuration in the SIO/2 driver to not enable or use SIO/2 in interrupt mode? - and leave interrupts for the wider platform still enabled?

wwarthen commented 1 month ago

Yes, I can definitely provide a config switch to disable the use of interrupts within the SIO driver independently. I already do this in some other drivers and it is not hard. I will try to get that done today.

I don't think I have done a good job describing my concern about the character reception issue...

If you think about the reception of a character (from host to RC2014), there are essentially two transfers that occur. First is the transfer of the bits over the line that are interpreted by the SIO chip and placed in the SIO receive holding register. Second is the transfer of the character byte from the SIO holding register to the CPU.

If I have understood the way that the Turbo CPU works, it will slow down the CPU during the second part of the transfer (SIO register to CPU). However, it will not slow down the clock during the reception of the character bits (unless the CPU happens to be making I/O calls).

During the reception of the bits and the SIO is interpreting them, the SIO depends on the baud clock to do this correctly. Since the baud clock is the same as the CPU clock, I would think that for the SIO to properly interpret the incoming bits, the CPU clock would need to be running in slow mode.

If the CPU is not making I/O calls during the reception of the character bits, won't the bits be interpreted using the wrong baud clock?

I sincerely hope I am not beating a dead horse here.

Thanks, Wayne

wwarthen commented 1 month ago

Commit 7e2b2b8 addresses the implementation of the SIO interrupt enable/disable mechanism.

I have posted RomWBW Development Snapshot v3.5.0-dev.65 with these changes.

To disable SIO interrupts on a system that has interrupts enabled globally, add this line to your config file:

SIOINTS .SET FALSE

Thanks,

Wayne

dinoboards commented 1 month ago

Thank you very much @wwarthen . That was so quick! I will try and test this weekend.

Hopefully this 'fixes' or at least, works around the issue.


During the reception of the bits and the SIO is interpreting them, the SIO depends on the baud clock to do this correctly. Since the baud clock is the same as the CPU clock, I would think that for the SIO to properly interpret the incoming bits, the CPU clock would need to be running in slow mode

If I understand what you are saying here - then your statement is not the way it works. The BUS clock and CPU clocks are independent. The BUS clock is always the standard rate (~3.5 or 7Mhz, etc as per jumper settings). So the SIO/2 chip will always get a constant single clock rate for its divisor to use for baud rate generation. This insure the goal, that as far as the SIO/2 chip is concerned - it can never know that there is a 'fast' cpu using it. As it always sees the same clock and the timing for the I/O data exchange is the same - the only way it does experience something different - is the time between various I/O operations may be too quick for it - as the cpu can get to the next I/O faster than a standard CPU can.

The constant rate for the bus clock is also important for any other module that use this clock for its logic - such as sound modules.

I have a similar, but different, issue with the eZ80 - we need a bus clock that various modules will use thats at a rate that is constant and typical.

Does that make sense?

Dean

wwarthen commented 1 month ago

Yes, sorry Dean. I get it now.

Based on this, I don't have any immediate thoughts about why the Turbo CPU would be failing with interrupts enabled.

As another data point, I tried running my RC2014 faster. My SIO module has it's own baud rate oscillator, so I can run the CPU at different speeds without messing up the baud rate. I can go as fast as 16 MHz without any problems (interrupts enabled). I can't get to 20 MHz, but I can see that the system fails long before it tries to get to the SIO. I also have one of Sergey's EZZ80 boards. This board uses an SIO and runs solid at 20 MHz (with interrupts). As a result, I don't think the time between the I/O calls would be the issue.

I'll keep thinking about this, but not sure I have anything more to add. I will be interested to know if the latest RomWBW with SIO interrupts disabled works OK.

Thanks, Wayne