ZX Spectrum Cartridges

1246

Comments

  • edited August 2016
    Next are issued 4 operations:
    1 Cmd sequence (running from ROM), to set Bank 21 (bin 10101)
    2 Simple ROM read at addr #0000
    3 Simple ROM read at addr #0001
    4 Cmd sequence (running from ROM), to set Bank 0 (bin 00000)

    NOTE: Bank number is taken from A4..A0 lines.

    Prototype-Signals_V0-ROM-Cmd.png

    White lines show when 3 consecutive addresses match (for now, checking only partial addr #xxFE).
    NOTE: Looking at the counter (CNT) lines, it's easy to follow sequence detection.

    Yellow lines, show when Cmd data/parameter is read.

    Green highlight shows regular ROM reads.

    NOTES:
    Supporting commands from ROM, is precarious, since code must be done in a very specific way to make it work, and may not be very useful, due to current implementation.
    If gate usage limit is hit, I'll probably will not support BANK swapping from ROM.
    Post edited by RMartins on
  • edited August 2016
    Next, to support writting to Flash is a Cmd to set Bank and Enable Write.

    Prototype-Signals_V0-RAM-Cmd-WR.png

    Currently I'm using A7, of Cmd parameter, to define WRite enable (=1).
    Internal WR_CMD flag is changed according to A7.

    The Write Enable Cmd has one extra state, to allow byte to be written, which is shown by the RED line.

    Post edited by RMartins on
  • edited August 2016
    However, there is a problem in WRITE, since FLASH Memory requires a set consecutive writes to enable actual writing to Flash, as a safety measure. So reads MUST NOT be done between these consecutive writes.

    Prototype-Signals_V0-RAM-Cmd-WR_Trouble.png

    Looking at the Orange spots, it can clearly be seen that reads are being done before and after write.

    This happens because while testing, Cmd Parameter, which is an address anyway, is targeting a ROM area (A15,A14) = (0,0), which is a valid address that ROM cartridge must reply to.

    So when writing to Flash, it clearly must be done from RAM.

    And Cmd Parameter (Registers I/R), must be set to a non ROM address (A15,A14) != (0,0),
    to avoid ! F_CE and ! F_OE to enable intermediate accesses.

    This can easily be implemented/forced in code to avoid problems.
    Post edited by RMartins on
  • Forgot to mention, but ! ROMCS is being floated, in order to support other interfaces to take over ROM addresses, if cartridge is disabled. A sort of play nice with others.

    Since ! ROMCS has a pull down on ZX Spectrum motherboard, floating this line on cartridge is all that is required.
  • I need A15, A14, to be able to handle ROM accesses, and I only have enough pins to use A9..A0, due to CPLD pin count limit, and intended support to Write Flash Memory (required 2 more pins).
    So, I'm short of 5 address lines (A13..A10).

    I'm not sure if it's really needed, to prevent triggering false commands in cartridge, but I'll see if it's possible to use an additional external chip to cover missing address lines.

    We need one or two address bits, to be able to place control code in more than one place, but too much flexibility, and it might trigger false positives.

    A possible work around, is to do some extra checks on address lines at parameter step (check A15, A14, A9, A8, A6, A5), to further minimize the possibility of false positives, since I currently only use A7 and A4..A0 for parameter inputs.

    Can't wait, for the parts to actually arrive :)


  • edited August 2016
    From all the interfaces I checked, including original cartridges, they all force !ROMCS to VCC (5V). to disabled ZX Spectrum Internal ROM.

    Due to timing constraints, it might be better to always signal this line to VCC, instead of doing it just when a ROM address is accessed. If directly connect to VCC, it would be one extra free pin, for address decoding.

    However, this would not allow to disabled the cartridge, so that other ROMS can work.

    Do any of you have some documentation on how Interface1 for example, swaps the extra ROM ?
    Is there anything special about it, or is just a regular !ROMCS disable?

    I suppose that DIV-IDE and DIV-MMC also do some ROMCS disabling/hacking, to be able to control NMI functionality, since NMI always forces a jump into a ROM address, and that memory need to come from the interface, and not ZX ROM.

    I would like to remain compatible to interfaces like DIV-IDE, DIV-MMC, etc...

    I have been wondering, if it's best to use !ROMCS pin in a bidirectional way, to be able to sense the line, to see if someone else is driving it High (VCC), assuming other devices continuously drive it High.

    I haven't figured out yet, the best way and time to handle this, since cartridge needs to be able to supply startup boot address #0000, so to check the line, it can only be done before reset finishes, which we don't have access too.

    There is always option of an RC solution connected to !MEMRQ to detect RESET, since !MEMRQ activity stops when RESET is active.

    Post edited by RMartins on
  • edited August 2016
    Speaking of RESET, what are user expectations of cartridge up on RESET ?

    From a regular original cartridge, it's supposed to just start again.

    But since this is a programmable paged ROM, the expectation should be to reset to page 0, which means it should detect RESET and act upon it.

    However, if a pré-written cartridge, always RESETs, what solutions exist (besides adding extra inputs/buttons), in order to enter regular ZX ROM, which will allow to program the FLASH ?

    One solution, is to have that option on a menu on first page, while developing.
    Later, after development, by removing this page, Cartridge will become READ-ONLY, since no option for write will be available.

    If !ROMCS line detection is implemented, like mentioned in previous message, then with a Special Cartridge connector, it could be possible to signal that we want to disable cartridge on boot, and then use software loaded from TAPE or DIV-IDE/MMC to re-write a bootstrap on Page/Bank 0, and recover Cartridge to developer mode.

    Another possible solution, which requires no extra hardware, is to always have a bootstrap Page/Bank 0 (reduces available ROM for applications by 16K), that could check some key combination, to disable Cartridge at boot, or optionally change to application page, and fake a boot from there.

    Since we are using flash, this information (boot app or enter Dev Menu) could be saved somewhere in Page/Bank 0, so that it becomes persistent.

    I still have to wrap my head around these required features for programmability.

    Any possible requirements/ideas from other developers ?
    Post edited by RMartins on
  • edited August 2016
    Some other devices that drive the /ROMCS line, do so via a latch (flip-flop) followed by a transistor to actually drive /ROMCS to 5V.
    There are a number of different events that can cause the latch/flip-flop to change state. The simplest is when the CPU writes to it as a I/O port (OUT). This is very commonly used to exit CPU execution from an external ROM and transfer back to the Spectrum ROM.

    Some devices "watch" the address bus (plus /M1) and when the device logic sees a trigger address, it sets the latch and so drives /ROMCS high so that the device's own ROM will supply the data to the CPU (if /M1 is included, this will be during the CPU instruction fetch cycle).

    The speed (propagation time) of the detection of the address, the latch and the time it takes the transistor to pull up the /ROMCS, plus the time the Spectrum ROM takes to respond (stop driving the bus) and the time it takes the external ROM to present valid data on the data bus all determine if the Z80 reads the Spectrum ROM, garbage or the data from the external ROM. IF your circuit is fast, the CPU will execute an instruction from the external ROM. If it is slow, the CPU will still execute the first instruction byte from the Spectrum ROM, but use the external ROM for the remaining instruction bytes / next instruction.

    Some systems duplicate the instruction in the Spectrum ROM in the external ROM at the target address to prevent problems. That way, both ROMs have the same data, so less chance of the CPU receiving garbage if the timing is slightly wonky.

    Mark
    Post edited by 1024MAK on
    Sinclair FAQ Wiki
    Repair Guides. Spanish Hardware site.
    WoS - can't download? Info here...
    former Meulie Spectrum Archive but no longer available :-(
    Spectranet: the TNFS directory thread

    ! Standby alert !
    “There are four lights!”
    Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb!
    Looking forward to summer in Somerset later in the year :)
  • edited August 2016
    Of course, due to the limited available signals on the cartridge port edge-connector, both the methods described above are not practical.

    So instead, either a on board timer gives defined page switching with the CPU running in a waiting loop between timed ROM page switches.

    Or just the address bus (and /MEMRQ) is used to trigger the ROM page switching, with the latch updating ready for the next CPU access. Best is for the CPU to read data from said address (or addresses) and never be allowed to try to perform an instruction fetch from this address (or addresses).

    Mark
    Post edited by 1024MAK on
    Sinclair FAQ Wiki
    Repair Guides. Spanish Hardware site.
    WoS - can't download? Info here...
    former Meulie Spectrum Archive but no longer available :-(
    Spectranet: the TNFS directory thread

    ! Standby alert !
    “There are four lights!”
    Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb!
    Looking forward to summer in Somerset later in the year :)
  • edited August 2016
    1024MAK wrote: »
    Of course, due to the limited available signals on the cartridge port edge-connector, both the methods described above are not practical.

    So instead, either a on board timer gives defined page switching with the CPU running in a waiting loop between timed ROM page switches.

    Or just the address bus (and /MEMRQ) is used to trigger the ROM page switching, with the latch updating ready for the next CPU access. Best is for the CPU to read data from said address (or addresses) and never be allowed to try to perform an instruction fetch from this address (or addresses).

    Mark
    One possible solution I have been thinking about is to latch in the !ROMCS signal on the rising edge of !MEMRQ, so that it's previous state is known on !MEMRQ falling edge, when the real memory access is being made.

    This would allow to detect if other interfaces are driving !ROMCS high.

    However, this will probably create race conditions, when cartridge (our selfs) are driving !ROMCS high.

    A possible work around, is to disabled !ROMCS detection, once we determined that we will drive it, hence becoming the master, so no need to check.
    But this will preclude the usage of other interfaces, until Cartridge relinquishes control of !ROMCS line.

    A typical example, would be: while running some cartridge application, it will not allow or be compatible with other interfaces (ex: DIV-MMC).
    But there might be some corner cases, for example when pressing RESET on other interface that replaces ZX ROM like DIV-MMC.

    The main problem here, is that !ROMCS line was never designed to be shared by multiple devices, and there is no clear protocol to follow that works with all legacy or modern interfaces.

    I may have to sniff the interface expansion port, while using these other interfaces, to check what they are doing, unless it's developer(s) have it documented somewhere.

    For example, I believe that DIV-MMC, forces !ROMCS line high on RESET, in order to run it's own boot code, and later fakes a reboot by jumping to address #0000 while relinquishing control of !ROMCS line, or if it was REALLY SMART, it would RESET ZX again, knowing that it was already initialized, it wouldn't take over !ROMCS line on this restart (but from screen behaviour this is not what is happening).

    So in order to be compatible with other bootable devices, one has to detect that the line is being controlled by others (so that we allow them to boot properly), and detect the fake boot (or SMART BOOT), so that we can take over.
    Unfortunately, this requires to completely match 16 address lines, so we can detect address #0000.

    A simple pageable - READ ONLY - Cartridge can simply take over !ROMCS line and be done with it.

    Supporting direct cartridge development while trying to maintain compatibility with other interface devices, is complex.

    But I wish I could use DIV-MMC or similar to load content into memory, and then save it to cartridge, even if it required a reboot (If Cartridge takes over boot, we can prevent memory clean up/reset done by ZX ROM startup code).

    A possibly viable solution, could be an interface Adapter, that could multiplex between Cartridge socket and other interfaces connected to it, so that only one boot device takes control at a time.
    Obviously, this is only required for developers.
    Post edited by RMartins on
  • edited August 2016
    I checked all original Cartridges contents, and all of them start with DI ("F3") like Spectrum ROM, except "QBert" (uses an unconditional JUMP => C3 3D 00).

    If all ROMs started with the same byte instruction, this would allow to check !ROMCS, on first ROM access (#0000), and decide control over it for next access.

    But this would place this constraint on all Cartridges, to always start with DI or NOP. (I'm not sure I want to force this).

    NOTE: in reality DI is not really needed since RESET guarantees that interrupt flip-flops (IFF1/IFF2) are disabled already. So DI at #0000 is similar to a NOP after a RESET, unless, you jump to #0000 to fake a boot, without first issuing a DI.
    Post edited by RMartins on
  • edited August 2016
    Update:

    Added A9 and A8 signals into address decoding (see orange labels on left side).

    Changed WRite trigger to use A8 (instead of A7), so that command can be fully contained in I register.

    Prototype-Signals_V1.png

    Vertical YELLOW line, represents affected simulation position.

    NOTE: Actual write to FLASH Memory (RED line), MUST be issued into ROM address space (A15,A14) = (0,0), so that no actual RAM memory is affected by this write operation.

    Output Enable (!F_OE) is inactive (High), so that CPU can effectively write to an external ROM address.
    Post edited by RMartins on
  • edited August 2016
    Currently what I'm struggling is the fact that if a developer my mistake erases or damages the bootloader on the first bank, then he might have a turd on his hands, since the cartridge always boots, and there is no way to re-flash it, if it's done only with software, since ZX ROM, never has a chance to start.

    This will probably force me to have some hardware as backup to reset a cartridge.

    One solution is re-write CPLD so that it doesn't take over ROM address area.
    Which could be implemented in two hardware versions: one for development and another for release.

    NOTE: Not everyone has an hardware programmer capable of writing these chips, specially if the only access is trough a Cartridge socket interface (once the chips are soldered to the board), which requires at least an adapter to connect it to a programmer.

    NOTE: one solution that comes to mind is to never allow the bootloader to be overwritten (by software), and prepare it to check some of the cartridge contents (one of the other three 4K pages in the first bank), to determine what to do. Flash is erased in $K pages, and written byte by byte.
    This way, bootloader can still provide a Keyboard shortcut (configurable?) at boot to determine what to do, boot into application or applications menu, or alternatively DEV mode with data write menu.
    Post edited by RMartins on
  • Could the CPLD prevent writes to the boot loader area?
    Sinclair FAQ Wiki
    Repair Guides. Spanish Hardware site.
    WoS - can't download? Info here...
    former Meulie Spectrum Archive but no longer available :-(
    Spectranet: the TNFS directory thread

    ! Standby alert !
    “There are four lights!”
    Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb!
    Looking forward to summer in Somerset later in the year :)
  • edited August 2016
    1024MAK wrote: »
    Could the CPLD prevent writes to the boot loader area?

    Almost beat me to my edit :)

    Yes it can, but then it means that not even I can update it (without re-writing CPLD logic). :(
    It's probably better to do it by software in the bootloader itself.


    Post edited by RMartins on
  • edited August 2016
    Maybe do something like a "ping-pong" boot loader toggle.

    First bank, as four 4K pages.
    So first page, MUST be the "Master" bootloader itself, for obvious reasons.

    Second and third page, could be used as alternative locations to save alternative bootloaders, i.e. "Master" boot loader, looks at these pages, and runs some CheckSum on them, to determine if they are valid, and alternativelly could read some settings from fourth page, which would select which bootloader to use, or something like this.

    The idea, is to try and guarantee, that a minimum bootloader (AKA Master bootloader) is always valid and hence capable of writting/resetting other 4K pages and banks (16K), including other alternative bootloaders.

    First bank should be reserved for bootloaders, since applications might need Interrupt handler control, so they must use another start bank, since paging works in banks(16K), only FLASH writting, works in 4K pages.
    Post edited by RMartins on
  • If there was more space in a cart, a small switch could be used (operated by a metal pin through a small hole by developers so that it is not accidentally disturbed by users) to enable or disable the boot loader.
    But I suspect even a SMD ON/OFF switch would be too large. And this means another pin on the CPLD :(

    Mark
    Sinclair FAQ Wiki
    Repair Guides. Spanish Hardware site.
    WoS - can't download? Info here...
    former Meulie Spectrum Archive but no longer available :-(
    Spectranet: the TNFS directory thread

    ! Standby alert !
    “There are four lights!”
    Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb!
    Looking forward to summer in Somerset later in the year :)
  • edited August 2016
    1024MAK wrote: »
    If there was more space in a cart, a small switch could be used (operated by a metal pin through a small hole by developers so that it is not accidentally disturbed by users) to enable or disable the boot loader.
    But I suspect even a SMD ON/OFF switch would be too large. And this means another pin on the CPLD :(

    Mark

    If I implement the detection feature on ROMCS, this could be done, but instead of using a pin, some other ROM interface would have to be in place, to take control of ROMCS line (something like DIV-MMC).

    A pin solution could be implemented, with a very tiny hole, that would allow to shortcut VCC or GND throw a resistor, into a CPLD pin. but has you say, this requires another pin, and I'm already short on pins :)

    A simple trick might also work, to fool ROMCS line sensing, if a diode is placed between CPLD and ZX ROMCS line. The idea is to be able to read the line normally, but fake a ROMCS active as seen from cartridge perspective, but not disturb the ZX ROMCS line, when pin is inserted, so that ZX ROM can start normally.

    The problem here is that ROMCS is like a master signal, there is not handshake, so if we set it to some value we expect to get control, since there is no feedback from CPU acknowledging our intention, like in a Bus Request.




    Post edited by RMartins on
  • RMartins wrote: »
    A simple trick might also work, to fool ROMCS line sensing, if a diode is placed between CPLD and ZX ROMCS line. The idea is to be able to read the line normally, but fake a ROMCS active as seen from cartridge perspective, but not disturb the ZX ROMCS line, when pin is inserted, so that ZX ROM can start normally
    Thinking more about it, a simple diode won't work, since we need bidirectinality, to be able to control ROMCS line.
  • First prototype PCB batch ordered :)

    NOXROM_PCB_V1.0.png
  • Personally I don't have any special need for gaming cartridges but it would be interesting if it was possible to translate multi load games like Lemmings into a single cartridge and possibly design some real artwork for the case instead of plain text (Mega Drive style would be the right way).
  • maiki wrote: »
    Personally I don't have any special need for gaming cartridges but it would be interesting if it was possible to translate multi load games like Lemmings into a single cartridge and possibly design some real artwork for the case instead of plain text (Mega Drive style would be the right way).

    It shouldn't be too complex to do, since you only have to change the load process.
    Same for artwork. just be sure to stick to original cartridge label sizes.

    Hope to see that Lemmings in Cartridge version soon :)

  • Could this be taken a step further and produced as a product that is similar to the ZX Interface II? It would be cool to offer a solution for 16K/48K users that includes:

    1 - 2 Kempston joystick interfaces
    2 - Cartridge Port
    3 - 64K RAM expansion
    4 - AY Sound chip

    I would love to purchase individual games on cartridge for it :)
  • edited August 2016
    Rebelstar wrote: »
    Could this be taken a step further and produced as a product that is similar to the ZX Interface II? It would be cool to offer a solution for 16K/48K users that includes:

    1 - 2 Kempston joystick interfaces
    2 - Cartridge Port
    3 - 64K RAM expansion
    4 - AY Sound chip

    I would love to purchase individual games on cartridge for it :)

    I have an intention plan, to produce an interface further ahead, for items 1 and 2 of your list. Could be interesting to add item 4 to it.

    Item 3 might make it more expensive with small added benefit, because only new code could use this extra RAM and if you have lots of pageable ROM, you typically don't need it.

    Alternatively, you might be suggesting, to mimick the 128K paging mechanism in this extension (hence an extra 64K), but even in this scenario, some programs might fail to detect the extra memory, depending on which method they use to determine, if it's a 128K machine or not.

    If they test the page register and accessible memory, they would work.

    However, if they rely on some Sinclair 128K model ROM specific validation, they will fail to detect the extra RAM.
    Post edited by RMartins on
  • Hi, in all 48k models, external memory peripherals can only take control of the rom space. There is no external way you can disable the internal upper ram to occupy that space with a banked external memory like you suggest. This is, however, possible in a Spectrum 16k model.
  • Although Dan Dare is correct, there is a way of having external RAM in the 16k to 32k area. But because any writes by the CPU in this area will be stored in the internal RAM as well it's normally of no practical use.

    For a 48k machine, either the user would have to remove the "upper" DRAM chips. Or where they are soldered in, solder in a wire to disable these DRAM chips.

    It is a shame that Sinclair did not include a /RAMCS line on the edge-connector like in the ZX81 :(

    Mark
    Sinclair FAQ Wiki
    Repair Guides. Spanish Hardware site.
    WoS - can't download? Info here...
    former Meulie Spectrum Archive but no longer available :-(
    Spectranet: the TNFS directory thread

    ! Standby alert !
    “There are four lights!”
    Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb!
    Looking forward to summer in Somerset later in the year :)
  • 1024MAK wrote: »
    Although Dan Dare is correct, there is a way of having external RAM in the 16k to 32k area. But because any writes by the CPU in this area will be stored in the internal RAM as well it's normally of no practical use.
    ...
    Mark

    Please share this hack, it's always nice to know these extra "features".
    They might become handy in some peculiar situation.
  • Because resistors R1 to R8 "isolate" the data bus into two sections, external devices (like modern CMOS SRAM) can easily override the 4116 DRAM chips data when the CPU performs a read from this address area.

    Mark
    Sinclair FAQ Wiki
    Repair Guides. Spanish Hardware site.
    WoS - can't download? Info here...
    former Meulie Spectrum Archive but no longer available :-(
    Spectranet: the TNFS directory thread

    ! Standby alert !
    “There are four lights!”
    Step up to red alert. Sir, are you absolutely sure? It does mean changing the bulb!
    Looking forward to summer in Somerset later in the year :)
  • edited August 2016
    1024MAK wrote: »
    Because resistors R1 to R8 "isolate" the data bus into two sections, external devices (like modern CMOS SRAM) can easily override the 4116 DRAM chips data when the CPU performs a read from this address area.

    Mark
    That can easily be used for a WRITE once, READ many times, that could be enabled/disabled by some IO port.

    It can actually be useful, to extend available memory, when not writing to screen, since it will be overloading with screen address range, although ULA, will still be happy with it's own access to local 4166 DRAMs. But all these accesses will be be potentially contended.

    It can also be used as a way to identify some hardware, that can return some special info in those addresses, when access is enabled.

    The key to being useful, this area should stick to read only, and not be used while writing to screen.
    Post edited by RMartins on
  • RMartins wrote: »
    Rebelstar wrote: »
    Could this be taken a step further and produced as a product that is similar to the ZX Interface II? It would be cool to offer a solution for 16K/48K users that includes:

    1 - 2 Kempston joystick interfaces
    2 - Cartridge Port
    3 - 64K RAM expansion
    4 - AY Sound chip

    I would love to purchase individual games on cartridge for it :)

    I have an intention plan, to produce an interface further ahead, for items 1 and 2 of your list. Could be interesting to add item 4 to it.

    Item 3 might make it more expensive with small added benefit, because only new code could use this extra RAM and if you have lots of pageable ROM, you typically don't need it.

    Alternatively, you might be suggesting, to mimick the 128K paging mechanism in this extension (hence an extra 64K), but even in this scenario, some programs might fail to detect the extra memory, depending on which method they use to determine, if it's a 128K machine or not.

    If they test the page register and accessible memory, they would work.

    However, if they rely on some Sinclair 128K model ROM specific validation, they will fail to detect the extra RAM.

    hi :)

    Item 3 was just an idea to allow new games to be larger and run on older Spectrums without altering the internals of those older machines. If larger games can be ran quickly from ROM cartridge then I guess additional RAM is not needed :)

    The AY sound chip was an idea to make the expansion into a 'console' style upgrade. Having fast access to games with various models of joypads and joysticks is great but it doesnt feel like a complete gaming experience without music. It would have been good to add a Yamaha sound chip for 16/48K Spectrums but it wouldn't add anything extra for 128K models so I was thinking about it having a Philips SAA1009 sound chip (same one used in Sam Coupe) to offer 6 channel sound. there is already one or two products that offer this as a standalone solution.
Sign In or Register to comment.