jwolfram wrote: ↑11 Jan 2019, 08:29
Hardware:
I had to read over this section several times, but I believe I'm starting to grasp it, modulo a couple of details I point out below. I like the direction it's taking!
Note 1: The concept is memory mapped I/O, where:
- the SPI hardware gets a small part of the high memory address space to listen to, and
- lower address lines encode all SPI parameters: MOSI, SCK (SCLK) and the slave enable lines, and
- from the 8-bit code point of view, both SPI reads and SPI writes look like a series of well-crafted memory reads, and
- in full Gigatron style, the SPI protocol, every edge transition of it, is fully driven by software.
- 64K (128K) RAM is mandatory
Note 2: The concept for SPI
read is that data coming from an SPI slave (over the MISO line) doesn't enter the Gigatron data bus directly. Instead, it first enters the RAM through one of its address lines, and from there the RAM puts the correct bit value on the data bus. This works if the dedicated memory area is initialised properly. The 32K system doesn't have enough free memory space for doing that, so we need 64K. But we don't need a tristate buffer chip with its own enable support logic. Nice.
, probably it should be possible to make the upper 32K switchable if a 128K RAM is used
Note 3: I don't get the 128K story yet, or the upper 32K reference. But that's because lack of trying from my side. I park that for now.
- Fill at startup 0xF000 to F7FF with 0x01, 0xF800 to 0xFFFF with 0x00
Code: Select all
RAM[ 1111.0xxx.xxxx.xxxx ] reads as 1
RAM[ 1111.1xxx.xxxx.xxxx ] reads as 0
^
Derived from MISO
Note 4: There is a data inversion done by the RAM. This undoes the inversion introduced later when calculating A10_RAM.
Note 5: You're using A10 below, but this memory initialisation pivots around A11. Is this a small oversight? I would expect the following initialisation:
Code: Select all
RAM[ 1111.10xx.xxxx.xxxx ] reads as 1
RAM[ 1111.11xx.xxxx.xxxx ] reads as 0
^
Derived from MISO
And therefore:
"- Fill at startup 0xF800 to 0xFBFF with 0x01, 0xFC00 to 0xFFFF with 0x00"
- /IOSEL decoder with 74xx30 /IOSEL = /(A11 & A12 & A13 & A14 & A15 & (inv)OE)
Note 6: We take five address lines A11:A15 to distinguish I/O from RAM access. As stated, we do RAM
reads for any I/O (reading or writing). Using the five lines means we have 1/32nd of the 64K address space in use for the I/O extension. So we lose just the top 2K of memory for user applications.
Note 7: The 7430 is an octal NAND, so in the above, 2 of its input pins are unused. We can use those 2 to shrink the lost area from 2K to 512 bytes?
Note 8: Tiny BASIC v2 puts program variables at the top page of the available memory, and it lays out its arrays downwards from the top. This is done so that a 64K system has larger arrays than a 32K system. The memory size check during hard reset only tests memory presence in powers of two. So there is a conflict here to consider.
Note 9: The hard reset sequence in ROM page 0 always walks through the entire 16-bit RAM address space, and reads every byte. It does this to seed the entropy pool. (In the case of a 32K system, it reads every byte twice.) When hitting the top of the address space, this will result in activity on the SPI interface. This activity is deterministic, and perhaps we can arrange the address line mapping in a way to mitigate any unwanted effects of this.
- 74xx175 as register (reset with MR at startup), clock with (inv)/IOSEL
* A7 = MOSI
* A8 -> inverter -> /CS1
* A9 -> inverter -> /CS2
* A10 -> SCK
the delay of the 74xx30 + inverter should be enough to register correct signals.
Note 10: I was expecting to see A6:A9 here, because now A10 has a double meaning. But the way A10 is rewired that's ok. But why not something like A0:A3? (But also see note 13 below...)
Note 11: The 74175 is a quad flip-flop with both Q and /Q outputs. We need flip-flops for stable outputs (just like the OUT/XOUT registers on the main board). Outputs are MISO, SCLK, and the SPI slave enable lines. With 4 flip-flops we therefore can have 2 SPI slaves. But with the 74174 we have 6 flip-flops or 4 slaves (and with octal 74273 we have 6...).
Note 12: I presume /CS1 and /CS2 are the slave select lines (and not RAM selects). Why do we need the inverted outputs to produce /CS1 and /CS2? Can't the driving software handle that inversion?
-if IOSEL=LOW, exchange A10 to the RAM with the MISO signal. This could be critical but we can say, we read only data
if SCK is HIGH. So we can reduce the path to an AND gatter. [gate? -MvK]
A10_RAM = A10 & (inv)((inv)/IOSEL & MISO)
Note 13: Is that why A10 is having the double function? To avoid glitches? But A10 is not the same as SCK. I admit I need to put more thinking in this area.
Note 14: The MAU (Memory Address Unit) is always active, and so it can be glitchy at the beginning of a memory read cycle. That's also one of the reasons why the /WE signal is OR'ed with the clock: to prevent bad writes into memory. If the Y register contains all-ones (for example because we have just done a far jump high into the program memory), and somewhat later we perform a zero-page memory read, isn't it possible to glitch /IOSEL?
Note 15: Timing wise, this is adding nanoseconds to the critical path of a Gigatron cycle. It's perhaps not an issue for the 55ns RAM that comes with the kit edition. It's more likely to become an issue with the 70ns RAM that the Gigatron was originally designed for. Well, so be it. But your next idea solves that concern:
So OE remains low between two RAM acesses we can do a second ld[y,x] to compensate the longer access time.
Note 16: That's a perfectly valid solution! And also the reason why vCPU can't do it, I get it now. SYS functions are a possible solution indeed. We can also think of integrating it with the video/audio loop.
So You will need an additional RAM, a 74xx30, a 75xx175, a 74xx08 and a 74xx04
Note 17: That was a very high information density description, wow! Thank you so much! I do think I want to prototype this, and also look at the general availability of these IC types. From my understanding, we can go to a 4-slave or 6-slave configuration just as easily. The devil is in the details, and it's clear your have thought them through pretty well!
Note 18: I think I would prefer a decoder for driving the SPI selects, rather than independent address lines. This prevents enabling multiple SPI slaves through an accidental memory access from user code. That will become a short circuit, and that's not great? (Or is the MISO open collector, and this is not a concern?)