Page 1 of 1

Yet another (clock stretching/underclocking/slowbus?) w/ PLD

Posted: Sat May 06, 2023 7:43 pm
by and3rson
I know there are *a lot* of threads on this subject here, but I decided to share the solution which I found easiest to implement by myself.

I recently got a really neat display based on T6963C. Its resolution is 240x64 and it supports both character & graphic modes. It also includes char generator ROM.
Image from product page on AliExpress
Image from product page on AliExpress
However, it doesn't support 4-bit addressing as HD44780 & friends do, so using VIA is off the table since it needs 8 data bits + /RD & /WR + EN + C/D (12 total, reset & font selection can be hardwired.)
I could probably use some shift registers, but man - this display would work so well with native 6502 parallel bus... And it would be much faster than bit-banging with VIA.

"Why not connect it to 6502 directly then?" - well, I run @ 8 MHz, and T6963C is said to work properly at <4 MHz. So let's underclock the bus then!

I spend a fair amount of time trying to get this working with D flip-flops, however most of components are hard to find over the weekend, so I tried simulating them. Eventually I remembered I still have several GAL20V8B around.

Here's my idea:
- GAL20V8 operating in registered mode, master clock (16 MHz, comes directly from oscillator) drives GAL's CLK line, GAL is permanently enabled.
- GAL controls PHO ("Phase Out") output as register, which goes to 6502's PHI2.
- If /SLOW is asserted, GAL serves as 3-bit counter and flips PHO on overflow: f(PHO) = f(CLK) / 16 = 1 MHz
- Otherwise, GAL flips PHO every cycle: f(PHO) = f(CLK) / 2 = 8 MHz

Code: Select all

GAL20V8
Slowbus

CLK   NC   /SLOW NC   NC   NC   NC   NC   NC   NC   NC   GND
/OE   NC   PHO   Q2   Q1   Q0   NC   NC   NC   NC   NC   VCC

; If /SLOW is asserted, this works as 3-bit counter: [PHO (MSB), Q1, Q0]

; Q0 (LSB)
Q0.R = SLOW * /Q0
; Q1
Q1.R = SLOW * /Q1 * Q0 + SLOW * Q1 * /Q0
; Q2 (used for debugging only)
Q2.R = SLOW * /Q2 * Q1 * Q0 + SLOW * Q2 * /Q1 + SLOW * Q2 * /Q0
; Output clock
PHO.R =
    ; Fast mode, f(PHO) = f(CLK) / 2
    /SLOW * /PHO
    ; Slow mode (3-bit ocunter, PHO as Q2), f(PHO) = f(CLK) / 16
  +  SLOW * /PHO *  Q1 * Q0
  +  SLOW *  PHO * /Q1
  +  SLOW *  PHO * /Q0

DESCRIPTION
PHO = CLK / 16 if /SLOW is asserted or CLK / 2 otherwise
Simulated timing diagram:
slowbus_diagram.png
Test program:

Code: Select all

main:
        nop
        nop
        stz $D200  ; Write to I/O region, $D200-$D2FF mapped via '138 to /SLOW
        jmp main
