Ripping cartridges

This is the right place to discuss on how to implement hardware vsync, adding a VIA or AY chipset, puting multiple roms, or how to design a new flash expansion card.
User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Ripping cartridges

Post by NekoNoNiaow »

Sir Dbug mentioned the idea of a ripping cartridge in Symoon's tape loading thread recently and I think it was worth discussing on its own merits so I am reposting as its own thread:
Dbug wrote: Tue Apr 24, 2018 7:39 am
Symoon wrote: Mon Apr 23, 2018 11:48 pm (and blind when the loading hangs on real machines, no way to go back to the interpreter and save the memory).
I wonder if it's possible to implement "ripping cartridges" on the Oric.

On machines like the Commodore 64, Atari ST, etc... it was possible to plug cartridges on the expansion bus, and by pressing some button you would reset the machine using the cartridge instead of the on-board rom, which would preserve the state of the memory and allows you to see what was there, search for graphics, fonts, sprites, but also disassemble source code or view memory in hex, eventually saving that to disk.

I guess on the Oric that could be done with a dual ROM, or maybe by replicating the Microdisc boot process with a 16KB eprom overlayed on top of the ROM.
This would definitely be possible if the expansion bus exposes enough CPU signals to:
- generate an interruption
- freeze the CPU while acquiring bus master status.

If this is the case, I can imagine two possible ways to do this nowadays:

Dedicated CPU (Arduino/PI)

An Arduino or Raspberry PI can be used to generate all the signals necessary to freeze the CPU, drive the address bus and CAS/RAS lines and would also have a few input lines to read the results on the data bus.

When the button is pressed, the cartridge freezes the CPU and emulates all the signals of a full bus master in order to read all the bytes in memory.
It would also have to trick the CPU into revealing its internal state, possibly by forcing it to execute code generated by the cartridge.

Most of the work would be to write the software to generate all the signals of a full bus master. This would be quite complex and tricky to tune properly. ;)

Classic : logic + ROM

Essentially do what the ripping cartridges on other machines did:
have just enough circuitry to generate an interrupt and place its own interrupt vector in memory instead of those in RAM.

When the button is pressed, it generates an interruption and its own ROM code is executed which can then execute whatever it wants and store the memory + state of the CPU in a file on disk or tape, or in flash memory.

This is relatively simple to do nowadays with just a few logic gates and possibly a CPLD since all this does is generate an interruption signal, and decode a few addresses. All the dumping and saving logic is just regular ORIC code located in the ROM.

---

The simpler way to proceed overall would probably be to start with a ripping cartridge for the C64 and adapt it for the Oric.
I guess that the expansion used by JeDe for Orix would also be a good starting point.
jede
Flying Officer
Posts: 191
Joined: Tue Mar 14, 2006 11:53 am
Location: France

Re: Ripping cartridges

Post by jede »

NekoNoNiaow wrote: Tue May 08, 2018 6:17 am
The simpler way to proceed overall would probably be to start with a ripping cartridge for the C64 and adapt it for the Oric.
I guess that the expansion used by JeDe for Orix would also be a good starting point.
It's almost possible, i did not tested it but it should work. On the telestrat (or with Twilighte card), when you push reset button, the 7th bank rom is always selected (it's a hardware trick).

At this step, you can do what you want. For example, i am looking for a Debug bank (with disassembler). It could be easy to reset and press a key on the keyboard to force to run in the debug bank.

The hardware is ready, not the software :)
User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Re: Ripping cartridges

Post by NekoNoNiaow »

(EDITED: Merged the three posts to make it easier to follow)
jede wrote: Tue May 08, 2018 7:26 am It's almost possible, i did not tested it but it should work. On the telestrat (or with Twilighte card), when you push reset button, the 7th bank rom is always selected (it's a hardware trick).
I guess you mean the Telestrat cartridge rather than the computer?

