As the proud owner of a ZX-81 I remember staring at the Z80 instruction reference at the end of the user's manual without the faintest clue of what any of that meant. It took me some while before I managed to wrap my head around how CPUs actually run programs (vs. the high level abstractions like BASIC or other languages).
That machine was my intro to computers too, and I was fascinated by “fast mode” blanking the screen and the interesting tradeoffs between hardware and software.
Another proud ZX-81 owner, my first computer bought as kit. It made me the TI pioneer in my little city. So cool times, everything was complex and simple at the same time. I had a flight simulator in only 1Kb ram :D
Actually, BASIC’s flat structure helped me a lot in understanding Z80 assembly when I was 12. You see, memory addresses were line numbers, registers were variables, JP was GOTO, CALL was GOSUB. CP was IF, JP, Z was THEN GOTO, and LD was LET, and so forth.
No mention of the TI-84 calculator? Used by millions of American schoolchildren, programmable in BASIC, and runs on Z80 (B/W models)/eZ80 (color display models) to this day
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.
Same here (actually had a voyage 200, but same same I guess). It's actually quite insulting that TI kept (and keeps?) selling waaay outdated hardware at horrendous prices. It's the SAP/Oracle business model applied to school hardware.
While I agree on bit about horrible prices, the TI calculators are well suited to their intended task[1] so I will object to the outdated hardware part. Stability is a good thing in the context of classrooms. Why should schools be spending money on replacement hardware, software, and textbooks when the curriculum itself is fundamentally unchanged?[2]
[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 found a funny irony that in the country of free market, a calculator model was enforced nation wide in the schools. Here, in Spain, the teacher would only ask to the kids to get a calculator. They never ask for a concrete model or brand. Perhaps, they will only go ask to not get a programmeble calculator.
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.
> Same here (actually had a voyage 200, but same same I guess).
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.
We had both depending on the school and sometimes even the teacher. fx-9750G and GII didn't support assembly programming... unless you used an undocumented procedure to flash them with unsupported firmware from a different calculator model...
We were specifically told to buy TI-84 Plus. Also, there was a list of specific brands and specific models that were approved for use on math exams.
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.
There are plenty of open core alternatives that replicate the architecture and ISA. Many of these are cycle accurate. Some have been tape-out proven. Hobbyist retro-computing enthusiasts who wish to build a Z80 system still have options even once new old stock and recovered CPUs become scarce.
I started programming in 1978 (In Assembler) and wanted to know not only how the software worked but how the hardware worked.
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.
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.
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.
I started 3 years later than you on a 4K Radio Shack computer running a 6809 8-bit CPU. I can still remember quite a few opcodes and a few months ago helped some on retrocomputing.stackexchange.com find a rather tricky 6809 assembly language bug without looking anything up. It's weird how stuff sticks around in our heads, since I haven't written any 6809 code in more than 40 years.
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.
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.
That just means you have a more exciting design problem! Now you have to stop the clock and then assert TEST for probably a certain maximum number of cycles (dynamic logic) before enabling the clock...
Are you sure about that anecdote around the GBA? It would make more sense that they used the Sharp SM83 core - which is pretty far from a Z80 considering it's missing IX, IY and the entire alternate register set. It certainly does have some Z80 instructions and even some SM83 specific instructions. On the dial between 8080 and Z80 it feels closer to 8080 to me.
[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."
Happy birthday! The Z80 was the first CPU I rode, more luxurious than the subsequent 6502 and 6510. I still have a TI calculator with a low-energy 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...
Spoiler: the undocumented WZ registers are just microcode temporaries to hold large operands. For instance when reading a jump instruction, the jump destination can't be read directly into PC since that would mess up reading the second half of it, so it's read into WZ and then WZ is transferred to PC. This is invisible to the programmer.
One might say the instruction is really "jump to WZ", or JWZ, which, of course, refers to Jamie Zawinski (not really).
This is the CPU that I first learned to code on, first in TI Basic (TI-8[1356] ftw) and then Z80 assembler. Crazy to think that the CPU was "old" when I started, and it's still doing good work in those calculators even 20+ years later.
I still remember clearly sitting down to play with the TRS-80 at the local Radio Shack in the 1970s
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
Z-80 was the processor for my introduction to programming in assembly language on a TRS-80 model I in early 1983. Bill Barden's assembly language books and Hardin Brothers' "The Next Step" column in 80 Micro magazine paved the way.
I wrote a quick post a while back about my Z-80 experiences here:
When I was a teenager ca. 1980, my local Radio Shack had a shelf of books, and I worked my way through them as my funds allowed. Since the TRS-80 used a Z80, they had Barden's book on the Z80, published by Howard Sams. I already understood programming a bit thanks to learning BASIC, and my curiosity about micro's was piqued by my mom's subscription to Byte Magazine.
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.
Agreed. I only recently found out about a book that Barden wrote (also a Sams book) that was published in 1977 called "How to Program Microcomputers". It explains the common workings of microprocessors and then goes over the makeup and instruction sets of the Z-80, 6502, and 6800. I wish I'd had that as a primer on assembly language and programming for microprocessors.
The article claims:
> The Z80 is fully binary compatible with the 8080 instruction set.
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.
By the same thinking that have the parent post The 80286 and 80386 aren't binary compatible with the 8086. Because they replaced undefined opcodes with new stuff.
Making the parity flag not perfectly compatible was a wise choice.
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.
It doesn't have a carry flag either. Multiprecision integer operations absolutely suck in RISC-V, you need three operations (SLT and two adds, with an awful dependency chain too) to do an add with carry, and op fusion can only do so much. At least add an instruction that computes the carry out, like "Rd = Cout(Rs1 + Rs2)" and the similar one for overflow...
Unfortunately the criticism from that link is absolutely correct.
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.
taking architecture that explicitly removed carry flag for performance and then trying to to emulate carry flag anyway was stupid in 2021 and is still stupid today
Limbs work well only when the operations with them are implemented with vector or matrix instructions.
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).
In modern OoOE CPUs the flag register is renamed, like all other architectural registers, so it does not hinder in any way the parallel execution.
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.
What really hindered flags and OOOE were instructions that only partially updated flag bits. For example if increment sets the overflow and zero flags but doesn't change the negative flag, it has a dependency on the old value of the flags register and a chain of increments must be serialised. Not fundamentally, but yes if you treat flags as a single register.
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?
What you say about partially updated flag registers is right.
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).
IMO, the "out-of-order performance/complexity" excuse is complete bullshit.
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.
True, and I wouldn't be surprised if modern x86 implementations need to do something a bit smarter.
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.
In ISAs where this problem exists, i.e. in x86-64 where the carry flag is updated or not updated regardless of what happens with the other flags, the flags register is split into 2 separate registers, which are renamed independently.
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.)
> 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.
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.
I wonder if the issue is actually the cost of calculating the flags.
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.
Zilog Z80 was orders of magnitude simpler, but its designers never did something so foolish.
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 heart of the mighty Australian Microbee. I still have the Rodney Zak’s book somewhere although I’ll admit doing anything fancy with assembler back then was a bit beyond me
The Z80 was how I learned assembly programming in high school.[0] Was a bit of an unusual choice, but high school students still carry these funky Z80 (or eZ80 now with the color screens) devices every day, so being able to hack on it and have plausible deniability while in class felt great :)
35 years ago I had to program a Z80 by "assembling" programs by hand and punching hexcodes into a board. This was made easier by writing an assembler for it. This was my way into tools which took me eventually to working on a major C++ compiler.
Yeah but that would have been the late 70's... oh my gosh that was 1991!
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.
During the eighties, there were a lot of people, including myself, who could read directly the hex codes of the Z80 instructions as easily as its symbolic assembly language.
That was very handy for reverse engineering programs like the Microsoft CP/M BASIC interpreter or FORTRAN compiler.
When I started TAFE (the equivalent of community college in the US I assume?) in Australia in 2003, one of the subjects in the electronic engineering course was to study and program a Z80. I was awful at it, but it was a good introduction to how a computer works. I wonder if they're still using this CPU as a way to teach the fundamentals of computers?
Happy Birthday Z80!!!!! My first little Timex computer! <3
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.....
Arguably, Exxon's plan to build a computing ecosystem rival to IBM's would have worked too, if the 16 bit successor of the Z80 would have maintained upward binary compatibility with Z80.
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.
The Z80 has a relative jump. Teenage me was loading a hand-assembled search function as an initialised array of integers in Basic, and relative jumps didn't need to be adjusted for the load location, which reduced the amount of post-load adjusting of addresses. It was +100x faster than Basic, just a straight scan.
yes, that looks like the one. I think I was using the conditional jump, so it could have been djnz, but I think it was jr. 1 byte jump offset, and I recall my little function bumping against that limit - I might have re-arranged it.
http://z80-heaven.wikidot.com/instructions-set:jr
Happy Birthday Z80! My first job out of university was in Z80 assembly. (Sega Game Gear.)
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
Annoying part of 8080 was that the command set had holes in it and mystery restrictions. Which were hard to remember. And 12 undefined opcodes. Z80 solved all that.
However, you had to be a programmer Anno Dominii 1975 to fully understand what heavenly Joy and Jubilation Z80 was.
And yes. There was 8080-assembler in PDP-11, but it was just regular PDP assembler with extra macroes. It did not know those forbidden commands and thus produced undefined opcodes with random and entertaining results.
8080 assembly language makes it easy to understand what the restrictions are. Z80 much less so.
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.
Next to the TI calculators already mentioned by someone else, I think what might be the largest use of a Z80 core in a consumer product happened approximately 2 decades ago: https://en.wikipedia.org/wiki/S1_MP3_player
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.
I started out on Z80 when HLL compilers were expensive for me and the shareware alternatives weren’t so accessible as open source is today. Everyone should do at least a little assembler to gain an appreciation of what they are asking the machine to do, and the Z80 was simple enough to reason about.
Being too poor to buy professional software, with Rodney Zack's book in hand I wrote myself a Z80 assembly in MSX BASIC in 1986/87 :) That was my first tough programming stint ever...
I learned BASIC in 1981 on the TRS-80 Model I with 4k RAM (later upgraded to a massive 16k), and it wasn't long before someone showed me EDTASM [1], and I was hooked. My parents couldn't believe me when I asked them to buy "How to Program the Z80" by Rodnay Zaks [2]. They were shocked, it was the first time I asked them to buy a technical book. I was so excited I couldn't sleep for days. I was in High School, and I would carry the book around and read, use the lookup tables, and write Z80 assembly in my spiral-bound 8.5"x11" notebook.
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...
Does anyone know what (if any) open source assemblers exist, that are written in Z80 assembly themselves?
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.
I built a computer around the Z80 from a kit of a TV Series („Klein Microcomputer Sebstgebaut und Programmiert“) when I was 12, with a Märklin trafo as power source and a Telefunken tape recorder as datasette. Typed moon lander into it in Z80 machine code and was so afraid to lose the program that I didn‘t turn it off for 2 weeks.
This reminds me, a couple of months ago I made my Z80 assembler public on GitHub [1] but never mentioned it anywhere.
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 :)
YZF | a day ago
Scubabear68 | a day ago
xcf_seetan | a day ago
TheOtherHobbes | 23 hours ago
sedatk | a day ago
lelanthran | 4 hours ago
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.
Georgelemental | a day ago
QuantumNomad_ | a day ago
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.
blauditore | a day ago
II2II | a day ago
[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.
Zardoz84 | 15 hours ago
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.
duskwuff | a day ago
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/
aarroyoc | a day ago
inigyou | a day ago
Zardoz84 | 15 hours ago
QuantumNomad_ | 12 hours ago
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.
pjmlp | 15 hours ago
TheBigSalad | a day ago
vq | a day ago
1bpp | 19 hours ago
GalaxyNova | a day ago
nanolith | a day ago
stevekemp | a day ago
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).
ozhero | a day ago
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
digitalsankhara | a day ago
KiwiJohnno | 23 hours ago
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
mrandish | 20 hours ago
ozhero | 6 hours ago
chasil | 22 hours ago
I'd love to see another designer introduce a FORK86-64, but things are much more complex now.
brucehoult | 20 hours ago
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.
mrandish | 20 hours ago
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.
djmips | 15 hours ago
ozhero | 6 hours ago
ozhero | 6 hours ago
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 :-)
whartung | a day ago
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.
inigyou | a day ago
djmips | 14 hours ago
zimpenfish | 12 hours ago
[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."
classified | a day ago
Cheers to Rodnay Zaks for "Programming the Z80"!
GeorgeTirebiter | a day ago
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...
inigyou | a day ago
One might say the instruction is really "jump to WZ", or JWZ, which, of course, refers to Jamie Zawinski (not really).
stevekemp | 15 hours ago
dpcx | a day ago
smartmic | a day ago
vsviridov | a day ago
JoeAltmaier | a day ago
haunter | a day ago
ck2 | a day ago
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
jdw64 | a day ago
djmips | 14 hours ago
jim_lawless | a day ago
I wrote a quick post a while back about my Z-80 experiences here:
https://jimlawless.net/blog/posts/z-80/
analog31 | 21 hours ago
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.
jim_lawless | 9 hours ago
tasty_freeze | a day ago
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.
kazinator | 22 hours ago
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".
Zardoz84 | 16 hours ago
adrian_b | 17 hours ago
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.
djmips | 15 hours ago
bonzini | 14 hours ago
https://gmplib.org/list-archives/gmp-devel/2021-September/00...
adrian_b | 14 hours ago
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.
NooneAtAll3 | 12 hours ago
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
adrian_b | 12 hours ago
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).
NooneAtAll3 | 13 hours ago
modern out-of-order execution gets hindered by such non-parallel cpu state, so it wasn't included
adrian_b | 11 hours ago
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.
inigyou | 11 hours ago
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?
adrian_b | 11 hours ago
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).
phire | 11 hours ago
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.
inigyou | 11 hours ago
phire | 11 hours ago
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.
adrian_b | 11 hours 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.)
camel-cdr | 9 hours ago
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)
phire | 6 minutes ago
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.
inigyou | 11 hours ago
adrian_b | 11 hours ago
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.
smackeyacky | a day ago
apple4ever | a day ago
siraben | a day ago
[0] https://github.com/siraben/zkeme80
groos | 23 hours ago
asdefghyk | 23 hours ago
You translated you assembly language to machine language. ( Machine language is the only language a CPU can understand. )
rahimnathwani | 22 hours ago
I wouldn't call it a 'translation'. It's encoding. (We don't think of converting between ASCII codes and symbols as translation.)
ColdStream | 22 hours ago
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.
adrian_b | 17 hours ago
That was very handy for reverse engineering programs like the Microsoft CP/M BASIC interpreter or FORTRAN compiler.
decryption | 22 hours ago
kazinator | 22 hours ago
jenova-marie | 22 hours ago
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.....
jujube3 | 21 hours ago
dhosek | 21 hours ago
cornholio | 16 hours ago
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.
iDon | 20 hours ago
mito88 | 20 hours ago
iDon | 13 hours ago
emptybits | 18 hours ago
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
luciana1u | 17 hours ago
timonoko | 15 hours ago
However, you had to be a programmer Anno Dominii 1975 to fully understand what heavenly Joy and Jubilation Z80 was.
timonoko | 14 hours ago
rep_lodsb | 7 hours ago
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.
userbinator | 14 hours ago
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.
nickdothutton | 14 hours ago
wazoox | 13 hours ago
Razengan | 13 hours ago
vmilner | 13 hours ago
https://spectrumcomputing.co.uk/entry/2000237/Book/Mastering...
http://www.primrosebank.net/computers/zxspectrum/docs/Comple...
hkclawrence | 12 hours ago
kator | 12 hours ago
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.
RetroTechie | 8 hours ago
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.
fallat | 8 hours ago
mitjam | 5 hours ago
kcartlidge | 33 minutes ago
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 :)
[1] https://github.com/kcartlidge/GoZ80