gfoot wrote:
Quote:
Though I still wish WinCUPL's UI did not suck so hard under Wine though... But hey - at least it works!
WinCupl's GUI socks even in native Windows - it is awful and crashes a lot. I'm not sure if I said to you before, but I use WinCupl from the command line instead. At first using cygwin, but later using Wine. I use a bash script to wrap the tool and make it behave a bit better, putting generated files away from the source code, spreading useless output, etc. It has made my life a lot easier.
Quote:
EDIT: Seems like I'll have hard time programming ATF750...
viewtopic.php?f=10&t=4323&p=104766#p104766The newer version of the TL866 - the T56 - can program them. It's not cheap but I've heard good things about the device. However, I don't believe there is any Linux software for it, you'd need to use the Windows software.
Thanks - I've ordered T56 today because I'm a sucker for DIP PLD chips. I managed to get WinCUPL (somewhat) working and even got used to its terrible pet peeves, learning what not to do in order to keep it from crashing.
BruceRMcF wrote:
That's the kind of issue that leads some people to using separate MISO and MOSI serial shift registers, which can be clocked on PHI1 or PHI2 as works best for that side of the operation.
If using a latch, since there are dual '74 clocked latches with direct and inverse outputs and /clear and /preset, perhaps there is a way to use the other side of the latch to eliminate some of the other logic.
Yeah, a latch to buffer MISO is definitely the missing link.
BruceRMcF wrote:
The first PHI1_SCLK clock tick is for loading, not for the SPI bus
Yeah, I just realized this today when I was trying to implement my circuit with ATF750C - I had to use modulo-9 counter to properly time everything, including the last clock tick which is easy to miss.
BruceRMcF wrote:
I think the Counter is loaded with $7, but I'm not sure: for a '193, load is asynchronous, so the rising Phi2 before the USR is loaded won't tick the counter, so I think it's 1 tick before each shift and then one tick following the last shift. Since a carry overflow is being used rather than the state of the counter Q3, it's not required to count to exactly eight.
For my circuit, I swapped '163 & '191 in and out, trying to find the best fit, but I was always lacking an additional asynchronous reset/preset. Still, your idea sounds nice!
BruceRMcF wrote:
Since it's system clocked, it doesn't seem crucial to have a Busy status, just add three NOPs between writing the output byte and reading the input byte, the eighth SPI clock cycle will be finished before the final clock cycle of the read.
Totally! I decided to ditch that output as well, since NOPs are sufficient for proper delay (which is constant) and simplifies the design.
I eventually implemented my design into ATF750C, and this is probably my most complex PLD project so far:
Code:
Name SPI;
PartNo 00;
Date 29.11.2023;
Revision 01;
Designer Engineer;
Company Andrew;
Assembly None;
Location ;
Device v750;
/* Unused pins for nicer group separation in simulator */
pin 7 = NOP1;
pin 8 = NOP2;
pin 9 = NOP3;
/* Inputs */
pin 1 = CLK;
pin 2 = !RD;
pin 3 = !WR;
pin 4 = !CS;
pin 5 = !RES;
pin 6 = MISO;
pin 13 = !EN;
/* Bidirectional */
pin 14 = D0;
pin 15 = D1;
pin 16 = D2;
pin 17 = D3;
pin 18 = D4;
pin 19 = D5;
pin 20 = D6;
pin 21 = D7;
/* Outputs */
pin 22 = MOSI;
pin 23 = SCK;
/* Buffer for MISO */
node MISO_BUF;
/* 4-bit modulo-9 counter, active when TEN is high */
node T0;
node T1;
node T2;
node T3;
node TEN;
T0.CK = CLK;
T0.D = TEN & !T0 & !T3;
T1.CK = CLK;
T1.D = TEN & (!T1 & T0 # T1 & !T0);
T2.CK = CLK;
T2.D = TEN & (T2 & !T1 # T2 & !T0 # !T2 & T1 & T0);
T3.CK = CLK;
T3.D = TEN & (T3 # T2 & T1 & T0);
/* Timer is activated when /CS & /WR are active, and deactivated when 8 is reached. */
TEN.CK = !CLK;
TEN.D = EN & WR # (TEN & !T3);
[T0..T3].SP = 'b'0;
[T0..T3].AR = RES;
TEN.SP = 'b'0;
TEN.AR = RES;
/* Data is sampled/shifted on falling edge of CLK and is tri-stated when /EN is high or /RD is high. */
[D0..D7].OE = EN & RD;
[D0..D7].CK = !CLK;
[D0..D7].SP = 'b'0;
/* If timer is active, data is shifted. Otherwise, data is sampled if /EN & /WR active or held otherwise. */
D7.D = TEN & D6 # !TEN & EN & WR & D7.IO # !TEN & (!EN # !WR) & D7; /* D7 drives MOSI */
D6.D = TEN & D5 # !TEN & EN & WR & D6.IO # !TEN & (!EN # !WR) & D6;
D5.D = TEN & D4 # !TEN & EN & WR & D5.IO # !TEN & (!EN # !WR) & D5;
D4.D = TEN & D3 # !TEN & EN & WR & D4.IO # !TEN & (!EN # !WR) & D4;
D3.D = TEN & D2 # !TEN & EN & WR & D3.IO # !TEN & (!EN # !WR) & D3;
D2.D = TEN & D1 # !TEN & EN & WR & D2.IO # !TEN & (!EN # !WR) & D2;
D1.D = TEN & D0 # !TEN & EN & WR & D1.IO # !TEN & (!EN # !WR) & D1;
D0.D = TEN & MISO_BUF # !TEN & EN & WR & D0.IO # !TEN & (!EN # !WR) & D0; /* D0 is shifted in from MOSI */
/* MOSI is set from D7 and is always active */
MOSI = D7;
MOSI.OE = 'b'1;
/* MISO is sampled on rising edge of CLK. */
MISO_BUF.CK = CLK;
MISO_BUF.SP = 'b'0;
MISO_BUF.D = MISO;
/* SCK is set from CLK, but only when timer is active */
SCK = CLK & TEN;
Test vertors:
Code:
Name SPI;
PartNo 00;
Date 29.11.2023;
Revision 01;
Designer Engineer;
Company Andrew;
Assembly None;
Location ;
ORDER: CLK, !RES, !EN, !RD, !WR, NOP1, D0, D1, D2, D3, D4, D5, D6, D7, NOP2, MISO, MOSI, SCK, NOP3, T0, T1, T2, T3, TEN;
VECTORS:
0K111XZZZZZZZZX1**X*****
C1111XZZZZZZZZX1**X*****
C1111XZZZZZZZZX1**X*****
11010XZZZZZZZZX1**X*****
01010X01100011X1**X*****
01001X********X0**X*****
11001X********X0**X*****
01001X********X1**X*****
11001X********X1**X*****
01001X********X0**X*****
11001X********X0**X*****
01001X********X1**X*****
11001X********X1**X*****
01001X********X0**X*****
11001X********X0**X*****
01001X********X0**X*****
11001X********X0**X*****
01001X********X1**X*****
11001X********X1**X*****
01001X********X1**X*****
11001X********X1**X*****
01001X********X0**X*****
11001X********X0**X*****
01001X********X0**X*****
11001X********X0**X*****
01001X********X0**X*****
11001X********X0**X*****
01001X********X0**X*****
11001X********X0**X*****
01001X********X0**X*****
Result (sending 11000110, receiving 01010011):
It currently works in SPI mode 0 only, but I was thinking of trying to implement all 4 modes which can be configured by writing to a different address. There's still plenty of buried registers for this, but I'm afraid I might run into the term limit, since changing CPOL & CPHA will require some heavy XOR-ing which cupl might not like...
Attachment:
spi4.png [ 461.57 KiB | Viewed 4008 times ]