Assuming that this is the case, if I understand correctly, when the reset button is pressed, the cartridge ensures that the 7th bank section of its ROM is mapped at the address at which the CPU will jump upon reset, so essentially it will reboot into whatever code is in this bank?

Does the reset mechanism also reset the CPU though? Because then the issue would be that this would prevent from saving the CPU internal status (PC, Accumulator, X, Y, status register, stack register).

Am I understanding this correctly?

Some additional information from the Oric Service Manual:
The signal MAP deserves some explanation since it is this which modifies the address map for I/O expansion, and it works in the following way:-
The ULA which monitors the top 8 bits of the address bus, detects when the top 16K is being addressed, and when the bottom 48K is being addressed. If the top 16K is being addressed (C000-FFFF) when MAP is generated, the ULA (IC7) generates a signal CS which inhibits the ROM(s) from using the data bus. In addition, the entire 64K of RAM is enabled (made available to the data bus). This feature is used by the Microdisc drive system whose software (DOS) occupies the top 16K of DRAM, thus ensuring that the ROM and the DOS cannot use the data bus at the same time and maintaining the 48K of DRAM for user programs. If the bottom 48K is being addressed (0000 to BFFF) when MAP is detected, the entire 64K of DRAM is inhibited and the data bus is free to be used by external memory (RAM or ROM) connected to PL2.
If I understand this correctly, this means that it is at least possible to intercept all read and writes to and from memory and/or ROM and redirect them to the cartridge address and data buses -> setting the MAP signal does exactly that.

The general scheme for the cartridge would thus be to:
  • generate an IRQ upon press of the button
  • set MAP to 1 to ensure all reads and writes to ROM/RAM are handled by the cartridge.
  • decode the IRQ vector address and output the address of our own boot address in the cartridge ROM
  • dump the CPU state into the cartridge RAM
  • dump screen and character set into the cartridge RAM
  • display the cartridge menu on screen
EDIT: Actually... since the cartridge ROM is the only one on the bus after MAP is asserted, we just need to burn our ROM with our own vector at FFFE. No need for address decoding logic. ;)
jede
Flying Officer
Posts: 191
Joined: Tue Mar 14, 2006 11:53 am
Location: France

Re: Ripping cartridges

Post by jede »

NekoNoNiaow wrote: Wed May 09, 2018 5:18 am (EDITED: Merged the three posts to make it easier to follow)
jede wrote: Tue May 08, 2018 7:26 am It's almost possible, i did not tested it but it should work. On the telestrat (or with Twilighte card), when you push reset button, the 7th bank rom is always selected (it's a hardware trick).
I guess you mean the Telestrat cartridge rather than the computer?

Assuming that this is the case, if I understand correctly, when the reset button is pressed, the cartridge ensures that the 7th bank section of its ROM is mapped at the address at which the CPU will jump upon reset, so essentially it will reboot into whatever code is in this bank?

Does the reset mechanism also reset the CPU though? Because then the issue would be that this would prevent from saving the CPU internal status (PC, Accumulator, X, Y, status register, stack register).

Am I understanding this correctly?
Yes, when you do a reset on telestrat or Twilighte card, you returns to 7th bank, but it resets also CPU and others registers. it means that you can read memory but you don't keep all registers states (cpu, via).

For example, if i run any program (even when irq adress is set) on atmos rom on twilighte card, i reset and i can read the memory.

Anyway, it could be change on the twilighte card, because it could be possible to code this in the CPLD chip and add an external button to activate what you want.
User avatar
Chema
Game master
Posts: 3013
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: Ripping cartridges

Post by Chema »

This thread is too out of my reach, but this behaviour of the RESET is something I did not get.

Is it a kind of "special" reset? Because Oric's reset button (beneath the keyboard) is attached to the NMI signal of the processor, so it should work as any other IRQ with the exception that it jumps to a different vector ($fffa-fffb). From the Service routine you should be able to recover the values of all the registers (A,Y,X are unmodified and P and PC are pushed to the stack - only the stack pointer changes, obviously).

