Isetta TTL computer, runs 6502 and Z80 code

Hi all,

I’ve been working on a new computer, called the Isetta TTL computer.

The prototype is working, it runs ZX spectrum games, Altair BASIC and Apple 1 BASIC.

It is built from TTL chips. There is no microprocessor or FPGA. Most important features:

CPU clock speed: 12.5 MHz
Instruction set: 6502 and Z80
memory: 512 kByte RAM (8 bit wide)
microcode: 24 bits wide (3 flash chips)
video: VGA graphic 320 x 200 (64 colors), or 640 x 400 (16 colors)
filesystem: 32 MByte fixed, micro-SD card interchangeable
input: PS/2 keyboard, PS/2 mouse
connectivity: File transfer from/to Raspberry Pi, and WiFi module
sound: 8 bit samples, 31 kHz sample rate.
size: 119 x 150 mm PCB

I intend to offer it as a kit and/or complete system when I have all functions working.

Details can be found here: Isetta TTL computer | Hackaday.io

happy hacking,
Roelh

4 Likes

(Welcome - I thought your name was familiar, probably because I’ve seen your projects over on Hackaday!)

Sounds nice. The 3rd cpu could be a tiny pascal p-code.

Thanks for posting, Roelh! That is beautiful work. One thing I missed reading your work on Hackaday - how does mode switching (6502 to Z80) work? Is it an external signal, overloaded opcode, I/O, or ?

Hi pdxjjb (not the easiest nickname)

“how does mode switching (6502 to Z80) work?”
At the end of the microcode for an instruction, a microcode is executed that reads a new opcode from (pc) and puts it in the instruction register. At the same time, a 4-bit constant from the same microcode is put in the page register.
The opcodes for 6502 are in page 1, and the opcodes for the basic Z80 instructions are in page 2.
The address for the microcode flash-ROM is composed of the 8-bit instruction register, the page register and a 4-bit step counter.

So for a 6502 program, at the end of an instruction, “1” will be written to the page register, so the next instruction will again come from page 1.

But if we make an instruction in page 1, that gets the next instruction from page 2, that will essentially be a switch to the Z80 instruction set. The same program counter and accumulator will be used for Z80. The other registers are in memory, and might partially overlap, depending on their definition in the Javascript microcode generator.

Several Z80 instruction are followed by an extra opcode, these extra opcodes have their own page in Isetta. So there are separate pages for IX, IY, “CB” and “ED”.

At reset, the page and instruction are cleared, so the processor will start with instruction 0 in page 0. It will do several initializations, and copy a start-up program from microcode to RAM. The start-up code is a Z80 program that has some debugging functions, but will normally get the “boot.bin” program from the serial flash, and start that.

For the Z80, there is also a special page for I/O instructions. That means that every I/O port has its own microcode sequence of 16 steps max. But if 16 steps is not enough, microcode can directly jump to another microcode section of 16 steps. One of the I/O ports is dedicated to switching from Z80 to 6502.
The I/O instructions are also available for the 6502 (with the same opcodes as in Z80, possible because 6502 has a lot of unused opcodes).
The Isetta has a special (memory-resident) register that keeps the current running processor number. At the end of an I/O instruction, this register is used to return to the correct processor page.

I hope this makes it clear.

Happy Hacking,
Roelh

2 Likes

Oh, that’s cool. Thanks!

I first posted my Isetta computer as a response to another topic, but now it has it’s own topic here.

1 Like

Congratulations on a very cool project! Like Ben said, UCSD P-code might be a suitably retro third ISA to implement. Though it was a software virtual machine on Apples, PCs and TI-99/4A (among others), Western Digital patched the microcode for the PDP-11 implementation to make their Pascal Microengine product.

Thank you, Jecel !
A P-code interpreter will certainly be possible. But it won’t be very efficient, because as I read here, it is stack-based. Isetta has only one HW memory pointer (DPH/DPL), if we would use that as stack pointer, we would have to save/restore it at every non-trivial memory access.
For 6502/Z80 the single memory pointer is not a big problem because stack operations are not very frequent, so memory accesses can always use the HW pointer.
It would be better to use an architecture that has a lot (8? 16? 32?) of registers. For byte-sized memory-resident registers, only a single cycle is required to get it into a hardware register (and it can even operate on it with an ALU operation with ACC or T, or an INC/DEC, at the same time). Word-size registers would just take two cycles to load.
Isetta can (in next pcb version) address 64 ‘fixed’ registers, and also 64 ‘exchangeable’ registers (used for Z80 alternative registers). But several of these registers are in use by microcode that operates the I/O devices (screen, sound, serial, keyboard, mouse etc).

1 Like

I had the impression that the microcode had access to only 8 registers of 8 bits each.

You are right that swapping a stack pointer back and forth (no pun intended) would hurt performance.

The 6809 was considered the “king of 8 bit processors”. Having written an object Logo interpreter in both Z80 and 6809 assembly I can confirm that pointer chasing is more elegant on the 6809. Besides the main instruction byte there is an optional operand byte a bit like the VAX or 8086 which would be a problem for many microcoded machines but works well with your design.

1 Like

Hi Jecel,

I’ve been looking at the 6809 instruction set.

Isetta can handle opcodes that are multiple bytes long.
But this is most effective when the actions of these opcode bytes are independent.

As an example, let’s take the bit-set instructions SET 1,(hl) and SET 1,(IX+5) in Z80 mode.