Schematic (I used GAL16V8 for presentation purpose since my Kicad doesn't have GAL20V8):
slowbus_schematic.png
Actual test:
slowbus_real.png
Surprisingly, this worked really well. Obviously, PHO will go to 6502 only: VIA will still use CLK/2 (probably divided through GAL as well in order to avoid clock skew between 6502 & VIA and ensure matching clock edges).

EDIT: I think that with enough tinkering it would be possible to use the same GAL for Clock Domain Crossing (if that's the correct term) to communicate with SID (which always has to run on 1 MHz).
EDIT 2: Clock speed is addicting... I used to run my SBC @ 1 MHz for some time and it felt great, but once I went to 8 MHz - the former feels so slow! Especially with LCD redraws & lots of I2C/SPI bit-banging. But I feel like 8 MHz is the best of both worlds for me: fast enough to feel good, and slow enough to still be analyzable, compatible with most components, and also relieving me from thinking about all the timings of my daisy-chained 7400 glue logic & ROM/RAM timings.

Re: Yet another (Clock stretching? Underclocking? Slow bus?)

Posted: Sat May 06, 2023 8:28 pm
by BigDumbDinosaur
One caution with using the output of a GAL to drive the Ø2 inputs of the 65C02/65C816/65C22, etc., is a GAL’s output levels are TTL, not CMOS. According to the WDC data sheets, clock inputs are supposed to swing at CMOS levels, and should have a rise/fall time no greater than 5ns. While the GAL’s outputs will easily meet the 5ns requirement, it is questionable as to whether they will reach what constitutes a valid CMOS logic 1 when high.

Re: Yet another (Clock stretching? Underclocking? Slow bus?)

Posted: Sun May 07, 2023 2:28 pm
by and3rson
BigDumbDinosaur wrote:
One caution with using the output of a GAL to drive the Ø2 inputs of the 65C02/65C816/65C22, etc., is a GAL’s output levels are TTL, not CMOS. According to the WDC data sheets, clock inputs are supposed to swing at CMOS levels, and should have a rise/fall time no greater than 5ns. While the GAL’s outputs will easily meet the 5ns requirement, it is questionable as to whether they will reach what constitutes a valid CMOS logic 1 when high.
I did not think about this! Thanks for pointing that out. I might add a TTL-CMOS level converter in my next build for this. Would a Schmitt trigger be sufficient for this or is something more complex required?

Meanwhile, my 6502/6522/T6963C/GAL are doing really well together: I was able to load & run a program from uSD card (through VIA) which properly initialized my 24064 display (underclocked with GAL):
IMG_20230507_172834_988.jpg
(Might be hard to notice "Hello" in the top-left corner since I forgot to clear screen VRAM beforehand.)

This display can draw up to 48 cols x 8 rows (with 5x8 font). Plenty of space for my needs, and those 4 extra rows are exactly what I was missing with my 4004 LCD.

Re: Yet another (Clock stretching? Underclocking? Slow bus?)

Posted: Sun May 07, 2023 3:54 pm
by plasmo
Gal22V10 datasheet shows Voh vs Ioh curve. You can see at output current of 2-3mA, the output voltage will reach 3.5V. So you should be able to drive W65C02 clock if GAL output is not loaded.
Bill

Re: Yet another (Clock stretching? Underclocking? Slow bus?)

Posted: Wed May 10, 2023 6:20 pm
by and3rson
So Lattice's GAL20V8 worked with my SBC, however it was failing test vectors with my TL866-II unless I set test levels to 3.3V instead of 5V. :) Seems like TL866 probably latches asserted pins too fast, before the levels rise to CMOS level due to higher input capacitance (if I understand electronics, which I sometimes feel like I don't.)

I've decided to switch to ATF PLDs for several reasons:
- They are TTL/CMOS compatible;
- They are still made.

I've ordered a bunch from Mouser, 8 outputs feels enough for my purposes, including address decoding & R/W qualification:
gal_slowbus_addr_rw.png

Code: Select all

GAL16V8
Addr

CLK  /SLOW /RST   A15   A14   A13   A12   RW    NC    GND
/OE   PHV   Q2    Q1    PHI2 /WD   /RD   /ROM  /IO    VCC

;;;;;;;;;;;;;;;;;;;;;;;;
; Address decoder, bus underclocking, R/W qualifier
; If /SLOW is asserted, this works as 3-bit counter: [PHV (MSB), Q1, PHI2 (LSB)]
;


;;;;;;;;;;;;;;;;;;;;;;;;
; Bus underclocking
;
PHI2.R = /RST  * /PHI2

Q1.R =   /RST  *  SLOW  * /Q1  *  PHI2
       + /RST  *  SLOW  *  Q1  * /PHI2

Q2.R =   /RST  *  SLOW  * /Q2  *  Q1 * PHI2
       + /RST  *  SLOW  *  Q2  * /Q1
       + /RST  *  SLOW  *  Q2  * /PHI2

PHV =
    ; Fast mode (PHV=Q0)
         /SLOW  *  PHI2
    ; Slow mode (PHV=Q2)
       +  SLOW  *  Q2

; PHI2 =     Q0


;;;;;;;;;;;;;;;;;;;;;;;;
; R/W qualifier
;
WD =      PHV  * /RW
RD =      PHV  *  RW


;;;;;;;;;;;;;;;;;;;;;;;;
; Address decoder
;
; RAM =    /A15
ROM =     A15  * /A14  +  A15  *  A14  *  A13
IO =      A15  *  A14  * /A13  *  A12

DESCRIPTION
PHV = CLK / 16 if /SLOW is asserted or CLK / 2 otherwise
PHI2 = CLK / 2
RAM/EN is not managed by GAL, since it's simply tied to RAM's A15 ($0000-$7FFF), and I still use '138 for 8x256B I/O segments.

I also found this nice utility that can convert to and from .lgc format and a more human-readable .toml - https://github.com/evolutional/xgpro-logic - and made some tests to make sure my PLD behaves as expected:

Code: Select all

[[ics]]
# Test vectors for GAL20V8 since I don't have GAL16V8 on me yet.
name = "SlowBus-GAL20V8"
pins = 24
vcc = 3.3
vectors = [
    #  __        _     ____
    #  SR5432R   O V21ФWRRI

    # Reset
	"CX10XXXXXXXG1XLZZZHHXXXV",

    # Slow bus
    # Fast mode
	"CX11XXXXXXXG0XHLLHXXXXXV",
	"CX11XXXXXXXG0XLLLLXXXXXV",
    # Slow mode
	"CX01XXXXXXXG0XLLLHXXXXXV",
	"CX01XXXXXXXG0XLLHLXXXXXV",
	"CX01XXXXXXXG0XLLHHXXXXXV",
	"CX01XXXXXXXG0XHHLLXXXXXV",
	"CX01XXXXXXXG0XHHLHXXXXXV",
	"CX01XXXXXXXG0XHHHLXXXXXV",
	"CX01XXXXXXXG0XHHHHXXXXXV",
	"CX01XXXXXXXG0XLLLLXXXXXV",
    # Fast mode (again)
	"CX11XXXXXXXG0XHLLHXXXXXV",
	"CX11XXXXXXXG0XLLLLXXXXXV",

    # Read/write qualifier
    # /WD + /RD when Ф2=0
	"0X11XXXX0XXG0XLLLLHHXXXV",
	"0X11XXXX1XXG0XLLLLHHXXXV",
    # /WD + /RD when Ф2=1
	"CX11XXXX0XXG0XHLLHLHXXXV",
	"0X11XXXX1XXG0XHLLHHLXXXV",
    # /WD + /RD when Ф2=0 (again)
	"CX11XXXX1XXG0XLLLLHHXXXV",

    # Address decoder
    # /RAM enable ($0000-$7FFF)
	"0X110000XXXG0XXXXXXXHHXV",
	"0X110001XXXG0XXXXXXXHHXV",
	"0X110010XXXG0XXXXXXXHHXV",
	"0X110011XXXG0XXXXXXXHHXV",
	"0X110100XXXG0XXXXXXXHHXV",
	"0X110101XXXG0XXXXXXXHHXV",
	"0X110110XXXG0XXXXXXXHHXV",
	"0X110111XXXG0XXXXXXXHHXV",
    # /ROM enable ($8000-$BFFF, 16K LOROM)
	"0X111000XXXG0XXXXXXXLHXV",
	"0X111001XXXG0XXXXXXXLHXV",
	"0X111010XXXG0XXXXXXXLHXV",
	"0X111011XXXG0XXXXXXXLHXV",
    # Unused ($C000-$CFFF)
	"0X111100XXXG0XXXXXXXHHXV",
    # I/O ($D000-$DFFF)
	"0X111101XXXG0XXXXXXXHLXV",
    # /ROM enable ($E000-$DFFF, 8K HIROM)
	"0X111110XXXG0XXXXXXXLHXV",
	"0X111111XXXG0XXXXXXXLHXV",
]
I'm running XGPro under wine with patched libusb, works great:
gal_test_pass.png

Re: Yet another (clock stretching/underclocking/slowbus?) w/

Posted: Sat May 20, 2023 10:19 pm
by and3rson
New board - GAL + 240x64 LCD (T6963C) are doing great! Using GAL20V8 until my ATF EEPLD arrives.

I'm running master clock @ 16 MHz, CPU is clocked between 8 MHz & 2 MHz based on LCD/EN.

Also, some new fancy stuff:
  • DS1307 (I2C RTC) with CR2032 battery
  • MCP9808 (temperature sensor, mounted under the 6502 (well, it's all CMOS nowadays and things aren't getting as hot as NMOS did, but I still wanted to be able to "get CPU temperature" in a fancy way).
  • Slot for ESP8266 (ESP01) to talk to it with 6551 - I want to write a simple telnet client to be able to connect to some C64 BBS that are still running. Gonna try out something like https://github.com/dhansel/WifiModem or write my own firmware - I worked a lot with ESP8266 and really love them.
Still left one '00 for reset LED and also just in case I'll need to reroute things. Life taught me it's always good to have at least several spare NAND gates on the board which is still WIP.

1K pot for LCD contrast is definitely too low and is getting warm, will replace it with 10K.

Last but not least, it took me 16 revisions to add the damn power switch. Friggin' finally!
v16_gal_and_t6963c.jpg
And the entire thing is lass than 1" thick (excluding standoff legs):
v16_thicc.jpg
Perfect fit! (Well, I had to slightly bend metal legs that hold display's case & PCB together.) Clearance is ~0.4" (11 mm) - just enough to fit chips with machine-tooled sockets, as well as barrel jack.
v16_it_fits.jpg
I also renamed my SBC to Deck65 - the name might imply that there should be like a dozen of stacked things, but I'm a modest person and only have 2 layers!

/Andrew

Re: Yet another (clock stretching/underclocking/slowbus?) w/

Posted: Thu Jun 01, 2023 6:20 pm
by and3rson
Turns out ATF16V8 is (fully?) compatible with GAL16V8 (at least for my usecase). I was able to program it using the same .jed file that I used for my GAL16V8 (actually GAL20V8B - I simply changed pin mapping by removing 4 pins, because I don't have GAL16V8). I used galasm & minipro for programming both (using TL866-II). I expected some incompatibility, but it worked out of the box!

Also, I found it simple to temporarily use '20V8 in place of '16V8, since I don't use pins 2, 11, 13, & 23 (all of them are inputs). So I simply had to join some pins: CLK (1+2), GND (11+12), /CE (13+14), & VCC (23+24).