https://wiki.nesdev.com/w/index.php/CPU_interrupts
User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Re: Ripping cartridges

Post by NekoNoNiaow »

Chema wrote: Thu May 10, 2018 12:52 pm This thread is too out of my reach, but this behaviour of the RESET is something I did not get.

Is it a kind of "special" reset? Because Oric's reset button (beneath the keyboard) is attached to the NMI signal of the processor, so it should work as any other IRQ with the exception that it jumps to a different vector ($fffa-fffb). From the Service routine you should be able to recover the values of all the registers (A,Y,X are unmodified and P and PC are pushed to the stack - only the stack pointer changes, obviously).
I was not aware that the NMI had a dedicated vector and that the reset button of the Oric was tied to it, this might indeed be relevant, thanks for the information!

This mechanism does half of the work required for a ripping cartridge: it allows to trigger a dedicated interrupt at the press of a button and the challenge now becomes to find a way for this interruption to be hijacked by the cartridge without hindering normal execution before the reset button is pressed.

There are thus two problems to solve:
- how to detect the NMI occurred? Since the signal is not available on the expansion port, this is tricky
- how to redirect the NMI vector to point to the "capture" code?

After the button press, the Oric will fetch the NMI vector at $FFFA, which normally would be in the Oric's ROM and thus not under the control of the cartridge. If the cartridge asserted the MAP and ROMDIS signals to disable the internal ROM then any program which relies on the ROM to be present would stop working normally as soon as they try to call ROM functions or rely on ROM data so the ROM data must somehow still be present when the CPU accesses these addresses.

This could be worked around simply by having the cartridge copy the ORIC ROM into its own RAM at the same address and only modify the 2 bytes at $FFFA to point to the desired "capturing" code but the issue is that there really is no available RAM to place this code: an Oric program might very well need all the RAM for its own purpose.

Moreover, even MicroDrive based programs must be kept working normally, which means that the cartridge must obey these constraints:
- it must offer a passthrough of the expansion bus so normal extensions can be plugged normally
- the cartridge must introduce as little delay or signal or timing modifications which might cause extensions to not work
- it must let the extensions drive the MAP and ROMDIS signal directly and should not install its own RAM or ROM

So this would leave only one avenue for NMI interception: interception of the reads to $FFFA and $FFFB which occur after the NMI and of the subsequent CPU instruction fetch at the address stored at this vector. Only then can the cartridge properly deduce that the NMI has occurred at which point it has to:
- assert MAP and ROMDIS
- mask any RAM/ROM available via the passthrough and stop relaying the signals to and from any plugged extension
- install its own RAM so that the opcodes fetched by the CPU are the code it wants to execute

All of this must be done in probably less than one clock cycle. :D
Needless to say that this would be quite tricky.

If the cartridge has its own "rip"button and generates RESET (since it is available on the expansion bus, as an input from the cartridge to control the Oric), then it already knows that the NMI will be triggered and has much more time to prepare even before the interruption occurs.

So all in all, it is probably simpler to not rely on the Oric's reset button, unless something is wrong in my reasoning, in which case you are all more than welcome to correct me. ;)
User avatar
NekoNoNiaow
Flight Lieutenant
Posts: 272
Joined: Sun Jan 15, 2006 10:08 pm
Location: Montreal, Canadia

Re: Ripping cartridges

Post by NekoNoNiaow »

jede wrote: Thu May 10, 2018 10:13 am Anyway, it could be change on the twilighte card, because it could be possible to code this in the CPLD chip and add an external button to activate what you want.
Aside from the additional "rip/freeze" button, how much work would you estimate this would require for you if you decided to do it?
I naively assume that the only change needed would be in the code which programs the CPLD chip. Is the source of that code available online? If it is, then I could possibly give it a try since I assume you must be pretty busy with your own task list. ;)

And do you have debug/test boards available just in case I get my hands on an actual Oric and want to debug/test that feature? ;)
Post Reply