• Please review our updated Terms and Rules here

PET ROM/RAM replacement board

Thanks for the links. The first one is quite a bit cheaper than the SRAM I'm using now, so I may pick up a few of these.
Further progress has been made -
I finished wiring up the MCU to the main RAM. I loaded the mapping RAM with a pattern which enables the SRAM and isolates the bus when the address corresponds to a RAM read/write or a read/write to ROM address A000-AFFF. For testing, I am loading some data into the SRAM in this rom segment, and although I think I have a bad address line connection somewhere, it is working!
Next is to track down the glitch, and then load a full set of ROMs into memory, and replace the full ROM map from the main PET board.
 
I loaded the mapping RAM with a pattern which enables the SRAM and isolates the bus when the address corresponds to a RAM read/write or a read/write to ROM address A000-AFFF. For testing, I am loading some data into the SRAM in this rom segment, and although I think I have a bad address line connection somewhere, it is working!
Next is to track down the glitch, and then load a full set of ROMs into memory, and replace the full ROM map from the main PET board.

That's cool that it appears to be working. If it turns out the trick does work reliably I have this harebrained idea about using a similar "mapping RAM" arrangement for adding EMS-style expansion memory into the unusued ROM spaces that would be fun for someone competent at actually building this sort of stuff to try. ;^)

(Of course, the number of people actively programming the PET who'd use such a thing is probably numbered in the... aughts, but the idea could be more generally applied to 8-bit single board computers.)
 
So far the mapping RAM is working well - I managed to replace the screen editor ROM space with a ROM image loaded into memory. Changed some characters in the 'COMMODORE BASIC' string to confirm, and indeed my computer now says 'CODDODORE BASIC' :)
You should be able to use the unused ROM space as memory - in fact I tried poking some values into the 0x9000 ROM space and it worked. Haven't yet write protected the ROM area.
It would be great if this board was useful to other 6502 computers as well..
 
You should be able to use the unused ROM space as memory - in fact I tried poking some values into the 0x9000 ROM space and it worked. Haven't yet write protected the ROM area.
It would be great if this board was useful to other 6502 computers as well..

Cool.

Basically the idea I had for "EMS" goes something like this... For a given page of memory, in addition (or instead of) using the Mapping RAM chip to provide chip enable signals you directly tie its data outputs to the upper address lines of your bulk memory chip, so the byte stored in there will act as a page offset.

For instance, spitballing here: Let's say you're using a 512Kbyte chip for your bulk storage, of which in normal circumstances you're wasting a lot of in a PET memory board because best (worst?)-case you're only using 64k. We also have an 8 bit wide mapper chip, but we're only using, say, 2 bits, already, one for the bus isolator enable/disable and another for write protect. What we *could* do is tie three of the remaining data bits to the unused upper address lines of the bulk storage chip. Doing so would divide the entire chip into 8 "zones", and then by changing the byte stored in the mapping RAM you can choose which "zone" is actually mapped to the CPU. *IF* the design of the board were adjusted to allow messages to be passed from programs running on the 6502 to the onboard MCU to halt the CPU and write new bytes to the mapper RAM then in theory you could for a given address select one of eight different pages of memory. This would mean, for instance, that the 8K of unused space under BASIC 4.0 could hold a total of 64k of write-protect-able RAM. (And there's no reason in this situation that you couldn't do this mapping in the lower 32k of space as well, or for a machine language program temporarily swap out parts of ROM. If you were really terribly clever you could patch the interrupt handling routine to swap ROM in and out as needed for keyboard scanning, etc.)

The one drawback of the very simple version I lay out above is the memory mapping is pretty simplistic: A given area of RAM can only be swapped for eight other areas and you can't rearrange pages. A more advanced version might let you use other mapping RAM bits (we have three left over in this case) as "segment offsets", where the contents of them is added or subtracted from CPU-supplied physical address, at least for certain areas in the address space. (Again, I get fuzzy on this part. Combine the mapping RAM output with the CPU address bus with XOR gates or something?) Undoubtedly that would be more than somewhat confusing because the combination of the CPU bus addresses plus the offset addresses would require some non-linear thinking and not every combination of real vs. virtual address would necessarily make sense. But, hey, everyone loves segment arithmetic, right?
 
Like the idea of the EMS page swapping - I'll have to study this a bit more to make sure I fully understand. But as you said, we're only using 2 data lines from the mapping RAM at the moment, and the others of those could be used to toggle address pins on the main RAM. However, the MCU is just about out of free IO pins, which makes it hard to load that data into the mapping RAM, I'm currently using 31 of 32 IO pins when you include RX/TX on the UART.

