<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <updated>2026-10-16T11:59:12Z</updated>
  <generator>https://njump.me</generator>

  <title>Nostr notes by Ken Shirriff (Unofficial)</title>
  <author>
    <name>Ken Shirriff (Unofficial)</name>
  </author>
  <link rel="self" type="application/atom+xml" href="https://njump.me/npub17wkn0phaxyncs8ya2pyxgy5n9fc3yz8tc36fvsaxaqy0dcyy7yyqhrlwfy.rss" />
  <link href="https://njump.me/npub17wkn0phaxyncs8ya2pyxgy5n9fc3yz8tc36fvsaxaqy0dcyy7yyqhrlwfy" />
  <id>https://njump.me/npub17wkn0phaxyncs8ya2pyxgy5n9fc3yz8tc36fvsaxaqy0dcyy7yyqhrlwfy</id>
  <icon>https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f43f.png</icon>
  <logo>https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f43f.png</logo>




  <entry>
    <id>https://njump.me/nevent1qqsfyutgec4c0fy9zgp8ty98nraap8375vlt8k5d36pmdj3ctmda6zgzyre66duxl5cj0zqun4gyseqjjv48zysga0z8f9jr5m5q3ahqsncssxzs5wr</id>
    
      <title type="html">Inside the Intel 8087 chip: floating-point addition and ...</title>
    
    <link rel="alternate" href="https://njump.me/nevent1qqsfyutgec4c0fy9zgp8ty98nraap8375vlt8k5d36pmdj3ctmda6zgzyre66duxl5cj0zqun4gyseqjjv48zysga0z8f9jr5m5q3ahqsncssxzs5wr" />
    <content type="html">
      Inside the Intel 8087 chip: floating-point addition and subtraction&lt;br/&gt;&lt;br/&gt;In 1980, Intel introduced the 8087, a chip that made floating-point operations much faster&lt;br/&gt;in the IBM PC and other systems.&lt;br/&gt;Although the 8087 supports advanced operations such as tangents, square roots, and logarithms,&lt;br/&gt;this article focuses on basic arithmetic operations: addition and subtraction.&lt;br/&gt;The 8087 provided a spectacular speed improvement over the 8086 processor, speeding up&lt;br/&gt;addition by a factor of almost 100, and complicated operations by even more.1&lt;br/&gt;In this article, I examine the 8087&amp;#39;s microcode and circuitry to explain exactly how&lt;br/&gt;floating-point addition and subtraction are implemented, including numerous special&lt;br/&gt;cases for infinities and other special values.&lt;br/&gt;To explore the 8087&amp;#39;s circuitry, I popped the lid off a chip with a chisel&lt;br/&gt;and used a microscope to create the high-resolution image below.&lt;br/&gt;The microcode ROM is the large rectangular region in the center of the die, holding the 1648 micro-instructions that control the chip.&lt;br/&gt;The bottom half of the chip (red box) is the datapath, the circuitry that performs floating-point calculations on 80-bit values.2&lt;br/&gt;A close-up of the 8087&amp;#39;s datapath, showing functional blocks that are used for addition and subtraction. Click this image (or any other) for a larger version.&lt;br/&gt;Zooming in on the datapath shows the functional blocks that are important for&lt;br/&gt;addition and subtraction.&lt;br/&gt;The key component is the integer adder, located in the center. It receives one argument from&lt;br/&gt;the B register and another argument from a component such as the temporary registers or&lt;br/&gt;the stack registers.&lt;br/&gt;The adder&amp;#39;s output is stored in the sum register.&lt;br/&gt;The shifter can shift the bits in a value to the left or the right.&lt;br/&gt;The shifter occupies a lot of space on the die because its circuitry allows a value to&lt;br/&gt;be rapidly shifted by an arbitrary number of bits.&lt;br/&gt;Floating-point operations make heavy use of the shifter to align values; the leading zero&lt;br/&gt;circuitry counts the number of zero bits or bytes on the left of a value so they can&lt;br/&gt;be shifted away.&lt;br/&gt;The exponent converter processes exponents, detecting&lt;br/&gt;overflows and underflows.&lt;br/&gt;These specialized circuits helped the 8087 achieve its high performance.&lt;br/&gt;Floating-point addition and subtraction&lt;br/&gt;Most computers use integers as their basic representation for numbers.&lt;br/&gt;But many applications need to use numbers with a fractional part, such as 1.23.&lt;br/&gt;Moreover, integers have a very limited range: a 32-bit integer can express numbers from&lt;br/&gt;about -2 billion to 2 billion.&lt;br/&gt;To solve these problems,3 computers usually implement floating-point numbers, which provide&lt;br/&gt;fractional numbers over an enormous range.&lt;br/&gt;In most cases, a floating-point number is represented by sign × significand × 2exponent.&lt;br/&gt;The significand is a binary number of the form 1.bbb…:&lt;br/&gt;a leading 1, followed by the binary point (the binary equivalent of the decimal point) and the rest of the bits.4&lt;br/&gt;In a binary number, each bit represents a power of 2. For the fractional part, the part&lt;br/&gt;after the binary point, the powers of 2 are negative: 2-1, 2-2,&lt;br/&gt;and so forth.&lt;br/&gt;So the binary number 1.1 is 1 &#43; 1/2, or 1.5 in decimal. Similarly, binary 1.0011 is&lt;br/&gt;1 &#43; 1/8 &#43; 1/16 or 1.1875.&lt;br/&gt;The exponent allows numbers to escape the limited range of the significand.&lt;br/&gt;For instance, 1.1 (binary) × 28 is 384.&lt;br/&gt;With larger exponents, floating-point numbers can cover a huge range;&lt;br/&gt;even a 32-bit short floating-point number covers a range exceeding 10-36 to 1038.&lt;br/&gt;Floating-point addition and subtraction are more complicated than&lt;br/&gt;integer operations. Before the numbers can be added (or subtracted), their binary points&lt;br/&gt;must be aligned, the same as aligning the decimal points for decimal numbers.&lt;br/&gt;After the operation, the exponent of the result must be adjusted, normalizing the&lt;br/&gt;significand so it starts with a 1 bit.&lt;br/&gt;The steps for a simple floating-point addition.&lt;br/&gt;The diagram above illustrates a simple floating-point addition: 13.5&#43;3.5.&lt;br/&gt;The first two lines show the two arguments expressed with an exponent and significand.&lt;br/&gt;Both arguments are normalized, so the leftmost bit is a 1.&lt;br/&gt;Before adding, the second argument must be aligned—making the exponents equal—by shifting it two positions&lt;br/&gt;to the right. (The difference between the exponents in this case is two.)&lt;br/&gt;The values are then added, using integer addition on the aligned significands.&lt;br/&gt;In this case, adding the values causes an overflow, an &amp;#34;extra&amp;#34; bit&lt;br/&gt;on the left.&lt;br/&gt;The result must be normalized by shifting it one position to the right and incrementing the&lt;br/&gt;exponent by 1.&lt;br/&gt;Floating-point subtraction is similar, but has a few more complications.&lt;br/&gt;The result can be positive, negative, or zero. The result can be orders of magnitude smaller than the arguments.&lt;br/&gt;The figure below shows a basic subtraction, 8-7.5.&lt;br/&gt;As with addition, the second argument is shifted right so the exponents match (i.e., the binary points line up). The two significands are subtracted with integer subtraction.&lt;br/&gt;The result is normalized by shifting to the left so the top bit is a 1. Unlike the addition case, normalization may require a large shift.&lt;br/&gt;In this case, the shift is four bits and the exponent is decremented by 4 to yield the result.&lt;br/&gt;A simple floating-point subtraction.&lt;br/&gt;One complication with subtraction is that the result can be negative. If that occurs,&lt;br/&gt;the significand is made positive, and the sign of the result is flipped.&lt;br/&gt;Subtraction can also result in zero. In this case, normalization cannot be performed; instead,&lt;br/&gt;a special value &#43;0 or -0 is returned as appropriate.&lt;br/&gt;Relevant hardware details of the 8087&lt;br/&gt;In this section, I&amp;#39;ll explain some features of the 8087 that play important roles&lt;br/&gt;in the microcode implementation of addition and subtraction.&lt;br/&gt;The 8087 supports a variety of data types, but&lt;br/&gt;internally, the 8087 stores numbers in an 80-bit format called &amp;#34;temporary real&amp;#34;.&lt;br/&gt;A temporary real number has a sign bit, a 15-bit exponent, and a 64-bit significand.&lt;br/&gt;The 15-bit exponent allows numbers that are absurdly large, over 104932.&lt;br/&gt;The 64-bit significand supports extremely accurate numbers.&lt;br/&gt;The exponent is stored with a &amp;#34;bias&amp;#34; of 16383 added to it. Thus, the stored exponent is always positive, even if the real&lt;br/&gt;exponent is negative. For instance, an exponent of 1 is stored as 0x4000, and an exponent of -16 is stored as 0x3fef.&lt;br/&gt;The 80-bit temporary real format and the register formats. The dot indicates the binary point, analogous to the decimal point.&lt;br/&gt;The 8087 has eight internal registers, organized as a stack.&lt;br/&gt;The programmer uses these registers when programming the 8087.&lt;br/&gt;Each register holds an 80-bit floating-point number.&lt;br/&gt;To optimize performance,&lt;br/&gt;each value in the register stack also has an associated &amp;#34;tag&amp;#34; value:&lt;br/&gt;zero, valid, special, or empty.&lt;br/&gt;A value of zero is tagged as zero.&lt;br/&gt;A &amp;#34;normal&amp;#34; floating-point value is tagged as valid. If the value is infinity, Not a Number (NaN), or a denormalized value,&lt;br/&gt;then it is tagged as special.&lt;br/&gt;Finally, an empty tag indicates that a register does not hold a value; this allows detection of&lt;br/&gt;stack underflow (reading an empty register) or stack overflow (storing to a non-empty&lt;br/&gt;register).&lt;br/&gt;The 8087 also has temporary registers that it uses internally.&lt;br/&gt;tmpA and tmpB are 80-bit registers, along&lt;br/&gt;with two tag bits.&lt;br/&gt;However, tmpC is different: it doesn&amp;#39;t have a sign, exponent, or tag.&lt;br/&gt;Moreover,&lt;br/&gt;the significand is 68 bits; tmpC has an additional&lt;br/&gt;bit to prevent overflow and three additional low-order bits for rounding, known as&lt;br/&gt;guard, round, and sticky.&lt;br/&gt;In the microcode,&lt;br/&gt;each 16-bit micro-instruction performs one low-level operation.&lt;br/&gt;Many of the operations move data from one register to another.&lt;br/&gt;Other operations provide conditional jumps, subroutine calls, and returns.&lt;br/&gt;The heart of the 8087&amp;#39;s processing is the 69-bit integer adder, which I discussed here.&lt;br/&gt;(The adder has more than 64 bits because it has three rounding bits and a couple of&lt;br/&gt;additional high-order bits for overflow and multiplication.)&lt;br/&gt;Integer addition takes two micro-instructions. The first micro-instruction&lt;br/&gt;specifies the first argument to add and selects various options such as&lt;br/&gt;carry and rounding.&lt;br/&gt;(For subtraction, an option complements the second argument.)&lt;br/&gt;The second argument to the adder always comes from the B register, which confusingly is&lt;br/&gt;unrelated to the tmpB register.&lt;br/&gt;The result of the addition operation is placed in a special register called the sum register.&lt;br/&gt;A second micro-instruction (which may be many instructions after the first) moves the result from the sum register to a destination.&lt;br/&gt;Floating-point also makes extensive use of the bit shifter, which shifts a 68-bit value&lt;br/&gt;by an arbitrary number of positions, left or right; I wrote about it here.&lt;br/&gt;Like the adder, a bit shift operation takes two micro-instructions: the first moves a value to the shifter and&lt;br/&gt;configures the direction and amount of shift. The second micro-instruction&lt;br/&gt;moves the result from the shifter to a destination.&lt;br/&gt;The addition/subtraction microcode&lt;br/&gt;The 8087 implements almost all of its operations in microcode.&lt;br/&gt;The basic math operations (addition, subtraction, multiplication,&lt;br/&gt;and division) start by executing the same microcode (at decimal address #0001.&lt;br/&gt;The microcode moves the two arguments into temporary registers tmpA and tmpB.&lt;br/&gt;Normally, these arguments are taken from the stack registers. The arguments can also&lt;br/&gt;be taken from memory, but I won&amp;#39;t discuss that here.&lt;br/&gt;Next, the microcode does a micro-subroutine call to handle the specific operation type.&lt;br/&gt;The 8087&amp;#39;s microcode engine has a tiny ROM that holds a table of addresses, targets for microcode jumps or&lt;br/&gt;subroutine calls.&lt;br/&gt;Target 0 is special, however; it has three different addresses for multiplication, division,&lt;br/&gt;or addition/subtraction.&lt;br/&gt;(This is implemented by special-case circuitry in the ROM. When you&amp;#39;re designing the chip, you can&lt;br/&gt;do weird, hacky optimizations like this if you want.)&lt;br/&gt;The addition/subtraction micro-subroutine starts at address #0232; this microcode&lt;br/&gt;is shown below. The control flow is complicated, so I&amp;#39;ve put a flowchart in the footnotes.5&lt;br/&gt;The microcode first handles the zero cases 0&#43;0 or 0-0.&lt;br/&gt;Next, it subtracts the exponents of the two arguments.&lt;br/&gt;If the first argument has a smaller exponent (i.e., the result is negative), the arguments&lt;br/&gt;are swapped so the argument with the larger argument is first.&lt;br/&gt;(The 8087 keeps track of the sign of the result in the &amp;#34;sign latch&amp;#34;; if exchanging&lt;br/&gt;the arguments would change the sign, the latch is toggled at #0244.)&lt;br/&gt;#0232 jmp #0236 if not tmpA:tag ZERO Check for 0&#43;0&lt;br/&gt;#0233 jmp #0236 if not tmpB:tag ZERO&lt;br/&gt;#0234 return if not unsigned sub 0&#43;0 same signs&lt;br/&gt;#0235 jmp #0263 handle 0&#43;0 different signs&lt;br/&gt;#0236 tmpA sign -&amp;gt; sign latch nonzero: tmpA sign to sign latch&lt;br/&gt;#0237 tmpB:exp -&amp;gt; Breg&lt;br/&gt;#0238 adder: tmpA:exp - Breg cin=1 compare exponents&lt;br/&gt;#0239 jmp #0245 if adder pos&lt;br/&gt;#0240 sumreg:frac -&amp;gt; Breg swap if tmpB&amp;#39;s exponent larger&lt;br/&gt;#0241 adder: zero - Breg cin=1&lt;br/&gt;#0242 xchg tmp&lt;br/&gt;#0243 jmp #0245 if not unsigned sub&lt;br/&gt;#0244 !sign latch -&amp;gt; sign latch toggle sign if swapping matters&lt;br/&gt;#0245 xchg tmp continue&lt;br/&gt;#0246 shift zero R 0 bytes, 0 bits zero&lt;br/&gt;#0247 call CREATE_DENORM shift tmpB to match exponents&lt;br/&gt;#0248 xchg tmp&lt;br/&gt;#0249 zero -&amp;gt; tmpB:exp store exp adjustment in tmpB:exp&lt;br/&gt;#0250 jmp #0269 if not unsigned sub base addition?&lt;br/&gt;#0251 adder: tmpA:frac - Breg cin=1, roundmode tmp A - tmpB&lt;br/&gt;#0252 jmp #0256 if adder pos&lt;br/&gt;#0253 sumreg:frac,rnd -&amp;gt; Breg/rnd negate frac&lt;br/&gt;#0254 adder: zero - Breg cin=1, roundmode&lt;br/&gt;#0255 !sign latch -&amp;gt; sign latch toggle sign&lt;br/&gt;#0256 jmp #0275 if Sum register is zero jump if result zero&lt;br/&gt;#0257 shift R -&amp;gt; tmpB:frac orig tmpB, from CREATE_DENORM&lt;br/&gt;#0258 jmp #0282 if tmpA top bit tmpA not denorm?&lt;br/&gt;#0259 jmp #0282 if tmpB:frac[63] tmpB not denorm?&lt;br/&gt;#0260 jmp #0289 skip normalization if both denorms&lt;br/&gt;#0261 tmpA:exp -&amp;gt; expConv handle zero&lt;br/&gt;#0262 jmp #0264 if not tmpA top bit&lt;br/&gt;#0263 zero -&amp;gt; tmpA handle zero cases&lt;br/&gt;#0264 0 -&amp;gt; tmpA sign &#43;0&lt;br/&gt;#0265 zero -&amp;gt; tmpA:frac&lt;br/&gt;#0266 return if not round chop&lt;br/&gt;#0267 1 -&amp;gt; tmpA sign return -0&lt;br/&gt;#0268 return&lt;br/&gt;#0269 adder: tmpA:frac &#43; Breg cin=0, roundmode base addition: tmpA &#43; tmpB&lt;br/&gt;#0270 jmp #0289 if not sumreg[64] check for overflow&lt;br/&gt;#0271 shift 1 sumreg:sign,frac,rnd R shift right 1 bit to normalize&lt;br/&gt;#0272 shift R -&amp;gt; sumreg:frac,sign,rnd&lt;br/&gt;#0273 expAdj&#43;&#43; increment exp adjustment&lt;br/&gt;#0274 jmp #0289 wrap up addition&lt;br/&gt;#0275 shift sumreg:frac,rnd L 0 bytes, 3 bits zero? shift to get rounding bits&lt;br/&gt;#0276 shift L -&amp;gt; sumreg:frac&lt;br/&gt;#0277 jmp #0261 if Sum register is zero jump if no rounding bits&lt;br/&gt;#0278 zero -&amp;gt; sumreg:frac clear result&lt;br/&gt;#0279 jmp #0289 if not tmpA top bit denorm?&lt;br/&gt;#0280 expAdj-- if not denorm, adjust exp down&lt;br/&gt;#0281 1 -&amp;gt; sumreg:frac,rnd set lowest bit in result&lt;br/&gt;#0282 lzcount -&amp;gt; shiftcountH leading zero adjust: handle bytes&lt;br/&gt;#0283 shift sumreg:frac,rnd L count byte sticky&lt;br/&gt;#0284 shift L -&amp;gt; sumreg:frac,rnd&lt;br/&gt;#0285 lzcount -&amp;gt; shiftcountL handle leading zero bits&lt;br/&gt;#0286 shift sumreg:frac,rnd L count bit sticky&lt;br/&gt;#0287 shift L -&amp;gt; sumreg:frac,rnd&lt;br/&gt;#0288 shiftcount -&amp;gt; tmpB:exp remember the bit shift amount&lt;br/&gt;#0289 sign latch -&amp;gt; tmpA sign store sign&lt;br/&gt;#0290 call ADJUST_PRECISION if not FBLD/FBSTP adjust precision if necessary&lt;br/&gt;#0291 sumreg:frac -&amp;gt; tmpA:frac store adjusted frac part&lt;br/&gt;#0292 tmpB:exp -&amp;gt; Breg get exp&lt;br/&gt;#0293 adder: tmpA:exp - Breg cin=0 adjust by Breg&lt;br/&gt;#0294 expAdj -&amp;gt; Breg&lt;br/&gt;#0295 adder: sumreg:frac &#43; Breg cin=0 adjust by expAdj&lt;br/&gt;#0296 sumreg:frac -&amp;gt; expConv exp in expConv to check for overflow, etc&lt;br/&gt;#0297 sumreg:frac -&amp;gt; tmpA:exp store exp in tmpA&lt;br/&gt;#0298 return done&lt;br/&gt;At address #0247, the important alignment step takes place, shifting tmpB so the&lt;br/&gt;binary point lines up with tmpA. This is done by the microcode subroutine CREATE_DENORM.&lt;br/&gt;The number of positions to shift tmpB is passed in the sum register; the difference&lt;br/&gt;between the two exponents was calculated in the previous subtraction.&lt;br/&gt;(If the difference was negative, it was complemented, so the value passed in is positive.)&lt;br/&gt;Typically, the exponent of the result will be the same as the exponent of the (larger) value,&lt;br/&gt;but not always.&lt;br/&gt;Changes to the exponent are tracked in two places. First, a special two-bit register that I&lt;br/&gt;call the exponent adjustment (expAdj) holds adjustments due to one-bit shifts left or&lt;br/&gt;right. The hardware initializes the expAdj register to 1 so there is room for a decrement.&lt;br/&gt;Larger exponent changes are tracked in the tmpB register&amp;#39;s exponent field;&lt;br/&gt;the microcode initializes it to 0 at #0249.&lt;br/&gt;At address #0250, the microcode makes a key decision: is the low-level operation&lt;br/&gt;unsigned addition&lt;br/&gt;or unsigned subtraction?&lt;br/&gt;Depending on the signs involved, the high-level operation (addition or subtraction) may&lt;br/&gt;not match the low-level operation.&lt;br/&gt;For example, for 2&#43;3, -2-3, -2&#43;(-3), and so forth, the two unsigned numbers are added; the result is 5, either positive or negative.&lt;br/&gt;But for -2&#43;3, 2-3, 3-2, and so forth, the two unsigned numbers are subtracted; the result is 1, either positive or negative.&lt;br/&gt;I&amp;#39;ll use &amp;#34;unsigned addition&amp;#34; to refer to the former cases, where the unsigned magnitudes are added,&lt;br/&gt;and &amp;#34;unsigned subtraction&amp;#34; to refer to the latter cases, where the unsigned magnitudes are subtracted.&lt;br/&gt;The key point is that an addition instruction may result in unsigned addition or subtraction,&lt;br/&gt;and the same with a subtraction instruction.&lt;br/&gt;The 8087 has specialized circuitry to determine whether the low-level unsigned operation is addition or subtraction, allowing this to be tested with a conditional.&lt;br/&gt;The tmpA and tmpB values have sign bits of 1 for negative, 0 for positive.&lt;br/&gt;If you assign 1 to subtraction and 0 to addition, then tmpAsign⊕​tmpBsign⊕op yields 1 if the unsigned operation is subtraction and 0 if the unsigned operation is addition.&lt;br/&gt;The 8087 also has a conditional to test if the signs are the same or different.&lt;br/&gt;Unsigned addition&lt;br/&gt;Since the unsigned addition path is simpler, I&amp;#39;ll start with it, at address #0269.&lt;br/&gt;The steps are essentially the same as described earlier: aligning the numbers, adding them,&lt;br/&gt;and normalizing.&lt;br/&gt;First, the smaller number, in tmpB, is shifted right until the exponents match.&lt;br/&gt;Then the (unsigned) values are added.&lt;br/&gt;If there is a carry from the top bit, the result is shifted right at #0271.&lt;br/&gt;Because the result is shifted right one bit,&lt;br/&gt;the special two-bit expAdj counter is incremented to track the required exponent adjustment.&lt;br/&gt;At #0289, the result&amp;#39;s sign is updated with the value in the sign register.&lt;br/&gt;The 8087 supports three sizes of values: 80-bit temporary reals, 64-bit reals, or 32-bit&lt;br/&gt;reals.&lt;br/&gt;For the smaller sizes, the microcode subroutine ADJUST_PRECISION t&lt;br/&gt;&lt;br/&gt;&lt;a href=&#34;http://www.righto.com/2026/10/8087-addition-subtraction-microcode.html&#34;&gt;http://www.righto.com/2026/10/8087-addition-subtraction-microcode.html&lt;/a&gt;&lt;br/&gt; &lt;img src=&#34;https://static.righto.com/images/8087-fadd/8087-datapath-zoom-diagram-w600.jpg&#34;&gt; &lt;br/&gt; &lt;img src=&#34;https://static.righto.com/images/8087-fadd/add1-w350.jpg&#34;&gt; &lt;br/&gt; &lt;img src=&#34;https://static.righto.com/images/8087-fadd/sub1-w320.jpg&#34;&gt; &lt;br/&gt;&lt;br/&gt;#rss #feeds #linksharing #qwibbit
    </content>
    <updated>2026-10-19T03:03:53Z</updated>
  </entry>

</feed>