It has the usual opcodes and directives, includes, relocation data etc, with a couple of other helpful output files alongside the expected binary one.
Because the driver for it was coding on the ZX Spectrum it will also create tap files with a BASIC loader and loading screen support. And it has a not very featuresome sprite editor built in for the Spectrum screen and attributes. Oh, and a PNG-to-SCR conversion process for loading screens that does a bit of work to show problem areas (as heatmaps).
It's only actually been used by myself and one other person so there may be a few hiccups, but it WOMM :)
There was only a single[1] register though, the accumulator.
[1] Okay, there was the PC as well. Maybe a flags register too? But only one used for variables, IIRC.
https://spectrumcomputing.co.uk/entry/2000237/Book/Mastering...
http://www.primrosebank.net/computers/zxspectrum/docs/Comple...
It wasn't in regards to the flag register. The parity flag behaved differently for some ops.
And of course it would be possible to write an 8080 program that used undefined ops that would execute in some random way (often just duplicating an existing instruction) while the Z80 repurposed that opcode for something new.
In legacy programs the parity flag was seldom tested and practically never after the instructions where in Z80 it behaved differently.
This allowed the repurposing of the parity flag as an overflow flag, which was an extremely useful extension of Z80.
The instruction sets of Datapoint 2200, Intel 8008 and Intel 8080 share with that of RISC-V the distinction of belonging to the extremely few ISAs where overflow is not detected by hardware.
Datapoint 2200 and its first successors had the excuse that they were extremely simple and cheap designs, which were never intended for general-purpose computing.
RISC-V has absolutely no excuse. The lack of overflow detection is its greatest mistake.
https://gmplib.org/list-archives/gmp-devel/2021-September/00...
even on x64 you get better performance when you don't use carry flag and just use limbs https://www.chosenplaintext.ca/articles/radix-2-51-trick.htm... - risc-v is even more so
and experimentally gmp bench results show performance in line with arm https://old.reddit.com/r/RISCV/comments/1jsnbdr/gnu_mp_bignu... so panic was for nothing
Using limbs is a workaround for the fact that most vector instruction sets also do not implement carry flags (an exception was the discontinued Intel Larrabee). Moreover, usually the fastest integer performance is obtained when using the floating-point multipliers, which limits the size of the limbs to 52 bits.
Despite the fact that using limbs is more cumbersome, the much greater number of arithmetic execution units available for vector instructions compensates that and ensures a greater performance.
Saying that RISC-V "removed carry flag for performance" is a fantasy. The saved hardware is completely negligible and significant performance is lost, not gained.
Moreover, the carry flag is required not only for multi-word operations, but also for detecting unsigned overflow. For this purpose, no limbs can save you.
Regarding the benchmarks linked by you, they show a really pathetic performance. They do not seem so bad as they really are only because they are not compared with x86 CPUs or with any ARM CPU more recent than the 10-year old and obsolete Cortex-A72, which is many times slower than modern ARM CPU cores. Cortex-A53 is an even worse comparison point, being a little core that is much older than a decade (from 2012).
"why do you compare 15y.o. chess GM against 15y.o. Carlsen instead of world champion he is today? if you do you'll see how pathetic performance actually is"
everything gets a weight category. immature architecture gets benched against immature state of architecture. narrow OoO gets compared against narrow OoO
check in 4 more years for results closer to frontline - but where we are, theoretical worries did not come to pass
Moreover, at that link it is shown only the ugly way in which RISC-V does multi-word addition.
Checking the standard arithmetic operations for overflow is much more horrible and inefficient than that, and checking for overflows must be done in any program that claims to follow safe practices.
Unlike in software, computing the carry and overflow flags in hardware is absolutely trivial and the extra gates needed for this add a cost that is below a rounding error in the total chip cost.
With Z80, it was much easier to compute arithmetic expressions than it is with RISC-V, especially when working with big numbers and especially when mandating correct computations, with no undetected errors.
modern out-of-order execution gets hindered by such non-parallel cpu state, so it wasn't included
OoOE CPUs need hundreds of registers in order to not hinder the parallel execution, so even the 32 general-purpose registers are not enough, so they must be renamed. Once register renaming is implemented, it does not matter any more if there is a single architectural flags register.
When a cheaper solution than register renaming is desired, the correct solution was that of IBM POWER (1990), where there are 8 flag registers (with 4 flags in each, so the total size is 32 bits). That allows the parallel execution of up to 8 instructions per cycle, even without register renaming.
The superior IBM POWER ISA was implemented even in microcontrollers that were smaller and cheaper than the current RISC-V cores.
An alternative solution to having a flags register is to implement instructions with 3 input operands and 2 output operands. In this case, for the instructions that generate flags, they are stored in the second output registers.
In reality, all the 4 basic arithmetic operations with integers have 3 inputs and 2 outputs, when defined correctly. They are redefined to have 2 inputs and 1 output only to allow cheaper hardware, and in this case the additional input and additional output may be enabled only for some of the instructions, where they are stored in special registers, like the flag register, or in some ISAs in special extension registers used for multiplication/division/rotation/shifting.
If you fix that by saying that every instruction sets the whole flags register, then it only makes sense to read the flags register in the very next instruction after setting it, and you may as well combine those into one single instruction and then you don't need the register at all.
Exception is ADC chains which both read and set the register. I think RISC-V doesn't support them?
Because of this, most modern ISAs take care so that the flags register is always updated completely.
In legacy ISAs, like in x86-64 where the carry flag is updated or not updated separately from the other flags, it is handled by the CPU as a distinct register, so the carry flag is renamed independently of the other flags.
Moreover, in x86-64 the overflow flag can be used as second carry flag in some instructions. Having 2 carry flags permits the elimination of some functional dependencies between instructions that would not be eliminated by the renaming of a single carry flag (renaming solves only resource dependencies, not data dependencies).
Out-of-order pipelines actually have a really elegant way of handling flags, they just store a copy of the flags register on every ROB entry. During renaming, instructions that consume flags just gain an extra implicit input pointing to the ROB that will contain the correct flags.
Such pipelines already need deal with so much serialised state. The flags are actually one of the easier things to deal with, they basically get support for free when they implement register renaming.
It's actually the "classic RISC" style in-order pipelines where flags are annoying to deal with. They pipelines don't need to do any register renaming, so they don't have a free solution to handle flags. And the RISC-V ISA is very much optimised for these simpler pipelines.
But if you are designing a new ISA for the modern era (the purported selling point of RISC-V), you just don't implement any such instructions. Only implement clean instructions that update all the flags or none. ARM and PowerPC already did this 35-40 years ago.
The 2 parts of the flags register are reunited only for the purpose of saving or restoring from the main memory. (Actually the x86-64 flags register has 3 independent parts, the carry flag, the other status flags, and a set of configuration flags, which are not modified by most instructions.)
And yet, flag writing instructions are usually half the throughput on regular ALU instructions, on modern wide ooo designs. [1, 2]
But I generally agree, there is a good way of handling them, it's hust unclear to me how expensive it is. It can't be that expensive, but apparently it is expensive enough, to not put a mask register write port on all integer execution units.
[1] https://dougallj.github.io/applecpu/firestorm-int.html (see how ADD is 6-issue and ADDS 3-issue)
[2] https://developer.arm.com/documentation/111027/4-0/ (again 8-issue ADD, but 4-issue ADDS)
N and C are basically free (copy of bit 63, and it's carry out), V is an extra gate or two, but Z requires a full 64-bit wide NOR gate.
Or it might be about making the register file holding the flags smaller (only 3R3W, instead of 6R6W), along with simplifying the associated bypass network and routing (the first three ALUs are also the only units that can consume flags).
When I say ooo cpus get flag handling for "essentially free", I'm only actually talking about the complexity of tracking "implicit state", and that it can be done without extra latency. You still need to spend transistors to support renaming flags, and to actually calculate and storing the flags.
I can see an argument for an ISA that got rid of the N and Z flags, but kept C/V (potentially merged into a single flag). You can trivially reconstruct N/Z from the result register, but not C/V.
At that time, many people still used assembly language and they would have never accepted to write arithmetic expressions in the contorted way forced by RISC-V.
Now compilers hide this aspect of RISC-V so most are not aware of this. Moreover, most people are still using programs compiled from C/C++ with unsafe compilation options, or even from Rust, where by default integer overflow is not checked in programs compiled for "release", so they do not see how much performance RISC-V loses when executing programs that are designed to produce correct results.
The parity flag is a breaker though; "binary compatible for code only relying on the 8080 instruction set, other than values of the parity flag".
I wrote a quick post a while back about my Z-80 experiences here:
Maybe it's because it was so clearly written that a kid could understand it, but it was a revelation, and I read it cover to cover. I never actually touched a real Z80, but it was a good enough introduction that I had no problem understanding other micro's including the 6502 and early microcontrollers such as 8051 and PIC.
Even today, I suspect that I "understand" modern micros by falling back on the Z80, and I recommend learning an 8-bit micro because they're simple enough for mere mortals to comprehend.
I was just thinking of you the other day in fact! Do you remember that terrible flight simulator we wrote in your BASIC, then discovering your assembly!!!! Yes, I remember, at 10 I was incapable of ASM, but that's why they made the 6502C years later!!!!! I still love you Z80, you did pop my cherry! <3
I hope ur not still upset about that whole AIM-65 incident.....
That was very handy for reverse engineering programs like the Microsoft CP/M BASIC interpreter or FORTRAN compiler.
It was cool to do that kind of stuff, you knew exactly what your program was doing (if all went right) at all times, but it sure was a slog to get anything complex moving.
You translated you assembly language to machine language. ( Machine language is the only language a CPU can understand. )
I wouldn't call it a 'translation'. It's encoding. (We don't think of converting between ASCII codes and symbols as translation.)
Europe too :) When I was in high school, TI-84 Plus was the calculator the school told all of us to buy. And I see that stores in my country are still stocking them so I have to assume they are still being bought and used.
Many hours were spent by me and my friends making and showing off little programs in TI-BASIC on those calculators. None of us ever took it all the way to learning Z80 assembly however. I printed a whole manual about Z80 assembly programming for the TI-84 Plus and started reading it but never wrote a single line of assembly for it. Yet.
If someone wanted to use a Casio instead, they could. But the teachers also said that if you buy a different brand and model other than TI-84 Plus, you are on your own to figure out how to use it for all the different things we needed graphing calculators for.
Everyone in my class did the sensible thing given that they told us this, and bought the TI-84 Plus. There was no reason to buy a different one when our classes assumed the TI-84 Plus. Only making extra problems for oneself.
Not the same, actually! Unlike the TI-83/84 series, the TI-89, -92, and Voyage-200 all used a 68000 CPU, with a completely different (and much better) operating system.
I wrote a web-based emulator for the Voyage-200 a few years ago: https://woofle.net/v200/
[1] Except the screens on the older models were truly horrible, from a brightness and contrast perspective.
[2] From my recollection, the calculators interfaced with hardware and software from other vendors. Then, of course, there was the vendor lock-in provided by textbook publishers.
I agree that you not need to have more powerful calculator. A cheap Casio or HP calculator it's enough for the 99% of time. I keep using my old Casio from my formative years. It's in an interesting calc. Powerful enough to write formulas and complex calculations, but can't store formulas or programs. Just in the nice spot that allowed it to be used in exams.
There was an active modding scene around them, and even some attempts at creating a replacement firmware, but unfortunately most of that seems to have disappeared.
One three-day weekend, I slept about 4 hours while I was disassembling the BASIC ROM to find nuggets I could call in my Z80 programs, and also to learn so much more about the video, the cassette interface, interrupts, etc. My notebook looked like something a madman had scribbled on the walls of an asylum to everyone around me, but to me it was perfectly organized, and I used it to reference things I would use later in my programs. I got to the point where I could read the hex dumps and "see" the op codes in my mind; people would look over my shoulder while I was debugging, and I'd be explaining what the code was doing, but I hadn't disassembled it yet. I didn't even realize I was doing that until one of my classmates pointed it out: "Hey, disassemble that. I'm not following you, how the heck do you see that?"
And all of this because my science teacher had that TRS-80 Model I sitting in the corner of his classroom gathering dust; nobody knew what it was, I didn't either, but I had to figure it out. I've always had this bug, I don't believe in magic, I want to know how everything works, it's been an insatiable thing all my life, that first machine set me on a course of learning for the rest of my life.
Thanks, Mr. Kruzan, you changed my life. I'll never forget you. Oh, and thanks to all the people who created the Z80, the TRS-80 Model I, and paved the path for me to learn computers and never stop learning.
We are truly building on the shoulders of giants; every generation, more giants. It's humbling to look back and think about it forty-five years later...
[1] https://www.trs-80.org/edtasm.html
[2] http://www.z80.info/zip/zaks_book.pdf
PS: Pretty sure the memcpy examples have a stack bug.
I'm aware of: proprietary ones like GEN80 (my fav way back), M80/L80, at least one open source assembler written in plain C, and probably some table-driven assemblers targeting multiple architectures.
As a kid, it was all about 6502 micros, but my early professional love was Z80 and it still warms my heart to think about. Sure, the “other” 8 bit CPUs had zero page, but block instructions and 16 bit extensions FTW. <3
Still I've always loved the z80, since my first computer the ZX Spectrum. Even now I play with z80 assembly now and again (mostly for CP/M retro-use).
First, my Father wanted to try to add some peripherals to the original TRS-80 Model 1. So, what he was interested in doing was asserting the BUSREQ pin to tell the Z80 to get ready so that he could have the bus, ideally waiting for the BUSACK signal to know when it was his.
Unfortunately, on the Model 1, when you assert the BUSREQ pin, it is tied directly to the tri-state buffers that handle the address and data bus. So, as soon as you make the request, the Z80 loses all access to its memory and data -- mid cycle. Which, you know, can be Bad. Radio Shack labels this pin TEST and uses it for internal testing. But it was definitely a bit of a disappointment to my Fathers efforts.
The second one is when I learned that the Game Boy Advance has a Z80 built into its chip. The designers drag and dropped a Z80 core (tweaked for GB) just so they could run legacy GB games on it. It just kind of bends your view of the computing world when something as significant as a Z80 can just be shoved into the corner of a die for "just in case" functionality.
Just shows how far we had come at the time.
[0] https://en.wikipedia.org/wiki/Game_Boy_Advance - "Manufactured by the Sharp Corporation, the SoC contains two processors: the ARM7TDMI running at a clock rate of 16.776 megahertz (MHz) for GBA games, and the Sharp SM83 running at 4.194 MHz or 8.389 MHz for backward compatibility with Game Boy and Game Boy Color games."
CP/M was an absolute beast in the era, with massive installed base and software support, employing 500 people in 1982. A CPU that could run unmodified Z80 software in a 64k segment would have allowed DRI to ship 16 bit CP/M with only basic tweaks and likely kill the market for the PC.
It was, famously, DRI dragging their feet on 8086 support that motivated the release of QDOS, which was then bought by Microsoft and relicensed at an immense markup to IBM as MS-DOS.
Cheers to Rodnay Zaks for "Programming the Z80"!
The MOS 6502 was introduced at the WESCON tradeshow in September 1975 and sold for $25 quantity 1. They had a transparent vase full of them, 'proving' they did volume -- but those were all chips that failed post-manufacturing testing, except for the very top layer. Still...
One might say the instruction is really "jump to WZ", or JWZ, which, of course, refers to Jamie Zawinski (not really).
Unlike anything I had ever experienced, it was life changing, I would bike to the store every day after school
Family couldn't afford the computer but I bought all the books and would read them at home over and over and gawk at all the accessories in the catalogs
Then family surprised me with it as a birthday present with all the relatives paying for it, pretty sure I was the only person in town with one, even the school didn't get one for years
Didn't have any way to save programs, not even the cassette recorder which was too expensive, had to memorize them and retype every time I turned it on
However, you had to be a programmer Anno Dominii 1975 to fully understand what heavenly Joy and Jubilation Z80 was.
Much of the instruction set was carried over from the 8008, that's where you get MOV & ALU operations, the pseudo-register M standing for memory at address HL, etc. The 8080 then added to that some extensions that weren't as orthogonal, but greatly improved the usability.
That memory copy example, rewritten for the 8008, would take more than 30 instructions, constantly juggling pointers in and out of HL, because there was absolutely no other way to access memory. For that you needed an extra free register as well (no XCHG instruction!), so only a single 8 bit register would be available to use as a counter. Or you could store the counter in memory, but in that case there would be even more instructions to first load the address of that variable into HL!
In 8080 assembly as defined by Intel, each of these extended instructions has a unique mnemonic. LDAX = load A extended, etc. There's a one-to-one correspondence with the opcodes, so it's easy to memorize the encoding (best in octal), and what register can be used for what purpose.
Zilog added even more unorthogonal extensions to this set, but "simplified" the assembly so that one mnemonic could produce many different opcodes, some with an additional prefix. Most of these don't provide any benefit over using the existing 8080 opcodes, and you have to memorize lots of seemingly arbitrary restrictions. If you first learn Z80, those make no sense at all.
Found a great kit using the Z80 and built it and spent many nights with a logic probe and oscilloscope learning digital eletronics. Also devoured the Z80 manual learning the instruction set.
I'm nearly 70 now but remember those days like they were yesterday.
Truly a magnificent CPU
Despite being entirely self-taught due to never having programming classes or books, I enjoyed a long, quite successful career as a serial startup entrepreneur. In 1981 the only info for 'toy micros' was small hobby zines, local user's groups and just learning by disassembling other people's code. I started with the ROMs in the computer and learned by looking up the opcodes on a Motorola quick reference card. I got it by cold calling Motorola trying to sound like an 'adult' and the salesperson took pity on me and mailed the card for free.
I still think there's something invaluable about learning computers from first principles down to the metal.
Totally agree!
I never went to Uni either (at least not until I retired) yet have had a very succesful career in IT and still love tinkering like it sounds you do.
Those were heady days :-)
It sounds like it may be right up your alley. Its a simplified digital logic simulator, you make basic circuits from NAND gates, and then build these into functional units in later levels, then further on you build an instruction decoder, and combine it with these functional units and before long you have a Turing complete architecture and you are writing your own assembly on it - Assembly language that you defined, from scratch. You'll find the need for new opcodes... so, you build them! Challenging game for sure, but very, very rewarding.
The game is still in early access, but very near a full release. They just put out a trailer: https://www.youtube.com/watch?v=goclUECM2ds
I'd love to see another designer introduce a FORK86-64, but things are much more complex now.
Software binary compatibility is less important now than it has been for 30 or 40 years of x86 dominance because now we are so over-served by hardware that most software runs just fine in emulation (especially transpiling/JIT).
Compatibility also wan't too important in the 70s and the 6502 wasn't compatible with anything else. Everyone expected to rewrite everything back then whether between manufacturers or just a new model from the same manufacturer.