{"id":406,"date":"2010-09-28T00:38:29","date_gmt":"2010-09-28T08:38:29","guid":{"rendered":"http:\/\/www.pagetable.com\/?p=406"},"modified":"2010-09-28T00:38:29","modified_gmt":"2010-09-28T08:38:29","slug":"measuring-the-ror-bug-on-the-early-mos-6502","status":"publish","type":"post","link":"https:\/\/www.pagetable.com\/?p=406","title":{"rendered":"Measuring the ROR Bug in the Early MOS 6502"},"content":{"rendered":"<p>The MOS 6502 CPU was introduced in September of 1975, and while the documentation described the three shift\/rotate instructions ASL, LSR and ROL, <a href=\"http:\/\/www.pagetable.com\/?p=45\">the ROR instruction was missing<\/a> &#8211; the documentation said that ROR would be available in chips starting in June 1976. In fact, the reason for this omission was that the instruction, while being present, didn&#8217;t behave correctly. Only few 6502s with the defect are in existence, and nobody seemed to have checked what was actually going on in these chips.<\/p>\n<p>Simon C got <a href=\"http:\/\/www.pagetable.com\/?p=359\">my KIM-1<\/a> working again, which has a 6502 from week 51 of 1975. There are 512 possible inputs to ROR (8 bit A plus 1 bit C; assuming it doesn&#8217;t have dependencies on other registers), and roughly two bytes of output: the 8 bit result and the processor status (flags) register. We ran the following programs on the KIM-1 &#8211; note that we had to split the task into several programs, because the KIM-1 doesn&#8217;t have enough RAM to hold all results.<\/p>\n<p>Program 1a: for A=00..FF, with C=0, execute &#8220;ROR A&#8221;, save result into array<\/p>\n<pre>\n.C:0200   A2 00      LDX #$00\n.C:0202   8A         TXA\n.C:0203   18         CLC\n.C:0204   6A         ROR A\n.C:0205   9D 00 03   STA $0300,X\n.C:0208   E8         INX\n.C:0209   D0 F7      BNE $0202\n.C:020B   00         BRK\n<\/pre>\n<p>Program 1b: for A=00..FF, with C=1, execute &#8220;ROR A&#8221;, save result into array<\/p>\n<pre>\n.C:0200   A2 00      LDX #$00\n.C:0202   8A         TXA\n.C:0203   38         SEC\n.C:0204   6A         ROR A\n.C:0205   9D 00 03   STA $0300,X\n.C:0208   E8         INX\n.C:0209   D0 F7      BNE $0202\n.C:020B   00         BRK\n<\/pre>\n<p>Program 2a: for A=00..FF, with C=0, execute &#8220;ROR A&#8221;, save flags into array<\/p>\n<pre>\n.C:0200   A2 00      LDX #$00\n.C:0202   8A         TXA\n.C:0203   38         SEC\n.C:0204   6A         ROR A\n.C:0205   08         PHP\n.C:0206   68         PLA\n.C:0207   9D 00 03   STA $0300,X\n.C:020a   E8         INX\n.C:020b   D0 F5      BNE $0202\n.C:020d   00         BRK\n<\/pre>\n<p>Program 2b: for A=00..FF, with C=1, execute &#8220;ROR A&#8221;, save flags into array<\/p>\n<pre>\n\n.C:0200   A2 00      LDX #$00\n.C:0202   8A         TXA\n.C:0203   38         SEC\n.C:0204   6A         ROR A\n.C:0205   08         PHP\n.C:0206   68         PLA\n.C:0207   9D 00 03   STA $0300,X\n.C:020a   E8         INX\n.C:020b   D0 F5      BNE $0202\n.C:020d   00         BRK\n<\/pre>\n<p>These are the results:<\/p>\n<p>Program 1a and 1b (result with C=0 and C=1) produced the same output!<\/p>\n<pre>\n00 -> 00\n01 -> 02\n02 -> 04\n03 -> 06\n04 -> 08\n05 -> 0A\n[...]\nFF -> FE\n<\/pre>\n<p>This is a shift left (!!!) of the input value; and it is independent of the carry flag &#8211; just like ASL.<\/p>\n<p>Program 2a (status when C=0) produced the following output:<\/p>\n<pre>\n00:     7E (Z=1, N=0, C=0)\n01..3F: 7C (Z=0, N=0, C=0)\n40..7F: FC (Z=0, N=1, C=0)\n80:     7E (Z=1, N=0, C=0)\n81..BF: 7C (Z=0, N=0, C=0)\nC0..FF: FC (Z=0, N=1, C=0)\n<\/pre>\n<p>Program 2b (status when C=1) produced the following output:<\/p>\n<pre>\n00:     7F (Z=1, N=0, C=1)\n01..3F: 7D (Z=0, N=0, C=1)\n40..7F: FD (Z=0, N=1, C=1)\n80:     7F (Z=1, N=0, C=1)\n81..BF: 7D (Z=0, N=0, C=1)\nC0..FF: FD (Z=0, N=1, C=1)\n<\/pre>\n<p>These are the correct flags corresponding to the incorrect results in A. The carry flag is the same as the input carry flag, i.e. it is unmodified.<\/p>\n<p>Our preliminary summary is this:<\/p>\n<table border=\"1\">\n<tr>\n<td>\n<pre>\n  ROR          Broken ROR on pre-June '76 CPU (Memory or Accumulator)\n                   +-+-+-+-+-+-+-+-+\n  Operation:       |7|6|5|4|3|2|1|0| <- 0\n                   +-+-+-+-+-+-+-+-+                    N Z C I D V\n                                                        \/ \/ _ _ _ _\n<\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<p>So ROR on early 6502s does three things wrong:<\/p>\n<ol>\n<li>It shifts left, instead of right (behaves like ASL)<\/li>\n<li>It shifts a zero in, instead of C (behaves like ASL)<\/li>\n<li>It doesn't update C (as if it wasn't a rotate instruction)<\/li>\n<\/ol>\n<p>All three problems are flags that are sent to the ALU: the shift direction, the input bit, and the carry writeback.<\/p>\n<p>Unresolved questions:<\/p>\n<ul>\n<li>We only tested ROR A; other addressing modes of ROR might behave differently. Other addressing modes might even be working - but I doubt that, since MOS would certainly have documented the working ones then.<\/li>\n<li>ROR might have more dependencies than A and C.<\/li>\n<li>What is it in the chip that causes the bug? I'm sure the fine guys at <a href=\"http:\/\/visual6502.org\/\">visual6502.org<\/a> will be able to figure this one out soon. It is unlikely to be a bug in the <a href=\"http:\/\/www.pagetable.com\/?p=39\">PLA ROM<\/a>, because a bug there would not affect different addressing modes of the same instruction with very different timings. It is more likely that it is in the \"Random Control Logic\" part.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>The MOS 6502 CPU was introduced in September of 1975, and while the documentation described the three shift\/rotate instructions ASL, LSR and ROL, the ROR instruction was missing &#8211; the documentation said that ROR would be available in chips starting in June 1976. In fact, the reason for this omission was that the instruction, while &#8230; <a title=\"Measuring the ROR Bug in the Early MOS 6502\" class=\"read-more\" href=\"https:\/\/www.pagetable.com\/?p=406\" aria-label=\"Read more about Measuring the ROR Bug in the Early MOS 6502\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,5],"tags":[],"class_list":["post-406","post","type-post","status-publish","format-standard","hentry","category-2","category-archeology"],"_links":{"self":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts\/406","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=406"}],"version-history":[{"count":0,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts\/406\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=406"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=406"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=406"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}