CINXE.COM

Ken Shirriff's blog: April 2023

<!DOCTYPE html> <html class='v2' dir='ltr' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <meta content='width=1100' name='viewport'/> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='http://www.righto.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='http://www.righto.com/2023/04/' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Ken Shirriff&#39;s blog - Atom" href="http://www.righto.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Ken Shirriff&#39;s blog - RSS" href="http://www.righto.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Ken Shirriff&#39;s blog - Atom" href="https://www.blogger.com/feeds/6264947694886887540/posts/default" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='http://www.righto.com/2023/04/' property='og:url'/> <meta content='Ken Shirriff&#39;s blog' property='og:title'/> <meta content='Computer history, restoring vintage computers, IC reverse engineering, and whatever' property='og:description'/> <title>Ken Shirriff's blog: April 2023</title> <style type='text/css'>@font-face{font-family:'Play';font-style:normal;font-weight:400;font-display:swap;src:url(//fonts.gstatic.com/s/play/v19/6aez4K2oVqwIvtg2H68T.woff2)format('woff2');unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;}@font-face{font-family:'Play';font-style:normal;font-weight:400;font-display:swap;src:url(//fonts.gstatic.com/s/play/v19/6aez4K2oVqwIvtE2H68T.woff2)format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;}@font-face{font-family:'Play';font-style:normal;font-weight:400;font-display:swap;src:url(//fonts.gstatic.com/s/play/v19/6aez4K2oVqwIvtY2H68T.woff2)format('woff2');unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF;}@font-face{font-family:'Play';font-style:normal;font-weight:400;font-display:swap;src:url(//fonts.gstatic.com/s/play/v19/6aez4K2oVqwIvto2H68T.woff2)format('woff2');unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;}@font-face{font-family:'Play';font-style:normal;font-weight:400;font-display:swap;src:url(//fonts.gstatic.com/s/play/v19/6aez4K2oVqwIvts2H68T.woff2)format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;}@font-face{font-family:'Play';font-style:normal;font-weight:400;font-display:swap;src:url(//fonts.gstatic.com/s/play/v19/6aez4K2oVqwIvtU2Hw.woff2)format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}</style> <style id='page-skin-1' type='text/css'><!-- /* ----------------------------------------------- Blogger Template Style Name: Simple Designer: Blogger URL: www.blogger.com ----------------------------------------------- */ /* Variable definitions ==================== <Variable name="keycolor" description="Main Color" type="color" default="#66bbdd"/> <Group description="Page Text" selector="body"> <Variable name="body.font" description="Font" type="font" default="normal normal 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="body.text.color" description="Text Color" type="color" default="#222222"/> </Group> <Group description="Backgrounds" selector=".body-fauxcolumns-outer"> <Variable name="body.background.color" description="Outer Background" type="color" default="#66bbdd"/> <Variable name="content.background.color" description="Main Background" type="color" default="#ffffff"/> <Variable name="header.background.color" description="Header Background" type="color" default="transparent"/> </Group> <Group description="Links" selector=".main-outer"> <Variable name="link.color" description="Link Color" type="color" default="#2288bb"/> <Variable name="link.visited.color" description="Visited Color" type="color" default="#888888"/> <Variable name="link.hover.color" description="Hover Color" type="color" default="#33aaff"/> </Group> <Group description="Blog Title" selector=".header h1"> <Variable name="header.font" description="Font" type="font" default="normal normal 60px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="header.text.color" description="Title Color" type="color" default="#3399bb" /> </Group> <Group description="Blog Description" selector=".header .description"> <Variable name="description.text.color" description="Description Color" type="color" default="#777777" /> </Group> <Group description="Tabs Text" selector=".tabs-inner .widget li a"> <Variable name="tabs.font" description="Font" type="font" default="normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="tabs.text.color" description="Text Color" type="color" default="#999999"/> <Variable name="tabs.selected.text.color" description="Selected Color" type="color" default="#000000"/> </Group> <Group description="Tabs Background" selector=".tabs-outer .PageList"> <Variable name="tabs.background.color" description="Background Color" type="color" default="#f5f5f5"/> <Variable name="tabs.selected.background.color" description="Selected Color" type="color" default="#eeeeee"/> </Group> <Group description="Post Title" selector="h3.post-title, .comments h4"> <Variable name="post.title.font" description="Font" type="font" default="normal normal 22px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> </Group> <Group description="Date Header" selector=".date-header"> <Variable name="date.header.color" description="Text Color" type="color" default="#222222"/> <Variable name="date.header.background.color" description="Background Color" type="color" default="transparent"/> <Variable name="date.header.font" description="Text Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="date.header.padding" description="Date Header Padding" type="string" default="inherit"/> <Variable name="date.header.letterspacing" description="Date Header Letter Spacing" type="string" default="inherit"/> <Variable name="date.header.margin" description="Date Header Margin" type="string" default="inherit"/> </Group> <Group description="Post Footer" selector=".post-footer"> <Variable name="post.footer.text.color" description="Text Color" type="color" default="#666666"/> <Variable name="post.footer.background.color" description="Background Color" type="color" default="#f9f9f9"/> <Variable name="post.footer.border.color" description="Shadow Color" type="color" default="#eeeeee"/> </Group> <Group description="Gadgets" selector="h2"> <Variable name="widget.title.font" description="Title Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="widget.title.text.color" description="Title Color" type="color" default="#000000"/> <Variable name="widget.alternate.text.color" description="Alternate Color" type="color" default="#999999"/> </Group> <Group description="Images" selector=".main-inner"> <Variable name="image.background.color" description="Background Color" type="color" default="#ffffff"/> <Variable name="image.border.color" description="Border Color" type="color" default="#eeeeee"/> <Variable name="image.text.color" description="Caption Text Color" type="color" default="#222222"/> </Group> <Group description="Accents" selector=".content-inner"> <Variable name="body.rule.color" description="Separator Line Color" type="color" default="#eeeeee"/> <Variable name="tabs.border.color" description="Tabs Border Color" type="color" default="#eeeeee"/> </Group> <Variable name="body.background" description="Body Background" type="background" color="#f6fbf6" default="$(color) none repeat scroll top left"/> <Variable name="body.background.override" description="Body Background Override" type="string" default=""/> <Variable name="body.background.gradient.cap" description="Body Gradient Cap" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="body.background.gradient.tile" description="Body Gradient Tile" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/body_gradient_tile_light.png)"/> <Variable name="content.background.color.selector" description="Content Background Color Selector" type="string" default=".content-inner"/> <Variable name="content.padding" description="Content Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.padding.horizontal" description="Content Horizontal Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.shadow.spread" description="Content Shadow Spread" type="length" default="40px" min="0" max="100px"/> <Variable name="content.shadow.spread.webkit" description="Content Shadow Spread (WebKit)" type="length" default="5px" min="0" max="100px"/> <Variable name="content.shadow.spread.ie" description="Content Shadow Spread (IE)" type="length" default="10px" min="0" max="100px"/> <Variable name="main.border.width" description="Main Border Width" type="length" default="0" min="0" max="10px"/> <Variable name="header.background.gradient" description="Header Gradient" type="url" default="none"/> <Variable name="header.shadow.offset.left" description="Header Shadow Offset Left" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.offset.top" description="Header Shadow Offset Top" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.spread" description="Header Shadow Spread" type="length" default="1px" min="0" max="100px"/> <Variable name="header.padding" description="Header Padding" type="length" default="30px" min="0" max="100px"/> <Variable name="header.border.size" description="Header Border Size" type="length" default="1px" min="0" max="10px"/> <Variable name="header.bottom.border.size" description="Header Bottom Border Size" type="length" default="0" min="0" max="10px"/> <Variable name="header.border.horizontalsize" description="Header Horizontal Border Size" type="length" default="0" min="0" max="10px"/> <Variable name="description.text.size" description="Description Text Size" type="string" default="140%"/> <Variable name="tabs.margin.top" description="Tabs Margin Top" type="length" default="0" min="0" max="100px"/> <Variable name="tabs.margin.side" description="Tabs Side Margin" type="length" default="30px" min="0" max="100px"/> <Variable name="tabs.background.gradient" description="Tabs Background Gradient" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="tabs.border.width" description="Tabs Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="tabs.bevel.border.width" description="Tabs Bevel Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="post.margin.bottom" description="Post Bottom Margin" type="length" default="25px" min="0" max="100px"/> <Variable name="image.border.small.size" description="Image Border Small Size" type="length" default="2px" min="0" max="10px"/> <Variable name="image.border.large.size" description="Image Border Large Size" type="length" default="5px" min="0" max="10px"/> <Variable name="page.width.selector" description="Page Width Selector" type="string" default=".region-inner"/> <Variable name="page.width" description="Page Width" type="string" default="auto"/> <Variable name="main.section.margin" description="Main Section Margin" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding" description="Main Padding" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding.top" description="Main Padding Top" type="length" default="30px" min="0" max="100px"/> <Variable name="main.padding.bottom" description="Main Padding Bottom" type="length" default="30px" min="0" max="100px"/> <Variable name="paging.background" color="#ffffff" description="Background of blog paging area" type="background" default="transparent none no-repeat scroll top center"/> <Variable name="footer.bevel" description="Bevel border length of footer" type="length" default="0" min="0" max="10px"/> <Variable name="mobile.background.overlay" description="Mobile Background Overlay" type="string" default="transparent none repeat scroll top left"/> <Variable name="mobile.background.size" description="Mobile Background Size" type="string" default="auto"/> <Variable name="mobile.button.color" description="Mobile Button Color" type="color" default="#ffffff" /> <Variable name="startSide" description="Side where text starts in blog language" type="automatic" default="left"/> <Variable name="endSide" description="Side where text ends in blog language" type="automatic" default="right"/> */ /* Content ----------------------------------------------- */ body { font: normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #222222; background: #f6fbf6 none repeat scroll top left; padding: 0 40px 40px 40px; } html body .region-inner { min-width: 0; max-width: 100%; width: auto; } h2 { font-size: 22px; } a:link { text-decoration:none; color: #121fb3; } a:visited { text-decoration:none; color: #121fb3; } a:hover { text-decoration:underline; color: #1a00ff; } .body-fauxcolumn-outer .fauxcolumn-inner { background: transparent url(//www.blogblog.com/1kt/simple/body_gradient_tile_light.png) repeat scroll top left; _background-image: none; } .body-fauxcolumn-outer .cap-top { position: absolute; z-index: 1; height: 400px; width: 100%; } .body-fauxcolumn-outer .cap-top .cap-left { width: 100%; background: transparent url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll top left; _background-image: none; } .content-outer { -moz-box-shadow: 0 0 40px rgba(0, 0, 0, .15); -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .15); -goog-ms-box-shadow: 0 0 10px #333333; box-shadow: 0 0 40px rgba(0, 0, 0, .15); margin-bottom: 1px; } .content-inner { padding: 10px 10px; } .content-inner { background-color: #ffffff; } /* Header ----------------------------------------------- */ .header-outer { background: #f6fbf7 url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll 0 -400px; _background-image: none; } .Header h1 { font: normal normal 42px Play; color: #666666; text-shadow: 1px 2px 3px rgba(0, 0, 0, .2); } .Header h1 a { color: #666666; } .Header .description { font-size: 140%; color: #666666; } .header-inner .Header .titlewrapper { padding: 22px 30px; } .header-inner .Header .descriptionwrapper { padding: 0 30px; } /* Tabs ----------------------------------------------- */ .tabs-inner .section:first-child { border-top: 0 solid #eeeeee; } .tabs-inner .section:first-child ul { margin-top: -0; border-top: 0 solid #eeeeee; border-left: 0 solid #eeeeee; border-right: 0 solid #eeeeee; } .tabs-inner .widget ul { background: #f5f5f5 url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll 0 -800px; _background-image: none; border-bottom: 1px solid #eeeeee; margin-top: 0; margin-left: -30px; margin-right: -30px; } .tabs-inner .widget li a { display: inline-block; padding: .6em 1em; font: normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #999999; border-left: 1px solid #ffffff; border-right: 1px solid #eeeeee; } .tabs-inner .widget li:first-child a { border-left: none; } .tabs-inner .widget li.selected a, .tabs-inner .widget li a:hover { color: #000000; background-color: #eeeeee; text-decoration: none; } /* Columns ----------------------------------------------- */ .main-outer { border-top: 0 solid #eeeeee; } .fauxcolumn-left-outer .fauxcolumn-inner { border-right: 1px solid #eeeeee; } .fauxcolumn-right-outer .fauxcolumn-inner { border-left: 1px solid #eeeeee; } /* Headings ----------------------------------------------- */ div.widget > h2, div.widget h2.title { margin: 0 0 1em 0; font: normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #000000; } /* Widgets ----------------------------------------------- */ .widget .zippy { color: #999999; text-shadow: 2px 2px 1px rgba(0, 0, 0, .1); } .widget .popular-posts ul { list-style: none; } /* Posts ----------------------------------------------- */ h2.date-header { font: normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif; } .date-header span { background-color: transparent; color: transparent; padding: inherit; letter-spacing: inherit; margin: inherit; } .main-inner { padding-top: 30px; padding-bottom: 30px; } .main-inner .column-center-inner { padding: 0 15px; } .main-inner .column-center-inner .section { margin: 0 15px; } .post { margin: 0 0 25px 0; } h3.post-title, .comments h4 { font: normal normal 22px Arial, Tahoma, Helvetica, FreeSans, sans-serif; margin: .75em 0 0; } .post-body { font-size: 110%; line-height: 1.4; position: relative; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 2px; background: #ffffff; border: 1px solid #ffffff; -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); } .post-body img, .post-body .tr-caption-container { padding: 5px; } .post-body .tr-caption-container { color: #222222; } .post-body .tr-caption-container img { padding: 0; background: transparent; border: none; -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .1); box-shadow: 0 0 0 rgba(0, 0, 0, .1); } .post-header { margin: 0 0 1.5em; line-height: 1.6; font-size: 90%; } .post-footer { margin: 20px -2px 0; padding: 5px 10px; color: #666666; background-color: #f9f9f9; border-bottom: 1px solid #eeeeee; line-height: 1.6; font-size: 90%; } #comments .comment-author { padding-top: 1.5em; border-top: 1px solid #eeeeee; background-position: 0 1.5em; } #comments .comment-author:first-child { padding-top: 0; border-top: none; } .avatar-image-container { margin: .2em 0 0; } #comments .avatar-image-container img { border: 1px solid #ffffff; } /* Comments ----------------------------------------------- */ .comments .comments-content .icon.blog-author { background-repeat: no-repeat; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9sLFwMeCjjhcOMAAAD+SURBVDjLtZSvTgNBEIe/WRRnm3U8RC1neQdsm1zSBIU9VVF1FkUguQQsD9ITmD7ECZIJSE4OZo9stoVjC/zc7ky+zH9hXwVwDpTAWWLrgS3QAe8AZgaAJI5zYAmc8r0G4AHYHQKVwII8PZrZFsBFkeRCABYiMh9BRUhnSkPTNCtVXYXURi1FpBDgArj8QU1eVXUzfnjv7yP7kwu1mYrkWlU33vs1QNu2qU8pwN0UpKoqokjWwCztrMuBhEhmh8bD5UDqur75asbcX0BGUB9/HAMB+r32hznJgXy2v0sGLBcyAJ1EK3LFcbo1s91JeLwAbwGYu7TP/3ZGfnXYPgAVNngtqatUNgAAAABJRU5ErkJggg==); } .comments .comments-content .loadmore a { border-top: 1px solid #999999; border-bottom: 1px solid #999999; } .comments .comment-thread.inline-thread { background-color: #f9f9f9; } .comments .continue { border-top: 2px solid #999999; } /* Accents ---------------------------------------------- */ .section-columns td.columns-cell { border-left: 1px solid #eeeeee; } .blog-pager { background: transparent none no-repeat scroll top center; } .blog-pager-older-link, .home-link, .blog-pager-newer-link { background-color: #ffffff; padding: 5px; } .footer-outer { border-top: 0 dashed #bbbbbb; } /* Mobile ----------------------------------------------- */ body.mobile { background-size: auto; } .mobile .body-fauxcolumn-outer { background: transparent none repeat scroll top left; } .mobile .body-fauxcolumn-outer .cap-top { background-size: 100% auto; } .mobile .content-outer { -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .15); box-shadow: 0 0 3px rgba(0, 0, 0, .15); } .mobile .tabs-inner .widget ul { margin-left: 0; margin-right: 0; } .mobile .post { margin: 0; } .mobile .main-inner .column-center-inner .section { margin: 0; } .mobile .date-header span { padding: 0.1em 10px; margin: 0 -10px; } .mobile h3.post-title { margin: 0; } .mobile .blog-pager { background: transparent none no-repeat scroll top center; } .mobile .footer-outer { border-top: none; } .mobile .main-inner, .mobile .footer-inner { background-color: #ffffff; } .mobile-index-contents { color: #222222; } .mobile-link-button { background-color: #121fb3; } .mobile-link-button a:link, .mobile-link-button a:visited { color: #ffffff; } .mobile .tabs-inner .section:first-child { border-top: none; } .mobile .tabs-inner .PageList .widget-content { background-color: #eeeeee; color: #000000; border-top: 1px solid #eeeeee; border-bottom: 1px solid #eeeeee; } .mobile .tabs-inner .PageList .widget-content .pagelist-arrow { border-left: 1px solid #eeeeee; } .content-outer { max-width: 1400px !important; } /* fix header */ #header-inner { width: 100% !important; background-position: right !important; } .titlewrapper { padding: 11px 30px 0 !important; } .descriptionwrapper { margin-bottom: 0 !important; } .description { font-size: 120% !important; } /* suppress things */ .date-header { display: none; } #Attribution1 { display: none; } .post-author, .post-timestamp, .reaction-buttons { display: none; } /* h2: sidebar titles */ /* h3: post title */ .post-title , .entry-title { font-size: 180% !important; margin-top: 0 !important; } .entry-title a:link, .entry-title a:visited, .entry-title a:active{ color: #a03; } #main h2 { color:#333; margin-bottom:.4em; margin-top: 13px; font-size:140%; } #main h3 { color:#333; margin-bottom:.4em; margin-top: 13px; font-size:110%; } #main h4 { color:#333; margin-bottom:.5em; } #sidebar-right-1 a:link, #sidebar-right-1 a:visited, #sidebar-right-1 a:active { color: #666; } #sidebar-right-1 h2 { font-size: 100%; color: #666; } /* disable image box */ element.style { } table.chargers img { height: 18px; } table.chargers img { height: 18px; } .post-body img, .post-body .tr-caption-container { padding: 5px; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 0; background: #ffffff; border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } /* Special items */ a:link img.hilite, a:visited img.hilite { color: #fff; } a:hover img.hilite, a:hover img.hilite2 { color: #f66; } a:active img.hilite { color: #33c; } .hilite {cursor:zoom-in} pre {color:#000000;border:1px solid #000000;} pre.repl { background-color:#e0e0f0; font-size:120%;} pre.arc { background-color:#e0e0f0; font-size:120%;} pre.code { background-color:#e0f0e0; font-size:120%; white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;text-wrap:unrestricted;} code { font-size: 100%;} blockquote { font-size: 110%; background: transparent url("//static.righto.com/images/blockquote.gif") no-repeat 0 0; margin: 20px 0px; padding: 0px 40px;} div.cite {font-size: .8em;.; font-style: italic; color: #888; margin-bottom: 9px;} a.ref { color: gray;vertical-align: super; text-decoration: none; font-size:60%;margin-left: 2px;} a img.hilite { border: 1px solid; color: #888; z-index: 2; } a img.hilite2, a:active img.hilite2 { border: 1px solid; color: #f6fbf6; } table.chargers { border-width: 1px; border-spacing: 2px; border-style: outset; border-color: gray; border-collapse: collapse; background-color: white; } table.chargers th.maker { padding-right: 5px; text-align: right; } table.chargers th { border-width: 1px; padding: 3px; border-style: inset; border-color: gray; background-color: white; text-align: center; } table.chargers img { height: 18px; } table.chargers td { text-align: center; border-width: 1px; padding: 2px 8px; border-style: inset; border-color: gray; background-color: white; } --></style> <style id='template-skin-1' type='text/css'><!-- body { min-width: 750px; } .content-outer, .content-fauxcolumn-outer, .region-inner { min-width: 750px; max-width: 750px; _width: 750px; } .main-inner .columns { padding-left: 0px; padding-right: 240px; } .main-inner .fauxcolumn-center-outer { left: 0px; right: 240px; /* IE6 does not respect left and right together */ _width: expression(this.parentNode.offsetWidth - parseInt("0px") - parseInt("240px") + 'px'); } .main-inner .fauxcolumn-left-outer { width: 0px; } .main-inner .fauxcolumn-right-outer { width: 240px; } .main-inner .column-left-outer { width: 0px; right: 100%; margin-left: -0px; } .main-inner .column-right-outer { width: 240px; margin-right: -240px; } #layout { min-width: 0; } #layout .content-outer { min-width: 0; width: 800px; } #layout .region-inner { min-width: 0; width: auto; } --></style> <meta content='width=device-width, initial-scale=1.0, maximum-scale=12.0, minimum-scale=.25, user-scalable=yes' name='viewport'/> <meta content='mw8ww70r3jW0GzXY6j1d' name='follow_it-verification-code'/> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=6264947694886887540&amp;zx=ee9ac79c-a7e3-41c3-b260-c102f65f80e8' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=6264947694886887540&amp;zx=ee9ac79c-a7e3-41c3-b260-c102f65f80e8' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> </head> <body class='loading'> <div class='navbar no-items section' id='navbar'> </div> <div class='body-fauxcolumns'> <div class='fauxcolumn-outer body-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content'> <div class='content-fauxcolumns'> <div class='fauxcolumn-outer content-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content-outer'> <div class='content-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left content-fauxborder-left'> <div class='fauxborder-right content-fauxborder-right'></div> <div class='content-inner'> <header> <div class='header-outer'> <div class='header-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left header-fauxborder-left'> <div class='fauxborder-right header-fauxborder-right'></div> <div class='region-inner header-inner'> <div class='header section' id='header'><div class='widget Header' data-version='1' id='Header1'> <div id='header-inner' style='background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-4KXwYe0lQ4HFzhAye9vvRlij2ZYvMbfPCnqEE__1o85Fjo3XgefxJQhWRdwR3EzNWNMWT3yMaj2QZaT9GazqQx3C6oWa3-hBNlRHG7f-Oib-lv1Wq_C2_A0rt8xZgs87iNqzRVKK7H0A/s800/background.jpg"); background-position: left; width: 550px; min-height: 105px; _height: 105px; background-repeat: no-repeat; '> <div class='titlewrapper' style='background: transparent'> <h1 class='title' style='background: transparent; border-width: 0px'> <a href='http://www.righto.com/'> Ken Shirriff's blog </a> </h1> </div> <div class='descriptionwrapper'> <p class='description'><span>Computer history, restoring vintage computers, IC reverse engineering, and whatever</span></p> </div> </div> </div></div> </div> </div> <div class='header-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </header> <div class='tabs-outer'> <div class='tabs-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left tabs-fauxborder-left'> <div class='fauxborder-right tabs-fauxborder-right'></div> <div class='region-inner tabs-inner'> <div class='tabs no-items section' id='crosscol'></div> <div class='tabs no-items section' id='crosscol-overflow'></div> </div> </div> <div class='tabs-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='main-outer'> <div class='main-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left main-fauxborder-left'> <div class='fauxborder-right main-fauxborder-right'></div> <div class='region-inner main-inner'> <div class='columns fauxcolumns'> <div class='fauxcolumn-outer fauxcolumn-center-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-left-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-right-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <!-- corrects IE6 width calculation --> <div class='columns-inner'> <div class='column-center-outer'> <div class='column-center-inner'> <div class='main section' id='main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='blog-posts hfeed'> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://static.righto.com/images/8086-div/die-labeled-w600.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='5693917346966509204' itemprop='postId'/> <a name='5693917346966509204'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2023/04/reverse-engineering-8086-divide-microcode.html'>Reverse-engineering the division microcode in the Intel 8086 processor</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5693917346966509204' itemprop='description articleBody'> <style> .hilite {cursor:zoom-in} a:link img.hilite, a:visited img.hilite {color: #fff;} a:hover img.hilite {color: #f66;} </style> <style> pre.microcode {font-family: courier, fixed; padding: 10px; background-color: #f5f5f5; display:inline-block;border:none;} pre.microcode span {color: green; font-style:italic; font-family: sans-serif; font-size: 90%;} </style> <p>While programmers today take division for granted, most microprocessors in the 1970s could only add and subtract &mdash; division required a slow and tedious loop implemented in assembly code. One of the nice features of the Intel 8086 processor (1978) was that it provided machine instructions for integer multiplication and division. Internally, the 8086 still performed a loop, but the loop was implemented in microcode: faster and transparent to the programmer. Even so, division was a slow operation, about 50 times slower than addition.</p> <p>I recently examined <a href="https://www.righto.com/2023/03/8086-multiplication-microcode.html">multiplication in the 8086</a>, and now it's time to look at the division microcode.<span id="fnref:microcode"><a class="ref" href="#fn:microcode">1</a></span> (There's a lot of overlap with the multiplication post so apologies for any deja vu.) The die photo below shows the chip under a microscope. I've labeled the key functional blocks; the ones that are important to this post are darker. At the left, the ALU (Arithmetic/Logic Unit) performs the arithmetic operations at the heart of division: subtraction and shifts. Division also uses a few special hardware features: the X register, the F1 flag, and a loop counter. The microcode ROM at the lower right controls the process.</p> <p><a href="https://static.righto.com/images/8086-div/die-labeled.jpg"><img alt="The 8086 die under a microscope, with main functional blocks labeled. This photo shows the chip with the metal and polysilicon removed, revealing the silicon underneath. Click on this image (or any other) for a larger version." class="hilite" height="592" src="https://static.righto.com/images/8086-div/die-labeled-w600.jpg" title="The 8086 die under a microscope, with main functional blocks labeled. This photo shows the chip with the metal and polysilicon removed, revealing the silicon underneath. Click on this image (or any other) for a larger version." width="600" /></a><div class="cite">The 8086 die under a microscope, with main functional blocks labeled. This photo shows the chip with the metal and polysilicon removed, revealing the silicon underneath. Click on this image (or any other) for a larger version.</div></p> <h2>Microcode</h2> <p>Like most instructions, the division routines in the 8086 are implemented in microcode. Most people think of machine instructions as the basic steps that a computer performs. However, many processors have another layer of software underneath: microcode. With microcode, instead of building the CPU's control circuitry from complex logic gates, the control logic is largely replaced with code. To execute a machine instruction, the computer internally executes several simpler micro-instructions, specified by the microcode. This is especially useful for a machine instruction such as division, which performs many steps in a loop.</p> <!-- The 8086 uses a hybrid approach: although it uses microcode, much of the instruction functionality is implemented with gate logic. This approach removed duplication from the microcode and kept the microcode small enough for 1978 technology. In a sense, the microcode is parameterized. For instance, the microcode can specify a generic Arithmetic/Logic Unit (ALU) operation and a generic register. The gate logic examines the instruction to determine which specific operation to perform and the appropriate register. --> <p>Each micro-instruction in the 8086 is encoded into 21 bits as shown below. Every micro-instruction moves data from a source register to a destination register, each specified with 5 bits. The meaning of the remaining bits depends on the type field and can be anything from an ALU operation to a memory read or write to a change of microcode control flow. Thus, an 8086 micro-instruction typically does two things in parallel: the move and the action. For more about 8086 microcode, see my <a href="https://www.righto.com/2022/11/how-8086-processors-microcode-engine.html">microcode blog post</a>.</p> <p><a href="https://static.righto.com/images/8086-div/microcode-format.jpg"><img alt="The encoding of a micro-instruction into 21 bits. Based on NEC v. Intel: Will Hardware Be Drawn into the Black Hole of Copyright?" class="hilite" height="203" src="https://static.righto.com/images/8086-div/microcode-format-w700.jpg" title="The encoding of a micro-instruction into 21 bits. Based on NEC v. Intel: Will Hardware Be Drawn into the Black Hole of Copyright?" width="700" /></a><div class="cite">The encoding of a micro-instruction into 21 bits. Based on <a href="https://digitalcommons.law.scu.edu/cgi/viewcontent.cgi?referer=&httpsredir=1&article=1031&context=chtlj">NEC v. Intel: Will Hardware Be Drawn into the Black Hole of Copyright?</a></div></p> <p>A few details of the ALU (Arithmetic/Logic Unit) operations are necessary to understand the division microcode. The ALU has three temporary registers that are invisible to the programmer: tmpA, tmpB, and tmpC. An ALU operation takes its first argument from the specified temporary register, while the second argument always comes from tmpB. An ALU operation requires two micro-instructions. The first micro-instruction specifies the ALU operation and source register, configuring the ALU. For instance, <code>ADD tmpA</code> to add tmpA to the default tmpB. In the next micro-instruction (or a later one), the ALU result can be accessed through a register called <code>危</code> (Sigma) and moved to another register.</p> <p>The carry flag plays a key role in division. The carry flag is one of the programmer-visible status flags that is set by arithmetic operations, but it is also used by the microcode. For unsigned addition, the carry flag is set if there is a carry out of the word (or byte). For subtraction, the carry flag indicates a borrow, and is set if the subtraction requires a borrow. Since a borrow results if you subtract a larger number from a smaller number, the carry flag also indicates the "less than" condition. The carry flag (and other status flags) are only updated if micro-instruction contains the <code>F</code> bit.</p> <p>The <code>RCL</code> (Rotate through Carry, Left) micro-instruction is heavily used in the division microcode.<span id="fnref:rcl"><a class="ref" href="#fn:rcl">2</a></span> This operation shifts the bits in a 16-bit word, similar to the <code>&lt;&lt;</code> bit-shift operation in high-level languages, but with an additional feature. Instead of discarding the bit on the end, that bit is moved into the carry flag. Meanwhile, the bit formerly in the carry flag moves into the word. You can think of this as rotating the bits while treating the carry flag as a 17th bit of the word. (The <code>RCL</code> operation can also act on a byte.)</p> <p><a href="https://static.righto.com/images/8086-div/lrcy.jpg"><img alt="The rotate through carry left micro-instruction." class="hilite" height="51" src="https://static.righto.com/images/8086-div/lrcy-w300.jpg" title="The rotate through carry left micro-instruction." width="300" /></a><div class="cite">The rotate through carry left micro-instruction.</div></p> <p>These shifts perform an important part of the division process since shifting can be viewed as multiplying or dividing by two. <code>RCL</code> also provides a convenient way to move the most-significant bit to the carry flag, where it can be tested for a conditional jump. (This is important because the top bit is used as the sign bit.) Another important property is that performing <code>RCL</code> on a lower word and then <code>RCL</code> on an upper word will perform a 32-bit shift, since the high bit of the lower word will be moved into the low bit of the upper word via the carry bit. Finally, the shift moves the quotient bit from the carry into the register.</p> <h2>Binary division</h2> <p>The division process in the 8086 is similar to grade-school long division, except in binary instead of decimal. The diagram below shows the process: dividing 67 (the dividend) by 9 (the divisor) yields the quotient 7 at the top and the remainder 4 at the bottom. Long division is easier in binary than decimal because you don't need to guess the right quotient digit. Instead, at each step you either subtract the divisor (appropriately shifted) or subtract nothing. Note that although the divisor is 4 bits in this example, the subtractions use 5-bit values. The need for an "extra" bit in division will be important in the discussion below; 16-bit division needs a 17-bit value.</p> <style type="text/css"> table.divdia {border-collapse: collapse; font-family: "courier-new", courier, monospace; padding: 5px;} table.divdia tr.top {border-bottom: 1px solid #ccc;} table.divdia tr.sum {border-top: 1px solid #ccc;} table.divdia .dim {color: #aaa;} table.divdia td.l {border-left: 2px solid #444;} table.divdia td.t {border-top: 2px solid #444;} table.divdia td.ul {border-bottom: 1px solid #888;} </style> <table class="divdia"> <tr><td colspan=8>&nbsp;</td><td>0</td><td>1</td><td>1</td><td>1</td></tr> <tr><td>1</td><td>0</td><td>0</td><td>1</td><td class="t l">0</td><td class="t">1</td><td class="t">0</td><td class="t">0</td><td class="t">0</td><td class="t">0</td><td class="t">1</td><td class="t">1</td></tr> <tr><td colspan=4>&nbsp;</td><td>-</td><td class="ul dim">0</td><td class="ul dim">0</td><td class="ul dim">0</td><td class="ul dim">0</td> <tr><td colspan=5>&nbsp;</td><td>1</td><td>0</td><td>0</td><td>0</td><td class="u">0</td></tr> <tr><td colspan=5>&nbsp;</td><td>-</td><td class="ul">1</td><td class="ul">0</td><td class="ul">0</td><td class="ul">1</td> <tr><td colspan=6>&nbsp;</td><td>0</td><td>1</td><td>1</td><td>1</td><td class="u">1</td></tr> <tr><td colspan=6>&nbsp;</td><td>-</td><td class="ul">1</td><td class="ul">0</td><td class="ul">0</td><td class="ul">1</td> <tr><td colspan=7>&nbsp;</td><td>0</td><td>1</td><td>1</td><td>0</td><td class="u">1</td></tr> <tr><td colspan=7>&nbsp;</td><td>-</td><td class="ul">1</td><td class="ul">0</td><td class="ul">0</td><td class="ul">1</td> <tr><td colspan=8>&nbsp;</td><td>0</td><td>1</td><td>0</td><td>0</td></tr> </table> <p>Instead of shifting the divisor to the right each step, the 8086's algorithm shifts the quotient and the current dividend to the left each step. This trick reduces the register space required. Dividing a 32-bit number (the dividend) by a 16-bit number yields a 16-bit result, so it seems like you'd need four 16-bit registers in total. The trick is that after each step, the 32-bit dividend gets one bit smaller, while the result gets one bit larger. Thus, the dividend and the result can be packed together into 32 bits. At the end, what's left of the dividend is the 16-bit remainder. The table below illustrates this process for a sample dividend (blue) and quotient (green).<span id="fnref:table"><a class="ref" href="#fn:table">3</a></span> At the end, the 16-bit blue value is the remainder.</p> <style type="text/css"> table.div {border-collapse: collapse; border: 1px solid #888; font-family: "courier-new", courier, monospace; padding: 5px;} table.div th {border-bottom: 1px solid #444;} table.div th:nth-child(1) {border-left: 1px solid #444;} table.div th:nth-child(3) {border-left: 1px solid #444;} table.div th:nth-child(4) {padding: 0 4px;} table.div tr:nth-child(2) {border-bottom: 1px solid #444;} table.div tr:nth-child(2) {border-bottom: 1px solid #444;} table.div td:nth-child(8) {border-right: 1px solid #444;} table.div td:nth-child(16) {border-right: 2px solid #444;} table.div td:nth-child(24) {border-right: 1px solid #444;} table.div td.a {background-color: #ddf;} table.div td.b {background-color: #cfc;} </style> <table class="div"> <tr style="font-family: sans-serif; color: blue"><th colspan=16>dividend</th><th colspan=16 style="font-family:sans-serif; color: green">quotient</th></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">0</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">1</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">1</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">0</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">0</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">0</td><td class="b">1</td></tr> <tr><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">1</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">1</td></tr> </table> <h2>The division microcode</h2> <p>The 8086 has four division instructions to handle signed and unsigned division of byte and word operands. I'll start by describing the microcode for the unsigned word division instruction <code>DIV</code>, which divides a 32-bit dividend by a 16-bit divisor. The dividend is supplied in the AX and DX registers while the divisor is specified by the source operand. The 16-bit quotient is returned in AX and the 16-bit remainder in DX. For a divide-by-zero, or if the quotient is larger than 16 bits, a type 0 "divide error" interrupt is generated.</p> <h3><code>CORD</code>: The core division routine</h3> <p>The <code>CORD</code> microcode subroutine below implements the long-division algorithm for all division instructions; I think <code>CORD</code> stands for Core Divide. At entry, the arguments are in the ALU temporary registers: tmpA/tmpC hold the 32-bit dividend, while tmpB holds the 16-bit divisor. (I'll explain the configuration for byte division later.) Each cycle of the loop shifts the values and then potentially subtracts the divisor. One bit is appended to the quotient to indicate whether the divisor was subtracted or not. At the end of the loop, whatever is left of the dividend is the remainder.</p> <p>Each micro-instruction specifies a register move on the left, and an action on the right. The moves transfer words between the visible registers and the ALU's temporary registers, while the actions are mostly ALU operations or control flow. As is usually the case with microcode, the details are tricky. The first three lines below check if the division will overflow or divide by zero. The code compares tmpA and tmpB by subtracting tmpB, discarding the result, but setting the status flags (<code>F</code>). If the upper word of the divisor is greater or equal to the dividend, the division will overflow, so execution jumps to <code>INT0</code> to generate a divide-by-zero interrupt.<span id="fnref:interrupts"><a class="ref" href="#fn:interrupts">4</a></span> (This handles both the case where the dividend is "too large" and the divide-by-0 case.) The number of loops in the division algorithm is controlled by a special-purpose loop counter. The <code>MAXC</code> micro-instruction initializes the counter to 7 or 15, for a byte or word divide instruction respectively.</p> <pre class="microcode"> move action SUBT tmpA <span><b>CORD:</b> set up compare</span> 危 &#8594; no dest MAXC F <span>compare, set up counter, update flags</span> JMP NCY INT0 <span>generate interrupt if overflow</span> RCL tmpC <span><b>3:</b> main loop: left shift tmpA/tmpC</span> 危 &#8594; tmpC RCL tmpA <span></span> 危 &#8594; tmpA SUBT tmpA <span>set up compare/subtract</span> JMPS CY 13 <span>jump if top bit of tmpA was set</span> 危 &#8594; no dest F <span>compare, update flags</span> JMPS NCY 14 <span>jump for subtract</span> JMPS NCZ 3 <span>test counter, loop back to 3</span> RCL tmpC <span><b>10:</b> done:</span> 危 &#8594; tmpC <span>shift last bit into tmpC</span> 危 &#8594; no dest RTN <span>done: get top bit, return</span> RCY <span><b>13:</b> reset carry</span> 危 &#8594; tmpA JMPS NCZ 3 <span><b>14:</b> subtract, loop</span> JMPS 10 <span>done, goto 10</span> </pre> <p>The main loop starts at <em>3</em>. The tmpC and tmpA registers are shifted left. This has two important side effects. First, the old carry bit (which holds the latest quotient bit) is shifted into the bottom of tmpC. Second, the top bit of tmpA is shifted into the carry bit; this provides the necessary "extra" bit for the subtraction below. Specifically, if the carry (the "extra" tmpA bit) is set, tmpB can be subtracted, which is accomplished by jumping to <em>13</em>. Otherwise, the code compares tmpA and tmpB by subtracting tmpB, discarding the result, and updating the flags (<code>F</code>). If there was no borrow/carry (tmpA &#8805; tmpB), execution jumps to <em>14</em> to subtract. Otherwise, the internal loop counter is decremented and control flow goes back to the top of the loop if not done (<code>NCZ</code>, Not Counter Zero). If the loop is done, tmpC is rotated left to pick up the last quotient bit from the carry flag. Then a second rotate of tmpC is performed but the result is discarded; this puts the top bit of tmpC into the carry flag for use later in <code>POSTIDIV</code>. Finally, the subroutine returns.</p> <p>The subtraction path is <em>13</em> and <em>14</em>, which subtract tmpB from tmpA by storing the result (危) in tmpA. This path resets the carry flag for use as the quotient bit. As in the other path, the loop counter is decremented and tested (<code>NCZ</code>) and execution either continues back at <em>3</em> or finishes at <em>10</em>.</p> <p>One complication is that the carry bit is the opposite of the desired quotient bit. Specifically, if tmpA &lt; tmpB, the comparison generates a borrow so the carry flag is set to 1. In this case, the desired quotient bit is 0 and no subtraction takes place. But if tmpA &#8805; tmpB, the comparison does not generate a borrow (so the carry flag is set to 0), the code subtracts tmpB, and the desired quotient bit is 1. Thus, tmpC ends up holding the <em>complement</em> of the desired result; this is fixed later.</p> <p>The microcode is carefully designed to pack the divide loop into a small number of micro-instructions. It uses the registers and the carry flag in tricky ways, using the carry flag to hold the top bit of tmpA, the comparison result, and the generated quotient bit. This makes the code impressively dense but tricky to understand.</p> <h3>The top-level division microcode</h3> <p>Now I'll pop up a level and take a look at the top-level microcode (below) that implements the <code>DIV</code> and <code>IDIV</code> machine instructions. The first three instructions load tmpA, tmpC, and tmpB from the specified registers. (The <code>M</code> register refers to the source specified in the instruction, either a register or a memory location.) Next, the <code>X0</code> condition tests bit 3 of the instruction, which in this case distinguishes <code>DIV</code> from <code>IDIV</code>. For signed division (<code>IDIV</code>), the microcode calls <code>PREIDIV</code>, which I'll discuss below. Next, the <code>CORD</code> micro-subroutine discussed above is called to perform the division.</p> <pre class="microcode"> DX &#8594; tmpA <span><b>iDIV rmw:</b> load tmpA, tmpC, tmpB </span> AX &#8594; tmpC RCL tmpA <span>set up RCL left shift operation</span> M &#8594; tmpB CALL X0 PREIDIV <span>set up integer division if IDIV</span> CALL CORD <span>call CORD to perform division </span> COM1 tmpC <span>set up to complement the quotient </span> DX &#8594; tmpB CALL X0 POSTIDIV <span>get original dividend, handle IDIV</span> 危 &#8594; AX NXT <span>store updated quotient</span> tmpA &#8594; DX RNI <span>store remainder, run next instruction</span> </pre> <p>As discussed above, the quotient in tmpC needs to be 1's-complemented, which is done with <code>COM1</code>. For <code>IDIV</code>, the micro-subroutine <code>POSTIDIV</code> sets the signs of the results appropriately. The results are stored in the <code>AX</code> and <code>DX</code> registers. The <code>NXT</code> micro-operation indicates the next micro-instruction is the last one, directing the microcode engine to start the next machine instruction. Finally, <code>RNI</code> directs the microcode engine to run the next machine instruction.</p> <h2>8-bit division</h2> <p>The 8086 has separate opcodes for 8-bit division. The 8086 supports many instructions with byte and word versions, using 8-bit or 16-bit arguments respectively. In most cases, the byte and word instructions use the same microcode, with the ALU and register hardware using bytes or words based on the instruction. In the case of division, the shift micro-operations act on tmpA and tmpC as 8-bit registers rather than 16-bit registers. Moreover, the <code>MAXC</code> micro-operation initializes the internal counter to 7 rather than 15. Thus, the same <code>CORD</code> microcode is used for word and byte division, but the number of loops and the specific operations are changed by the hardware.</p> <p>The diagram below shows the tmpA and tmpC registers during each step of dividing 0x2345 by 0x34. Note that the registers are treated as 8-bit registers. The divisor (blue) steadily shrinks with the quotient (green) taking its place. At the end, the remainder is 0x41 (blue) and the quotient is 0xad, complement of the green value.</p> <table class="div"> <tr style="font-family: sans-serif"><th colspan=16>tmpA</th><th colspan=16 style="font-family:sans-serif">tmpC</th></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="b">0</td></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="b">0</td><td class="b">1</td></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td><td class="b">1</td></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td><td class="b">0</td></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td><td class="b">0</td><td class="b">1</td></tr> <tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">0</td><td class="a">1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td class="b">0</td><td class="b">1</td><td class="b">0</td><td class="b">1</td><td class="b">0</td><td class="b">0</td><td class="b">1</td><td class="b">0</td></tr> </table> <p>Although the <code>CORD</code> routine is shared for byte and word division, the top-level microcode is different. In particular, the byte and word division instructions use different registers, requiring microcode changes. The microcode below is the top-level code for byte division. It is almost the same as the microcode above, except it uses the top and bottom bytes of the accumulator (<code>AH</code> and <code>AL</code>) rather than the <code>AX</code> and <code>DX</code> registers.</p> <pre class="microcode"> AH &#8594; tmpA <span><b>iDIV rmb:</b> get arguments</span> AL &#8594; tmpC RCL tmpA <span>set up RCL left shift operation</span> M &#8594; tmpB CALL X0 PREIDIV <span>handle signed division if IDIV</span> CALL CORD <span>call CORD to perform division</span> COM1 tmpC <span>complement the quotient</span> AH &#8594; tmpB CALL X0 POSTIDIV <span>handle signed division if IDIV</span> 危 &#8594; AL NXT <span>store quotient</span> tmpA &#8594; AH RNI <span>store remainder, run next instruction</span> </pre> <h2>Signed division</h2> <p>The 8086 (like most computers) represents signed numbers using a format called two's complement. While a regular byte holds a number from 0 to 255, a signed byte holds a number from -128 to 127. A negative number is formed by flipping all the bits (known as the one's complement) and then adding 1, yielding the two's complement value. For instance, +5 is <code>0x05</code> while -5 is <code>0xfb</code>. (Note that the top bit of a number is set for a negative number; this is the sign bit.) The nice thing about two's complement numbers is that the same addition and subtraction operations work on both signed and unsigned values. Unfortunately, this is not the case for signed multiplication and division.</p> <p>The 8086 has separate <code>IDIV</code> (Integer Divide) instructions to perform signed division. The 8086 performs signed division by converting the arguments to positive values, performing unsigned division, and then negating the results if necessary. As shown earlier, signed and unsigned division both use the same top-level microcode and the microcode conditionally calls some subroutines for signed division. These additional subroutines cause a significant performance penalty, making signed division over 20 cycles slower than unsigned division. I will discuss those micro-subroutines below.</p> <h3><code>PREIDIV</code></h3> <p>The first subroutine for signed division is <code>PREIDIV</code>, performing preliminary operations for integer division. It converts the two arguments, stored in tmpA/tmpC and tmpB, to positive values. It keeps track of the signs using an internal flag called <code>F1</code>, toggling this flag for each negative argument. This conveniently handles the rule that two negatives make a positive since complementing the <code>F1</code> flag twice will clear it. The point of this is that the main division code (<code>CORD</code>) only needs to handle unsigned division.</p> <p>The microcode below implements <code>PREIDIV</code>. First it tests if tmpA is negative, but the 8086 does not have a microcode condition to directly test the sign of a value. Instead, the microcode determines if a value is negative by shifting the value left, which moves the top (sign) bit into the carry flag. The conditional jump (<code>NCY</code>) then tests if the carry is clear, jumping if the value is non-negative. If tmpA is negative, execution falls through to negate the first argument. This is tricky because the argument is split between the tmpA and tmpC registers. The two's complement operation (<code>NEG</code>) is applied to the low word, while either 2's complement or one's complement (<code>COM1</code>) is applied to the upper word, depending on the carry for mathematical reasons.<span id="fnref:neg"><a class="ref" href="#fn:neg">5</a></span> The <code>F1</code> flag is complemented to keep track of the sign. (The multiplication process reuses most of this code, starting at the <code>NEGATE</code> entry point.)</p> <pre class="microcode"> 危 &#8594; no dest <span><b>PREIDIV:</b> shift tmpA left</span> JMPS NCY 7 <span>jump if non-negative</span> NEG tmpC <span><b>NEGATE:</b> negate tmpC</span> 危 &#8594; tmpC COM1 tmpA F <span>maybe complement tmpA</span> JMPS CY 6 NEG tmpA <span>negate tmpA if there's no carry</span> 危 &#8594; tmpA CF1 <span><b>6:</b> toggle F1 (sign)</span> RCL tmpB <span><b>7:</b> test sign of tmpB</span> 危 &#8594; no dest NEG tmpB <span>maybe negate tmpB</span> JMPS NCY 11 <span>skip if tmpB positive</span> 危 &#8594; tmpB CF1 RTN <span>else negate tmpB, toggle F1 (sign)</span> RTN <span><b>11:</b> return</span> </pre> <p>The next part of the code, starting at <em>7</em>, negates tmpB (the divisor) if it is negative. Since the divisor is a single word, this code is simpler. As before, the <code>F1</code> flag is toggled if tmpB is negative. At the end, both arguments (tmpA/tmpC and tmpB) are positive, and <code>F1</code> indicates the sign of the result.</p> <h3><code>POSTIDIV</code></h3> <p>After computing the result, the <code>POSTIDIV</code> routine is called for signed division. The routine first checks for a signed overflow and raises a divide-by-zero interrupt if so. Next, the routine negates the quotient and remainder if necessary.<span id="fnref:signs"><a class="ref" href="#fn:signs">6</a></span></p> <p>In more detail, the <code>CORD</code> routine left the top bit of tmpC (the complemented quotient) in the carry flag. Now, that bit is tested. If the carry bit is 0 (<code>NCY</code>), then the top bit of the quotient is 1 so the quotient is too big to fit in a signed value.<span id="fnref:overflow"><a class="ref" href="#fn:overflow">7</a></span> In this case, the <code>INT0</code> routine is executed to trigger a type 0 interrupt, indicating a divide overflow. (This is a rather roundabout way of testing the quotient, relying on a carry bit that was set in a previous subroutine.)</p> <pre class="microcode"> JMP NCY INT0 <span><b>POSTIDIV:</b> if overflow, trigger interrupt</span> RCL tmpB <span>set up rotate of tmpB</span> 危 &#8594; no dest NEG tmpA <span>get sign of tmpB, set up negate of tmpA</span> JMPS NCY 5 <span>skip if tmpB non-negative</span> 危 &#8594; tmpA <span>otherwise negate tmpA (remainder)</span> INC tmpC <span><b>5:</b> set up increment</span> JMPS F1 8 <span>test sign flag, skip if set</span> COM1 tmpC <span>otherwise set up complement</span> CCOF RTN <span><b>8:</b> clear carry and overflow flags, return</span> </pre> <p>Next, tmpB (the divisor) is rotated to see if it is negative. (The caller loaded tmpB with the original divisor, replacing the dividend that was in tmpB previously.) If the divisor is negative, tmpA (the remainder) is negated. This implements the 8086 rule that the sign of the remainder matches the sign of the divisor.</p> <p>The quotient handling is a bit tricky. Recall that tmpC holds the complemented quotient. the <code>F1</code> flag is set if the result should be negative. In that case, the complemented quotient needs to be incremented by 1 (<code>INC</code>) to convert from 1's complement to 2's complement. On the other hand, if the quotient should be positive, 1's-complementing tmpC (<code>COM1</code>) will yield the desired positive quotient. In either case, the ALU is configured in <code>POSTIDIV</code>, but the result will be stored back in the main routine.</p> <p>Finally, the <code>CCOF</code> micro-operation clears the carry and overflow flags. Curiously, the 8086 documentation declares that the status flags are undefined following <code>IDIV</code>, but the microcode explicitly clears the carry and overflow flags. I assume that the flags were cleared in analogy with <code>MUL</code>, but then Intel decided that this wasn't useful so they didn't document it. (Documenting this feature would obligate them to provide the same functionality in later x86 chips.)</p> <h2>The hardware for division</h2> <p>For the most part, the 8086 uses the regular ALU addition and shifts for the division algorithm. Some special hardware features provide assistance. In this section, I'll look at this hardware.</p> <h3>Loop counter</h3> <p>The 8086 has a 4-bit loop counter for multiplication and division. This counter starts at 7 for byte division and 15 for word division, based on the low bit of the opcode. This loop counter allows the microcode to decrement the counter, test for the end, and perform a conditional branch in one micro-operation. The counter is implemented with four flip-flops, along with logic to compute the value after decrementing by one. The <code>MAXC</code> (Maximum Count) micro-instruction sets the counter to 7 or 15 for byte or word operations respectively. The <code>NCZ</code> (Not Counter Zero) micro-instruction has two actions. First, it performs a conditional jump if the counter is nonzero. Second, it decrements the counter.</p> <h3>The F1 flag</h3> <p>Signed multiplication and division use an internal flag called <code>F1</code><span id="fnref:f1"><a class="ref" href="#fn:f1">8</a></span> to keep track of the sign. The <code>F1</code> flag is toggled by microcode through the <code>CF1</code> (Complement F1) micro-instruction. The <code>F1</code> flag is implemented with a flip-flop, along with a multiplexer to select the value. It is cleared when a new instruction starts, set by a <code>REP</code> prefix, and toggled by the <code>CF1</code> micro-instruction. The diagram below shows how the F1 latch and the loop counter appear on the die. In this image, the metal layer has been removed, showing the silicon and the polysilicon wiring underneath.</p> <p><a href="https://static.righto.com/images/8086-div/counter.jpg"><img alt="The counter and F1 latch as they appear on the die. The latch for the REP state is also here." class="hilite" height="308" src="https://static.righto.com/images/8086-div/counter-w600.jpg" title="The counter and F1 latch as they appear on the die. The latch for the REP state is also here." width="600" /></a><div class="cite">The counter and F1 latch as they appear on the die. The latch for the REP state is also here.</div></p> <h3>X register</h3> <p>The division microcode uses an internal register called the <code>X</code> register to distinguish between the <code>DIV</code> and <code>IDIV</code> instructions. The <code>X</code> register is a 3-bit register that holds the ALU opcode, indicated by bits 5&ndash;3 of the instruction.<span id="fnref:x-reg"><a class="ref" href="#fn:x-reg">9</a></span> Since the instruction is held in the Instruction Register, you might wonder why a separate register is required. The motivation is that some opcodes specify the type of ALU operation in the second byte of the instruction, the ModR/M byte, bits 5&ndash;3.<span id="fnref:opcode"><a class="ref" href="#fn:opcode">10</a></span> Since the ALU operation is sometimes specified in the first byte and sometimes in the second byte, the <code>X</code> register was added to handle both these cases.</p> <p>For the most part, the <code>X</code> register indicates which of the eight standard ALU operations is selected (<code>ADD</code>, <code>OR</code>, <code>ADC</code>, <code>SBB</code>, <code>AND</code>, <code>SUB</code>, <code>XOR</code>, <code>CMP</code>). However, a few instructions use bit 0 of the <code>X</code> register to distinguish between other pairs of instructions. For instance, it distinguishes between <code>MUL</code> and <code>IMUL</code>, <code>DIV</code> and <code>IDIV</code>, <code>CMPS</code> and <code>SCAS</code>, <code>MOVS</code> and <code>LODS</code>, or <code>AAA</code> and <code>AAS</code>. While these instruction pairs may appear to have arbitrary opcodes, they have been carefully assigned so the microcode can distinguish them.</p> <p>The implementation of the <code>X</code> register is straightforward, consisting of three flip-flops to hold the three bits of the instruction. The flip-flops are loaded from the prefetch queue bus during First Clock and during Second Clock for appropriate instructions, as the instruction bytes travel over the bus. Testing bit 0 of the <code>X</code> register with the <code>X0</code> condition is supported by the microcode condition evaluation circuitry, so it can be used for conditional jumps in the microcode.</p> <h2>Algorithmic and historical context</h2> <p>As you can see from the microcode, division is a complicated and relatively slow process. On the 8086, division takes up to 184 clock cycles to perform all the microcode steps. (In comparison, two registers can be added in 3 clock cycles.) Multiplication and division both loop over the bits, performing repeated addition or subtraction respectively. But division requires a decision (subtract or not?) at each step, making it even slower, about half the speed of multiplication.<span id="fnref:history"><a class="ref" href="#fn:history">11</a></span></p> <p>Various algorithms have been developed to speed up division. Rather than performing long division one bit at a time, you can do long division in, say, base 4, producing two quotient bits in each step. As with decimal long division, the tricky part is figuring out what digit to select. The <a href="https://en.wikipedia.org/wiki/Division_algorithm#SRT_division">SRT algorithm</a> (1957) uses a small lookup table to estimate the quotient digit from a few bits of the divisor and dividend. The clever part is that the selected digit doesn't need to be exactly right at each step; the algorithm will self-correct after a wrong "guess". The Pentium processor (1993) famously had a <a href="https://math.mit.edu/~edelman/homepage/papers/pentiumbug.pdf">floating point division bug</a> due to a few missing values in the SRT table. This bug cost Intel $475 million to replace the faulty processors.</p> <p>Intel's x86 processors steadily improved divide performance. The 80286 (1982) performed a word divide in 22 clocks, about 6 times as fast as the 8086. In the <a href="https://www.cubawiki.com.ar/images/b/b3/Orga2_paper_penyn.pdf">Penryn</a> architecture (2007), Intel upgraded from Radix-4 to Radix-16 division. Rather than having separate integer and floating-point hardware, integer divides were handled through the floating point divider. Although modern Intel processors have greatly improved multiplication and division compared to the 8086, division is still a relatively slow operation. While a Tiger Lake (2020) processor can perform an integer multiplication every clock cycle (with a latency of 3 cycles), division is much slower and can only be done once every 6-10 clock cycles (<a href="https://agner.org/optimize/">details</a>).</p> <p>I've written numerous <a href="https://www.righto.com/search/label/8086">posts on the 8086</a> so far and plan to continue reverse-engineering the 8086 die so follow me on Twitter <a href="https://twitter.com/kenshirriff">@kenshirriff</a> or <a href="http://www.righto.com/feeds/posts/default">RSS</a> for updates. I've also started experimenting with Mastodon recently as <a href="https://oldbytes.space/@kenshirriff">@<span class="__cf_email__" data-cfemail="7a111f140912130808131c1c3a15161e18030e1f0954090a1b191f">[email&#160;protected]</span></a>.</p> <h2>Notes and references</h2> <div class="footnote"> <ol> <li id="fn:microcode"> <p>My microcode analysis is based on Andrew Jenner's <a href="https://www.reenigne.org/blog/8086-microcode-disassembled/">8086 microcode disassembly</a>.&#160;<a class="footnote-backref" href="#fnref:microcode" title="Jump back to footnote 1 in the text">&#8617;</a></p> </li> <li id="fn:rcl"> <p>The 8086 patent and Andrew Jenner's microcode use the name <code>LRCY</code> (Left Rotate through Carry) instead of <code>RCL</code>. I figure that <code>RCL</code> will be more familiar to people because of the corresponding machine instruction.&#160;<a class="footnote-backref" href="#fnref:rcl" title="Jump back to footnote 2 in the text">&#8617;</a></p> </li> <li id="fn:table"> <p>In the dividend/quotient table, the tmpA register is on the left and the tmpC register is on the right. 0x0f00ff00 divided by 0x0ffc yielding the remainder 0x0030 (blue) and quotient 0xf04c (green). (The green bits are the complement of the quotient due to implementation in the 8086.)&#160;<a class="footnote-backref" href="#fnref:table" title="Jump back to footnote 3 in the text">&#8617;</a></p> </li> <li id="fn:interrupts"> <p>I described the 8086's interrupt circuitry in detail in <a href="https://www.righto.com/2023/02/8086-interrupt.html">this post</a>.&#160;<a class="footnote-backref" href="#fnref:interrupts" title="Jump back to footnote 4 in the text">&#8617;</a></p> </li> <li id="fn:neg"> <p>The negation code is a bit tricky because the result is split across two words. In most cases, the upper word is bitwise complemented. However, if the lower word is zero, then the upper word is negated (two's complement). I'll demonstrate with 16-bit values to keep the examples small. The number 257 (0x0101) is negated to form -257 (0xfeff). Note that the upper byte is the one's complement (0x01 vs 0xfe) while the lower byte is two's complement (0x01 vs 0xff). On the other hand, the number 256 (0x0100) is negated to form -256 (0xff00). In this case, the upper byte is the two's complement (0x01 vs 0xff) and the lower byte is also the two's complement (0x00 vs 0x00).</p> <p>(Mathematical explanation: the two's complement is formed by taking the one's complement and adding 1. In most cases, there won't be a carry from the low byte to the upper byte, so the upper byte will remain the one's complement. However, if the low byte is 0, the complement is 0xff and adding 1 will form a carry. Adding this carry to the upper byte yields the two's complement of that byte.)</p> <p>To support multi-word negation, the 8086's <code>NEG</code> instruction clears the carry flag if the operand is 0, and otherwise sets the carry flag. (This is the opposite of the above because subtractions (including <code>NEG</code>) treat the carry flag as a borrow flag, with the opposite meaning.) The microcode <code>NEG</code> operation has identical behavior to the machine instruction, since it is used to implement the machine instruction.</p> <p>Thus to perform a two-word negation, the microcode negates the low word (tmpC) and updates the flags (<code>F</code>). If the carry is set, the one's complement is applied to the upper word (tmpA). But if the carry is cleared, the two's complement is applied to tmpA.&#160;<a class="footnote-backref" href="#fnref:neg" title="Jump back to footnote 5 in the text">&#8617;</a></p> </li> <li id="fn:signs"> <p>There is a bit of ambiguity with the quotient and remainder of negative numbers. For instance, consider -27 &#247; 7. -27 = 7 &times; -3 - 6 = 7 * -4 + 1. So you could consider the result to be a quotient of -3 and remainder of -6, or a quotient of -4 and a remainder of 1. The 8086 uses the rule that the remainder will have the same sign as the dividend, so the first result would be used. The advantage of this rule is that you can perform unsigned division and adjust the signs afterward: <br/>27 &#247; 7 = quotient 3, remainder 6. <br/>-27 &#247; 7 = quotient -3, remainder -6. <br/>27 &#247; -7 = quotient -3, remainder 6. <br/>-27 &#247; -7 = quotient 3, remainder -6.</p> <p>This rule is known as truncating division, but some languages use different approaches such as floored division, rounded division, or Euclidean division. <a href="https://en.wikipedia.org/wiki/Modulo#Variants_of_the_definition">Wikipedia</a> has details.&#160;<a class="footnote-backref" href="#fnref:signs" title="Jump back to footnote 6 in the text">&#8617;</a></p> </li> <li id="fn:overflow"> <p>The signed overflow condition is slightly stricter than necessary. For a word division, the 16-bit quotient is restricted to the range -32767 to 32767. However, a 16-bit signed value can take on the values -32768 to 32767. Thus, a quotient of -32768 fits in a 16-bit signed value even though the 8086 considers it an error. This is a consequence of the 8086 performing unsigned division and then updating the sign if necessary.&#160;<a class="footnote-backref" href="#fnref:overflow" title="Jump back to footnote 7 in the text">&#8617;</a></p> </li> <li id="fn:f1"> <p>The internal <code>F1</code> flag is also used to keep track of a <code>REP</code> prefix for use with a string operation. I discussed string operations and the <code>F1</code> flag in <a href="https://www.righto.com/2023/04/8086-microcode-string-operations.html">this post</a>.&#160;<a class="footnote-backref" href="#fnref:f1" title="Jump back to footnote 8 in the text">&#8617;</a></p> </li> <li id="fn:x-reg"> <p>Curiously, the <a href="https://patents.google.com/patent/US4449184A/">8086 patent</a> states that the <code>X</code> register is a 4-bit register holding bits 3&ndash;6 of the byte (col. 9, line 20). But looking at the die, it is a 3-bit register holding bits 3&ndash;5 of the byte.&#160;<a class="footnote-backref" href="#fnref:x-reg" title="Jump back to footnote 9 in the text">&#8617;</a></p> </li> <li id="fn:opcode"> <p>Some instructions are specified by bits 5&ndash;3 in the ModR/M byte rather than in the first opcode byte. The motivation is to avoid wasting bits for instructions that use a ModR/M byte but don't need a register specification. For instance, consider the instruction <code>ADD [BX],0x1234</code>. This instruction uses a ModR/M byte to specify the memory address. However, because it uses an immediate operand, it does not need the register specification normally provided by bits 5&ndash;3 of the ModR/M byte. This frees up the bits to specify the instruction. From one perspective, this is an ugly hack, while from another perspective it is a clever optimization.&#160;<a class="footnote-backref" href="#fnref:opcode" title="Jump back to footnote 10 in the text">&#8617;</a></p> </li> <li id="fn:history"> <p>Even the earliest computers such as ENIAC (1945) usually supported multiplication and division. However, early microprocessors did not provide multiplication and division instructions due to the complexity of these instructions. Instead, the programmer would need to write an assembly code loop, which was very slow. Early microprocessors often had binary-coded decimal instructions that could perform additions and subtractions in decimal. One motivation for these instructions was that converting between binary and decimal was extremely slow due to the need for multiplication and division. Instead, it was easier and faster to keep the values as decimal if that was how they were displayed.</p> <p>The Texas Instruments TMS9900 (1976) was one of the first microprocessors with multiplication and division instructions. Multiply and divide instructions remained somewhat controversial on RISC (Reduced Instruction-Set Computer) processors due to the complexity of these instructions. The early ARM processors, for instance, did not support multiplication and division. Multiplication was added to ARMv2 (1986) but most ARM processors still don't have integer division. The popular open-source RISC-V architecture (2015) doesn't include integer multiply and divide by default, but provides them as an optional "M" extension.</p> <p>The 8086's algorithm is designed for simplicity rather than speed. It is a "restoring" algorithm that checks before subtracting to ensure that the current term is always positive. This can require two ALU operations (comparison and subtraction) per cycle. A slightly more complex approach is a "nonrestoring" algorithm that subtracts even if it yields a negative term, and then adds during a later loop iteration.&#160;<a class="footnote-backref" href="#fnref:history" title="Jump back to footnote 11 in the text">&#8617;</a></p> </li> </ol> </div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/5693917346966509204' onclick=''> 4 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post/6264947694886887540/5693917346966509204' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=5693917346966509204&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5693917346966509204&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5693917346966509204&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5693917346966509204&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5693917346966509204&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5693917346966509204&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/8086' rel='tag'>8086</a>, <a href='http://www.righto.com/search/label/chips' rel='tag'>chips</a>, <a href='http://www.righto.com/search/label/intel' rel='tag'>intel</a>, <a href='http://www.righto.com/search/label/reverse-engineering' rel='tag'>reverse-engineering</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://static.righto.com/images/8086-str/die-labeled-w600.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='6370120370244800510' itemprop='postId'/> <a name='6370120370244800510'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2023/04/8086-microcode-string-operations.html'>The microcode and hardware in the 8086 processor that perform string operations</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-6370120370244800510' itemprop='description articleBody'> <style> .hilite {cursor:zoom-in} a:link img.hilite, a:visited img.hilite {color: #fff;} a:hover img.hilite {color: #f66;} </style> <style> pre.microcode {font-family: courier, fixed; padding: 10px; background-color: #f5f5f5; display:inline-block;border:none;} pre.microcode span {color: green; font-style:italic; font-family: sans-serif; font-size: 90%;} </style> <p>Intel introduced the 8086 microprocessor in 1978. This processor ended up being hugely influential, setting the path for the x86 architecture that is extensively used today. One interesting feature of the 8086 was instructions that can efficiently operate on blocks of memory up to 64K bytes long.<span id="fnref:history"><a class="ref" href="#fn:history">1</a></span> These instructions rapidly copy, compare, or scan data and are known as "string" instructions.<span id="fnref:string"><a class="ref" href="#fn:string">2</a></span></p> <p>In this blog post, I explain string operations in the 8086, analyze the microcode that it used, and discuss the hardware circuitry that helped it out. My analysis is based on reverse-engineering the 8086 from die photos. The photo below shows the chip under a microscope. I've labeled the key functional blocks; the ones that are important to this post are darker. Architecturally, the chip is partitioned into a Bus Interface Unit (BIU) at the top and an Execution Unit (EU) below. The BIU handles memory accesses, while the Execution Unit (EU) executes instructions. The microcode ROM at the lower right controls the process.</p> <!-- This post is part of my [series](https://www.righto.com/search/label/8086) on the internals of the 8086. --> <p><a href="https://static.righto.com/images/8086-str/die-labeled.jpg"><img alt="The 8086 die under a microscope, with main functional blocks labeled. This photo shows the chip with the metal and polysilicon removed, revealing the silicon underneath. Click on this image (or any other) for a larger version." class="hilite" height="624" src="https://static.righto.com/images/8086-str/die-labeled-w600.jpg" title="The 8086 die under a microscope, with main functional blocks labeled. This photo shows the chip with the metal and polysilicon removed, revealing the silicon underneath. Click on this image (or any other) for a larger version." width="600" /></a><div class="cite">The 8086 die under a microscope, with main functional blocks labeled. This photo shows the chip with the metal and polysilicon removed, revealing the silicon underneath. Click on this image (or any other) for a larger version.</div></p> <h2>Segments and addressing</h2> <p>Before I get into the details of the string instructions, I need to give a bit of background on how the 8086 accesses memory through segments. Earlier microprocessors such as the Intel 8080 (1974) used 16 bits to specify a memory address, allowing a maximum of 64K of memory. This memory capacity is absurdly small by modern standards, but at the time when a 4K memory board cost hundreds of dollars, this limit was not a problem. However, due to Moore's Law and the exponential growth in memory capacity, the follow-on 8086 processor needed to support more memory. At the same time, the 8086 needed to use 16-bit registers for backward compatibility with the 8080.</p> <p>The much-reviled solution was to create a 1-megabyte (20-bit) address space consisting of 64K segments, with a 16-bit address specifying a position within the segment. In more detail, the memory address was specified by a 16-bit offset address along with a particular 16-bit segment register selecting a segment. The segment register's value was shifted by 4 bits to give the segment's 20-bit base address. The 16-bit offset address was added, yielding a 20-bit memory address. This gave the processor a 1-megabyte address space, although only 64K could be accessed without changing a segment register. The 8086 had four segment registers so it could use multiple segments at the same time: the Code Segment, Data Segment, Stack Segment, and Extra Segment.</p> <p>The 8086 chip is split into two processing units: the Bus Interface Unit (BIU) that handles segments and memory accesses, and the Execution Unit (EU) that executes instructions. The Execution Unit is what comes to mind when you think of a processor: it has most of the registers, the arithmetic/logic unit (ALU), and the microcode that implements instructions. The Bus Interface Unit interacts with memory and other external systems, performing the steps necessary to read and write memory.</p> <p>Among other things, the Bus Interface Unit has a separate adder for address calculation; this adds the segment register to the base address to determine the final memory address. Every memory access uses the address adder at least once to add the segment base and offset. The address adder is also used to increment the program counter. Finally, the address adder increments and decrements the index registers used for block operations. This will be discussed in more detail below.</p> <h2>Microcode in the 8086</h2> <p>Most people think of machine instructions as the basic steps that a computer performs. However, many processors (including the 8086) have another layer of software underneath: microcode. With microcode, instead of building the control circuitry from complex logic gates, the control logic is largely replaced with code. To execute a machine instruction, the computer internally executes several simpler micro-instructions, specified by the microcode. This provides a considerable performance improvement for the block operations, which requires many steps in a loop. Performing this loop in microcode is considerably faster than writing the loop in assembly code.</p> <!-- The 8086 uses a hybrid approach: although it uses microcode, much of the instruction functionality is implemented with gate logic. This approach removed duplication from the microcode and kept the microcode small enough for 1978 technology. In a sense, the microcode is parameterized. For instance, the microcode can specify a generic Arithmetic/Logic Unit (ALU) operation and a generic register. The gate logic examines the instruction to determine which specific operation to perform and the appropriate register. --> <p>A micro-instruction in the 8086 is encoded into 21 bits as shown below. Every micro-instruction specifies a move operation from a source register to a destination register, each specified with 5 bits. The meaning of the remaining bits depends on the type field and can be anything from an ALU operation to a memory read or write to a change of microcode control flow. Thus, an 8086 micro-instruction typically does two things in parallel: the move and the action. For more about 8086 microcode, see my <a href="https://www.righto.com/2022/11/how-8086-processors-microcode-engine.html">microcode blog post</a>.</p> <p><a href="https://static.righto.com/images/8086-str/microcode-format.jpg"><img alt="The encoding of a micro-instruction into 21 bits. Based on NEC v. Intel: Will Hardware Be Drawn into the Black Hole of Copyright?" class="hilite" height="203" src="https://static.righto.com/images/8086-str/microcode-format-w700.jpg" title="The encoding of a micro-instruction into 21 bits. Based on NEC v. Intel: Will Hardware Be Drawn into the Black Hole of Copyright?" width="700" /></a><div class="cite">The encoding of a micro-instruction into 21 bits. Based on <a href="https://digitalcommons.law.scu.edu/cgi/viewcontent.cgi?referer=&httpsredir=1&article=1031&context=chtlj">NEC v. Intel: Will Hardware Be Drawn into the Black Hole of Copyright?</a></div></p> <p>I'll explain the behavior of an ALU micro-operation since it is important for string operations. The Arithmetic/Logic Unit (ALU) is the heart of the processor, performing addition, subtraction, and logical operations. The ALU has three temporary input registers that are invisible to the programmer: tmpA, tmpB, and tmpC. An ALU operation takes its first argument from any temporary register, while the second argument always comes from tmpB. Performing an ALU operation requires two micro-instructions. The first micro-instruction specifies the ALU operation and source register, configuring the ALU. For instance, <code>ADD tmpA</code> configures the ALU to add the tmpA register to the default tmpB register. In the next micro-instruction (or a later one), the ALU result can be accessed through a special register called <code>危</code> (SIGMA) and moved to another register.</p> <p>I'll also explain the memory read and write micro-operations. A memory operation uses two internal registers: <code>IND</code> (Indirect) holds the memory address, while <code>OPR</code> (Operand) holds the word that is read or written. A typical memory micro-instruction for a read is <code>R DS,BL</code>. This causes the Bus Interface Unit to compute the memory address by adding the Data Segment (<code>DS</code>) to the <code>IND</code> register and then perform the read. The Bus Interface Unit determines if the instruction is performing a byte operation or a word operation and reads a byte or word as appropriate, going through the necessary bus cycles. The <code>BL</code> option<span id="fnref:bl"><a class="ref" href="#fn:bl">3</a></span> causes the Bus Interface Unit to update the <code>IND</code> register as appropriate,<span id="fnref2:bl"><a class="ref" href="#fn:bl">3</a></span> incrementing or decrementing it by 1 or 2 depending on the Direction Flag and the size of the access (byte or word). All of this complexity happens in the hardware of the Bus Interface Unit and is invisible to the microcode. The tradeoff is that this simplifies the microcode but makes the chip's hardware considerably more complicated.</p> <h2>The string move instruction</h2> <p>The 8086 has five types of string instructions, operating on blocks of memory: <code>MOVS</code> (Move String), <code>CMPS</code> (Compare Strings), <code>SCAS</code> (Scan String), <code>LODS</code> (Load String), and <code>STOS</code> (Store String). Each instruction operates on a byte or word, but by using a <code>REP</code> prefix, the operation can be repeated for up to 64k bytes, controlled by a counter. Conditional repetitions can terminate the loop on various conditions. The string instructions provide a flexible way to operate on blocks of memory, much faster than a loop written in assembly code.</p> <p>The <code>MOVS</code> (Move String) operation copies one memory region to another. The <code>CMPS</code> (Compare Strings) operation compares two memory blocks and sets the status flags. In particular, this indicates if one string is greater, less, or equal to the other. The <code>SCAS</code> (Scan String) operation scans memory, looking for a particular value. The <code>LODS</code> (Load String) operation moves an element into the accumulator, generally as part of a more complex loop. Finally, <code>STOS</code> (Store String) stores the accumulator value, either to initialize a block of memory or as part of a more complex loop.<span id="fnref:morse"><a class="ref" href="#fn:morse">4</a></span></p> <p>Like many 8086 instructions, each string instruction has two opcodes: one that operates on bytes and one that operates on words. One of the interesting features of the 8086 is that the same microcode implements the byte and word instructions, while the hardware takes care of the byte- or word-sized operations as needed. Another interesting feature of the string operations is that they can go forward through memory, incrementing the pointers, or they can go backward, decrementing the points. A special processor flag, the Direction Flag, indicates the direction: 0 for incrementing and 1 for decrementing. Thus, there are four possibilities for stepping through memory, part of the flexibility of the string operations.</p> <p>The flowchart below shows the complexity of these instructions. I'm not going to explain the flowchart at this point, but the point is that there is a lot going on. This functionality is implemented by the microcode.</p> <p><a href="https://static.righto.com/images/8086-str/flowchart.png"><img alt="This flowchart shows the operation of a string instruction. From The 8086 Family Users Manual, fig 2-33." class="hilite" height="803" src="https://static.righto.com/images/8086-str/flowchart-w400.png" title="This flowchart shows the operation of a string instruction. From The 8086 Family Users Manual, fig 2-33." width="400" /></a><div class="cite">This flowchart shows the operation of a string instruction. From <a href="http://bitsavers.org/components/intel/8086/9800722-03_The_8086_Family_Users_Manual_Oct79.pdf">The 8086 Family Users Manual</a>, fig 2-33.</div></p> <p>I'll start by explaining the <code>MOVS</code> (Move String) instruction, which moves (copies) a block of memory. Before executing this instruction, the registers should be configured so the <code>SI</code> Source Index register points to the first block, the <code>DI</code> Destination Index register points to the second block, and the <code>CX</code> Count register holds the number of bytes or words to move. The basic action of the <code>MOVS</code> instruction reads a byte (or word) from the <code>SI</code> address and updates <code>SI</code>, writes the value to the <code>DI</code> address and updates <code>DI</code>, and decrements the <code>CX</code> counter.</p> <p>The microcode block below is executed for the <code>MOVS</code> (and <code>LODS</code>) instructions. There's a lot happening in this microcode with a variety of control paths, so it's a bit tricky to understand, but let's see how it goes. Each micro-instruction has a register-to-register move on the left and an action on the right, happening in parallel. The first micro-instruction handles the <code>REP</code> prefix, if any; let's assume for now that there's no prefix so it is skipped. Next is the read from memory, which requires the memory address to be in the <code>IND</code> register. Thus, the micro-instruction moves <code>SI</code> to <code>IND</code> and starts the read cycle (<code>R DS,BL</code>). When the read completes, the updated <code>IND</code> register is moved back to <code>SI</code>, updating that register. Meanwhile, <code>X0</code> tests the opcode and jumps to "8" for <code>LODS</code>. The <code>MOVS</code> path falls through, getting the address from the <code>DI</code> register and writing to memory the value that we just read. The updated <code>IND</code> register is moved to <code>DI</code> while another conditional jump goes to "7" if there's no <code>REP</code> prefix. Micro-instruction 7 performs an <code>RNI</code> (Run Next Instruction), which ends the microcode and causes the next machine instruction to be decoded. As you can see, microcode is very low-level.</p> <pre class="microcode"> move action CALL F1 RPTS <span><b>MOVS/LODS:</b> handle REP if active</span> SI &#8594; IND R DS,BL <span><b>1:</b> Read byte/word from SI</span> IND &#8594; SI JMPS X0 8 <span>test instruction bit 3: jump if LODS</span> DI &#8594; IND W DA,BL <span>MOVS path: write to DI</span> IND &#8594; DI JMPS NF1 7 <span><b>4:</b> run next instruction if not REP</span> 危 &#8594; tmpC JMP INT RPTI <span><b>5:</b> handle any interrupt</span> tmpC &#8594; CX JMPS NZ 1 <span>update CX, loop if not zero</span> RNI <span><b>7:</b> run next instruction</span> OPR &#8594; M JMPS F1 5 <span><b>8:</b> LODS path: store AL/AX, jump back if REP</span> RNI <span>run next instruction</span> </pre> <p>Now let's look at the case with a <code>REP</code> prefix, causing the instruction to loop. The first step is to test if the count register <code>CX</code> is zero, and bail out of the loop if so. In more detail, the <code>REP</code> prefix sets an internal flag called <code>F1</code>. The first micro-instruction for <code>MOVS</code> above conditionally calls the <code>RPTS</code> subroutine if <code>F1</code> is set. The <code>RPTS</code> subroutine below is a bit tricky. First, it moves the count in <code>CX</code> to the ALU's temporary C register. It also configures the ALU to pass tmpC through unchanged. The next move discards the ALU result 危, but as a side effect, sets a flag if the value is zero. This micro-instruction also configures the ALU to perform <code>DEC tmpC</code>, but the decrement doesn't happen yet. Next, if the value is nonzero (<code>NZ</code>), the microcode execution jumps to 10 and returns from the microcode subroutine, continuing execution of the <code>MOVS</code> code described above. On the other hand, if <code>CX</code> is zero, execution falls through to <code>RNI</code> (Run Next Instruction), which terminates execution of the <code>MOVS</code> instruction.</p> <pre class="microcode"> CX &#8594; tmpC PASS tmpC <span><b>RPTS:</b> test CX</span> 危 &#8594; no dest DEC tmpC <span>Set up decrement for later</span> JMPS NZ 10 <span>Jump to 10 if CX not zero</span> RNI <span>If 0, run next instruction</span> RTN <span><b>10:</b> return</span> </pre> <p>If execution returns to the <code>MOVS</code> microcode, it will execute as described earlier until the <code>NF1</code> test below. With a <code>REP</code> prefix, the test fails and microcode execution falls through. The next micro-instruction performs <code>危 &#8594; tmpC</code>, which puts the ALU result into tmpC. The ALU was configured back in the <code>RPTS</code> subroutine to decrement tmpC, which holds the count from <code>CX</code>, so the result is that <code>CX</code> is decremented, put into tmpC, and then put back into <code>CX</code> in the next micro-instruction. It seems like a roundabout way to decrement the counter, but that's microcode. Finally, if the value is nonzero (<code>NZ</code>), microcode execution jumps back to 1 (near the top of the <code>MOVS</code> code earlier), repeating the whole process. Otherwise, <code>RNI</code> ends processing of the instruction. Thus, the <code>MOVS</code> instruction repeats until <code>CX</code> is zero. In the next section, I'll explain how <code>JMP INT RPTI</code> handles an interrupt.</p> <pre class="microcode"> IND &#8594; DI JMPS NF1 7 <span><b>4:</b> run next instruction if not REP</span> 危 &#8594; tmpC JMP INT RPTI <span><b>5:</b> handle any interrupt</span> tmpC &#8594; CX JMPS NZ 1 <span>update CX, loop if not zero</span> RNI <span><b>7:</b> run next instruction</span> </pre> <p>The <code>NZ</code> (not zero) condition tests a special 16-bit zero flag, not the standard zero status flag. This allows zero to be tested without messing up the zero status flag.</p> <h3>Interrupts</h3> <p>Interrupts pose a problem for the string operations. The idea behind interrupts is that the computer can be interrupted during processing to handle a high-priority task, such as an I/O device that needs servicing. The processor stops its current task, executes the interrupt handling code, and then returns to the original task. The 8086 processor normally completes the instruction that it is executing before handling the interrupt, so it can continue from a well-defined state. However, a string operation can perform up to 64k moves, which could take a large fraction of a second.<span id="fnref:memory"><a class="ref" href="#fn:memory">5</a></span> If the 8086 waited for the string operation to complete, interrupt handling would be way too slow and could lose network packets or disk data, for instance.</p> <p>The solution is that a string instruction can be interrupted in the middle of the instruction, unlike most instructions. The string instructions are designed to use registers in a way that allows the instruction to be restarted. The idea is that the <code>CX</code> register holds the current count, while the <code>SI</code> and <code>DI</code> registers hold the current memory pointers, and these registers are updated as the instruction progresses. If the instruction is interrupted it can simply continue where it left off. After the interrupt, the 8086 restarts the string operation by backing the program counter up by two bytes (one byte for the <code>REP</code> prefix and one byte for the string opcode.) This causes the interrupted string operation to be re-executed, continuing where it left off.</p> <p>If there is an interrupt, the <code>RPTI</code> microcode routine below is called to update the program counter. Updating the program counter is harder than you'd expect because the 8086 prefetches instructions. The idea is that while the memory bus is idle, instructions are read from memory into a prefetch queue. Then, when an instruction is needed, the processor can (hopefully) get the instruction immediately from the prefetch queue instead of waiting for a memory access. As a result, the program counter in the 8086 points to the memory address of the next instruction to <em>fetch</em>, not the next instruction to <em>execute</em>. To get the "real" program counter value, prefetching is first suspended (<code>SUSP</code>). Then the <code>PC</code> value is corrected (<code>CORR</code>) by subtracting the length of the prefetch queue. At this point, the <code>PC</code> points to the next instruction to execute.</p> <pre class="microcode"> tmpC &#8594; CX SUSP <span><b>RPTI:</b> store CX</span> CORR <span>correct PC</span> PC &#8594; tmpB DEC2 tmpB 危 &#8594; PC FLUSH RNI <span>PC -= 2, end instruction</span> </pre> <p>At last, the microcode gets to the purpose of this subroutine: the <code>PC</code> is decremented by 2 (<code>DEC2</code>) using the ALU. The prefetch queue is flushed and restarted and the <code>RNI</code> micro-operation terminates the microcode and runs the next instruction. Normally this would execute the instruction from the new program counter value (which now points to the string operation). However, since there is an interrupt pending, the interrupt will take place instead, and the interrupt handler will execute. After the interrupt handler finishes, the interrupted string operation will be re-executed, continuing where it left off.</p> <p>There's another complication, of course. An 8086 instruction can have multiple prefixes attached, for example using a segment register prefix to access a different segment. The approach of backing up two bytes will only execute the last prefix, ignoring any others, so if you have two prefixes, the instruction doesn't get restarted correctly. The 8086 documentation describes this unfortunate behavior. Apparently a comprehensive solution (e.g. counting the prefixes or providing a buffer to hold prefixes during an interrupt) was impractical for the 8086. I think this was fixed in the 80286.</p> <!-- p3-31 of the 8086/88/186/188 manual states this problem. http://www.bitsavers.org/components/intel/80186/210911-001_iAPX86_88_186_188_Programmers_Reference_1983.pdf But the 286 manual doesn't mention it. --> <h3>The remaining string instructions</h3> <p>I'll discuss the microcode for the other string operations briefly. The <code>LODS</code> instruction loads from memory into the accumulator. It uses the same microcode routine as <code>MOVS</code>; the code below is the same code discussed earlier. However, the path through the microcode is different for <code>LODS</code> since the <code>JMPS X0 8</code> conditional jump will be taken. (This tests bit 3 of the opcode, which is set for <code>LODS</code>.) At step 8, a value has been read from memory and is in the <code>OPR</code> (Operand) register. This micro-instruction moves the value from <code>OPR</code> to the accumulator (represented by <code>M</code> for complicated reasons<span id="fnref:m"><a class="ref" href="#fn:m">6</a></span>). If there is a repeat prefix, the microcode jumps back to the previous flow (5). Otherwise, <code>RNI</code> runs the next instruction. Thus, <code>LODS</code> shares almost all its microcode with <code>MOVS</code>, making the microcode more compact at the cost of slowing it down slightly due to the conditional jumps.</p> <pre class="microcode"> move action CALL F1 RPTS <span><b>MOVS/LODS:</b> handle REP if active</span> SI &#8594; IND R DS,BL <span><b>1:</b> Read byte/word from SI</span> IND &#8594; SI JMPS X0 8 <span>test instruction bit 3: jump if LODS</span> DI &#8594; IND W DA,BL <span>MOVS path: write to DI</span> IND &#8594; DI JMPS NF1 7 <span><b>4:</b> run next instruction if not REP</span> 危 &#8594; tmpC JMP INT RPTI <span><b>5:</b> handle any interrupt</span> tmpC &#8594; CX JMPS NZ 1 <span>update CX, loop if not zero</span> RNI <span><b>7:</b> run next instruction</span> OPR &#8594; M JMPS F1 5 <span><b>8:</b> LODS path: store AL/AX, jump back if REP</span> RNI <span>run next instruction</span> </pre> <p>The <code>STOS</code> instruction is the opposite of <code>LODS</code>, storing the accumulator value into memory. The microcode (below) is essentially the second half of the <code>MOVS</code> microcode. The memory address in <code>DI</code> is moved to the <code>IND</code> register and the value in the accumulator is moved to the <code>OPR</code> register to set up the write operation. (As with <code>LODS</code>, the <code>M</code> register indicates the accumulator.<span id="fnref2:m"><a class="ref" href="#fn:m">6</a></span>) The <code>CX</code> register is decremented using the ALU.</p> <pre class="microcode"> DI &#8594; IND CALL F1 RPTS <span><b>STOS:</b> if REP prefix, test if done</span> M &#8594; OPR W DA,BL <span><b>1:</b> write the value to memory</span> IND &#8594; DI JMPS NF1 5 <span>Quit if not F1 (repeat)</span> 危 &#8594; tmpC JMP INT RPTI <span>Jump to RPTI if interrupt</span> tmpC &#8594; CX JMPS NZ 1 <span>Loop back if CX not zero</span> RNI <span><b>5:</b> run next instruction</span> </pre> <p>The <code>CMPS</code> instruction compares strings, while the <code>SCAS</code> instruction looks for a zero or non-zero value, depending on the prefix. They share the microcode routine below, with the <code>X0</code> condition testing bit 3 of the instruction to select the path. The difference is that <code>CMPS</code> reads the comparison character from <code>SI</code>, while <code>SCAS</code> compares against the character in the accumulator. The comparison itself is done by subtracting the two values and discarding the result. The <code>F</code> bit in the micro-instruction causes the processor's status flags to be updated with the result of the subtraction, indicating less than, equal, or greater than.</p> <pre class="microcode"> CALL F1 RPTS <span><b>CMPS/SCAS:</b> if RPT, quit if done</span> M &#8594; tmpA JMPS X0 5 <span><b>1:</b>accum to tmpA, jump if SCAS</span> SI &#8594; IND R DS,BL <span>CMPS path, read from SI to tmpA</span> IND &#8594; SI <span>update SI</span> OPR &#8594; tmpA <span>fallthrough</span> DI &#8594; IND R DA,BL <span><b>5:</b> both: read from DI to tmpB</span> OPR &#8594; tmpB SUBT tmpA <span>subtract to compare</span> 危 &#8594; no dest DEC tmpC F <span>update flags, set up DEC</span> IND &#8594; DI JMPS NF1 12 <span>return if not RPT</span> 危 &#8594; CX JMPS F1ZZ 12 <span>update CX, exit if condition</span> 危 &#8594; tmpC JMP INT RPTI <span>if interrupt, jump to RPTI</span> JMPS NZ 1 <span>loop if CX &#8800; 0</span> RNI <span><b>12:</b> run next instruction</span> </pre> <p>One tricky part about the scan and compare instructions is that you can either repeat until the values are equal or until they are unequal, with the <code>REPE</code> or <code>REPNE</code> prefixes respectively. Rather than implementing this two-part condition in microcode, the <code>F1ZZ</code> condition above tests the right condition depending on the prefix.</p> <h2>Hardware support</h2> <p>Although the 8086 uses microcode to implement instructions, it also uses a considerable amount of hardware to simplify the microcode. This hybrid approach was necessary in order to fit the microcode into the small ROM capacity available in 1978.<span id="fnref:microcode"><a class="ref" href="#fn:microcode">7</a></span> This section discusses some of the hardware circuitry in the 8086 that supports the string operations.</p> <h3>Implementing the <code>REP</code> prefixes</h3> <p>Instruction prefixes, including <code>REPNZ</code> and <code>REPZ</code>, are executed in hardware rather than microcode. The first step of instruction decoding, before microcode starts, is the Group Decode ROM. This ROM categorizes instructions into various groups. For instructions that are categorized as prefixes, the signal from the Group Decode ROM delays any interrupts (because you don't want an interrupt between the prefix and the instruction) and starts the next instruction without executing microcode. The Group Decode ROM also outputs a <code>REP</code> signal specifically for these two prefixes. This signal causes the <code>F1</code> latch to be loaded with 1, indicating a <code>REP</code> prefix. (This latch is also used during multiplication to track the sign.) This signal also causes the <code>F1Z</code> latch to be loaded with bit 0 of the instruction, which is 0 for <code>REPNZ</code> and 1 for <code>REPZ</code>. The microcode uses these latches to determine the appropriate behavior of the string instruction.</p> <h3>Updating <code>SI</code> and <code>DI</code>: the Constant ROM</h3> <p>The <code>SI</code> and <code>DI</code> index registers are updated during each step to point to the next element. This update is more complicated than you might expect, though, since the registers are incremented or decremented based on the Direction Flag. Moreover, the step size, 1 or 2, varies for a byte or word operation. Another complication is unaligned word accesses, using an odd memory address to access a word. The 8086's bus can only handle aligned words, so an unaligned word access is split into two byte accesses, incrementing the address after the first access. If the operation is proceeding downward, the address then needs to be decremented by 3 (not 2) at the end to cancel out this increment. The point is that updating the index registers is not trivial but requires an adjustment anywhere between -3 and +2, depending on the circumstances.</p> <p>The Bus Interface Unit performs these updates automatically, without requiring the microcode to implement the addition or subtraction. The arithmetic is not performed by the regular ALU (Arithmetic/Logic Unit) but by the special adder dedicated to addressing arithmetic. The increment or decrement value is supplied by a special ROM called the Constant ROM, located next to the adder. The Constant ROM (shown below) is implemented as a PLA (programmable logic array), a two-level structured arrangement of gates. The first level (bottom) selects the desired constant, while the second level (middle) generates the bits of the constant: three bits plus a sign bit. The constant ROM is also used for correcting the program counter value as described earlier.</p> <p><a href="https://static.righto.com/images/8086-str/constant-die.jpg"><img alt="The Constant ROM, highlighted on the die. The correction constants are used to correct the PC." class="hilite" height="451" src="https://static.righto.com/images/8086-str/constant-die-w400.jpg" title="The Constant ROM, highlighted on the die. The correction constants are used to correct the PC." width="400" /></a><div class="cite">The Constant ROM, highlighted on the die. The correction constants are used to correct the PC.</div></p> <h3>Condition testing</h3> <p>The microcode supports conditional jumps based on 16 conditions. Several of these conditions are designed to support the string operations. To test if a <code>REP</code> prefix is active, microcode uses the <code>F1</code> test, which tests the <code>F1</code> latch. The <code>REPZ</code> and <code>REPNZ</code> prefixes loop while the zero flag is 1 or 0 respectively. This somewhat complicated test is supported in microcode by the <code>F1ZZ</code> condition, which evaluates the zero flag XOR the <code>F1Z</code> latch. Thus, it tests for zero with REPZ (<code>F1Z=0</code>) and nonzero with REPNZ (<code>F1Z=1</code>).</p> <p>Looping happens as long as the <code>CX</code> register is nonzero. This is tested in microcode with the <code>NZ</code> (Not Zero) condition. A bit surprisingly, this test doesn't use the standard zero status flag, but a separate latch that tracks if an ALU result is zero. (I call this the <code>Z16</code> flag since it tests the 16-bit value, unlike the regular zero flag which tests either a byte or word.) The <code>Z16</code> flag is only used by the microcode and is invisible to the programmer. The motivation behind this separate flag is so the string operations can leave the visible zero flag unchanged.<span id="fnref:z16"><a class="ref" href="#fn:z16">8</a></span></p> <p>Another important conditional jump is <code>X0</code>, which tests bit 3 of the instruction. This condition distinguishes between the <code>MOVS</code> and <code>LODS</code> instructions, which differ in bit 3, and similarly for <code>CMPS</code> versus <code>SCAS</code>. The test uses the <code>X</code> register which stores part of the instruction during decoding. Note that the opcodes aren't arbitrarily assigned to instructions like <code>MOVS</code> and <code>LODS</code>. Instead, the opcodes are carefully assigned so the instructions can share microcode but be distinguished by <code>X0</code>. Finally, the string operation microcode also uses the <code>INT</code> condition, which tests if an interrupt is pending.</p> <p>The conditions are evaluated by the condition PLA (Programmable Logic Array, a grid of gates), shown below. The four condition bits from the micro-instruction, along with their complements, are fed into the columns. The PLA has 16 rows, one for each condition. Each row is a NOR gate matching one bit combination (i.e. selecting a condition) and the corresponding signal value to test. Thus, if a particular condition is specified and is satisfied, that row will be 1. The 16 row outputs are combined by the 16-input NOR gate at the left. Thus, if the specified condition is satisfied, this output will be 0, and if the condition is unsatisfied, the output will be 1. This signal controls the jump or call micro-instruction: if the condition is satisfied, the new micro-address is loaded into the microcode address register. If the condition is not satisfied, the microcode proceeds sequentially. I discuss the 8086's conditional circuitry in more detail in <a href="https://www.righto.com/2023/01/reverse-engineering-conditional-jump.html">this post</a>.</p> <p><a href="https://static.righto.com/images/8086-str/condition-pla.jpg"><img alt="The condition PLA evaluates microcode conditionals." class="hilite" height="467" src="https://static.righto.com/images/8086-str/condition-pla-w300.jpg" title="The condition PLA evaluates microcode conditionals." width="300" /></a><div class="cite">The condition PLA evaluates microcode conditionals.</div></p> <h2>Conclusions</h2> <!-- These string instructions live on in the modern x86 architecture, mostly the same except they also support operation on double words or quad words (i.e. 32- or 64-bit operands).[^ins] [^ins]: The 80186 added block instructions to support block I/O: `INS` and `OUTS`. --> <p>Hopefully you have found this close examination of microcode interesting. Microcode is implemented at an even lower level than assembly code, so it can be hard to understand. Moreover, the microcode in the 8086 was carefully optimized to make it compact, so it is even more obscure.</p> <p>One of the big computer architecture debates of the 1980s was "<a href="https://en.wikipedia.org/wiki/Reduced_instruction_set_computer">RISC vs CISC</a>", pitting Reduced Instruction Set Computers against Complex Instruction Set Computers. Looking at the 8086 in detail has given me more appreciation for the issues in a CISC processor such as the 8086. The 8086's string instructions are an example of the complex instructions in the 8086 that reduced the "semantic gap" between assembly code and high-level languages and minimized code size. While these instructions are powerful, their complexity spreads through the chip, requiring additional hardware features described above. These instructions also caused a great deal of complications for interrupt handling, including prefix-handling bugs that weren't fixed until later processors.</p> <p>I've written multiple <a href="https://www.righto.com/search/label/8086">posts on the 8086</a> so far and plan to continue reverse-engineering the 8086 die so follow me on Twitter <a href="https://twitter.com/kenshirriff">@kenshirriff</a> or <a href="http://www.righto.com/feeds/posts/default">RSS</a> for updates. I've also started experimenting with Mastodon recently as <a href="https://oldbytes.space/@kenshirriff">@<span class="__cf_email__" data-cfemail="8ee5ebe0fde6e7fcfce7e8e8cee1e2eaecf7faebfda0fdfeefedeb">[email&#160;protected]</span></a>.</p> <h2>Notes and references</h2> <div class="footnote"> <ol> <li id="fn:history"> <p>Block move instructions didn't originate with the 8086. The IBM System/360 series of mainframes had an extensive set of block instructions providing moves, compare, logical operations (AND, OR, Exclusive OR), character translation, formatting, and decimal arithmetic. These operations supported blocks of up to 256 characters.</p> <p>The Z80 processor (1976) had block instructions to move and compare blocks of data. The Z80 supported ascending and descending movements, but used separate instructions instead of a direction flag like the 8086.&#160;<a class="footnote-backref" href="#fnref:history" title="Jump back to footnote 1 in the text">&#8617;</a></p> </li> <li id="fn:string"> <p>The "string" operations process arbitrary memory bytes or words. Despite the name, these instructions are not specific to zero-terminated strings or any other string format.&#160;<a class="footnote-backref" href="#fnref:string" title="Jump back to footnote 2 in the text">&#8617;</a></p> </li> <li id="fn:bl"> <p>The <code>BL</code> value in the micro-instruction indicates that the <code>IND</code> register should be incremented or decremented by 1 or 2 as appropriate. I'm not sure what <code>BL</code> stands for in the microcode. The patent says "BL symbolically represents a two bit code which causes external logic to examine the byte or word line and the direction flag in PSW register to generate, according to random logic well known to the art, the address factor required." So perhaps "Byte Logic"?&#160;<a class="footnote-backref" href="#fnref:bl" title="Jump back to footnote 3 in the text">&#8617;</a><a class="footnote-backref" href="#fnref2:bl" title="Jump back to footnote 3 in the text">&#8617;</a></p> </li> <li id="fn:morse"> <p>The designer of the 8086 instruction set, Steve Morse, discusses the motivation behind the string operations in his book <a href="https://amzn.to/3K2r92L">The 8086/8088 primer</a>. These instructions were designed to be flexible and support a variety of use cases. The <code>XLAT</code> (Translate) and <code>JCXZ</code> (Jump if <code>CX</code> Zero) instructions were designed to work well with the string instructions.</p> <p>The implementation of string instructions is discussed in detail in the <a href="https://patents.google.com/patent/US4449184A">8086 patent</a>, section 13 onward.&#160;<a class="footnote-backref" href="#fnref:morse" title="Jump back to footnote 4 in the text">&#8617;</a></p> </li> <li id="fn:memory"> <p>A string operation could perform 64k moves, each of which consists of a read and a write, yielding 128k memory operations. I think that if the memory accesses are unaligned, i.e. a word access to an odd address, then each byte of the word needs to be accessed separately. So I think you could get up to 256k memory accesses. Each memory operation takes at least 4 clock cycles, more if the memory is slow and has wait states. So one string instruction could take over a million clock cycles.&#160;<a class="footnote-backref" href="#fnref:memory" title="Jump back to footnote 5 in the text">&#8617;</a></p> </li> <li id="fn:m"> <p>You might wonder why the register <code>M</code> indicates the accumulator, and the explanation is a bit tricky. The microcode uses 5-bit register specifications to indicate the source and destination for a data move. Registers can be specified explicitly, such as <code>AX</code> or <code>BX</code>, or a byte register such as <code>AL</code> or an internal register such as <code>IND</code> or <code>tmpA</code>. However, the microcode can also specify a generic source or destination register with <code>M</code> or <code>N</code>. The motivation is that the 8086 has a lot of operations that use an arbitrary source and destination register, for instance <code>ADD AX, BX</code>. Rather than making the microcode figure out which registers to use for these instructions, the hardware decodes the register fields from the instruction and substitutes the appropriate registers for <code>M</code> and <code>N</code>. This makes the microcode much simpler.</p> <p>But why does the <code>LODS</code> microcode use the <code>M</code> register instead of <code>AX</code> when this instruction only works with the accumulator? The microcode takes advantage of another clever feature of the <code>M</code> and <code>N</code> registers. The hardware looks at the instruction to determine if it is a byte or word instruction, and performs an 8-bit or 16-bit transfer accordingly. If the <code>LODS</code> microcode was hardcoded for the accumulator, the microcode would need separate paths for <code>AX</code> and <code>AL</code>, the full accumulator and the lower byte of the accumulator.</p> <p>The final piece of the puzzle is how the hardware knows to use the accumulator for the string instructions when they don't explicitly specify a register. The first step of instruction decoding is the Group Decode ROM, which categorizes instructions into various groups. One group is "instructions that use the accumulator". The string operations are categorized in this group, which causes the hardware to use the accumulator when the <code>M</code> register is specified. (Other instructions in this group include the immediate ALU operations, I/O operations, and accumulator moves.)</p> <p>I discussed the 8086's register codes in more detail <a href="https://www.righto.com/2023/03/8086-register-codes.html">here</a>.&#160;<a class="footnote-backref" href="#fnref:m" title="Jump back to footnote 6 in the text">&#8617;</a><a class="footnote-backref" href="#fnref2:m" title="Jump back to footnote 6 in the text">&#8617;</a></p> </li> <li id="fn:microcode"> <p>The 8086's microcode ROM was small: 512 words of 21 bits. In comparison, the VAX 11/780 minicomputer (1977) had 5120 words of 96 bits, over 45 times as large.&#160;<a class="footnote-backref" href="#fnref:microcode" title="Jump back to footnote 7 in the text">&#8617;</a></p> </li> <li id="fn:z16"> <p>The internal <code>Z16</code> zero flag is mostly used by the string operations. It is also used by the <code>LOOP</code> iteration-control instructions and the shift instructions that take a shift count.&#160;<a class="footnote-backref" href="#fnref:z16" title="Jump back to footnote 8 in the text">&#8617;</a></p> </li> </ol> </div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/6370120370244800510' onclick=''> 10 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post/6264947694886887540/6370120370244800510' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=6370120370244800510&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6370120370244800510&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6370120370244800510&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6370120370244800510&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6370120370244800510&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6370120370244800510&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/8086' rel='tag'>8086</a>, <a href='http://www.righto.com/search/label/chips' rel='tag'>chips</a>, <a href='http://www.righto.com/search/label/reverse-engineering' rel='tag'>reverse-engineering</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='http://www.righto.com/search?updated-max=2023-10-07T09:04:00-07:00&max-results=7&reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'>Newer Posts</a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='http://www.righto.com/search?updated-max=2023-04-04T09:57:00-07:00&max-results=7' id='Blog1_blog-pager-older-link' title='Older Posts'>Older Posts</a> </span> <a class='home-link' href='http://www.righto.com/'>Home</a> </div> <div class='clear'></div> </div></div> </div> </div> <div class='column-left-outer'> <div class='column-left-inner'> <aside> </aside> </div> </div> <div class='column-right-outer'> <div class='column-right-inner'> <aside> <div class='sidebar section' id='sidebar-right-1'><div class='widget HTML' data-version='1' id='HTML2'> <div class='widget-content'> <style> @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,700'); .form-preview { display: flex; flex-direction: column; justify-content: center; margin-top: 30px; padding: clamp(17px, 5%, 40px) clamp(17px, 7%, 50px); max-width: 350px; min-height: 200px; border-radius: 6px; box-shadow: 0 5px 25px rgba(34, 60, 47, 0.25); } .form-preview, .form-preview *{ box-sizing: border-box; } .form-preview .preview-heading { width: 100%; } .form-preview .preview-heading h5{ margin-top: 0; margin-bottom: 0; } .form-preview .preview-input-field { margin-top: 20px; width: 100%; } .form-preview .preview-input-field input { width: 100%; height: 40px; border-radius: 6px; border: 2px solid #e9e8e8; background-color: #fff; outline: none; } .form-preview .preview-input-field input::placeholder, .form-preview .preview-input-field input { opacity: 0.5; color: #000; font-family: "Montserrat"; font-size: 14px; font-weight: 500; line-height: 20px; text-align: center; } .form-preview .preview-submit-button { margin-top: 10px; width: 100%; } .form-preview .preview-submit-button button { width: 100%; height: 40px; border: 0; border-radius: 6px; line-height: 0px; } .form-preview .preview-submit-button button:hover { cursor: pointer; } </style><form data-v-4c58e686="" action="https://api.follow.it/subscription-form/U3NBTmZKVkI1YVpCa000a0RCZHFiQ3FYMko1cWRTZTN6K3hJdWM2QWxJbE1uVXdXUHZZVzJVQzVLZGh5Y0RCVXB2d2JSTzBobGhuY0FsZnlHbVdFZ2VTN2Q4Vy84RnIxUTgzVlcrbXNIR0Y0aW93d3REM2J6VS9RL0gxWURnV1d8ZWN0YStwUWdWWUFiOTIyWDVGWjdYYVdGZEVNcC9qODZacjlwWXRIcEJQRT0=/8" method="post"><div data-v-4c58e686="" class="form-preview" style="background-color: rgb(255, 255, 255); border-style: solid; border-width: 1px; border-color: rgb(204, 204, 204); position: relative;"><div data-v-4c58e686="" class="preview-heading"><h5 data-v-4c58e686="" style="font-family: Montserrat; font-weight: bold; color: rgb(0, 0, 0); font-size: 12px; text-align: center;">Get new posts by email:</h5></div> <div data-v-4c58e686="" class="preview-input-field"><input data-v-4c58e686="" type="email" name="email" placeholder="Enter your email" spellcheck="false" /></div> <div data-v-4c58e686="" class="preview-submit-button"><button data-v-4c58e686="" type="submit" style="font-family: Montserrat; font-weight: bold; color: rgb(255, 255, 255); font-size: 12px; text-align: center; background-color: rgb(0, 0, 0);">Subscribe</button></div></div></form> </div> <div class='clear'></div> </div><div class='widget HTML' data-version='1' id='HTML3'> <h2 class='title'>About the site</h2> <div class='widget-content'> <a href="https://www.righto.com/p/index.html">Contact info and site index</a> </div> <div class='clear'></div> </div><div class='widget PopularPosts' data-version='1' id='PopularPosts1'> <h2>Popular Posts</h2> <div class='widget-content popular-posts'> <ul> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2025/03/mother-of-all-demos-usb-keyset-interface.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_sUBR6-eoH7AycDSCgF7L5-48Z7gd3VA0gI-ddEoCp1zcIYOR2PzuOOVNqXXlRMK_8NWZ_IGueTV_b-4j1W_kBTDv8rxR7At8wtLEWVXeYSskHK8B0nmfzdeJ9e1d-izdE=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2025/03/mother-of-all-demos-usb-keyset-interface.html'>A USB interface to the "Mother of All Demos" keyset</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2025/03/pentium-microcde-rom-circuitry.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_up97vUr4aqmARjVly6et99lDz8N44I7HqRIa8xpiSk80CH3Y6ADoUYMCksB7_-in_wqmrYzZUlwHV5oUD6PvzIufD3KwpQfMIQYmDNUyzDQzT_KMiexul5yVMggwoMRfrZ-OLKP_8rI95dSIuAlWs=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2025/03/pentium-microcde-rom-circuitry.html'>Notes on the Pentium's microcode circuitry</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2024/05/blog-post.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_udKqJ3dawEpB4rnUfAQJupdi05dtzM2IGK_pvqN81NQ4a-viU-MFyh73YLeaoW8R-b7ORGJPW0aulpmsY07poaVB5uySCYJlYbI0Wx167-o116xdzCvolrZ1dhjdjyqS8XGKSESrEzVYzwIqeqAnHF=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2024/05/blog-post.html'>Inside a vintage aerospace navigation computer of uncertain purpose</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2025/03/pentium-multiplier-adder-reverse-engineered.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_tBNI17JqSkMQ7yAZoXcapS42rn1GvAkBUspgvE0yKgYYObPs3CEiRmPRdIpBM5zBFowqCiuM1QVhyCsAEnHPoRRQiO_u9OjK0-QWgkyCo9Y-3UAZbR899o9ae2JmH4si8fIgJyAdSVgf0v=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2025/03/pentium-multiplier-adder-reverse-engineered.html'>The Pentium contains a complicated circuit to multiply by three</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_sMJPqeEtGjgaUEppCbnH1hqJ-fNyUrxcyp16ffLjT-hBm4iYv7cUDT1XkJFqnOmZ508mcOaKBJL0O1bFrhExY3ELt17jp3VP7Jl75z5yVl-zU=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html'>A Multi-Protocol Infrared Remote Library for the Arduino</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2012/10/a-dozen-usb-chargers-in-lab-apple-is.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_uR1CJEeo3W0VOfKkBPg8qhCm5kOLRvaZSBULMgBfwT7g1zeXLhnPKK9421517mXN5J1pGwSdxkT-Ot1Btp4F6L_iSTmEQuEzy_O4UsLsdxXUKb3p8CRlhx2xK03Q0=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2012/10/a-dozen-usb-chargers-in-lab-apple-is.html'>A dozen USB chargers in the lab: Apple is very good, but not quite the best</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2012/05/apple-iphone-charger-teardown-quality.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_uGL8l345fobDFFiNChKE2ptcligU8ZdF0yEBrSwV_PGEAwVrgHtJDTEQDzmjSN41Nja45QE4KrOMEBRsUxTQ22VAC8hdAEepD-wTDDKHqGrFFGsXVtapRVDEuZ6EyxScMyURkxqc3YzlnAB8KVtnZyCe4=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2012/05/apple-iphone-charger-teardown-quality.html'>Apple iPhone charger teardown: quality in a tiny expensive package</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2014/09/mining-bitcoin-with-pencil-and-paper.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_uW-8_mSIhQy51T1-Fm1a1wVxhqtslmgwZt5KyCVzA6j9sYI1d846F4sz_znqFuMs_qEiL5pd2t51Vmd-A3vIU6q58TWzh2bX_320yQJYlNROgSUgX1-easIrPGgjaSdfbC=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2014/09/mining-bitcoin-with-pencil-and-paper.html'>Mining Bitcoin with pencil and paper: 0.67 hashes per day</a></div> </div> <div style='clear: both;'></div> </li> </ul> <div class='clear'></div> </div> </div><div class='widget BlogSearch' data-version='1' id='BlogSearch1'> <h2 class='title'>Search This Blog</h2> <div class='widget-content'> <div id='BlogSearch1_form'> <form action='http://www.righto.com/search' class='gsc-search-box' target='_top'> <table cellpadding='0' cellspacing='0' class='gsc-search-box'> <tbody> <tr> <td class='gsc-input'> <input autocomplete='off' class='gsc-input' name='q' size='10' title='search' type='text' value=''/> </td> <td class='gsc-search-button'> <input class='gsc-search-button' title='search' type='submit' value='Search'/> </td> </tr> </tbody> </table> </form> </div> </div> <div class='clear'></div> </div><div class='widget Label' data-version='1' id='Label1'> <h2>Labels</h2> <div class='widget-content cloud-label-widget-content'> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/386'>386</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/6502'>6502</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8008'>8008</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/8085'>8085</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/8086'>8086</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8087'>8087</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8088'>8088</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/aerospace'>aerospace</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/alto'>alto</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/analog'>analog</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/Apollo'>Apollo</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/apple'>apple</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/arc'>arc</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/arduino'>arduino</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/arm'>arm</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/beaglebone'>beaglebone</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/bitcoin'>bitcoin</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/c%23'>c#</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/cadc'>cadc</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/calculator'>calculator</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/chips'>chips</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/css'>css</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/datapoint'>datapoint</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/dx7'>dx7</a> </span> <span class='label-size label-size-5'> <a dir='ltr' href='http://www.righto.com/search/label/electronics'>electronics</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/f%23'>f#</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/fairchild'>fairchild</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/fpga'>fpga</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/fractals'>fractals</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/genome'>genome</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/globus'>globus</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/haskell'>haskell</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/HP'>HP</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/html5'>html5</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/ibm'>ibm</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/ibm1401'>ibm1401</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/ibm360'>ibm360</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/intel'>intel</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/ipv6'>ipv6</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/ir'>ir</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/java'>java</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/javascript'>javascript</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/math'>math</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/microcode'>microcode</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/oscilloscope'>oscilloscope</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/Pentium'>Pentium</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/photo'>photo</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/power%20supply'>power supply</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/random'>random</a> </span> <span class='label-size label-size-5'> <a dir='ltr' href='http://www.righto.com/search/label/reverse-engineering'>reverse-engineering</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/sheevaplug'>sheevaplug</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/snark'>snark</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/space'>space</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/spanish'>spanish</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/synth'>synth</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/teardown'>teardown</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/theory'>theory</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/unicode'>unicode</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/Z-80'>Z-80</a> </span> <div class='clear'></div> </div> </div><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <h2>Blog Archive</h2> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2025/'> 2025 </a> <span class='post-count' dir='ltr'>(8)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2025/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2025/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2025/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/'> 2024 </a> <span class='post-count' dir='ltr'>(21)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/'> 2023 </a> <span class='post-count' dir='ltr'>(35)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/12/'> December </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='posts'> <li><a href='http://www.righto.com/2023/04/reverse-engineering-8086-divide-microcode.html'>Reverse-engineering the division microcode in the ...</a></li> <li><a href='http://www.righto.com/2023/04/8086-microcode-string-operations.html'>The microcode and hardware in the 8086 processor t...</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/02/'> February </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/01/'> January </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/'> 2022 </a> <span class='post-count' dir='ltr'>(18)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/04/'> April </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/'> 2021 </a> <span class='post-count' dir='ltr'>(26)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/12/'> December </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/'> 2020 </a> <span class='post-count' dir='ltr'>(33)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/08/'> August </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/05/'> May </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/03/'> March </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/'> 2019 </a> <span class='post-count' dir='ltr'>(18)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/'> 2018 </a> <span class='post-count' dir='ltr'>(17)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/'> 2017 </a> <span class='post-count' dir='ltr'>(21)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/12/'> December </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/'> 2016 </a> <span class='post-count' dir='ltr'>(34)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/10/'> October </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/09/'> September </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/06/'> June </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(12)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/'> 2014 </a> <span class='post-count' dir='ltr'>(13)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/02/'> February </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/'> 2013 </a> <span class='post-count' dir='ltr'>(24)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/'> 2012 </a> <span class='post-count' dir='ltr'>(10)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/11/'> November </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/'> 2011 </a> <span class='post-count' dir='ltr'>(11)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/'> 2010 </a> <span class='post-count' dir='ltr'>(22)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/11/'> November </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/04/'> April </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/'> 2009 </a> <span class='post-count' dir='ltr'>(22)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/11/'> November </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/08/'> August </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/'> 2008 </a> <span class='post-count' dir='ltr'>(27)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/04/'> April </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/03/'> March </a> <span class='post-count' dir='ltr'>(10)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/02/'> February </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> </li> </ul> </div> </div> <div class='clear'></div> </div> </div></div> </aside> </div> </div> </div> <div style='clear: both'></div> <!-- columns --> </div> <!-- main --> </div> </div> <div class='main-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <footer> <div class='footer-outer'> <div class='footer-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left footer-fauxborder-left'> <div class='fauxborder-right footer-fauxborder-right'></div> <div class='region-inner footer-inner'> <div class='foot no-items section' id='footer-1'></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='foot no-items section' id='footer-2-1'></div> </td> <td class='columns-cell'> <div class='foot no-items section' id='footer-2-2'></div> </td> </tr> </tbody> </table> <!-- outside of the include in order to lock Attribution widget --> <div class='foot section' id='footer-3'><div class='widget Attribution' data-version='1' id='Attribution1'> <div class='widget-content' style='text-align: center;'> Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div class='footer-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </footer> <!-- content --> </div> </div> <div class='content-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script type='text/javascript'> window.setTimeout(function() { document.body.className = document.body.className.replace('loading', ''); }, 10); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/2806328968-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY4aa305LIEGXtLz30_P_vL9gvVPTA:1743990292184';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d6264947694886887540','//www.righto.com/2023/04/','6264947694886887540'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '6264947694886887540', 'title': 'Ken Shirriff\x27s blog', 'url': 'http://www.righto.com/2023/04/', 'canonicalUrl': 'http://www.righto.com/2023/04/', 'homepageUrl': 'http://www.righto.com/', 'searchUrl': 'http://www.righto.com/search', 'canonicalHomepageUrl': 'http://www.righto.com/', 'blogspotFaviconUrl': 'http://www.righto.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': true, 'httpsEnabled': false, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'UA-3782444-1', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - Atom\x22 href\x3d\x22http://www.righto.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - RSS\x22 href\x3d\x22http://www.righto.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/6264947694886887540/posts/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/2c423cb85ff27b65', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'archive', 'pageName': 'April 2023', 'pageTitle': 'Ken Shirriff\x27s blog: April 2023'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'custom', 'localizedName': 'Custom', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': true}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Ken Shirriff\x27s blog', 'description': 'Computer history, restoring vintage computers, IC reverse engineering, and whatever', 'url': 'http://www.righto.com/2023/04/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2023, 'month': 4, 'rangeMessage': 'Showing posts from April, 2023'}}}]); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML2', 'sidebar-right-1', document.getElementById('HTML2'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML3', 'sidebar-right-1', document.getElementById('HTML3'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_PopularPostsView', new _WidgetInfo('PopularPosts1', 'sidebar-right-1', document.getElementById('PopularPosts1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogSearchView', new _WidgetInfo('BlogSearch1', 'sidebar-right-1', document.getElementById('BlogSearch1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_LabelView', new _WidgetInfo('Label1', 'sidebar-right-1', document.getElementById('Label1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar-right-1', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull')); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10