Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Reverse-engineering the multiplication algorithm in the Intel 8086 processor (righto.com)
171 points by CoBE10 on March 15, 2023 | hide | past | favorite | 34 comments


For those confused as to why there's all this signedness handling for the 2's complement multiplication algorithm we were all taught in school is identical for both signed and unsigned numbers: x86 multiplication is widening. The 8086 would compute the 32 bit product of two 16 bit values[1] (one of which must be AX) and place the result in two output registers (DX and AX, always).

If you interpret the arguments as unsigned, you can treat the input high bits as zeroes. But if it's signed then you need to conceptually sign-extend the high bit. So they're different operations with different results in the high word.

[1] There was an 8 bit multiply too. It didn't have this property and looked more like a normal instruction, kens would have to tell us if it shared the same microcode.


Also, we use sign-magnitude representation while x86 uses twos complement.

> It didn't have this property and looked more like a normal instruction, kens would have to tell us if it shared the same microcode.

If you're thinking of "IMUL reg,reg" it was added only in 80186. If instead you're thinking of AAD, then yes it reuses the CORX subroutine; it's only unsigned so it doesn't need the parts that deal with negation.


I meant the former, and indeed you're right it didn't even exist yet.

Until today, I don't believe I ever even realized that AAD could be used to perform a (non-widening) 8 bit multiplication by an immediate. Thanks for the reference.


Author here. I'm without electricity but can discuss the 8086 if anyone has questions :-)


Ken, I've read and enjoyed many of your posts and I always wonder: how do you find so much time to do that? Is that your full time occupation?

Thanks!


I'm retired, so I have time for various vintage computer projects.


As far as I know, x86 and x86-64 have never had microcode for ASCII (base 10 is what I'm interested in) to binary number conversion. Why do you think this is? It seems like a very common operation these days, and the reasons you gave for microcode multiply seem applicable.


Prime minicomputers had decimal arithmetic in microcode & hardware in the early 80's to support PL/I and COBOL "picture" data types and packed decimal. They also had sophisticated editing to pictures like ZZZ,ZZ9.99 which would display 1024 as 1,024.00

These instructions were also implemented in PMA, the Prime Macro Assembler, in the OS so that if a machine didn't have these instructions, a UII fault occurred and the instruction was simulated in software. I implemented a lot of the easier instructions in C in the Prime emulator, but for the more complex things like decimal math, I let those fault so the Prime OS would handle them.


The IBM System/360 (1964) had instructions to convert a character string to packed decimal, and to convert packed decimal to binary. This was motivated by the large amount of punch-card data that was handled back then, with all the numbers in decimal. But I guess Intel figured that string conversion wasn't common enough in modern systems to merit adding it to the instruction set.


Not a question, just a comment that after having read several of your posts now, building up knowledge as I go, this one is the first I've understood from start to end. Most satisfying!


What is your favorite BBQ sauce to pair with an 8086?


I think the Fairchild Microflame works better for barbecue :-)

https://en.wikipedia.org/wiki/Fairchild_9440


Interesting, any reason for not discussing AAD yet? (oh and great series BTW)


AAD is lower on the list since it is both complicated and kind of obscure. Also, it depends on multiplication and division, so I want to cover them first.


AAD is essentially a multiplication and a sum:

    170  Q     -> tmpc                            
    171  AH    -> tmpb      CALL  CORX
    172  AL    -> tmpb      ADD   tmpc
    173  ZERO  -> AH        JMP   179
    179  SIGMA -> AL        RNI      
   F
It doesn't depend on division despite the name, it performs ASCII to binary conversion.


CISC operations like 'imul' and 'idiv' were perceived like curse words in the RISC world of the day, but they were actually a beacon of hope. When x86 architecture matured, those operations became super fast thanks to the hardware acceleration.

So take it with a grain of salt when you hear someone claim that RISC is invariantly superior to CISC. Times and times again, the truth lies somewhere in the middle.


Really? Not sure why. MIPS had multiply and divide instructions; ARM had multiply instructions; I know SH-4 has at least multiply instructions.

I don't think hardware multiplication is a RISC or CISC thing. The "reduced instructions" that RISC is concerned with chiefly involve code flow mechanisms such as linkage, flag behavior, and interfacing with memory. It doesn't mean you need to create all your math operations from increment and bitwise instructions.

The RISC/CISC thing stopped being meaningful once ...

A) processors went all-in on out-of-order execution (this means everything was split into uops and reordered and your instruction stream no longer represents what the CPU does much of the time)

B) processors started having parallel vector instructions.

An article was posted here on HN making the case for considering "Out of Order" a new paradigm and it made a lot of sense to me.


RISC crowd presented lower number of transistors as one of the top selling points back in the day. Simpler instructions => fewer transistors => less heat => more room for performance, at least on paper.

MUL and DIV instructions are not exactly transistor count friendly, so they caused an expected contradiction at the RISC camp back in the day.


Some first-generation RISC processors, e.g. MIPS R2000, shipped with hardware multiply and divide, or even optional floating point.


> A) processors went all-in on out-of-order execution (this means everything was split into uops and reordered and your instruction stream no longer represents what the CPU does much of the time)

Yes. That's why it has become more and more ridiculous to claim that C is 'close to the metal'.


Well, idiv being super fast is new to me, but I guess it's relative.


Integer division is sufficiently famously slow that people (and compilers) go to great lengths to avoid it... which makes it rare enough that there's very little point implementing it.

If you really need integer division, you can typically optimize it by doing a FP iteration and then fixing up the approximate result.


The worst case integer divide times on newest Intel/AMD cpus are 15/18 for 64bit and 12/13 for 32-bit. Both do early out for easy values at around 10 cycles.

Integer division is still on the slower side operations on the machines, but the advice to avoid division at all costs is outdated. In comparison, the FP divide instructions are in the ~13/14 cycles, it would be hard for you to shuffle data to that side and back and not be slower. (And no, they are not doing this internally -- both have separate integer divide units.)


These things change over time, but at least a fair chunk of recent Intel CPUs had idiv handled by the floating-point unit. That is, it couldn't do an idiv and a fdiv in parallel.


As long as they're pipelined, slow operations are okay as long as you have enough other work to fill the pipeline until their result comes back.


Ken, please tell us you have a book deal, this is just awesome stuff.


I've been vaguely thinking about a book on the 8086 die. I'm sure I could sell at least 5 copies :-)


You'll add in the 6502 but more importantly items like the Globus (fascinating!), the Apollo equipment, the DX7 and the electromechanical Central Air Data Computer and you got yourself a best-seller, I predict 10 copies at least.


If that's all it takes then I pre-order five copies.


For the good of humanity -- or at least our industry -- or at least my intellectual curiosity -- or at least so I can have another cool book on my shelf to increase my geek cred -- please do this!


Count six. I'd buy it in a beat.


are there existing books of the sort on a simpler cpu, e.g. 6502?

one i could take with me on a holiday and return having every transistor accounted for (and probably foolishly assuming i finally understand how the wretched thing works!)


The only comment I have is about the first footnote. The 6809 had a MUL instruction, which was 8b unsigned only (register A * register B, high byte of result in A, low byte result in B). There is no DIV instruction.


Thanks! I've fixed that.




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: