• Please review our updated Terms and Rules here

Planning an 8-bit memory card design

Hak Foo

Experienced Member
Joined
Jul 18, 2021
Messages
218
My XT-alike machine (admittedly new build, but the fact it's running a V40 makes it inherently vintage-flavoured) was designed with all the RAM and ROM on a seperate expansion card.

This would be okay, except that it only has 512k + a 32k UMB at F0000. 32K of UMB isn't enough to load DOS high with USE!UMBS (seems to just freeze on boot), and 512K is whittled down to like 450k of usable low memory by the time DOS and the unimaginable luxury of a mouse driver and SETVER is loaded. I want to run GeoWorks 1.2 on it but I can see it swapping furiously when I try.

To fill the gaps, I could order an off-the-shelf 1MB card, like the Montech or Lo-Tech products, but since I'd still need the BIOS ROM somewhere, that wastes a slot just to keep the ROM around. Why not a single board with the full megabyte PLUS a ROM socket at F8000?

Here's the schematic I've been working on so far:

* Use two Alliance AS6C4008s to cover 1Mb

* I can do /SMEMW NAND /SMEMR to get a signal that's high when memory is accessed (either read or write), and AND that with AEN to get to "memory ready"-- we have a good address and actually want to interact with memory.

* I can invert A19 to decide if we're in the low 512K.

* Do "Memory Ready" NAND /A19 to decide if we should chip-select/output-enable the "low 512k " chip. The chip-select and output enable are active low, so it should only come on with both conditions true.

* Use inverted "Memory ready" and /A19 as the two active-low enable signals on a 74154 4-to-16 Multiplexer.

* Use A15-A18 as the four select bits for the 74154. This will drop one of 16 output lines low, corresponding to the 32k range desired.

Here's where it gets interesting:

* The 16th output line can be wired directly to the 32k ROM's chip-select and output-enable.
* The other 15 lines are put through jumpers or DIP switches.
The 15 outputs are AND'd back together with three 7421s, and a +5 (to finish off the last input on the 7421) so if any of them are low, it pushes a signal down that we can use as chip-select/output-enable the "Upper 512K RAM" chip.

This gives 15 user-controllable sections between 504k and 996k that can have the RAM deactivated to fit around peripherals and addon BIOSes.

This all seems to make sense to me in theory, but I suspect there's a lot of knowledge of physical-level behaviour I don't know about. My previous PCB-design projects have been keyboards with canned controllers, so pretty much laying out a fairly naive matrix with negligible timing requirements.

I'm worried about a few things:

1. Performance. The 74LS154 quotes a propagation delay of 35ns, and then you're also going through a couple additional gate delays. Is this likely to push things to slowly for zero-wait-state 8MHz operation?
2. Pullup resistors. Never tried it before-- am I speccing it correctly? see a lot of vague handwavy "anything from 10k to 100k will work" discussions, not sure if that's performance critical, but I suspect it varies by logic family.
3. Anything I missed from an analogue, timing, or missing signals standpoint. I know the spec needs decoupling caps on each chip, but I had a hard time getting either Kicad or EasyEDA to place them sensibly, they always want to tie them back into *some* 5V and ground pin, nowhere near the part being decoupled, so I figure I'll add those in once the schematic is finalized and the footprints are on the PCB.

I know some people have done RAM expansion circuits for XT-class machines here, so hopefully they can see what incredibly ignorant and stupid choices I've made.
[Edit] ... Yes, U5 is missing its ground connection. Somehow I lost the EasyEDA configuration and reverted to a saved copy. I could also eliminate the 7408 entirely by using the second 4-way AND gate in U10, and feeing in +5 for two inputs., but this is hard enough to read as-is. :)
 

Attachments

  • Schematic_1MB Memory Card_2022-05-30(1).png
    Schematic_1MB Memory Card_2022-05-30(1).png
    398.3 KB · Views: 16
Last edited:
I would like to grab a pcb from you for this project if you get to the first prototype stage. :)
 
Can you make the onboard ROM size optionally 64K? 32K isn't enough for the BIOS + BASIC.

