Page 1 of 1

The VIA shift register bug

Posted: Thu Jan 18, 2024 1:21 pm
by fachat
Hi there,

I wanted to use the VIA shift register in my re-creation of the _fast_ serial bus from Commodore (that uses the CIA 6526 shift register), and did some testing and deep dive (well not really deep for this forum, but anyway ;-) )

https://youtu.be/6cwVQahVCdc

Also Dave McMurties has published a companion video on the Commodore disk drive history and where the speed loss came in:
https://www.youtube.com/watch?v=kaeFV0oZaps&t=0s

Re: The VIA shift register bug

Posted: Sat Feb 17, 2024 8:08 pm
by BruceRMcF
Nice video, and the follow-up is even better.

Note that in the 2nd, the answer from WDC strikes me as a bit of a shell game ... I really don't think the "synchronous" in synchronous serial means synchronous to the system clock of the receiving device, but rather synchronous with the clock signal line in the serial channel itself.

Also note that I think it might be possible to convert from the intrinsically Mode3 VIA serial shift register to Mode0 with a quad 2-input NAND (74x00) and a single GPIO or selection line.

The idea is, suppose you have an Mode3 clock on a line SPI_CLK3, "/Mode0_Reset" as a GPIO or active low select line, an /S /R latch and an AND gate.

Tie the /Mode0_Reset to the /R reset of the latch, and pull it low, then release it, before selecting the Mode0 SPI device. Now the output of the latch is low.

Use the SPI_CLK3 as the /S set of the latch. So the first time that the SPI_CLK3 is pulled low, the output of the latch goes high.

At the AND gate:

AND_1A := SPI_CLK3
AND_1B := SRLATCH_Q
AND_1Y =: SPI_CLK0

... so when the SPI_CLK3 goes low, the SRLATCH_Q goes high, but SPI_CLK0 remains low until the first rise of the SPI_CLK3 clock phase.

So basically this makes the SPI_CLK0 clock cycle start a half clock phase after the SPI_CLK3 cycle.

When the SPI_CLK3 is finished 8 clock cycles, the SPI_CLK0 is halfway through its eighth clock cycle. Pull down the /R reset line of the latch, which pulls the SPI_CLK0 low, completing its last clock phase and placing it in its low idle state, until the next SPI_CLK3 cycle.

Note that an SPI_CLK1 is just an inverted SPI_CLK3 and an SPI_CLK2 is an inverted SPI_CLK0, so with a system SPI_CLK3 and one /Mode0_Reset, you can any or all of the four SPI clock modes on a dedicated CLKn line, and as long as the SPI servant is connected to the clock line that suits it, the software doesn't need to worry about the mode of the device. So you only need an /SPI_SELECT routine, and an SPI_TRX routine for your SPI devices.

However, most of the SPI device datasheets I have seen are Mode0 only, Mode0/Mode3, Mode0/Mode2 with a polarity select, or Mode1/Mode3 with a polarity select, so having both an SPI_CLK0 line and an SPI_CLK3 line may suffice.

As far as implementing it, two gates of a quad NAND can be used to make an /S /R latch. Using a NAND as the "half phase delay" filter generates a high rather than a low during idle and inverts the clock in operation, which is an SPI_CLK2 rather than an SPI_CLK0. However, that is just 3 of the four NAND gates, so the final NAND gate can be used as an inverter.

This is three gates of delay between SPI_CLK3 and SPI_CLK0, so if it was desired to have a choice between Mode3 and Mode0 based on which SPI_CLK line you hook to the SPI "servant" device, a slower NAND like a 74LS00 would require checking whether the clock delay causes an issue, but with a faster NAND, I'm guessing it wouldn't cause an issue.

Inputs:
SPI_CLK3: a source of a Phase 1, Polarity 1 SPI clock.
/Mode0_Reset: a VIA GPIO or an active low select line that triggers at an appropriate time.

Code: Select all

; NAND1 74x00
; VCC  4B  4A  4Y  3B  3A  3Y
;  14  13  12  11  10   9   8
;   1   2   3   4   5   6   7
;  1A  1B  1Y  2A  2B  2Y GND 
NAND_1A := SPI_CLK3 ; /S Set latch
NAND_1B := NAND_2Y
NAND_1Y =: NAND_2A =: NAND_3B ; /Idle_CLK0
NAND_2A := NAND_1Y
NAND_2B := /Mode0_Reset ; /R Reset Latch
NAND_2Y =: NAND_1B
NAND_GND := SYS_GND
;
NAND_VCC := SYS_VCC
NAND_4B := SYS_VCC
NAND_4A := NAND_3Y ; SPI_CLK2
NAND_4Y =: SPI_CLK0 ; => Mode0 SPI bus
NAND_3B := NAND_1Y ; /Idle_CLK0
NAND_3A := SPI_CLK3

Re: The VIA shift register bug

Posted: Sat Feb 17, 2024 11:10 pm
by fachat
Thanks Bruce for your suggestion. I still have to have a deeper look at it. I assume here is the same as you wrote on the video comment?

