When I found out about the Gigatron, I knew I had to build one. I ordered a Budgetronics kit and received it a couple weeks later. In the meantime I read a lot from the forums, found out the sad story of Marcel's passing, as well as his latest work. This is when I decided to build a 128K extension the way he meant. Here is my gigatron with its extension:
It indeed has 128KB
The extension card has a header to directly plug a cheap SD breakout. As promised by Marcel, the devrom can indeed boot "system.gt1" from the SD card. Small programs such as HelloWorld work fine. Large programs do not. This was work in progress I believe.
Finally if you look at my extension board, you might find that it is smallish and seems to lack components. Well I cheated! They're on the back and they're very small thanks to the JLCPCB SMT service. I got 5 boards for $25. But my board has a bug and needs a jumper. On the other hand I found amusing to have a vintage front and a modern back. I have more ideas to make it better. To be shared later.
Front:
Back:
If only my Pluggy was working (well it worked for 24 hours, then something gave, maybe the keyboard in fact.)
- Leon
New Gigatron with 128K expansion. Boots from SD!
Forum rules
Use this forum to show off your build photos. For build issues, please consult the directions in the sticky post on top instead.
Use this forum to show off your build photos. For build issues, please consult the directions in the sticky post on top instead.
Re: New Gigatron with 128K expansion. Boots from SD!
Nice work! We were just talking about whether anyone was going to pick this up again on the Discord today!
Re: New Gigatron with 128K expansion. Boots from SD!
Looks awesome, there's still some work that needs to be done on the software side, (which I am sure you have noticed), there are some bugs, pruning that needs to be done and missing features...would be fantastic if someone was to take up that mantle...*wink wink*
Re: New Gigatron with 128K expansion. Boots from SD!
Well, I thought about the software and I realized that the main problem is the occupancy of page zero locations. Both the native and virtual instruction sets are super dependent on page zero variables. Thanks to CALLI, we could write service routines and hide them in page 3. But they will still need a lot of locations in page zero, sure to conflict with other programs. That looked hopeless.
Then I realized that the solution would be to also bank the second half of the page zero. At the moment, the banking bits B0 and B1 affect only the cpu addresses 0x8000-0xffff. The idea is to logically swap the regions 0x0080-0x00ff and 0x8080-0x80ff. This means that the banking bits now affect the memory ranges 0x0080-0x00ff, 0x8000-0x807f, and 0x8100-0xffff. The consequence is that programs that hide in bank 2 or 3 can have their own private zero page variables in 0x0080-0x00ff. Meanwhile they can also rely on a non banked region for jump vectors in 0x8080-x80ff. I would find amusing to let the GTOS entry point be CALLI 0x8080.
Since there are also bugs in my initial expansion design --I need a jumper wire in the back and some timings are a bit tight,-- I've decided to design another one that is able to do zeropage banking. I get rid of SPI2 and SPI3 and I repurpose /SS2 and /SS3 as /SPOL and /ZPBANK instead. The first one /SPOL is to enable the other three SPI modes. The second one /ZPBANK decides whether zero page banking is active or not. Because that demands a little bit more logic, my new design relies on a GAL22V10 (Atmel still makes one). A staples of the eighties. So the top side has the memory chip and the gal. The bottom side has a 74hct244 and 74hct273, plus a bunch of diodes to properly merge the MISO0/MISO1 lines with a 3.3v pullup (something my current card already does). All this still fits in a roughly 5cm by 5cm board.
I am spending way too much time on this project.....
Then I realized that the solution would be to also bank the second half of the page zero. At the moment, the banking bits B0 and B1 affect only the cpu addresses 0x8000-0xffff. The idea is to logically swap the regions 0x0080-0x00ff and 0x8080-0x80ff. This means that the banking bits now affect the memory ranges 0x0080-0x00ff, 0x8000-0x807f, and 0x8100-0xffff. The consequence is that programs that hide in bank 2 or 3 can have their own private zero page variables in 0x0080-0x00ff. Meanwhile they can also rely on a non banked region for jump vectors in 0x8080-x80ff. I would find amusing to let the GTOS entry point be CALLI 0x8080.
Since there are also bugs in my initial expansion design --I need a jumper wire in the back and some timings are a bit tight,-- I've decided to design another one that is able to do zeropage banking. I get rid of SPI2 and SPI3 and I repurpose /SS2 and /SS3 as /SPOL and /ZPBANK instead. The first one /SPOL is to enable the other three SPI modes. The second one /ZPBANK decides whether zero page banking is active or not. Because that demands a little bit more logic, my new design relies on a GAL22V10 (Atmel still makes one). A staples of the eighties. So the top side has the memory chip and the gal. The bottom side has a 74hct244 and 74hct273, plus a bunch of diodes to properly merge the MISO0/MISO1 lines with a 3.3v pullup (something my current card already does). All this still fits in a roughly 5cm by 5cm board.
I am spending way too much time on this project.....
Re: New Gigatron with 128K expansion. Boots from SD!
If you want to retain 100% software compatibility you are left with only 2 choices as far as I can tell.lb3361 wrote: ↑18 Feb 2021, 05:18 Well, I thought about the software and I realized that the main problem is the occupancy of page zero locations. Both the native and virtual instruction sets are super dependent on page zero variables. Thanks to CALLI, we could write service routines and hide them in page 3. But they will still need a lot of locations in page zero, sure to conflict with other programs. That looked hopeless.
1) Hide the SDCard routines in bank switched RAM and page them in or out as needed.
2) Build a system that is able to expunge itself as the loading process commences, (which is what the current SDCard loading mechanism across Pluggy Reloaded does), it does this by cheating and calling the inbuilt Arduino Loader.
There is no *safe* memory where you can hide any code, data or even a single byte, (see *Note 1*). Every single byte on the Gigatron is fair game and is used by different coding environments and build systems, i.e. you cannot hide code/data in any of the following:
- 02XX, 03XX ... 0x6XX
- offscreen video regions 0x08A0 ... 0x7FA0
- any of *high* memory, i.e. 0x8000 ... 0xFFFF
- in zero page as the reset routine uses 0x30 to 0x44 for variables and 0xC0 to 0xFF for code at startup, also some legacy apps like Tetronis, Bricks and Frogstroll statically allocate call vectors in zero page, (initially they broke when the new reset system described here was added, but they were then modified to avoid allocating static data in the 0x30-0x44 and 0xC0-0xFF areas).
- screen memory as apps use the Loader to directly load statically defined data, (images, text, etc), directly into screen memory. Some apps even disable onscreen memory, (PucMon for example disables a couple of top and bottom scan-lines so that the free'd RAM becomes available for extra code and data).
*Note 1*: The only completely untouched pristine area of RAM is the three scanline of 160 bytes worth of onscreen memory starting at 0x5900, this is where Loader lives when it is loading an app over the Arduino interface, so if you are not going to be calling Loader, then you have 3x160 bytes of available onscreen RAM to use as you see fit. Apps are guaranteed to avoid this area completely and when loading full screen images will statically load around this area and then fill in the blanks after the Loader has finished it's job and the app has been launched.
As long the vCPU code has not touched the stack this should work, if you bank switch in the middle of vCPU code and you don't copy the stack across, the vCPU code is going to lala land on it's next POP-RET or stack access instruction.
I've spent thousands of hours coding and tinkering on the Gigatron over the last nearly 3 years, massive fun.
Last edited by at67 on 18 Feb 2021, 08:52, edited 1 time in total.
Re: New Gigatron with 128K expansion. Boots from SD!
Nice to see this. Although I think putting SMD there is a bit cheating with the whole retro concept, I like how you've hidden that from view
Btw that's a nice DIP40 socket you have in there.
Btw that's a nice DIP40 socket you have in there.
Re: New Gigatron with 128K expansion. Boots from SD!
The compact ZIF DIP40 socket is <https://www.digikey.com/en/products/det ... 6-10/20463>.
BTW, the forum software does not let me reply to private messages yet...
BTW, the forum software does not let me reply to private messages yet...
Re: New Gigatron with 128K expansion. Boots from SD!
To me this looks like the most reasonable option because, as you explain, all bytes in the first 32KB are accounted for, and because a gigatron that boots from a SD card must have one of these expansion boards so far. But even that is not enough. Although we can hide the code in bank 3, we cannot hide the zero page variables it relies on. This is why I believe that one should also bank a part of the zero page in order to provide a safe space for those variables.
This means a more complex expansion board. I followed several ideas. Keep in mind that I am a complete amateur. I thought of using a XC95xx CPLD. Although this could be a learning experience for me, it is a pity to rely on a device that can almost contain the whole Gigatron. I had a design with one GAL, one '244, and one '273, and, crucially, an address decoder made with a big wired OR that would either be too slow or too power-hungry. Now I have a retro-design (no SMT and zero vias) with two GALs and one '244 on a 80x50mm board. This does not look too bad, but the talking between the two GALs costs me another 10 to 15 nanoseconds...
- L.
Re: New Gigatron with 128K expansion. Boots from SD!
Would it be possible to do this completely in software, (obviously apart from the bank switching)? My idea is that native code doesn't give two cahoots about where it's vCPU context lives, i.e. you could switch RAM banks while native code was running and as long as you weren't trying to output the video stream and as long as the vCPU context was still valid, everything should work fine:lb3361 wrote: ↑21 Feb 2021, 22:10 To me this looks like the most reasonable option because, as you explain, all bytes in the first 32KB are accounted for, and because a Gigatron that boots from a SD card must have one of these expansion boards so far. But even that is not enough. Although we can hide the code in bank 3, we cannot hide the zero page variables it relies on. This is why I believe that one should also bank a part of the zero page in order to provide a safe space for those variables.
Process that occurs for a SDCard access whilst running from RAM bank 0, this assumes that there are three banks 0 to 3 in a 128K RAM expansion?
1) SDCard access is initiated, so wait for VBlank, call a native Sys function that copies page zero from bank 0 to page zero in bank 3.
2) Load vCPU SDCard reader/utils from ROM into bank 3 RAM, facilities for this are already built into the ROM's.
3) Execute the SDCard reader vCPU code that is now residing in RAM bank 3, (the issue here is that once the video stream needs to commence, you need to switch back to ram bank 0, (or have a full copy of video RAM in bank 3, or not care what is contained in the bank 3 mirror of video RAM).
4) If you don't have a copy of video RAM in bank 3, you would need to switch back to bank 0 at the end of VBlank, this would slow down your SDCard reader drastically as it could only get work done during VBlanks, (a much more complicated system could be setup that bank switches during non video/audio/io bit banging, i.e. horizontal blanks, but I fear that would require major ROM modifications to the ROM bit-banging code.
5) If you don't care that during SDCard reading/accesses that your video stream is not the same as bank 0's video stream, then you could fill the bank 3 mirror of bank 0 video ram with whatever values you like, (lets say an empty blue background that matches the default Gigatron blue background), as the monitor only requires valid sync signals, the video stream itself is purely for user feedback and is inconsequential to the actual functioning of the SDCard, (it might not be a great user experience, but it should work). You could make it look like upon starting the SDCard menu option in bank 0, the screen instantly clears, (as it bank-switches to bank 3 initialised video ram), and then run the SDCard code outputting results to bank 3 video RAM.
6) Whenever the SDCard code needs to copy code from the SDCard buffer in bank 3 to bank 0, it can do a simple bank switch for that copy, even if that copy is as granular as a byte, as long as the copying is done by native code, (i.e. a Sys function in ROM), then you don't have to worry about what RAM is currently enabled, or what the vCPU interpreter context currently is or when/what the video bit-banging is about to do; the native sys function is guaranteed to be processed outside of vCPU processing and outside of video bit-banging, (that's the way that native Sys calls work, i.e. Sys calls can never cause race conditions with vCPU code or the bit-banging code).
TLDR: or a simpler summary of what I am trying to say:
0) Initialise bank 3 mirror of video ram, (only on reboot).
1) vCPU SDCard code lives in ROM.
2) native bank switching code lives in ROM.
3) Bank switch from bank 0 to bank 3 when SDCard code is started and VBlank has commenced, (trivial to do in a ROMv5a/DEVROM VBlank interrupt).
4) Copy page zero in it's entirety from bank 0 to bank 3, this requires a trivial ROM Sys function addition and no modifications to internal ROM architecture.
5) Launch, (using the current vCPU from ROM launcher), ROM SDCard code into bank 3, (now with it's own valid page zero).
6) Each time bank 3 SDCard code wants to write a byte from SDCard to page 0, then bank switch to page zero and copy that byte through vAC or vTMP, this is another native Sys function that is trivial to add to the ROM, (but maybe not so trivial to write).
7) Once done copying, switch back to page 0 and execute the code through the normal execution process built into the current ROM.
P.S. This would necessitate a 160x120 mirror of video ram in bank 3 that would need to be fenced off from user applications, as it's sole purpose is to provide a glitch free user experience, (it could also be used for some other pretty nifty built in features, like double buffering or a copy/swap buffer for better native software sprites etc), so cordoning it off from the rest of the system and user may allow it to be used for advanced future possibilities.
Re: New Gigatron with 128K expansion. Boots from SD!
Just to be clear: Marcel designs always gives you bank 0 in the low memory 0x0000-0x7ffff. The video buffer leaves there. The bank bits B[1..0] select what you see in the high memory 0x8000-0xffff. If B[1..0]=0, then you have a copy of the low memory in high memory, like a 32KB Gigatron. If B[1..0]=1, which is what the rom does by default, then it looks like a 64KB Gigatron. Switching to bank 2 or bank 3 does not fundamentally change how the video is generated. Everything works, except that what appears in 0x8000-0xffff is changed.
The idea is to have the os assume total ownership of bank 3 for its codes, buffers, variables, etc.
So the boot process could work as follows
1- load a preloader that switches to bank 3, load the real os, and call its initialization routine.
2- the os installs an entry point in a non banked area and switches back to bank 1.
3- any program can call os services (console management, file management, file reading or writing) by calling the entry point with CALLI.
4- programs that don't do so can override the entry code and nothing bad happens since they don't use it.
5- program loading consists of opening a file, making it current, installing a small code that processes the gt1 data by repeatedly calling the ReadByteFromCurrentFile os service. This can live where the loader currently lives, with a private copy of the jumping code to make sure that nothing bad happens if the gt1 file overwrites it.
The entry code essentially, (1) saves the current bank, (2) switches to bank 3, (3) maybe saves VSPH, (4) calls the proper routine, (5) maybe restores VSPH, (6) restores the original bank, and (7) returns. Now the remaining problem is that the os code needs zero page variables. Let's say 64 bytes. Swapping 64 zp bytes takes at least 128 clock cycles, that is almost a full scanline. This has to be done on entry and exit. This cost prevents us to have small grain services such as reading one byte from the current file. This is doable, but clumsy and slow.
Suppose now that switching to bank 3 switches a part of the zero page, say 0x80-0xff that is not touched by the main gigatron loop. That solves the problem. Suppose also that the 0x8080-0x80ff area always shows bank 0. That gives a place where to put the jump code that is accessible from every bank. Meanwhile programs that don't use these services can remain happily ignorant of all this. They can even overwrite the entry point since they are not using it. They just see a 64KB Gigatron. If they start to use banking, then that is another story....
- L.
The idea is to have the os assume total ownership of bank 3 for its codes, buffers, variables, etc.
So the boot process could work as follows
1- load a preloader that switches to bank 3, load the real os, and call its initialization routine.
2- the os installs an entry point in a non banked area and switches back to bank 1.
3- any program can call os services (console management, file management, file reading or writing) by calling the entry point with CALLI.
4- programs that don't do so can override the entry code and nothing bad happens since they don't use it.
5- program loading consists of opening a file, making it current, installing a small code that processes the gt1 data by repeatedly calling the ReadByteFromCurrentFile os service. This can live where the loader currently lives, with a private copy of the jumping code to make sure that nothing bad happens if the gt1 file overwrites it.
The entry code essentially, (1) saves the current bank, (2) switches to bank 3, (3) maybe saves VSPH, (4) calls the proper routine, (5) maybe restores VSPH, (6) restores the original bank, and (7) returns. Now the remaining problem is that the os code needs zero page variables. Let's say 64 bytes. Swapping 64 zp bytes takes at least 128 clock cycles, that is almost a full scanline. This has to be done on entry and exit. This cost prevents us to have small grain services such as reading one byte from the current file. This is doable, but clumsy and slow.
Suppose now that switching to bank 3 switches a part of the zero page, say 0x80-0xff that is not touched by the main gigatron loop. That solves the problem. Suppose also that the 0x8080-0x80ff area always shows bank 0. That gives a place where to put the jump code that is accessible from every bank. Meanwhile programs that don't use these services can remain happily ignorant of all this. They can even overwrite the entry point since they are not using it. They just see a 64KB Gigatron. If they start to use banking, then that is another story....
- L.