For the SET 1,(HL) (instruction CB CE), the opcode starts with a 0xCB code that tells to the processor that this is a bit-or-shift instruction.
The 0xCB will put the registers H and L into the HW memory pointer DPH/DPL. It will
then execute the next opcode (0xCE), using the code page that implements the bit-or-shift instructions.

The bit-or-shift instruction can use a single register (A, B … H) but can also operate on (HL), and in that case it will use the byte that DPH/DPL points at.

Now for the SET 1,(IX+5). (instruction DD CB 05 CE)
The first opcode ix 0xDD, indicating that a normal instruction follows but HL is to be replaced by IX+5.
It will now read the next opcode, and use a code page that is special for the IX register. Here it will find the 0xCB opcode. But in this IX page, the 0xCB opcode will put the IX register in the DPH/DPL register. It will also read the displacement value from the following instruction byte (0x05) and add that to the DPH/DPL register (as a signed value).
Now it will get the next opcode, that is the bit-or-shift instruction 0xCE.

Now the bit-or-shift instruction executes the opcode CE. It is exactly the same as for the (HL) case. It will set bit 1 in the memory location that DPH/DPL points at. Note that this bit-or shift instruction has not the faintest idea if it handles a bit at (HL) or at (IX+d). The handling of the CE opcode is independent from the things that happened before it, in the same instruction.

Back to the 6809.
It will get the first opcode byte and put it in the instruction register.
If it is an instruction with indirect addressing, it will get the postbyte and put that in the instruction
register. It will calculate the effective address and put that in DPH/DPL. But now it has to
figure out what to do with the address. That information is in the first opcode byte, that is already gone !
We could re-fetch it, but that would mean decrementing the program counter. The PC can increment in the same cycle as an opcode fetch, but decrementing it will be clumsy.
We could also, when we are handling the first opcode byte, store that byte somewhere, so it is available to re-execute that (in another code page, with other actions) after the address has been calculated. So that will also need extra cycles that will make executing 6809 code not very effective.

Having two opcode bytes can be quite effective on Isetta, but we must split the instruction in independent sections.
For example, the first opcode byte could calculate an effective address and put that in DPH/DPL. The second opcode would then specify an action with the data that DPH/DPL points at. Or, the first opcode byte could fetch a value (this could also be an immediate value fetched from the instruction stream). This could also be a word (one byte in A and the other one in T). The second byte should then specify
what to do with that value. Both systems (effective address, or value) could also be combined in a single instruction set.

It might be possible to re-define the 6809 opcodes, to be effectively executed on Isetta.

But since there are so many (memory-based) registers, we could define a new instruction set inspired by the 68K, with 8 data registers (16 bit) and 8 address registers (also 16 bit).

NB Your “no pun intended” did put a smile on my face.

2 Likes

You are correct that it is more convenient if the operation is encoded in extension bytes instead of the first one. That is exactly what I did for the retro8 processor I defined in 2013 (but haven’t yet implemented) in response to a comment in the predecessor to this forum.

The advantage of handling unchanged 6809 binaries would be limited to text programs (like OS-9 applications) on a machine that doesn’t have CoCo compatible graphics (or Vectrex graphics).

I forgot to ask - is there any relation between your project and the Isetta car?

There was a joke in the 1960s that if you drove one of these from São Paulo, Brazil down to the beach you would be unable to drive it back up the mountain and would be forced to sell it to some local person.

Yes, I named it after the car, because just as the case with the car, the performance of the Isetta is much less than the current norm for computers.

Jecel, I just read about your Retro-8 design. Nice ! At first sight, this could be implemented on Isetta without much trouble. But accessing more than 64K could be a problem.

I thought your new “Application mode” made it easier to set the top 3 address bits for each cycle. If that is not the case then it would indeed complicate doing retro8 on your hardware. But since I haven’t implemented it yet I don’t know if it is any good, so it might not be a great loss. I was partly inspired by the awkwardness of programming the 65C816 and wanted to show that 24 bit addresses could be handled as easily as 16 bit ones.

Hi Jecel, yes, the application mode sets the top 3 bits, but the same 3 bits are used for the code space and that is not what you need. Actually I think this could be improved, the data bank should be more independent from the code bank. I’ll think about it. The new design has not been sent to the pcb maker yet, so there is still opportunity to change it.

I had imagined that the bank would have to be loaded up to three times for some instructions: from the top bits of the PC for instruction fetch, from the top bits of the source address and from the top bits of the destination address.

Another thread in this forum talks about how nice the extension in the eZ80 processor to 24 bits is. Implementing that on Isetta would have these same issues, but might be a good option for you as there are nice retrocomputers with this chip and you might be able to share programs (like the adapted BBC Basic, for example) with them.

Hi Jecel, I thought about it today. Figured out how to set indepent banks for code and data. But I decided against it, it will cost me too many extra parts, that’s against the design philosophy for this project.
But actually, we can reach almost everything needed with the current design. The code need not be in the same bank as the data.
The microinstructions that read from code space can use the Native mode. That means that the bank number is in that microinstruction, giving max code size of 64kByte. But if we always use an instruction of two bytes, we can put even bytes in a certain bank and odd bytes in another. That would give a max code size of 128kByte.
At the same time, microinstructions that use data will use the Application mode. That means that the upper 3 address bits come from an output register. That output register could be written with explicit instructions, but it is also possible that at every instruction this output register is written again with bit16, 17 and 18 of the used address register, although that will take some extra cycles per instruction.
As long as the output register is not changed, the above system will cost no extra cycles.

1 Like

Hi all,
The Isetta made it to the Hackaday frontpage ! See it here:
The Computer We All Wish We’d Had In The 8-Bit Era
Happy Hacking !

2 Likes