{"id":2325,"date":"2019-07-21T01:57:15","date_gmt":"2019-07-21T01:57:15","guid":{"rendered":"http:\/\/www.sydneysmith.com\/wordpress\/?p=2325"},"modified":"2019-07-21T01:57:15","modified_gmt":"2019-07-21T01:57:15","slug":"hp-25-run-loop","status":"publish","type":"post","link":"https:\/\/www.sydneysmith.com\/wordpress\/2325\/hp-25-run-loop\/","title":{"rendered":"The HP-25 Run Loop"},"content":{"rendered":"<p>When you run a program in a programmable calculator, it goes through a standard process of:<\/p>\n<ul>\n<li>get a program step to run,<\/li>\n<li>update the program counter (PC) to point to the next step, and<\/li>\n<li>run the step we got.<\/li>\n<\/ul>\n<p>It does that over and over again, mostly regardless of what the program step is. (The exception is a [R\/S] program step, which stops the process).<\/p>\n<p>Here&#8217;s what it looks like from the calculator&#8217;s side of the case:<!--more--><br \/>\n<code><\/p>\n<pre>\r\nRunLoop: ; aka $go\r\n01754 if 1 = s 15 then goto 01707        ; if key_pressed\r\n01756 display toggle\r\n\r\n01757 jsb 01472                          ; fetch\r\n; (selects a data reg and sets P based on the PC (step number))\r\n; In : M1=20000000001202 so PC=01\r\n; Out: data=9 P=12\r\n\r\n01760 jsb 01772                          ; $inc\r\n; (adds 1 to PC)\r\n; In : M1=20000000001202 so PC=01\r\n; Out: M1=20000000002202 so PC=02\r\n\r\n*** ram[9] -> c (=e5e5e5e5000000)\r\n01761 data register -> c 0               ; C= e5e5e5e5000000\r\n; (just got program steps 01..07 to C register. Step 01 at LHS)\r\n;\r\n01762 if p # 0 then goto 01575\r\n01575 shift right c[w]                   ; C= 0e5e5e5e500000\r\n01576 p - 1 -> p                         ; P= 11\r\n01577 if n\/c goto 01762\r\n;\r\n01762 ...                                ; C= 00e5e5e5e50000 P=10\r\n01762 ...                                ; C= 000e5e5e5e5000 P= 9\r\n01762 ...                                ; C= 0000e5e5e5e500 P= 8\r\n01762 ...                                ; C= 00000e5e5e5e50 P= 7\r\n01762 ...                                ; C= 000000e5e5e5e5 P= 6\r\n01762 ...                                ; C= 0000000e5e5e5e P= 5\r\n01762 ...                                ; C= 00000000e5e5e5 P= 4\r\n01762 ...                                ; C= 000000000e5e5e P= 3\r\n01762 ...                                ; C= 0000000000e5e5 P= 2\r\n01762 ...                                ; C= 00000000000e5e P= 1\r\n01762 ...                                ; C= 000000000000e5 P= 0\r\n01762 if p # 0 then goto 01575\r\n01764 0 -> c[ms]\r\n01765 display off\r\n; (P was 12 for PC=01. First step now in C[1,0]. pgmcode \"e5\") \r\n\r\nexecut:\r\n01766 0 -> c[xs]\r\n01767 c -> a[x]                          ; A= 200000000000e5\r\n01770 a + 1 -> a[xs]                     ; A= 200000000001e5\r\n01771 a -> rom address\r\n\r\n; (now running a prgcode in the range \"e0\" - \"ef\")\r\n; 1400 tbl1 prgcode.lhs= \"e\"\r\n01436 c + 1 -> c[xs]                     ; C= 000000000001e5\r\n01437 delayed rom 4\r\n01440 if n\/c goto 01460\r\n02060 shift left a[x]                    ; A= 20000000000e50\r\n02061 a exchange c[xs]                   ; A= 20000000000150 C= 00000000000ee5\r\n02062 m2 -> c                            ; C= 00000000000000\r\n02063 p <- 12                            ; P= 12\r\n02064 decimal\r\n02065 0 -> a[s]                          ; A= 00000000000150\r\n02066 0 -> s 9\r\n02067 a -> rom address\r\n\r\n; (now running prgmcode \"e5\")\r\n; 2000 tbl1 prgcode.rhs= \"5\"\r\n02025 if n\/c goto 02342\r\n02342 select rom 3\r\n01743 clear s                            ; S= .1.3.5..........\r\n01744 delayed rom 0\r\n01745 jsb 01705\r\n\r\n$overf: ; check for overflow.\r\n; 1. if mantissa=0, entire word=0 (0.00 EEX 0)\r\n; 2. if xs 5-8, must have underflowed. Set to 0.0\r\n; 3. if xs 1-4, must have overflowed. Set to 9.9999999e99\r\n00305 ...\r\n00273 return\r\n\r\n01746 m2 exch c\r\n01747 if p # 12 then goto 01752          ; =12 if overflow. stops running.\r\n01752 if 0 = s 1 then goto 00247         ; if not running (but we are)\r\n\r\nRunLoop:\r\n01754 ...\r\n<\/pre>\n<p><\/code><\/p>\n<p>What just happened? Here it is again but with a slightly higher level view:<br \/>\n<code><\/p>\n<pre>\r\nRunLoop: ; aka $go\r\n01754 if 1 = s 15 then goto 01707        ; if key_pressed\r\n01756 display toggle\r\n\r\n01757 ... ; fetch - set data reg and P from PC\r\n\r\n01760 ... ; PC++\r\n\r\n01761 ... ; get program steps\r\n\r\n01762 ... ; shift right by P to get step in A[1,0]\r\n\r\n01765 display off\r\n\r\nexecut:\r\n01766 0 -> c[xs]\r\n01767 c -> a[x]                          ; A= 200000000000e5\r\n01770 a + 1 -> a[xs]                     ; A= 200000000001e5\r\n01771 a -> rom address\r\n\r\n(run program step)\r\n\r\n01746 m2 exch c\r\n01747 if p # 12 then goto 01752          ; =12 if overflow. stops running.\r\n01752 if 0 = s 1 then goto 00247         ; if not running (but we are)\r\n\r\nRunLoop:\r\n01754 ...\r\n<\/pre>\n<p><\/code><br \/>\nIt&#8217;s basically: get the current program step, PC++, run the step; and then back again for the next one.<\/p>\n<p>It has to increment the PC (step number) before it runs the current one, so that the current one can be a &#8220;GTO &#8230;&#8221; that changes PC.<\/p>\n<p>Having overflow turn off &#8220;running&#8221; is a nice feature. I don&#8217;t recall seeing that in earlier calculators.<\/p>\n<p>Let&#8217;s have a look at some of the subroutines we skipped over in our first look:<\/p>\n<h2>Fetch<\/h2>\n<p><code><\/p>\n<pre>\r\n; M1[m]= PC, nxt prg step\r\n; out data= prg mem ie 9+int((PC-1)\/7)\r\n;     P   = 12-2*((PC-1)%7) ie shifts right to prgcode\r\nfetch:\r\n01472 m1 -> c                            ; C= 20000000001202\r\n01473 c -> a[w]                          ; A= 20000000001202\r\n01474 0 -> c[w]                          ; C= 00000000000000\r\n01475 p <- 0\r\n01476 load constant 8                    ; C= 00000000000008 P= 13\r\n01477 p <- 3                             ; P= 3\r\n01500 load constant 7                    ; C= 00000000007008 P= 2 \/\/ 7 steps per register\r\n01501 p <- 0                             ; P= 0\r\n01502 decimal\r\n01503 a - 1 -> a[m]                      ; A= 20000000000202 \/\/ PC-1\r\n01504 if n\/c goto 01701\r\n\r\n; subtract 7 from a[m] until it is -ve. c[p]++ each time to ref ram[9..15]\r\n; a[m] is 0..48 for step 01..49\r\n01701 binary\r\n01702 c + 1 -> c[p]                      ; C= 00000000007009 \/\/ ram[9]\r\n01703 if n\/c goto 01545                  ; can't go beyond ram[15] => 7 pgm regs\r\n01545 decimal\r\n01546 a - c -> a[m]                      ; A= 29999999993202 CY \/\/ (PC-1)-7 is -ve\r\n01547 if n\/c goto 01701                  ; if not -ve, add 1 to pgm reg and repeat\r\n;\r\n01550 c -> addr                          ; determined pgm reg. set that. (9 in our case)\r\n01551 a exchange c[w]                    ; A= 00000000007009 C= 29999999993202\r\n01552 c -> a[w]                          ; A= 29999999993202\r\n;\r\n01553 a + 1 -> a[m]                      ; A= 29999999994202 \/\/ add 1 again\r\n01554 if n\/c goto 01654\r\n01654 p + 1 -> p                         ; P= 1\r\n01655 p + 1 -> p                         ; P= 2 \/\/ and add 2 nibbles for ea step\r\n01656 if n\/c goto 01553                  ; repeats until we get a[m] to 0 again\r\n;\r\n01553 ...                                ; A= 29999999995202 P= 3, 4 \/\/ a[m]=-5\r\n01553 ...                                ; A= 29999999996202 P= 5, 6 \/\/     =-4\r\n01553 ...                                ; A= 29999999997202 P= 7, 8 \/\/     =-3\r\n01553 ...                                ; A= 29999999998202 P= 9,10 \/\/     =-2\r\n01553 ...                                ; A= 29999999999202 P=11,12 \/\/     =-1\r\n01553 a + 1 -> a[m]                      ; A= 20000000000202 CY      \/\/     = 0\r\n01554 if n\/c goto 01654\r\n01555 return\r\n<\/pre>\n<p><\/code><br \/>\nThe microcode starts with PC in M1. It converts PC=01..49 to 00..48. It starts with ram[9] (01476 load constant 8; then 01702 c + 1 -> c[p]) and counts up from there whilst deducting 7 steps from (PC-1) each time.<\/p>\n<p>When (PC-1) is negative, it knows it has the correct prg memory. Steps 01..07 are in ram[9], 08..14 in ram[10], &#8230;, and 43..49 in ram[15].<\/p>\n<p>Then, depending on &#8220;how negative&#8221; (PC-1) is, it can work out where the prgcode is in the selected ram[]. It adds 1 to the (PC-1) value and 2 to the &#8220;number of nibbles to shift by&#8221; until it gets (PC-1) back to 0.<\/p>\n<p>The result is this:<\/p>\n<table>\n<tr>\n<td>Step<\/td>\n<td>PC-1<\/td>\n<td>ram[]<\/td>\n<td>P<\/td>\n<\/tr>\n<tr>\n<td>01<\/td>\n<td>00<\/td>\n<td>9+int( 0\/7)= 9<\/td>\n<td>12-2*( 0%7)=12<\/td>\n<\/tr>\n<tr>\n<td>02<\/td>\n<td>01<\/td>\n<td>9+int( 1\/7)= 9<\/td>\n<td>12-2*( 1%7)=10<\/td>\n<\/tr>\n<tr>\n<td>03<\/td>\n<td>02<\/td>\n<td>9+int( 2\/7)= 9<\/td>\n<td>12-2*( 2%7)= 8<\/td>\n<\/tr>\n<tr>\n<td>&#8230;<\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>07<\/td>\n<td>06<\/td>\n<td>9+int( 6\/7)= 9<\/td>\n<td>12-2*( 6%7)= 0<\/td>\n<\/tr>\n<tr>\n<td>08<\/td>\n<td>07<\/td>\n<td>9+int( 7\/7)=10<\/td>\n<td>12-2*( 7%7)=12<\/td>\n<\/tr>\n<tr>\n<td>09<\/td>\n<td>08<\/td>\n<td>9+int( 8\/7)=10<\/td>\n<td>12-2*( 8%7)=10<\/td>\n<\/tr>\n<tr>\n<td>&#8230;<\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>49<\/td>\n<td>48<\/td>\n<td>9+int(48\/7)=15<\/td>\n<td>12-2*(48%7)= 0<\/td>\n<\/tr>\n<table>\n<h2>$inc<\/h2>\n<p><code><\/p>\n<pre>\r\n$inc: ; *** PC++\r\n01772 decimal\r\n01773 m1 -> c                            ; C= 20000000001202\r\n01774 c + 1 -> c[m]                      ; C= 20000000002202\r\n01775 m1 exch c                          ; C= 20000000001202 M1=20000000002202\r\n01776 binary\r\n01777 return\r\n<\/pre>\n<p><\/code><br \/>\n$inc just adds 1 to the mantissa in M1. In theory, it&#8217;ll happily go well beyond step 49 and even beyond step 224 (of a HP-67). However, instruction 01703 in &#8220;fetch&#8221; resets us if we go beyond ram[15]. It shouldn&#8217;t be too hard to add more ram to an emulator and a few extra instructions instead of 01703 to make it work past step 49. It does make one wonder how similar the HP-29 Run Loop is, given that one&#8217;s obvious evolution from the HP-25 and its 98 program steps.<\/p>\n<h2>$overf<\/h2>\n<p>There is little point exploring this subroutine here as we have 0.00 in the display and the processing for that is trivial. It will be worth looking at, after arithmetic operations that overflow or underflow. However, for the record, the 0.00 processing is:<br \/>\n<code><\/p>\n<pre>\r\n$overf: ; check for overflow.\r\n; 1. if mantissa=0, word=0;\r\n00305 m2 -> c\r\n00306 decimal\r\n00307 p <- 0                             ; P= 0\r\n00310 if c[m] = 0 then goto 00272\r\n00272 0 -> c[w]\r\n00273 return\r\n<\/pre>\n<p><\/code><br \/>\nYou can see that P#12 so it doesn&#8217;t stop running due to overflow (instruction 01747).<\/p>\n<p>This is part of the <a href=\"http:\/\/www.sydneysmith.com\/wordpress\/hp25-main\/\">HP-25 topic<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you run a program in a programmable calculator, it goes through a standard process of: get a program step to run, update the program counter (PC) to point to the next step, and run the step we got. It does that over and over again, mostly regardless of what the program step is. (The &hellip; <a href=\"https:\/\/www.sydneysmith.com\/wordpress\/2325\/hp-25-run-loop\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">The HP-25 Run Loop<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16,5,69],"tags":[],"_links":{"self":[{"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/posts\/2325"}],"collection":[{"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/comments?post=2325"}],"version-history":[{"count":6,"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/posts\/2325\/revisions"}],"predecessor-version":[{"id":2331,"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/posts\/2325\/revisions\/2331"}],"wp:attachment":[{"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/media?parent=2325"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/categories?post=2325"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sydneysmith.com\/wordpress\/wp-json\/wp\/v2\/tags?post=2325"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}