Btw here is the link to my follow-up video, with a response from WDC https://youtu.be/nvnz_34uWSg

André

Re: The VIA shift register bug

Posted: Sun Feb 18, 2024 2:00 am
by BruceRMcF
fachat wrote:
Thanks Bruce for your suggestion. I still have to have a deeper look at it. I assume here is the same as you wrote on the video comment?
Yes, this is in detail what I very briefly sketched in the Youtube.

(Doing a text picture of the pinout of a 74 series quad logic gate is trickier in a Youtube comments section, given the lack of a "code" markup.)

This is a different approach from pdragon, who is basically delaying a Mode3 clock and inverting it. That fits the VIA application, if you know how many system clocks you need to delay, and since it doesn't have the /Mode0_Reset action at the end of the byte, it is probably more efficient.

This is more a generic approach, since the second phase rising clock from Mode3 is being used to drive the first phase rising clock for Mode0, but if the /Mode0_Reset is bit banged, it will be a little less efficient pdragon's approach.
Quote:
Btw here is the link to my follow-up video, with a response from WDC https://youtu.be/nvnz_34uWSg ...
[thumbs up]

Re: The VIA shift register bug

Posted: Sun Feb 18, 2024 12:12 pm
by fachat
I tried to understand it and I think this is a really nice approach!

Let me know if I got it right in the attached picture.

It has to rely on that the last clock transition is ignored by the device, although one could - and probably has to - do the the /M0res for every byte anyway.
Combine that with an inbound shift register connected to port A, use CA2 as pulse mode handshake when reading PA and use it as /M0res, and this is a really minimal solution!

I really like it!

Edit: I think in my diagram I got the bit order wrong

Re: The VIA shift register bug

Posted: Sun Feb 18, 2024 12:33 pm
by fachat
Summarizing the thoughts here...
What do you think?

Re: The VIA shift register bug

Posted: Sun Feb 18, 2024 12:51 pm
by fachat
Of course I got the bit order wrong... SPI Default is MSB first.

Edit: just for completeness, and to be able to link to this post and have a basically complete description, here is a short description how to set it up:

Setup:
1) set the VIA T2 to the right speed you want to use (or ignore this if you want to go with Phi2 clock source, which is the fastest)
2) set the SR enabled and input from either T2 or Phi2 clock
3) set Port A into handshake mode, so that it outputs a single low pulse on CA2 when PA is read or written

for each set of bytes (just in case):
1) send a pulse on /ACK by reading PA (e.g. with BIT, so no register is needed)
for each byte:
2) write output data to SR
3) wait until data is shifted out, either counting clock cycles, or looking at IFR for SR done
4) read the data from PA (which automatically sends an /ACK pulse)
5) if more data is to be transferred, go back to 2)

Using phi2 as clock source, each bit uses 4 phi2 clock cycles, totaling in 24 cycles per byte direct transfer. Add the processing overhead to that.

You can interleave processing and transferring: once a byte has been read from the PA, you can already store a value in the SR to trigger the next transfer, then process the byte received while the next transfer is ongoing.

Re: The VIA shift register bug

Posted: Sun Feb 18, 2024 2:52 pm
by BruceRMcF
Yes,

Code: Select all


_______...______    __    __    __    __    __    __    __    ___________ SPI_CLK3 
       ...      \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/

__    _...________________________________________________________    ____ /Mode0_RST
  \__/ ...                                                        \__/

___    ...          __    __    __    __    __    __    __    _____        SPI_CLK3 
   \___..._________/  \__/  \__/  \__/  \__/  \__/  \__/  \__/     \_____ 

                  _____ _____ _____ _____ _____ _____ _____ _____ SPI_MOSI
                 X  b7 X  b6 X  b5 X  b4 X  b3 X  b2 X  b1 X  b0 X

The /Mode0_RST needs to be applied prior to the first byte and then following each byte,.

The /SPI_CLK0 line should be idle low before the /SPI_SELECT line is asserted low, so select should include a dummy read before pulling the select line down, but a dummy read would be faster than cycling a PortB pin down then up.

The last (bit0) Mode0 serial clock cycle in this approach is asymmetric, but since SPI is a patient protocol and the asymmetry involves a clock stretch, that should be OK.

I'm thinking that using a Read handshake to trigger /Mode0_RST would work for your circuit, since your MOSI SSR is the VIA SSR, which is Mode3, and your MISO SSR is intrinsically Mode0/Mode3, so the trailing downward clock cycle is only needed for the servant device on the other side of the SPI bus, which is what is making it a Mode0-only servant.

_________
Virtually, Bruce McFarling

(to be sure, it almost certainly would have been clan MacFarlane, but one presumes that if the mid-1700's immigrant in question had a thick Ulster plantations accent rather than a thick Scottish accent, "McFarling" is what the literate person writing the name down thought they heard. The same parents Scotland->Ireland, child Ireland->American colonies process also generated McFarley, McFarland, and similar surnames based on what some person who could read and write decided to write down. The MacFarlanes were so famous as night time cattle thieves that the full moon was sometimes known as the MacFarlane Lantern in surrounding territories, which might help explain why so many had to set off for the Ulster Plantations in the early 1700's and to Australia a century later.)