Now I've gotten the full RAM/ROM replacement working! Have not implemented ROM write-protect yet, but I was able to load a full ROM set into the SRAM, and start up a 2001 board with no ROMS and only 8k ram as a functioning 32k system. Yippee!
IMG_0817.jpg

I would like to try booting with BASIC 4 - does anyone know what ROMs would be used in a BASIC 4 setup on a non-CRTC 2001 PET?
 
Like the idea of the EMS page swapping - I'll have to study this a bit more to make sure I fully understand. But as you said, we're only using 2 data lines from the mapping RAM at the moment, and the others of those could be used to toggle address pins on the main RAM. However, the MCU is just about out of free IO pins, which makes it hard to load that data into the mapping RAM, I'm currently using 31 of 32 IO pins when you include RX/TX on the UART.

I was worried about pin count myself (the issue could certainly be solved with a multiplexer, but that's more parts), and I'm also wondering how one might implement a message-passing communication channel between the 6502 and the MCU. But assuming those are solvable problems the idea has a certain twisted appeal.

(If there's good documentation for how the extended memory in an 8096-style machine works it would be interesting to see if there were some way to cheaply emulate that with this technique plus a minimum of additional parts.)

Now I've gotten the full RAM/ROM replacement working! Have not implemented ROM write-protect yet, but I was able to load a full ROM set into the SRAM, and start up a 2001 board with no ROMS and only 8k ram as a functioning 32k system. Yippee!

Awesome. Now if we could just come up with a super-simplistic method of implementing a PET-style video display we're at least halfway to a complete single-board new-age PET. ;^)

I would like to try booting with BASIC 4 - does anyone know what ROMs would be used in a BASIC 4 setup on a non-CRTC 2001 PET?

http://www.zimmers.net/anonftp/pub/cbm/firmware/computers/pet/index.html

You should be able to use the three files named "basic-4-x000...", plus "kernal-4.901465-22.bin" and "edit-4-n.901447-29.bin". That's what I used for a burned BASIC 4.0 set.
 
Here's a head-hurter...

Here's a head-hurter...

A more advanced version might let you use other mapping RAM bits (we have three left over in this case) as "segment offsets", where the contents of them is added or subtracted from CPU-supplied physical address, at least for certain areas in the address space. (Again, I get fuzzy on this part. Combine the mapping RAM output with the CPU address bus with XOR gates or something?)

You know, I was thinking about this a little more, and scratching it out on a piece of paper convinces me that you could in theory access every scrap of memory in a 512Kbyte RAM chip inside of an 8K address window by using six bits on a mapper chip, set up as follows:

Three bits -> A16 through A18. (Or address line 17 through 19, whichever is less confusing.)

Other three bits -> Combine outputs via a 7486 XOR gate with A13 - A15 on the CPU bus.

The first part is easy: Setting the high address line bits selects which of eight 64K pages the CPU is mapping to for that byte/area. (Whether it's a "byte" or an "area" depends on the resolution you're using for the mapper.) The next part is confusing, so let's use a hypothetical example based on the following: You've installed this in a PET, you want to run BASIC 4.0 leaving an 8K area open in the form of two empty 4K ROM slots, &9000 and &A000, and you want to access as much RAM as possible inside that 8K area, leaving the ROMs and lower RAM spaces alone. So let's imagine how this will work.

For normal operation in booting up the PET we'll set up the mapper so everywhere in memory, IE, the ROM images and system RAM, is either coming from physical 64K page 0 or from the hardware RAM/ROM on the PET motherboard itself. So all the memory-mapping related bits are set to output "0" (And buffer/write protect bits are set appropriately as well). We also set it up so we have 8K of R/W RAM in &9000 and &A000. But... 8K isn't enough. Okay, easy enough, we'll bank switch it with the physical page bits. We got 8K worth of RAM when we had the "direct address" line bits set 000, if we want a different 8K all we need to do is set those bits to 001, 010, etc. That gives us 64K possible. But we want MOAR!

So... first off, we switch those areas to the second bank, physical address page bits to 001, to make sure we don't trod on anything vital in the zero page. Then we start playing with the three masking bits.

In binary the addresses for the start of each of our "EMS" slots is this:

1001.0000.0000.0000
1010.0000.0000.0000

Throw away everything but the first nibble (that's all tied straight through), leaving us with:

1001
1010

The last bit is also sourced directly from the CPU bus, so we can't change it, But we can mask all the others. Remember with the XOR gate we can negate anything that's set on the top three bits of the address bus. Which means, essentially, for a given address supplied by the CPU by setting or negating top three address lines you multiply the amount of memory you can reach with that address by eight. If you can supply a 4K window you can have 32K. *AND*, remember of course, you have eight pages, meaning in total you could access 256Kbytes of RAM within the address space occupied by a single ROM chip. And of course an 8K window lets you hit the entirety of a 64K physical page... and you have eight pages, giving you a grand total of 512K.

(It might be better in practice, however, to limit the maximum "EMS" memory in this scheme is 448K, saving the zero physical page for things you don't want touched in strange ways. If the MCU were setting the mapping bits rather than the 6502 writing bytes to the mapping RAM itself you could in theory even implement "memory protection" on the MCU by having it sanity check mapping requests. Actually, even better, if the MCU were accepting remap messages from the 6502 you could phrase them in a high-level manner. IE, instead of having to have the user calculate the raw mapping bit masks needed to access all the expanded RAM you could have the MCU handle the calculations and just number the pages arbitrarily, leaving it to the PET programmer to just say "I want page X of Y mapped to window Z, thank you".)

The still confusing part to remember is that by setting the appropriate mask bits within a 64K window the &9000 page will be able to access *every other 4K window of addresses*, while the &A000 page can access the opposite set of addresses, meaning the one thing you can't do is write to a page of memory mapped to the &9000 window and then read it back from the &A000 window. They're two separate address spaces. (The &9000 page will with the appropriate masking be able to hit &1000, &3000, etc, because A12 is "stuck on", while &A000 can reach &0000, &2000, etc. If we could do an 8K linear window *on an 8K boundary* then some of the confusion goes away. The problem with the &9000+&A000 example is it essentially induces an address line flip. Which can certainly be worked around, but should be called out.) The one thing you can't do is directly copy memory from one page (either direct or masked) in memory to the same location in another page within in the same window. To do that completely without compromise you'd have to be willing to allocate a total of 16K to remap windows. Which might be doable (There's nothing to say you couldn't borrow another 8K window somewhere as long as you took the proper precautions.)

Anyway, I guess I wasn't kidding when I said "segment arithmetic". This is almost weird enough to qualify as something out of an x86 programming manual. But it's lotsa RAM with almost no hardware! ;^b

(Of course, this was "back of the napkin" thinking, so I could of gotten something wrong. My boolean algebra's a little rusty.)
 
Last edited:
My hat is off to you for this mighty post, I haven't had a chance to read thoroughly but I'll need to sit down with it and a coffee to make sure I understand! I will let you know when I've gotten the chance to do this. :)
Just a quick note to say that I succeeded in getting the PET to load with a full set of BASIC 4.0 ROMs loaded into SRAM.

Now my thoughts turn to the process of loading/updating ROM images on the microcontroller..
I'm starting to wonder if having the SD card is necessary at all on this board. Since there will already be a serial port on the board for debugging purposes, there could just be a serial bootloader which can accept firmware updates complete with ROM and mapping configurations. I'm thinking the board could have an 'update mode' selected by a dip switch or jumper, during which it would wait for an update from the serial port.
Just thinking here but it seems like this would be a simpler design with fewer parts.
Especially if we use an MCU with plenty of program memory like the ATmega1284, that has 128k of memory. You could have several ROM alternatives in the flash, selectable by jumper/switch, and new updates available over serial.
Thoughts/comments?
 
My hat is off to you for this mighty post, I haven't had a chance to read thoroughly but I'll need to sit down with it and a coffee to make sure I understand! I will let you know when I've gotten the chance to do this. :)

*snicker* I could probably draw a diagram or two if pressed, but I guess it's not that bad really, assuming you can think of a method for programming all 8 data bits on the mapping RAM.

(The three bits that go to the otherwise-unused top three address lines on a 512Kbyte SRAM are pretty self-explanatory, as they directly act as an eight-value "bank selector" within the 8-times-larger-than 64K chip. The other three data bits, XOR'ed with the top three CPU address lines, then allow you to offset the physical address supplied by the CPU to any of eight 8Kb windows within the 64K address space simply by supplying the correct bitmask.)

From an implementation standpoint I imagine you'd want to make sure the XOR-ing is only done in front of the bulk RAM storage chip. I suppose in *theory* you could apply it to the whole bus, which could let you do really horrific things like virtually remap where video memory or the I/O addresses reside, but the relatively crude 8K granularity doesn't make it sound that attractive to me, at least for the PET. I could see the use of something like it in, say, a TRS-80 Model I/III, where swapping out ROM and moving video to the top of the address space instead of the 15K boundary could make the machine nominally CP/M compatible.

And there's still that issue about providing a message-passing protocol so memory can be swapped on the fly. Perhaps it would be possible without additional hardware to define a RAM memory location that the MCU could regularly read (by stealing some cycles) to "snoop" for messages written there by the 6502?
 
Last edited:
If it's just address window panning you're after, you could do this with a simple V series GAL. Alternatively if you want a challenge, you could also lay down a couple quad or hex flip-flops and build the holding register out of discrete logic.
 
Got the write-protect working for the ROM space. It looks like I can do it using only one pin from the mapping RAM. The one signal toggles both the '245 and the SRAM, it's connected to /E on the '245 and CS2 (active high) on the SRAM. R/W from the CPU is one of the address lines going into the mapping RAM, so for addresses in ROM space with R/W low (a write) the SRAM is disabled and the '245 enabled, so a write to ROM space just goes out to the main PET board, where it does nothing.
This saves one pin on the MCU so now there are 2 free pins.. one of them will be used for the RDY signal to the CPU, to halt it when needed. The other I was planning to use for a switch to select different ROM images.
My breadboard is getting insane now so I may transfer what I have to a schematic and have a couple of test PCBs made. I'll leave some headers open so continuing development can be done from this board.
 
Thanks Dave.

I added the basic debugging capability to the circuit. Connected RDY to the microcontroller, and triggered a halt of the CPU when a character was received through the serial port. Since the 6502 holds the address lines when halted, I added a pair of 74LS541 8-input buffers between the address lines coming from the 6502 to the SRAM. After RDY is lowered, these buffers are put into tri-state to allow the MCU to drive the address lines and read from SRAM. By doing this I can now halt the CPU, and dump out any location in memory through the serial port.
Currently working on the schematic and PCB layout for this version. Hope to have a first rev board shortly..
 
By doing this I can now halt the CPU, and dump out any location in memory through the serial port.

This will be a great troubleshooting aid. When the Ready line is released, does the PET cursor blinking resume i.e, does the PET come back to life or is a RESET necessary?
-Dave
 
Hey Dave,

The blinking cursor comes back after releasing the Ready line. I wrote a small program which repeatedly pokes changing values into memory and prints them out, and while it was running I triggered the debug mode several times and sent out the value at that address over the serial port. The value reported over the serial port matched what was on the screen, so I was convinced. So far no issues about halting and releasing the CPU. I'll check further when I get the new boards in.
For video RAM, I'm hoping to enable a write-through mode so when the CPU is writing to video ram, it is also writing to the SRAM on the board, and the values can be read through the serial port. I will need to rework the software a bit to do this as I ran out of pins on the MCU to control everything, including the mapping RAM, SRAM, address buffers, and data bus driver. To save a pin on the MCU I'm planning to just ground the chip select on the mapping RAM (which was previously controlled by the MCU) and do some trickery to first write the ROM images to SRAM while lowering /WE on the mapping ram, then write the address decoding bits to mapping RAM. Since the mapping RAM is directly connected to /WE on the SRAM, if the output is enabled at the wrong time it would cause garbage to be loaded into SRAM. Hopefully the trick of lowering /WE to silence the mapping ram, then writing after will work to save a pin. This will be connected to CS on the SRAM and a data pin on the mapping RAM, so I can selectively enable the SRAM if there is a write to the video space. I did a quick check of this and it seemed to work fine, so hopefully we can have a pseudo-terminal mode where you can use the serial port instead of or in addition to the CRT.
 
The boards have arrived, and I'll be building and testing one of them tonight. I'm tentatively calling it the "PETvet" in honor of its potential diagnostic/healing powers. Stay tuned for further updates.
 
First look at PETvet board

First look at PETvet board

It's alive! I put together one of the boards last night, and with a few adjustments it is working. I made a mistake on the transmit/receive lines going into the RS232 driver and reversed the two by accident, but added a wire jumper to fix it.
Everything seems to be working - I can boot my PET 2001 to either basic 2 or 4, selectable by jumper, and I can dump the memory over a serial port. Still to do is a serial bootloader to update the MCU's code over a serial port, for loading custom ROM images and such.
Here's a video of the PETvet in action.. enjoy!
 
Back
Top