Page 1 of 1

Building a 0 chip cartridge

Posted: Wed Feb 26, 2020 9:25 am
by krzysiobal
I have an evil and completely useless idea (just a proof of concept that this can be done) of making a cartridge that has 0 chips, only discrete elements (like resistors, diodes, probably transistors will be needed to). Let's assume that the "project" will be run on Famicom (or oter 100% compatible famiclone).

By wiring CIRAM-/CE to GND and CIRAM-A10 to PPU-A13 we can use the console's internal video RAM can be used as both nametable and pattern table.

Next step is to use internal CPU RAM as the place where code would be executed from. That gives only 2048 bytes of space (minus the amount of cells used for variables), but I believe this should be enough for a simple game or demo. Of course the code first need to be copied to the RAM from something, but I still want to have no single chip in the cartridge. So you ask how?

Let's assume that there is some passive logic in the cartridge that
* for read from $FFFC will set CPU-D7..D0 to $16
* for read from $FFFD will set CPU-D7..D0 to $40

That would force the CPU to try to fetch next opcode from $4016. If this is 1-byte opcode, next one will be fetch from $4017 (which will be be one-byte) If this is 2-byte opcode, its argument will be fetch from $4017. Let's assume we are not using 3-byte opcodes.

Next, CPU will try to fetch one from $4018 but then some passive logic in the cartridge will
* for read from $4018 will set CPU-D7..D0 to $4C (JMP $4016)
* for read from $4019 will set CPU-D7..D0 to $16
* for read from $4020 will set CPU-D7..D0 to $40

Now CPU is going to start executing code again from $4016.

But what will drive the data bus for reads from $4016-$4017? There will be some "magic-black-box", plugged into 15-pin expansion port that when read from $4016/$4017 will occur, it will transmit the true byte that should be executed using the $4016.D1/$4017.D1 (as data) and /IRQ line (as clock), bit per bit, on falling edge of /IRQ line:
^=HIGH, _=LOW, -=OPEN BUS, x=no matter

Code: Select all

M2         ___^^^^^^^^^^^^^^^^^^^___
$4016.CLK  ^^^___________________^^^
$4016.D1   ---__^^__^^__^^__^^^^^---
/IRQ       ^^^^_^__^__^__^__^_^^^^^^
CPU-D7     xxxxxxxxxxxxxxxxxxx^^^----
CPU-D6     xxxxxxxxxxxxxxxxxxx___----
CPU-D5     xxxxxxxxxxxxxxxxxxx^^^----
CPU-D4     xxxxxxxxxxxxxxxxxxx___----
CPU-D3     xxxxxxxxxxxxxxxxxxx^^^----
CPU-D2     xxxxxxxxxxxxxxxxxxx___----
CPU-D1     xxxxxxxxxxxxxxxxxxx^^^----
CPU-D0     xxxxxxxxxxxxxxxxxxx___----
The "passive logic" on the cartridge has access to the /IRQ line (and $4016.D1 because it is just inverted CPU-D1 on true famicom). After receiving those 8 bits, this logic will drive the D7..D0 with received value until end of cycle and CPU will interpret this as proper opcode and execute it.
Of course it cannot drive all bits, because some of them are connected to the 74368 inside famicom and are already driven, so bus conflict would appear. But those bits can be driven directly by the "magic black-box", while other bits can be driven using the passive logic inside cartridge.

Because after power-up, I-bit in status register is set so we can toggle /IRQ and nothing will happen. And because this is real famicom, so driving data bus from edge connector while reading from $4016/$4017 is still possible.

We are limited only to 1-byte and 2-byte opcodes, but that's not problem cause we can use the:
* LDA #$xx to load value
* STA ($xx),Y to store value at desired RAM cell
* PHA to push return address (-1)
* RTS to jump to RAM after execution is done

The "back-box" plugged inside 15-pin expansion port can be just simple CPLD + ROM chip for store opcodes.