Re: The VIA shift register bug

Posted: Sun Feb 18, 2024 7:31 pm
by fachat
Sorry about the name. I have corrected it in the other post.

Re: The VIA shift register bug

Posted: Sun Feb 18, 2024 9:47 pm
by BruceRMcF
fachat wrote:
Sorry about the name. I have corrected it in the other post.
No dramas. Technically, you were closer to my forbearer's original name than the name on my birth certificate. That'd be the fault of all those Scots-Irish immigrants to the US in the mid 1700's who were signing their name with an X next to whatever the literate person thought they were saying.

Re: The VIA shift register bug

Posted: Sat Jul 13, 2024 9:03 pm
by fachat
A comment after having played with it at bit, but only on the scope.

I _think_ that for mode 0/2, you don't even need to to the reset_mode0 pulse between two bytes. As I can see from the scope, the first clock transition of the following byte (in mode 3 as coming from the VIA), serves as the last (unimportant as no data transfer) clock transition of the previous byte.

So, it would only be necessary to do that before the first byte, and after the last byte (if at all).

This should definitely improve the performance.

André

Edit: this can even make the code mode-agnostic. Just do the mode0-reset and have the jumper select the actual clock signal fitting for the needed mode.
Edit 2: here's the actual implementation I tested: https://github.com/fachat/cbm_ultipet/tree/main/Board It's on sheet "Fast IEC", and shares two lines with the fast serial IEC bus. I used a 4-way jumper so you can select the clock mode freely depending on the attached hardware

Re: The VIA shift register bug

Posted: Fri Sep 06, 2024 9:38 am
by fachat
So, what did I find recently, in the preliminary VIA datasheet.... ( http://6502.org/documents/datasheets/mo ... v_1977.pdf )

Re: The VIA shift register bug

Posted: Wed May 07, 2025 1:47 am
by BruceRMcF
fachat wrote:
So, what did I find recently, in the preliminary VIA datasheet.... ( http://6502.org/documents/datasheets/mo ... v_1977.pdf )
Indeed, the Z180 CSIO seems to be designed to operate in a similar manner, so if care is taken to respect the timing limitations on both side, that could be used for communication between a 65xx bus system and a Z180 based system.

My application would be for a "CP/M Board" for a 65xx based system, with the 65xx acting as the terminal for the CP/M system, with the 3-wire SCLK / I-O / Attn interface for faster file transfers, so in my case I would have the 6502 be the master side, generating the clock for both reads and writes, and the Z180 be on the servant side. Having one side generate the clock for both reads and write means that the timing only has to be sorted out for the 6522 generating a clock that the Z180 CSOI port can handle as an external clock.

____________
fachat wrote:
A comment after having played with it at bit, but only on the scope.

I _think_ that for mode 0/2, you don't even need to to the reset_mode0 pulse between two bytes. As I can see from the scope, the first clock transition of the following byte (in mode 3 as coming from the VIA), serves as the last (unimportant as no data transfer) clock transition of the previous byte.

So, it would only be necessary to do that before the first byte, and after the last byte (if at all).

This should definitely improve the performance.

André

Edit: this can even make the code mode-agnostic. Just do the mode0-reset and have the jumper select the actual clock signal fitting for the needed mode.
Edit 2: here's the actual implementation I tested: https://github.com/fachat/cbm_ultipet/tree/main/Board It's on sheet "Fast IEC", and shares two lines with the fast serial IEC bus. I used a 4-way jumper so you can select the clock mode freely depending on the attached hardware
Yes, I believe this is correct. If the SPI device select routine does a deselect-all before selecting the desired device, then Mode0 reset can be done can be done just prior to the de-select all, and every SPI device select will be preceded by a Mode0 reset then a de-select of all devices.

This means that Mode0 will be reset prior to selecting a Mode0 device, and then when either changing devices or an SPI device requires a fresh select for each instruction, the Mode0 reset is done to complete a sequence of Mode0 transfers.

IIRC, the Mode0 Maxim MAX3100 SPI UART has 16bit operations that requires a select, a pair of bytes, and a a deselect, and building the Mode0 reset and deselect-all into the Select routine means that's bundled into a single call in between successive pairs of SPI byte transfers.

Rather than using a jumper, I am planning to have both an SCLK0 and an SCLK3 line coming out to a pin block header, so that the little break-out board connects the pin that is appropriate to the SPI IC on the board.

If there are exclusive Mode1 or Mode2 IC's, then the break-out board for that IC will have to include an inverter gate on Mode3 or Mode0 resp., but the cases I have seen so far are only-Mode0, only-Mode3, Mode0/2 (either with a polarity input pin or by using state of clock at time of select to latch polarity), or Mode0/3 (where the first bit is available on select, latched on a rising SCLK, so either SCLK with data latched on a rising clock will do).