Working around the W65C51 transmit buffer empty bug
Working around the W65C51 transmit buffer empty bug
After watching Ben Eaters W65C51 video and also reading some of the interesting comments.
If the 6551 is setup to generate interrupts is bit 4 of the status register "Transmitter Data Register Empty" strictly needed? I assume the intended usage of any 6551 was to drive the MPU by using interrupts. I doubt it was intended that the MPU should constantly poll the 6551 to see if it could send the next byte?
Let's say the W65C51 has both transmitter and receiver interrupts enabled. Then I think it should be possible to tell if it is time to transmit another byte if status register bit 7 "Interrupt (IRQ)" is set AND status register bit 3 "Bit 3 Receiver Data Register Full" is not set. I think that would imply that the Transmitter Data Register IS Empty (without polling the bugged bit 4). I suppose this wouldn't work so well if doing Tx and Rx at the same time.
The question behind my question is: is there a clean way to use the W65C51? Purely out of interest. I'm going to try and use a 16C550 instead.
If the 6551 is setup to generate interrupts is bit 4 of the status register "Transmitter Data Register Empty" strictly needed? I assume the intended usage of any 6551 was to drive the MPU by using interrupts. I doubt it was intended that the MPU should constantly poll the 6551 to see if it could send the next byte?
Let's say the W65C51 has both transmitter and receiver interrupts enabled. Then I think it should be possible to tell if it is time to transmit another byte if status register bit 7 "Interrupt (IRQ)" is set AND status register bit 3 "Bit 3 Receiver Data Register Full" is not set. I think that would imply that the Transmitter Data Register IS Empty (without polling the bugged bit 4). I suppose this wouldn't work so well if doing Tx and Rx at the same time.
The question behind my question is: is there a clean way to use the W65C51? Purely out of interest. I'm going to try and use a 16C550 instead.
Re: Working around the W65C51 transmit buffer empty bug
I think you might be right (oops, see below), but
> I suppose this wouldn't work so well if doing Tx and Rx at the same time.
is a bit of a spanner in the works.
I think there are workarounds, though - the bug is not a show-stopper, although it is irritating.
For example, if the baud rate isn't too high relative to the OS tick rate, a time-driven task could check the transmit side and keep it topped up from the OS-level output buffer. And if the baud rate is very high, draining the OS buffer by polling wouldn't be too time-consuming.
> I suppose this wouldn't work so well if doing Tx and Rx at the same time.
is a bit of a spanner in the works.
I think there are workarounds, though - the bug is not a show-stopper, although it is irritating.
For example, if the baud rate isn't too high relative to the OS tick rate, a time-driven task could check the transmit side and keep it topped up from the OS-level output buffer. And if the baud rate is very high, draining the OS buffer by polling wouldn't be too time-consuming.
Last edited by BigEd on Mon May 08, 2023 3:19 pm, edited 1 time in total.
Re: Working around the W65C51 transmit buffer empty bug
AndrewP wrote:
After watching Ben Eaters W65C51 video and also reading some of the interesting comments.
If the 6551 is setup to generate interrupts is bit 4 of the status register "Transmitter Data Register Empty" strictly needed? I assume the intended usage of any 6551 was to drive the MPU by using interrupts. I doubt it was intended that the MPU should constantly poll the 6551 to see if it could send the next byte?
Let's say the W65C51 has both transmitter and receiver interrupts enabled. Then I think it should be possible to tell if it is time to transmit another byte if status register bit 7 "Interrupt (IRQ)" is set AND status register bit 3 "Bit 3 Receiver Data Register Full" is not set. I think that would imply that the Transmitter Data Register IS Empty (without polling the bugged bit 4). I suppose this wouldn't work so well if doing Tx and Rx at the same time.
The question behind my question is: is there a clean way to use the W65C51? Purely out of interest. I'm going to try and use a 16C550 instead.
If the 6551 is setup to generate interrupts is bit 4 of the status register "Transmitter Data Register Empty" strictly needed? I assume the intended usage of any 6551 was to drive the MPU by using interrupts. I doubt it was intended that the MPU should constantly poll the 6551 to see if it could send the next byte?
Let's say the W65C51 has both transmitter and receiver interrupts enabled. Then I think it should be possible to tell if it is time to transmit another byte if status register bit 7 "Interrupt (IRQ)" is set AND status register bit 3 "Bit 3 Receiver Data Register Full" is not set. I think that would imply that the Transmitter Data Register IS Empty (without polling the bugged bit 4). I suppose this wouldn't work so well if doing Tx and Rx at the same time.
The question behind my question is: is there a clean way to use the W65C51? Purely out of interest. I'm going to try and use a 16C550 instead.
I've had luck running certain old-school 65C51 chips with the W65C02 at up to (and past) 14MHz. I believe this is due to the way W65C02 systems use the clock for Phi2, rather than the signal generated by the CPU.
Bill
Re: Working around the W65C51 transmit buffer empty bug
BillO wrote:
The interrupt doesn't fire either as it relies on the flag. So, no there is no way around the wait loop.
The most recent WDC datasheet has removed that note.
[EDIT]After re-reading this I realised my comment is ambiguous. I'm not doubting you, I'm implying WDC are a bunch of palookas for their datasheet content.[/EDIT]
BigEd wrote:
I think there are workarounds, though
Re: Working around the W65C51 transmit buffer empty bug
Garth wrote in his primer
> Edit, 2/8/19: I think 6502.org forum member GaBuZoMeu has the best solution yet: Use the 51's pin 5 (if in DIP), the x16 clock, as an output to drive a VIA's PB6 for its T2 to count pulses and generate an interrupt. The T2 latch value does not need to change with Φ2 rate nor with baud rate.
(Whereas Gordon not so far away just uses a timer interrupt.)
> Edit, 2/8/19: I think 6502.org forum member GaBuZoMeu has the best solution yet: Use the 51's pin 5 (if in DIP), the x16 clock, as an output to drive a VIA's PB6 for its T2 to count pulses and generate an interrupt. The T2 latch value does not need to change with Φ2 rate nor with baud rate.
(Whereas Gordon not so far away just uses a timer interrupt.)
- BigDumbDinosaur
- Posts: 9425
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: Working around the W65C51 transmit buffer empty bug
Nothing like beating a dead horse, eh?
You cannot use any interrupt processing with the WDC 65C51 because the stuck “transmitter ready” bit will result in a continuous IRQ, which would deadlock your machine. You are forced to use PIO, which is a royal pain, to put it mildly. Or as Ed noted, “is a bit of a spanner in the works.”
If you didn’t have separate flag bits for the receiver and transmitter, how would you know which one is interrupting?
You cannot use any interrupt processing with the WDC 65C51 because the stuck “transmitter ready” bit will result in a continuous IRQ, which would deadlock your machine. You are forced to use PIO, which is a royal pain, to put it mildly. Or as Ed noted, “is a bit of a spanner in the works.”
AndrewP wrote:
If the 6551 is setup to generate interrupts is bit 4 of the status register "Transmitter Data Register Empty" strictly needed?
If you didn’t have separate flag bits for the receiver and transmitter, how would you know which one is interrupting?
x86? We ain't got no x86. We don't NEED no stinking x86!
Re: Working around the W65C51 transmit buffer empty bug
AndrewP wrote:
I mentioned the 16C550 and I quite like it (if I can get it to work - I don't yet own one) because it comes with transmit and receive FIFOs.
(edit: Sorry, the ones I have 16C650s, but close)
Re: Working around the W65C51 transmit buffer empty bug
Thinking about this some, maybe one could put a FIFO along with a PLD of some sort and have the PLD drain the FIFO at some fixed rate into the 65C51. Then you can use the FIFO's flags to monitor things from the 65C02. Might be a bit complicated to setup though? Just counting some bits, might be able to do it with a simple counter IC.
Does this bug also affect the RTSB pin? (I would presume it does)
Does this bug also affect the RTSB pin? (I would presume it does)
Re: Working around the W65C51 transmit buffer empty bug
BigDumbDinosaur wrote:
Nothing like beating a dead horse, eh?
But seriously; you won't know which interrupt is happening in the normal case of both TX and RX. And if the interrupt is borked too then ... I dunno. How was the chip released in such a completely broken state?!
BigEd wrote:
Garth wrote in his primer
> Edit, 2/8/19: I think 6502.org forum member GaBuZoMeu has the best solution yet: Use the 51's pin 5 (if in DIP), the x16 clock, as an output to drive a VIA's PB6 for its T2 to count pulses and generate an interrupt. The T2 latch value does not need to change with Φ2 rate nor with baud rate.
> Edit, 2/8/19: I think 6502.org forum member GaBuZoMeu has the best solution yet: Use the 51's pin 5 (if in DIP), the x16 clock, as an output to drive a VIA's PB6 for its T2 to count pulses and generate an interrupt. The T2 latch value does not need to change with Φ2 rate nor with baud rate.
Yuri wrote:
I have a couple [of 16C650s] I got from Jamco; however they appear to be TTL level logic and not CMOS. They do run at both 5V and 3.3V though.
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Working around the W65C51 transmit buffer empty bug
AndrewP wrote:
But seriously; you won't know which interrupt is happening in the normal case of both TX and RX.
Quote:
How was the chip released in such a completely broken state?!
It was designed using software that's widely used in the industry (whose name I don't remember), not particular to WDC. Somehow it did not properly simulate and catch a race condition. The problem was not detected until long after WDC had a production run made and then started selling them. Apparently it was a big investment for such a small company, and they couldn't afford to do it again.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: Working around the W65C51 transmit buffer empty bug
Does anybody know if the UART's on the WDC microcontrollers (W65C134, W65C265) suffer from the same bug as the W65C51?
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Working around the W65C51 transmit buffer empty bug
Sean wrote:
Does anybody know if the UART's on the WDC microcontrollers (W65C134, W65C265) suffer from the same bug as the W65C51?
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
- floobydust
- Posts: 1394
- Joined: 05 Mar 2013
Re: Working around the W65C51 transmit buffer empty bug
Just an FYI on the W65C51 buggy chip...
You can use interrupt-driven receive on the chip, it works fine... it's just that you can't enable interrupts for the transmitter. The workarounds for this have been around the forum for a while.
If anyone is looking for a DIP UART to implement, you can always source one of the older NXP/Philips SCC2691 parts... they still pop up here and there. My C02 Pocket uses this UART and it works fine, but... your CPU clock speed is capped around 6MHz, as the SCC2691 won't run any faster.
You can use interrupt-driven receive on the chip, it works fine... it's just that you can't enable interrupts for the transmitter. The workarounds for this have been around the forum for a while.
If anyone is looking for a DIP UART to implement, you can always source one of the older NXP/Philips SCC2691 parts... they still pop up here and there. My C02 Pocket uses this UART and it works fine, but... your CPU clock speed is capped around 6MHz, as the SCC2691 won't run any faster.
Regards, KM
https://github.com/floobydust
https://github.com/floobydust
Re: Working around the W65C51 transmit buffer empty bug
Here's what I would like to try. It's the same approach as using the PB6 counter on a VIA, but without the VIA: I use a 74HC590 binary counter cascading into a 74HC191 binary counter, with a 74HC74 flip-flop driving DSRB high ("not ready") whenever the CPU writes to the data transmit register (register 0). The same signal that sets the flip-flop also resets both counters. The 74HC191, the "high order" counter, is LOADed with whatever countdown value has been entered into jumper blocks, and the inverse output from the flip flop enables both counters. The high order countdown value should be the number of bits per transmitted byte, e.g. 0x1010 == 10 for N,8,1 line discipline.
A jumper block is provided to allow setting of the bit pattern on the low order counter which will result in a cascade to the high order counter, and a reset of the low order counter. This should be set to the ratio of the crystal frequency to the baud rate, i.e. 0x01100000 == 96 for a 1.8432 MHz crystal and a baud rate setting of 19200. Finally, when the high order counter hits zero, its ripple carry output goes low. This resets the flip-flop, which brings DSRB low again ("ready").
The 6551 datasheet doesn't indicate any role for DSRB other than to appear in the status register (unlike, say, CTSB) so I think manipulating DSRB shouldn't cause any interference with the actual serial transmission.
On the software side, the CPU need only poll the status register to check DSR. As soon as DSR goes low again, it's safe to send the next character.
Same approach as using the PB6 counter, but no VIA, and no interrupts.
An RC network on the clock pulse input on the high order counter, ensures the cascade pulse from the low order counter is long enough to provide a decent clock pulse to the high order counter (25 ns for the part I chose) when the 8-input NAND gate decodes the cascade pattern on the binary counter. I just need that to last no longer than the time required to send one bit.
A drawback of this circuit is that you have to set the counter values with jumpers, but it would be pretty easy to trap commands to the ACIA and adjust latches that would adjust the delay to be appropriate to whatever values the programmer pushed to the ACIA command/control registers.
What do you think?
A jumper block is provided to allow setting of the bit pattern on the low order counter which will result in a cascade to the high order counter, and a reset of the low order counter. This should be set to the ratio of the crystal frequency to the baud rate, i.e. 0x01100000 == 96 for a 1.8432 MHz crystal and a baud rate setting of 19200. Finally, when the high order counter hits zero, its ripple carry output goes low. This resets the flip-flop, which brings DSRB low again ("ready").
The 6551 datasheet doesn't indicate any role for DSRB other than to appear in the status register (unlike, say, CTSB) so I think manipulating DSRB shouldn't cause any interference with the actual serial transmission.
On the software side, the CPU need only poll the status register to check DSR. As soon as DSR goes low again, it's safe to send the next character.
Same approach as using the PB6 counter, but no VIA, and no interrupts.
An RC network on the clock pulse input on the high order counter, ensures the cascade pulse from the low order counter is long enough to provide a decent clock pulse to the high order counter (25 ns for the part I chose) when the 8-input NAND gate decodes the cascade pattern on the binary counter. I just need that to last no longer than the time required to send one bit.
A drawback of this circuit is that you have to set the counter values with jumpers, but it would be pretty easy to trap commands to the ACIA and adjust latches that would adjust the delay to be appropriate to whatever values the programmer pushed to the ACIA command/control registers.
What do you think?
Last edited by AlanCanon on Fri Jul 07, 2023 4:34 pm, edited 2 times in total.
Re: Working around the W65C51 transmit buffer empty bug
Hey Alan, that's me who was chatting to you on YouTube. Good catch on needing to divide the 1.8432Mhz signal down.
Just to make sure I'm understanding. You're using the bottom set of jumpers to select the baud rate and the top set of jumpers to select the total number of bits?
Otherwise I haven't got much more to add. If I've understood that datasheet then DSRB being high should stop the transmit interrupt from being triggered even though the 65C51N thinks the transmit buffer is empty.
A couple of things I've noticed on your schematic. You might want to swap U49D with U88A to make wiring / trace routing easier. And I think there might be a GND label missing on J25.
Also if you're feeling industrious in the future you could swap out the top jumpers for a '573 latch and make the bit count programmable by the 6502. If you're even more industrious you could swap out the bottom jumpers for another latch and the NAND gate U6A for a '521 comparator; feeding both the latch and the '590 counter into the comparator. You could alternatively swap out the '590 counter for two presettable latches and load them from a latch to make a programmable frequency divider.
Of course at this point there are enough discrete ICs knocking around you could just about throw out the 65C51 and replace it with a couple of shift registers... Right, that's enough rambling from me.
Cheers,
Andrew
Just to make sure I'm understanding. You're using the bottom set of jumpers to select the baud rate and the top set of jumpers to select the total number of bits?
Otherwise I haven't got much more to add. If I've understood that datasheet then DSRB being high should stop the transmit interrupt from being triggered even though the 65C51N thinks the transmit buffer is empty.
A couple of things I've noticed on your schematic. You might want to swap U49D with U88A to make wiring / trace routing easier. And I think there might be a GND label missing on J25.
Also if you're feeling industrious in the future you could swap out the top jumpers for a '573 latch and make the bit count programmable by the 6502. If you're even more industrious you could swap out the bottom jumpers for another latch and the NAND gate U6A for a '521 comparator; feeding both the latch and the '590 counter into the comparator. You could alternatively swap out the '590 counter for two presettable latches and load them from a latch to make a programmable frequency divider.
Of course at this point there are enough discrete ICs knocking around you could just about throw out the 65C51 and replace it with a couple of shift registers... Right, that's enough rambling from me.
Cheers,
Andrew