Now I am wondering how to implement the described above "passive logic" in cartridge not using single chip.
* Buffers can be done using transistors in open collector manner.
* Decoders can be done using diodes and resistor (AND/OR logic or transistor as inverter).
* Shift register - using flip-flops and flip-flops using two transistor Eccles-Jordan

The question is.. if the 74368 inside FAMICOM is fast enough to drive data bus 8 times per CPU cycle.

Re: Building a 0 chip cartridge

Posted: Wed Feb 26, 2020 11:50 am
by lidnariq
krzysiobal wrote: Wed Feb 26, 2020 9:25 am Of course it cannot drive all bits, because some of them are connected to the 74368 inside famicom and are already driven, so bus conflict would appear. But those bits can be driven directly by the "magic black-box", while other bits can be driven using the passive logic inside cartridge.
Unfortunately, in the original Famicom, none of $4016d0, $4016d2, or $4017d0 can be driven by cart or expansion port: the first two because they're inaccessible, the last because it would cause a bus conflict with the permanently-tethered controller. $4016d2 is floating in the AV Famicom, and $4017d0 has no controller to conflict with in the AV Famicom or any famiclone without tethered controllers, but $4016d0 will pose a problem (and $4016d2 might also, depending on the specific console).
* Shift register - using flip-flops and flip-flops using two transistor Eccles-Jordan
Specifically figure #1, two inverters feeding back into each other. (Figure #2 is an S-R latch, which would require more effort to convert into part of a shift register)
The question is.. if the 74368 inside FAMICOM is fast enough to drive data bus 8 times per CPU cycle.
Er? But the 40H368 isn't involved with this serial link on the /IRQ line. Why would anything else need to change that quickly?

Re: Building a 0 chip cartridge

Posted: Wed Feb 26, 2020 1:34 pm
by Bregalad
Doesn't the GameGenie uses no ROM (OK it might have chips but only discrete logic) ?

Re: Building a 0 chip cartridge

Posted: Wed Feb 26, 2020 1:40 pm
by NewRisingSun
Game Genie has 4 KiB of PRG-ROM. It does connect the CHR address line in a funny way to do blocky graphics without CHR-ROM.

Re: Building a 0 chip cartridge

Posted: Fri Mar 06, 2020 4:06 am
by aquasnake
since we can only use $200-$6FF(1.25KiB=1280Bytes) as prg-ram to copy codes here.

so we need add a temporary prg rom to boot the code, which will be stored in a memory space from $FA00-FFFF. why not $FB00-$FFFF? the last 256K page needs to be mirrored to $FE00-$FEFF, which would be copied to $600-$6FF next, the reset/irq/nmi vectors are stored here fixedly. now the code size is 1.5KiB(1536Bytes) not 1.25KiB any more.

here is my thought:
1. boot from $FFFC[.segment "VECTORS"] and jump to [.segment "STARTUP"]

2. copy ram code form prg rom($FA00-$FEFF) to prg ram($200-$6FF)

3. jump to the entrance of ram code

4. you can remove the prg rom now

Re: Building a 0 chip cartridge

Posted: Fri Mar 06, 2020 11:21 am
by lidnariq
I did, technically, write a proof of concept for something that would run without any cartridge at all:
viewtopic.php?p=184247#p184247

However, I did use a ROM on a cartridge temporarily to copy data into RAM, and then relied on the specifics of how the 6502 boots to get a predictable reset vector.

Re: Building a 0 chip cartridge

Posted: Fri Mar 06, 2020 4:26 pm
by Ben Boldt
I just have to chime in and say that you guys are completely crazy. :beer: :beer:

Re: Building a 0 chip cartridge

Posted: Fri Mar 06, 2020 8:16 pm
by aquasnake
aquasnake wrote: Fri Mar 06, 2020 4:06 am the last 256K page needs to be mirrored to $FE00-$FEFF
256-byte

suppose hardware reset never clears the internal RAM, the next steps might be meaningful:
once the loader has finished copying code to ram, then set the mapper registers to map $FFFC-$FFFF to $6FC-$6FF, and never allow to write these registers again(lockout).

after doing this, restarting game will work fine