We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

ZX Spectrum in the New Millenium

00:00

Formal Metadata

Title
ZX Spectrum in the New Millenium
Subtitle
Upgrading ROM Cartridge to 512KB
Title of Series
Number of Parts
644
Author
License
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
EinsteckmodulComputer hardwareFirmwareSoftwareTouchscreenGame theorySpectrum (functional analysis)BefehlsprozessorFingerprintSpeech synthesisCASE <Informatik>AlgebraBlock (periodic table)Multiplication signNeuroinformatikOpcodeSelectivity (electronic)Connectivity (graph theory)1 (number)Radio-frequency identificationDifferent (Kate Ryan album)MetreSpacetimeWhiteboardGame theoryRight angleMereologyPrisoner's dilemmaLine (geometry)CASE <Informatik>Point (geometry)PhysicalismLimit (category theory)EinsteckmodulSimilarity (geometry)Object (grammar)CloningComputer programmingProjective planeSpectrum (functional analysis)Address spaceSemiconductor memoryTouchscreenComputer hardwareSoftwareBefehlsprozessorFirmwareInterface (computing)EmulatorWeb pageTelecommunicationVirtual machineVideoconferencingSoftware testingMedical imagingLevel (video gaming)Dressing (medical)Maxima and minimaCoprocessorPhase transitionMemory managementBitAreaArithmetic meanJust-in-Time-CompilerSoftware bugComputer animationLecture/Conference
Address spaceReading (process)Internet forumBefehlsprozessorLocal area networkForceSequenceAssembly languageMetropolitan area networkRead-only memoryAsynchronous Transfer ModeMIDIControl flowWeb pageRight angleBitLogicBus (computing)MereologyLine (geometry)Dressing (medical)MathematicsMultiplication signFunction (mathematics)Address spaceSelectivity (electronic)Graph coloringoutput1 (number)Standard deviationRoutingSimulationWritingCASE <Informatik>Personal identification numberSequenceSpacetimeAreaWeb pageInformationTouchscreenBinary fileFlash memoryEinsteckmodulGame controllerParameter (computer programming)OpcodeSemiconductor memoryCartesian coordinate systemRow (database)Reading (process)Uniform resource locatorBefehlsprozessorGreen computingPattern languageExploit (computer security)Software development kitSpeicheradresseImplementationDifferent (Kate Ryan album)Lecture/Conference
Web pageFlash memoryProof theoryInclusion mapData typeComputer iconSemiconductor memorySoftwareMathematicsDressing (medical)Right angleStructural loadProcess (computing)Game theorySelectivity (electronic)FirmwareSpacetimeoutputMereologyType theorySpectrum (functional analysis)Revision controlSequenceFlagWritingWeb pageParameter (computer programming)BitCASE <Informatik>Computer hardwareLine (geometry)Address spaceTouchscreenFlash memoryLevel (video gaming)Tape driveImplementationGame controllerCodeVideoconferencingLink (knot theory)Electronic mailing listMultiplication signBeta functionAxiom of choiceWhiteboardRepresentation (politics)PlanningPoint (geometry)MetreComplex programmable logic deviceFlip-flop (electronics)Video gameCycle (graph theory)1 (number)Position operatorLoop (music)PrototypePhase transitionDigital electronicsRoutingEinsteckmodulAreaInterrupt <Informatik>Parallel portReading (process)Lecture/Conference
Goodness of fitEinsteckmodulFlow separationLevel (video gaming)Multiplication signLibrary (computing)Power (physics)Control flowSoftware testingMassWhiteboardRight angleComputer programmingGame theoryKey (cryptography)Asynchronous Transfer ModeBootingBefehlsprozessorCodeCodeComputer hardwareSoftware developerStructural loadMathematicsCASE <Informatik>Revision controlData miningBitRoundness (object)1 (number)Lecture/Conference
BefehlsprozessorSocial classRight angleIterationProjective planeWeb 2.0Medical imagingGame theoryDialectPatch (Unix)PlanningSemiconductor memoryLecture/Conference
Revision controlMereologyDevice driverCollaborationismArtistic renderingCodeConnected spaceOnline helpWhiteboardFirmwareTouchscreenBinary codeMedical imagingFilm editingGame theoryInterface (computing)Right anglePlastikkarteWeb pageWeb 2.0Lecture/Conference
Program flowchart
Transcript: English(auto-generated)
So I would like to first apologize for all this hardware, but I think a retro talk should have retro stuff working, so I will show it after it. So we'll start presenting this.
So the agenda is basically to define the motivation for doing this thing, mainly what are the X cartridges, what were the objectives, what were the challenges, and the solution, the hardware I designed, the firmware, and lately the software that I implemented.
The motivation was basically to, I started my knowledge of computer programming by starting to program ZX Spectrum in 82, I started by learning BASIC and from that time I was
not aware how to do stuff in assembly. So the idea was I wanted to do something in assembly, but the time went by and then I went to college, university, got a computer course, and a few years later, like in 2015, I decided to make this game in assembly.
So I needed something to be able to do this game and to be able to do larger games because the Spectrum is limited to 48k RAM, right? So this spawned the idea and then someone created this competition and off I went to
do a game based in assembly. But my real goal was to make a port of this game, it's called POW or Prisoners of War, that was in the arcade. It was called Datsugoku in Japan, and it was called Prisoner of War in the EU and in the USA.
So what's the big difference on these goals? This is ZX Spectrum 48k, as I suppose you all know. And this one is a picture of a board that I own of POW. As you can see, it has a lot of different specs when compared to the mighty ZX Spectrum, right?
So there is a big difference either in CPU, ROM, RAM, and video capabilities. So if you can see, this game uses something like 800 kilobytes of ROM.
And the Spectrum, you have like 16 and we don't own it, right? So we need to fix that. And the rest I think we can just fake it and try to get to it. So that's what we usually do, right? So first test were to find if it was possible to convert this game.
So this is the arcade marquee, the thing that is on the top with a backlight over it. And this is my experimental images for the ZX loading screen. And this is the arcade first level. It's a prison area. And this is my idea of what it will look like on the ZX Spectrum.
As you can see, it's not finished and the game is large. I haven't done the rest yet, but these were the goals. So having such a large requirement for ROM means that we can't get away with the simple 48k that we have on the ZX Spectrum.
Obviously we could go to a 138, but it's not enough again. So maybe we could just use a cartridge that actually replaces the internal ROM. But the problem is that the ROM has a maximum size of 16 kilobytes, right? Which is not enough again.
So, and also it requires an interface adapter, but most of the people from back in the day know that there are at least these three ones that were very well known that provide the required interface to be able to use a cartridge. Officially there were only ten cartridges that were released.
There are something like ten more that were unofficial or never released that you can get online if you want to try it on an emulator. So what were my objectives? So I wanted to create a cartridge with electronics on it. I wanted to support at least 512 kilobytes of ROM.
I need to map that ROM to the Z80 address space, which is only 64 kilobytes, right? It only has 16 bits, and so it clearly doesn't fit, right? So obviously we have to do something like paging or similar.
And I also wanted to have PCB and chips must fit inside original case. The idea is to either recover old cases and use a new hardware inside, or also support the cloning of the old hardware and also the case.
So there are many of these small cartridges out there, but they are expensive. So if you can buy one or replace one that is damaged, that's also a goal of this project, okay? So what were the challenges? If you haven't noticed already, there are a lot of physical limitations.
The first one is 16 kilobytes, right? Over the rest of the space, so it goes from 0 to 3FFF. And the connector on the spectrum, maybe I could show one, sorry. So this is one of the cartridges, so the connector is something like this.
As a big drawback, because this was designed only for ROM. So Sir Clive Sinclair, as his usual self, decided we are going to save some bucks and not put the required lines. So read, write, and IO signals are not present, which is a problem hard to solve.
And I also wanted to have the original case or make the hardware that fits in the original case, as I said earlier. And the problem is that after measuring it, there is 2.2 millimeters of space between the case and the board on the back side,
and one millimeter on the front side, which is a problem. So issues to solve, auto trigger bug slash small staging. How do you hear me better? This thing is falling off.
Sorry, does this actual clip work? Sorry, maybe I'm moving too much. Okay, so this is the issue to solve.
And another one is, I need to find components that actually fit inside the case. And the only ones that are available with that small clearance are SMD chips, and not all SMD chips fit, so we have to find ones for it. Okay, this is probably the most important slide so
that you understand what's going on. If you can look at it, this is a usual instruction op code fetch on a Z80 processor. So it always has that four phases, T1 to T4. And you can see that always, the spectrum always does the instruction fetch
with the PC on the address space. And then to support dynamic memory, also does a refresh address that is automatic. So every instruction implies a refresh address that increments every instruction, okay? Only the first seven bits, but it does increment.
And the refresh address is calculated based on two registers, the I register and the R register. The problem, as I said, is that this is the interface of the cartridge. And we don't have all the other lines except these ones that are marked.
So we only have address, data, and the memory request, because that's what CircLife Sinclair found to be enough, which is not for us. So what other things could we think about? Maybe we could use the IO request and solve our problem, right?
But CircLife Sinclair, again, decided no, we cannot have that. We have to earn more money by putting less stuff in the machine, okay? So what kind of solutions can we find so that we can create paging triggers when we can actually not communicate with the thing, right?
So one idea, maybe we could use a fixed address and just hack it, right? Or maybe we could do like repeatable read. So if I read a specific address a few times, maybe I can get away with it.
So or maybe use a pattern sequence like an EEPROM. So an EEPROM or a flash chip has a sequence to protect against write. So if we do a sequence of reads in a specific pattern, it unlocks. But that is really complex.
And we would need to know that is a read. We don't know, right? We don't have the read or the write. So maybe we can exploit CPU features. Like what? Ports, out of the question, right? Maybe we could use the I register. It's messing up with the refresh, right?
And maybe we can use the R register, which also messes with the refresh. Or maybe we do something like, I'm going to use an improbable address. Something that will probably never happen when you are running an application. Is that possible? I think it is. So I went for it and the solution I found is that if you remember correctly,
every instruction does opcode fetch, which is an address. And then does a refresh address that indirectly we can control, right? So if I can somehow define that I can read the same address three times in a row.
Which seems impossible, right? Because the other guy's controlling the registers and he's incrementing. But it's possible. And it's possible because of this. Because there are two instructions called LDI and LDD that transfer
a byte from one location to another location that does exactly this. So they copy from one to the other. So there are two addresses that are being used and I can force them to be identical, okay? And if I do that, I still need the third access, right?
So the next instruction is my next access. So if the two addresses that I used on the first instruction are exactly the instruction of the next address, bingo, right? I have three identical addresses. So what do I need more to make this work?
I need a way to inform the cartridge that I want page X and not some random page or the next page or something like that. So I can have better control. So what I need is something that will give me a parameter, an input.
So what I did is, well, the next instruction has an opcode, but what comes next? The refresh address. Can I change it? Yes, I can with the I and R registers. So now I started thinking, how am I going to implement this, right?
So let's start adding up what we need. So we need two pins for VCC and ground. We need one bit for bus memory control line. This is available in the cartridge, right? And I need one bit to control bus ROM so that I can disable the internal ZX, internal ROM, so that it uses mine.
Okay, like the cartridge does. I have eight bit data lines, 16 bit bus address lines, three bits that I need extra because I have 512 kilobytes, which needs at least 19 pins, right? So three more than 16.
And I need three extra bits just to control the flash. So chip enable, output enable, and write enable. Well, if we add all this up, it's like 38 pins. That's hard to get on a CPLB, and it occupies a lot of lines.
And as you may probably know, or I can show you, here is one. There isn't a lot of space in this, right?
Even by today's standards. So this is a chip that is glued with epoxy, and that's it. That's why it's so thin, okay? So I can't route too many lines over there because it won't fit. Okay, so I have to do something, right? What? I can start cutting off stuff I don't need. Do I need a data line?
No, I can do magic, right? It's going to appear. Why do I need that? Well, but I would like to cut those 16 bits also because they are too many, right? I can't cut any of the rest, right? I need them. So I can cut the 16 bits. Well, kind of. The problem is that I need those bits to determine
my special address that I can repeat three times. So if you look at the address space of a ZX48K, it's actually 64K because 16 kilobytes is ROM. And we know that because the last bits of the address is 00, and
all the others is RAM. So we can only mess up with the first part, right? So what can we do? Maybe we could force that if A15 and A14 is 00, we are in business. Actually, we can't, because every access would give us that to ROM.
So maybe we can have a special address and include like A7 to A0 with A15 and A14. So like the ULA does in a weird way. So what this means is that I would have something like this,
which is a lot less than 16 bits. It's 9 bits, right? Well, not really. Maybe we can simplify this, okay? Do we really need this? Actually, we don't because we only need to know that it's a ROM access. But we don't need that to control the flash because the flash can read
directly those two bits, right? Because as you can see, so I didn't need this. Let me go a little bit further. So if you can see, this is the address space of the flash. So the last two bits of the 16-bit bus are in fact part of my flash page address,
right? So I don't need those to enter directly to my device that controls the logic. So they can go directly to the flash. I just need a way to trigger from them. So I cut the bus data lines, but now I'm using the 8-bit bus address lines to do this.
And I said I don't need the data lines, right? Why? Why don't I don't need them? Because I can pass all the information I can using the refresh address, right? So I'm going to use the refresh address as input. So I don't need those lines, so I'm saving a lot of bits.
Currently, I will map the A4 to A0 when I'm giving the special instruction to change page to the flash page area, okay? So I'm going to use this part, the A0 to A4, to give that page address.
Now, this is a simulation of the logic I created. And on top you see green, it's the input lines. And then you see blue and kind of, I don't know that color. Because it's different here, but the other ones were blue and
this was like magenta or something, but it's different here on the screen. Okay, so if we look on top, we have A15 and A14, which are the ROM addresses, right? What it identifies, so in dark gray, we see that it's a ROM address. They are both zero. Next, we see that they are swapping, so it's RAM address.
So I don't want to, if you see here, there is a chip select, okay? That's the one with the magenta color. That is only enabled when I'm accessing ROM, okay? When it is accessing RAM, I don't want to mess with it, right?
So that it works. And now here is the special case. If you will see the white line, it's the trigger address. So if you look closely, I had three clocks on top where the address didn't change. So it's my trigger, right? And the yellow line represents the input, my parameter. That's the flash page I want to select, right?
Then I have in green bars another access to ROM, but it's not special in any way. And then I have another access to ROM again. And this was just to try out if mixed accesses would work. And then here we have another example.
This was, I have a flash, right? And I can read it already with this idea. But could I write for it? Could I find a way to make it work? So the idea is, I'm going to use the A7 address bit to signal me a flag, if it's a read or a write.
And that has a problem, at least on this version. Because the flash chip doesn't like the chip select or the ROM something. I can't read it right now from that. It doesn't like it to be swapping. It must be stable. So what I did is, I still had space, so I added two more inputs.
With the advantage that this will allow me to put the control command in the I register, which is the other part of the address, okay? So, anyone scary of assembly?
This is really easy, it's commented, right? So the major, the most important thing is down here. So we have an LDI, it's the trigger sequence address. And then we have the load A with something. So these two instructions is what are going to do the job. The idea is that every instruction that I do, the R register will increment.
So I'm going to fool him, and before I calculate the change until I get to the LDI, right, to LDI and LDA, and I will put minus two. Because as soon as I write LDR comma A,
I'm going to do two extra instructions, right? With a special twist here, because I need the R to be correct on the second instruction. And there is a twist, LDI has a special instruction that increments twice. So that's why it's minus two. So this will implement this.
Now, the smart guys in the room would tell me there's something wrong with this. There are smart guys here, right? Well, I haven't put it because it's a lot of work to explain in detail in such a small area on screen.
But first, I need to set the I register, which is not there, right? But it's usually fixed at the value, but we can change it. And there is another important aspect, which is we need to disable interrupts, right, or else they will mess up my timing, right? Okay, so this is the version for write, so it's very similar.
We have to do an increase here in an instruction that just swaps the A and the flags register so that you can save the data while we change the R register. But actually, it's just the same until we find here which is a write and
not a read, okay? But it will work the same. I've tried it, and it was able to read the flash type, which gives me the size, okay? So what do we need to do to make this work?
We need to define a circuit diagram, and I decided to use wire wrapped prototype boards, something from the past. So it's suitable. Data analyzer for debugging, define a PCB board, and lately, and also design a case. So let's go and do this. So this is a very simple circuit.
We have here on top, it's the connector that represents the cartridge connector. Here we have the CPLD, which is an ATF22V10C. And we have the flash ship from Aetna that is hard to find because parallel ships, parallel flash ships are currently very hard to find.
Okay, so this is my prototype that you can see here and that you will see working. And it was done in three phases, like three slots, because it's easier. This mess you see here in the middle is the wire wrapping, or
a way to build a circuit without having to pay for the cost of the PCB. We use something that is already made and then route the rest ourselves. But sometimes this gets really messy when you have to take one of those wires that is behind the others. And another concern is that if the speed is very high,
every loop that you do to fix those wires will make it work like a coil. So that's a problem. Okay, this is hardware debugging. And you can see on top, I hope, there are three identical addresses, because I haven't all the addresses here, but the most important ones.
So I have three addresses. And after, in that green line, you can see that the green line is triggering one position too far, so it should be one before. Why does this happen? Because the guys from the manufacturer from the CPLD forgot to mention that there were flip flops that were master slaves, so it delays one clock cycle.
So this was the first version to see if the board would fit with the chips. This was the version 1.0 with the planes already defined.
And this is the board that was manufactured. I have some here if you then want to see. So it has small legs on the front so that you can see what's going on. And the ships is on the back side where we have the 2.2 millimeter space that is enough for the ships. So this is the original board that I've shown you.
This is a 3D representation of it so that I could model the case. And next step, and then I also want to do the part of the rubber because there is this red thing that is rubber to protect the connectors, okay?
So this was my first version of the firmware. The idea is to run code and see if the paging is actually working. This is a simple GIF. It's not running anything right here, but it's to show that we can use the 512 kilobytes
not just to have a bigger game, but to have a list of games that we can just dump to RAM so that 80 can start running the old games. This was a page I designed to be able to debug also the memory that is on the ROM that is not implemented yet.
So what do we need for software? Well, we need to make a proof of concept, adapt existing multi-level game R-type was my choice. And I have to thank Bob Pape, which was the original guy that transformed this from the arcade to the Spectrum. He participated and helped to do this.
And so I have to thank him. Thank you very much, Bob. So what we do is copy what is on ROM to RAM and run. And when we have the need to load, because this game has eight levels, and every time you play after level one, you have to load level two.
And that means you have to press the tape, wait five minutes or something like that. And if you die, you have to go back to level one. So back the tape and do it again. That's what this is going to avoid, right? And we can do some extra stuff when we do this. So we can implement invulnerability and load level with this.
So we can try, go and try the game. So let me try and show you. Sorry for being hidden. It's top secret.
We have to change the video, sorry. Oh, by the way, this is the link to the GitHub with the code for Knox ROM, for the firmware.
And it will also have the code for flashing the CPLB. Do I need to change something? Maybe power up?
Great. You know, this is my special tool. It's a wand. So if I can fit it here. I told you guys it was magic, right?
So, and now we, so I have to lean down a bit, but now we can play this game, right? And it's a special Knox ROM version.
The game is running. Okay, now if you press enter, you can select what you're going to do, fire and detach. And you can start playing, right? And I can't see, I can't say the other words, but I can see what I'm doing, right?
Right now, so I'm going to die. Great. So how do I fix this? Easy. I can boot again in invulnerability mode.
Okay. Let's select some keys again. Sorry. Up, down, fire, and this one, right? Let's hope I left the key pressed enough. Let's try and die.
Maybe down? Hmm, doesn't die. Great. So this is great. If you can't play, you can go to the top level. Okay, but, and now what if I want to load the next level or the last level? I never reached the last level, right? It was so hard.
So let's try that. So resetting again, and for example, let's load level three. Okay?
By the way, Bob was nice enough to tell me the codes to do this. I didn't have to search the code for it. So I'm playing level three directly from the cartridge. And I can load any level, and this is great if you want to get a good eye score because you can have passed the same level several times, for example,
if you reach the last one. But it's working. So the concept works. It's possible to communicate with the ROM and expand its size. I'm also planning to... I did a few test boards, like these ones. Don't mind, don't mind.
Didn't break. And this is an original box, a case, sorry. And I'm going to just see if it fits. And it fits, right? It's still missing this, right? But I'll get there. And I have to do the board like 3D printed or mass produced or something.
I don't want to wait 50 minutes for a case, right? And here is a warning for you all. So I made the design and trusted my library. So the layout of the chip should be correct, right? At least we hope so.
But what happens, I don't know, you probably can't see. Maybe I could find something white. The chip is here, right? And the contacts are there. Can you see it? Probably not. But you can come up and see because I'm done. So be careful when you draw this so that it doesn't work like you expect.
Any questions? What's your background? I'm a software developer by profession.
So how did you get into hardware? Well, I like hardware a lot. And I started studying it on my spare time for a few years back. So you started with a book about CPUs and then what? No, I have a background in programming. So I know what CPUs are like and how they work.
So I had digital classes on the university, right? So that was when I learned the more detailed stuff. But what you need to know is already on the web. So if you find it, you take a few iterations and you get there. Yeah, before it wasn't possible, you had to go to the lobby,
or some project on the book. I've got a probably stupid question. The image that you took off that was taken off the arcade machine, why did you not need to patch it to access other regions of memory? Or did this game not use all the 512?
This game uses like 120 kilobytes. I'm planning to do POW that will use the 512 kilobytes. But this one doesn't use that. So you didn't need to rewrite the binary in any way? No, I did. I did. But with the help from the guy that did it in the beginning.
So he helped you? He helped me to split the code in parts, and then I implemented the part of the paging and loading, etc. And everything was untouched, except the small item that he wrote like Knox ROM special version. So it was a collaboration effort.
There is one more here. Don't need to be all over each other. This is the original. This is a pristine one. You can also print a rubber. Yes, you can. It doesn't feel the same. It doesn't feel the same.
It doesn't. But it's not hard to study yourself and do a mold. You implement blow. You know how to have. You have to blow. Yeah, this is not Atari. It doesn't have the same problem. It doesn't have the same problem, yes. Very impressive. So it's just hacking, right?
It's just hacking. So we have to... But this is the Xpecto Plus. It's the same. The same hardware, yes. I have this one, but this driver cuts the image like two characters on the left.
So I use that one. But it works on both. Okay, I can show you. I have this. Well done, by the way. That was amazing work. One small spectrum, no more than it was designed for.
Yes. Actually, I was trying to see if someone would ask me why haven't I used something like DivMMC or... There are other interfaces that allow you to load from SSD card, right? So why can't we use that?
We can, but the problem is that you load games that only fit in 48K. I can do a game that is 512 kilobytes plus 48K of RAM, right? And I also can use this on a ZX80, which is the chip that only has one kilobyte.
Okay? So the firmware has to be adapted because the screen rendering is not the same, right? But it will work. 8 kilobytes of RAM. Let me see if it works without the one. No, no. Maybe, maybe.
Yes, it's working. The problem is that there is a small connector on this board. So sometimes it does a bad connection. We just put the magic wand and it works.