Also with regards to UMBs, make sure you are using the CLEAR_UMA option in the BIOS to avoid parity errors.
 
I can do /SMEMW NAND /SMEMR to get a signal that's high when memory is accessed (either read or write), and AND that with AEN to get to "memory ready"-- we have a good address and actually want to interact with memory.

Unless there's something unusual about your ISA bus implementation you shouldn't need to qualify RAM on AEN. Just connecting /MEMR and /MEMW to /OE and /W on the RAM chip works fine, it's how cards like the lo-tech 1MB do it. (I've done the same for the RAM cards I cooked up for my Tandy 1000s. There may in fact be an edge case with gating memory on AEN that breaks DMA.

Do "Memory Ready" NAND /A19 to decide if we should chip-select/output-enable the "low 512k " chip. The chip-select and output enable are active low, so it should only come on with both conditions true.

For the lower 512k you should fine literally just connecting A19 to /CE. Unless you intend to add something like an EMS 4.0 memory card or something that requires large pages below the 640K mark it's probably a reasonable design choice to make all memory below that mark "fixed". So...

Regarding the rest of the design, I guess I'll chuck this out there: If you're open to programmable logic you could simplify this immensely by using a GAL, like an ATF22v10. They're "obsolete" but still in production and can be easily programmed using one of the common TL866 programmers. The 22v10 has 22 I/O lines, 10 of which can be either inputs or outputs, the rest inputs; If you hook up A14 through A19 to the GAL you can get 16K resolution with only six lines; you'll use 3 lines as outputs to enable your ROM and RAM chips (maybe use a 4th to drive a '245 buffer on the data lines in front of the three memory devices, although I don't think that's really strictly necessary with only three devices), and then you'll have 10/11 leftover inputs you could use to read configuration switches. I don't think many people really *need* the ability to punch random holes in their UMBs, so adding a ton of switches to separately enable/disable each page would really add up; you could cut this down to, say four to eight of them, which are simply connected to DIP switch that can pull a given output to ground, and define them "functionally" for common scenarios, like VGA/EGA present (automatically knocks out the 160K of space that VGA uses, otherwise an MDA/CGA switch takes effect) and a few possible start/end scenarios for the main UMB block in the C/D/E pages. This is what I did with the latest version of my Tandy 1000 HX RAM card and it cuts the parts count down to almost nothing. IE, here's the card:

index.php


(Don't mind the jumper wires, those are for some after-the-fact alchemy I got up to.) Outside of the four memory chips (and the serial UART) you'll see there are 7 other chips; two are 74LS670 memory registers used to implement EMS, one is a clock calendar, two are 74245 buffers (one in front of the memory, one for the XT-CF port), and the other two are GALs. One is sitting on the upper address lines and decodes memory, which is the one we care about, the other is on the lower lines and decodes I/O for the serial, disk interface, and EMS registers, therefore doesn't count. So... long and short of it, if you used a GAL you could do this with one IC for the decoder instead of nine.

(FWIW I'd also suggest ditching the EEPROM and use a Microchip SST39SF010A (or 020/040) flash chip. They're dirt cheap. If you set up the socket so address pins higher than A15 are tied to ground you'll have 64K possible of flash that you could use to hold a complete deluxe BIOS loadout with BASIC running from F400-FFFF, and you could also burn the XTIDE BIOS into the first 16K and put it at F000; I did that on my Tandy memory card (after doing some black magic to make that accessible to an add-on card on a Tandy 1000) and the XTIDE BIOS runs fine at that slot. Most XT BIOSes will scan for option ROMs up to the F400 boundary. A setup like this can give you a contiguous 160K UMB from C800 up to EFFF even on a VGA machine, and a whopping 192K with CGA.)

If you'd rather stick with discrete logic I guess my main comment would be maybe you want to ditch that 74LS154 and use something that's actually still in production. I might suggest a pair of 74LS138s. Or... here's an idea to cut down the logic a lot:

1: For the lower 512K, use that idea of using A19 directly as CE.
2: For the upper 512k, use a 74HCT138 1-in-8 decoder; the "active high" enable line G1 will go on A19 so this decoder goes active to cut the top 512k into 8 64K chunks with A16-A18 as input.
3: Use a 74
HCT30 8-input NAND gate like the lo-tech 1MB cards do to collate the memory selects from the '138 for the upper RAM chip. It's annoying it's inverting, but I guess we'll live with that because they don't make an 8-input AND? Because of this we're also going to need a 74HCT04 hex inverter. Don't worry, we're going to use it for other stuff too. Inverted output from '30 is CE for upper RAM chip

Anyway, the output from the '138, let's call them 8 through F. We'll wire them up like so:

4: Wire your ST39 flash ROM's chip enable to the F output. This gives you a fixed 64K of ROM. This is slight overkill, but if you burn the XTIDE BIOS into this at the F000 position you'll win because you'll be able to disable the separate ROM on your storage card.
5: Wire 8 and 9 to the first two inputs of the '30. We don't need switches on these, hardwire it.
6. Outputs A and E go to the '30 through a *jumper*, not a switch. (10K pull-up after the jumper.) These are 64K or bust. Simple 2 position jumper, on or off.

There are four inputs left on the '30. Now we're adding another part, a 74LS32 quad 2-input OR gate

7: Connect '138 output "B" to one '32 gate, connect the other input to on gate to A15. This will give you a signal that's active from B0000 to B7FFF. Allow connection to '30 through jumper/pull-up
8. Connect '138 output "C" to a second '32 gate. Invert A15 using another gate on the 7400, connect this output to the other input on the '32 gate. This will create a signal active for C8000-CFFFF only. Set up the jumpers so *either* the "whole" C-signal or the "upper half-C" signal connects to the '30. (Don't forget the pull-up)
9: For the D page, use the other two gates on the '32 to create separate D0000-D7FFF and D8000-DFFFF signals using A15/the inverted A15 you already created. Set up jumpers so these can be separately connected to the two remaining '30 inputs.


So... there, it's a little clunky but this gives you partial 32K resolution for selecting memory blocks with only four chips. (IE, you can use either the whole, none, or just the top half of C, use or not use the 32K at B0000, and use either half or both of D. E and A are either on or off, which isn't great but it's as good as the lo-tech. And you get extra ROM in F that you can use if you're clever.)
 
Last edited:
… actually, thinking about things if you wanted to be able to split all of the C/D/E pages into 32k chunks you could use either the top, bottom, or both you could do it with to sets of three position jumpers for each ‘32 gate. One jumper would let you pick either “regular” A15 or inverted A15 for the input, and on the output side you could pick either the “full” or “halved” version of the ‘138 output to feed into the ‘30.
 
That's.... mindblowingly comprehensive.

I'm trying the following changes:
* Discard the whole AEN thing
* Write output-enable and write-enable right from /SMEMR and /SMEMW
* Drive the low 512k chip-enable out of A19 directly.
* Replace the 32k NVRAMs with the 128k flash suggested. I'll tie A16 to +5 to only use the top half of it, just because it's a tidier on the schematic. :) I used 28C256s because I had three handy originally, but at the price for the 39SF010A, I may as well buy a bunch and use them instead.



For the top 512k, I've tried to rearrange things based on a pair of 74138s. I still like the concept of 32k granularity. One is enabled by A19 high and A18 low, and the other is enabled by A19 high and inverted-A18 low. The selections are made from A15-A17.

One cheapening option I was considering was to assume Axxxx and Bxxxx are always off, much as 8xxxx, 9xxxx, and Fxxxx are already spoken for. Then you only have six 32k toggles to worry about, but

That gives 16 active-low selections for 32k blocks. I pass four (8000-9800) through directly, and route 10 (A000-E800) through jumpers/DIP switches, into two 7430s. The remaining inputs of the second 7430 are pulled high.

The outputs of the two 7430s are fed into a 7402 NOR gate, so if either one is high, we get the active-low chip-select for the top 512k RAM.
We also invert the two selections for F000 and F800, NOR them and use that as the chip-select for the 64k ROM at F0000.
 

Attachments

  • Schematic_1MB Memory Card_2022-05-31(1).png
    Schematic_1MB Memory Card_2022-05-31(1).png
    584.1 KB · Views: 9
I'll tie A16 to +5 to only use the top half of it, just because it's a tidier on the schematic.

FWIW, the argument for tying the upper address lines low instead of high is (and this is off the top of my head so possibly not entirely accurate) is you’ll need them low if you want the chip to be in-circuit programmable. I believe the magical unlock sequence to put it into write mode pounds on addresses around the 24k mark.
 
Just for laughs I banged out this schematic that illustrates my revised idea for giving you full 32K resolution in the B through E pages with only four chips for your decoding instead of six:


32Kres.png
Basically for each of those pages you have two 2-position jumpers. (Which give you three options; two different closed position and an empty position.) There's one that selects if you want the "whole" page to be RAM, half of it, or none of it, and there's a separate jumper that choses if the "half" is the top half or the bottom half. 8000 and 9000 go straight to the '30 without switches, A000 is a single jumper for all or nothing (which is fine, there's no real justification for splitting it), and F000 would go straight to the flash chip.

Pluses: you save two chips, and for the jumpers all you need is a strip of 0.1" pins and nine of those little plastic jumpers like you find on hard disks, which will be substantially cheaper than a quality 10-position DIP switch.

Minuses: It'll look sort of weird and the jumpers will take up more PCB space.
 
Okay, I think I'm ready to make this idea a questionable reality. I hooked the write-enable line of the ROM back up to /SMEMW and pulled A16 low on the ROM, but otherwise stuck with the plan of two 138s and ten switch-selectable 32k blocks. I then spent entirely too long fighting with EasyEDA's auto-router which desperately wants to put vias between the pins of the bus connector. It cost 20 bucks for ten PCBs from JLCPCB, and another 15 to mail them.

"Real" flash memory is an advantage here, I suppose. The 28C256, I had to remember to write-protect after programming after I discovered I could make a self-corrupting BIOS. :p

I can provide the export of the project if anyone wants to further riff on it, but I'd suggest holding off until I get the boards in hand and discover their huge and obvious faults. :) I know, I should be using KiCAD, it's what the cool kids use, but I've always been impressed what you can do with basically a glorified browser app.

... and I found the first mistake after it's too late to cancel the order. Switched signals going to pins 8 and 10 of the 7402, so the "enable top 512k" is an input to it, and "Some block between 8000 and B000 is selected" is an output. I suppose I can do some ugliness like pulling those two pins out of the socket, and cross-wiring them.

Another alternative: cut off those three pins, and jumper the pads intended for pin 8 to 4, pin 9 to 6, and 10 to 5 to use the other free gate. That might look a little cleaner than pins pried up and loosely wired.
 
Last edited:
Eh dont sweat what you use. I know how to use AutoCAD/Coreldraw, but making pcb'sis a massive learning curve. Nothing is straight forward. So I've been using DipTrace myself, instead. I find it amazing for tracing out old boards.
 
It's here!

(Technically, it was here a few days ago, but I was holding off on building the card until I got in the ZIF socket for the ROM)

Some quick first thoughts on the design:

1. The extra lug on the slot cutout is ugly and pointless. The card "floats in space" and it would probably make sense to lengthen the card to make attaching a mounting bracket easier. I wonder if card sag will be a problem over time. This is why I prefer desktop cases where the slots are perpendicular with the ground.
2. The decoupling capacitor footprints are too large. I wonder if they were intended for flat axial capacitors rather than the usual ceramic blobs.
3. Not sure if "fill available space with ground plane" was a good idea. Card looks nicer, but it does mean a big huge ground plane when you go to solder stuff to it.

I've only put it through basic smoke-testing at this point-- CheckIt and the Test!UMB utility from the USE!UMBS package finds the RAM I expect. I found a lot of frustration not realizing I had to disable RAM at C000 as well as AXXX and BXXX because the video BIOS was in the way.

At the same time, I did have a strange failing. I use the Malinov floppy/serial card, and somehow its BIOS got corrupted during testing. I suspect this was a side-effect of running probing software, since it uses a non-write-protected 28C64 NVRAM, possibly fighting with real memory, and being assaulted by test utilities trying to find RAM. Reflashing the 28C64 fixed it, and I disabled it, since I now have acres of free ROM space at F000 to store that BIOS in.

The ROM map currently looks like:
F0000 - floppy BIOS
F8000 - CH376S "hard disc" BIOS
F9000 - Stub loader in lieu of Cassette BASIC. Grabs 0x5000 bytes at F9100 and moves it down to RAM at 07D00 and then launches it. I've used it to load a rudimentary monitor, and to launch "boot sector" games.
FE000 - XT clone BIOS.

By moving the hard disc BIOS and stub loader down to say, F2000 and F3000, it would open up a much wider window for a loadable payload. Part of me wants to try to make a machine that will boot to 8088 Tetris Attack (https://mindbleach.itch.io/8088-tetris-attack) given that the author has made comments about "now only PCs without video can't run it" while neglecting people without disc drives. :) :) :)

I'm sort of intrigued if something like the Lo-Tech Flash Utility could write to this card, since it is capable of speaking to that model of SST flash chip, and I tried to wire Write Enable. The problem is likely that we have one monolithic ROM now-- you can't leave the main BIOS in flux because a rogue clock-tick or keystroke-handler interrupt could cause a jump to an address currently in flux.

But enough rambling-- pics attached. You can see the marks of shame around the 74HCT02-- three cut pins and fix wires.

front of card.jpgRear of card.jpgcheckit.jpgblank pcb.jpg
(Edit: added blank PCB front shot)

The ZIP file contains two exported files from EasyEDA, which seem to recover the design when re-imported. Their export facilities are sort of weird, being a cloud-first tool. Note that this version has the swapped lines I mentioned earlier fixed. Just because I already bought the PCBs doesn't mean the next person who does has to apply the same bodges.

@twolazy: The MOQ for the PCBs meant I have a few spares. If you'd like a blank PCB-- noting the bodge wires required-- I'm happy to send you a spare. Just send me a padded SASE big enough to hold the PCB (DM me for address). I can also list the parts I ordered to stuff it, but there's not really anything exotic there, aside from personal-taste choices like socket types. I don't know if the exact detailed part numbers on the silkscreen are accurate (they were derived from the parts in the schematic), but I'd expect one DIP-packaged 74HTC30 is pretty much interchangeable with any other.
 

Attachments

  • EasyEDA Exports.zip
    97.3 KB · Views: 6
Last edited:
If interrupts are disabled it should be fine to update the BIOS while the system is running.
 
I suspect the lo-tech flasher disables interrupts, because it potentially would be bad for a number of reasons. (Not only potentially hitting code in the being-flashed area; I think the flash command sequences are at least somewhat timing sensitive.)
 
I'm sort of intrigued if something like the Lo-Tech Flash Utility could write to this card, since it is capable of speaking to that model of SST flash chip
From Revision 620 > of the XUB, XTIDECFG.COM which is used to configure the XUB now supports the flash chips used on the lo-tech cards, But i'm guessing you want to update each stored ROM image in the chip independently ?, Neither the lo-tech flash utility or XTIDECFG can do that.
 
Yeah, the lo-tech flasher does a full blank and replace, so to use it you’ll need to concatenate all your various modules into a single 64k binary every time.

(Tangentially related, someday I’d like to try to convince someone smart enough with BIOS hacking to help me with an idea to modify the BIOS of the Tandy 1000ex and HX to support programming the video chip into the same RAM access configuration as a 1000TX with “768k”. This would let me build a RAM card that replaces all the lower 640k with SRAM and eliminate the “memory stealing”. I already have the hardware worked out to override the onboard BIOS of the HX with ROM on a card…)
 
Last edited:
I don't have a problem with the "Build a 64k binary" part-- I was already doing that with a batch file because it's a hassle to glue three or more seperate files together even with something like XGPro on a big desktop. I was more worried about the possibility of flash failure.

I'm curious how a more modern PC does flash in place. Even if interrupts are nominally off it seems like they'd need a known good version at the end, even if just so they can re-enable the keyboard/screen stuff for "press any key to reboot." Do they shadow to RAM at F0000, and then the actual ROM is mapped somewhere else when being flashed? Or maybe the ROM chip is never mapped to F0000 at all, and there's a "helper" that copies the flash into F0000 before starting the CPU.
 
On a 100% PC-compatible BIOS the entry points for interrupts like timer, keyboard, video (mono/cga), etc are constant. For backwards compatibility with early programs that hard coded stuff they shouldn't have. So all the critical interrupts will still be valid when re-enabled. Modern BIOS flash failures are handled by the "boot block" section, which doesn't normally get updated.

Socket 7 (maybe 5?) and later motherboards usually have a compressed BIOS. So the code that is on the flash chip is not the same as the code that ends up in F000 (which is the runtime only and none of the initial startup/test).
 
Last edited:
I thought I'd swing around this project again. I was unhappy about the PCB requiring bodge wires, and the fact it was both large and didn't really look commercial.

So I tried to reimplement the design I originally built in EasyEDA in KiCAD. I produced a much smaller "v0.25" PCB which looked professional and was manually routed... and didn't work right. I figured it must be my dubious AliExpress ZIF socket, which I destroyed trying to "bypass" by soldering the flash chip directly to the prongs. Still no dice, so I built a second one, and it also didn't work. It would work if you used the old design to provide the ROM, and if I bodged the board to expose the ROM at a lower address space, I could see *something* was going wrong.

Finally, I figured out that in the original design, I had pulled A16 on the ROM low to ensure it repeated at a 64k boundary, but here it was mapped, so it *wanted* to display the lower half of the ROM at E000, but never got the chance, and if I populated the top half of the ROM, it would work. So the v0.25 design *almost* works, but the only one I had was assembled with a normal ROM socket, having exhausted my spare ZIF socket.

My attempt to fix this was to redesign the PCB to pull A16 high, thus baking in the same bug in a different way. This was PCB v0.85. I also fixed a weird footprint choice for the decoupling caps-- they were so small that the caps I had had to be bent in weird ways to fit.

I realized I had bollixed it up before the v0.85 PCBs even arrived, so I decided to go in a new direction. I realized if I *can* have ROM at E000, that might expose new opportunities-- flash-in-place might be easier, and with extra ROM, maybe something like a minimal DOS-in-ROM (a la some of the Tandy 1000 series) would be feasible. So I fiddled around with a design involving a 7425 and making seperate RAM and ROM toggles for the Exxx area Then I started looking into PALs, but discovered the ecosystem consists of "parts that have been discontinued since the USSR was spoken of in the present tense" and "parts out of stock until the Neo-USSR will be spoken of in the present tense".

Finally, I came up with a "ROM all the things" design, basically using a parallel copy of the logic for RAM block select (74138s give us 16 block-level selects, then route the ones we actually map to ROM through 7430s and a 7402 to combine into a single chip select)

I redesigned the board so it can theory support a 39SF010, 020, or 040. Only the 010 is tested. The relevant high bit are wired up, although most are NC on an 010. Each 32k block from 512k to 1M can be mapped to the ROM, RAM, or neither. Now you can turn off the ROM at F000 for an extra 32K of UMBs, or bring in more ROM in the Exxxx range. I used FreeRouting to do the heavy lifting, so it's far less pretty than the manual-routing redesigns, but obviously more flexible.

Theoretically, with a 39SF040 and CGA or MDA video, you could make an absurd build with 512K of RAM and 448k of scattered additional ROM, leaving out only the necessary video segment at B0000 or B8000 and obviously demanding F8000 for BIOS ROM. It would need some software doing heavy lifting to glue it together, of course.

If anyone's interested in the KiCAD project files or the Gerbers, let me know.

A photo of the evolution:

IMG_20230618_225457.jpg
 
Back
Top