{"id":154,"date":"2006-09-15T08:19:22","date_gmt":"2006-09-15T08:19:22","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2006\/09\/15\/more-minimal-masochism-pathological-programming-in-oisc\/"},"modified":"2006-09-15T08:19:22","modified_gmt":"2006-09-15T08:19:22","slug":"more-minimal-masochism-pathological-programming-in-oisc","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2006\/09\/15\/more-minimal-masochism-pathological-programming-in-oisc\/","title":{"rendered":"More Minimal Masochism: Pathological Programming in OISC"},"content":{"rendered":"<p>Expanding on last weeks theme of minimalism, this week, we&#8217;ve got OISC: the One Instruction Set Computer. This is a machine-code level primitive language with exactly one instruction. There are actually a few variants on this, but my favorite is the &#8220;subleq&#8221; OISC, which I&#8217;ll describe beneath the fold.<\/p>\n<p><!--more--><br \/>\nOISC, aka the &#8220;One Instruction Set Computer&#8221; is based on the idea of the *Minsky Machine*. The Minsky machine is an extremely simply Turing complete machine proposed by Marvin Minsky. Back at the original GM\/BM, I wrote an [article on the Minsky machine][minsky] and a simple [Minsky interpreter][minsky-interp]. A Minsky machine is a register machine with two basic instructions: increment, and decrement-and-branch.<br \/>\nOISC does it one better. You don&#8217;t need the increment instruction. Given an unbounded set of registers, you can be Turing complete with only *one* instruction: subtract and branch if less than or equal to zero. (aka <code>SUBLEQ<\/code>.) SUBLEQ takes 3 operands: two registers A and B, and a jump location, C. What SUBLEQ does is subtract the contents of B from the contents of A; and if the resulting value in A is less than or equal to zero, it jumps to C; otherwise, it proceeds to the next instruction. For simplicity of notation, if C is the next instruction, we&#8217;ll just leave it blank. So if instruction N is &#8220;SUBLEQ 2, 4, N+1&#8221;, we&#8217;ll just write it as &#8220;SUBLEQ 2, 4&#8221;<br \/>\nTo make things easy, we&#8217;ll use numbers for the registers, and assume that register 0 contains the value 0 at all times. We can initialize it that way pretty easily; just start off the program with:<br \/>\nSUBLEQ 0, 0<br \/>\nSo how do we do anything real with this bugger? Let&#8217;s build some instructions. We definitely want to be able to do addition, right? So let&#8217;s suppose we want to add registers X and Y.<br \/>\nAdd(X,Y) =  SUBLEQ 0, Y ;; R0 now contains (-Y)<br \/>\nSUBLEQ X, 0 ;; X now contains X-(-Y) = X+Y<br \/>\nSUBLEQ 0, 0 ;; Restore R0=0<br \/>\nStoring a specific value in a register:<br \/>\nStore(X,V) = SUBLEQ X,X ;; clear X so that it contains 0<br \/>\nSUBLEQ 0, V ;; put -V in 0<br \/>\nSUBLEQ X, 0 ;; put -(-V) in X<br \/>\nSUBLEQ 0, 0 ;; restore 0<br \/>\nHow about a non-conditional jump to C? That&#8217;s an easy one.<br \/>\nJump(C) = SUBLEQ 0, 0, C<br \/>\nBranch to T if X=Y, or F otherwise, using<br \/>\nBranchIfEquals(X, Y, T, F) =<br \/>\nStore(1, X) ;; Store copies of X and Y that we can alter<br \/>\nStore(2, Y)<br \/>\nSUBLEQ 1, Y, L1 ;; subtract Y from X. If true, then x &lt;= y.<br \/>\nJump(F) ;; X was not &lt;= y, so branch to false<br \/>\nL1: SUBLEQ 2, X, T ;; subtract X from Y. If true, then Y &lt;= X, and<br \/>\n;; we already know X &lt;= Y, so X = Y<br \/>\nJump(F) ;; Y was not &lt;= X, so X != Y.<br \/>\nSo now, we&#039;ve got a useful conditional branch, addition, subtraction, unconditional branch, and copying values. That&#039;s pretty much the whole story &#8211; you don&#039;t need any more than that to be turing complete.<br \/>\nWant to see a real OISC program? There&#039;s an [OISC Interpreter written in OISC][interp], which is quite cute:<br \/>\n# Written by Clive Gifford, 29\/30 August 2006 based on the Wikipedia<br \/>\n# description of a OISC using the &quot;subleq&quot; instruction.<br \/>\n# 3 Sep 2006: did some &quot;constant folding&quot;, removing a few instructions.<br \/>\n# 8 Sep 2006, a few more changes resulting in smaller memory footprint.<br \/>\nstart:<br \/>\n# [A1] = [PC]<br \/>\nsubleq A1   A1<br \/>\nsubleq PC   ZERO<br \/>\nsubleq ZERO A1<br \/>\nsubleq ZERO ZERO<br \/>\n# Code below (after modification from above) is equivalent to [A] = [[PC]]<br \/>\nsubleq A    A<br \/>\nA1:    data   0<br \/>\ndata   ZERO<br \/>\ndata   A2<br \/>\nA2:    subleq ZERO A<br \/>\nsubleq ZERO ZERO<br \/>\n# [A] = [A] + [LEN]<br \/>\nsubleq NEGL A<br \/>\n# [PC] = [PC] + 1<br \/>\nsubleq NEG1 PC<br \/>\n# [B1] = [PC]<br \/>\nsubleq B1   B1<br \/>\nsubleq PC   ZERO<br \/>\nsubleq ZERO B1<br \/>\nsubleq ZERO ZERO<br \/>\n# Code below (after modification from above) is equivalent to [B] = [[PC] + 1]<br \/>\nsubleq B    B<br \/>\nB1:    data   0<br \/>\ndata   ZERO<br \/>\ndata   B2<br \/>\nB2:    subleq ZERO B<br \/>\nsubleq ZERO ZERO<br \/>\n# [B] = [B] + [LEN]<br \/>\nsubleq NEGL B<br \/>\n# We have to copy [C] now, just in case the emulated subtraction modifies [[PC] + 2].<br \/>\n# [PC] = [PC] + 1<br \/>\nsubleq NEG1  PC<br \/>\n# [C1] = [PC]<br \/>\nsubleq C1    C1<br \/>\nsubleq PC    ZERO<br \/>\nsubleq ZERO  C1<br \/>\nsubleq ZERO  ZERO<br \/>\n# Code below (after modification from above) is equivalent to [C] = [[PC] + 2]<br \/>\nsubleq C    C<br \/>\nC1:    data   0<br \/>\ndata   ZERO<br \/>\ndata   C2<br \/>\nC2:    subleq ZERO C<br \/>\nsubleq ZERO ZERO<br \/>\n# [[B]] = [[B]] &#8211; [[A]];<br \/>\n# if [[B]] &lt;= 0 goto LEQZ<br \/>\n# Earlier code referring to addresses A and B has modified the next<br \/>\n# couple of words to create the equivalent of &quot;subleq [A] [B] LEQZ&quot;<br \/>\n# This is where we&#039;re &quot;emulating&quot; the subtraction&#8230;<br \/>\nA:     data   0<br \/>\nB:     data   0<br \/>\ndata   LEQZ<br \/>\n# [PC] += 1<br \/>\nsubleq NEG1  PC<br \/>\nsubleq ZERO  ZERO START<br \/>\n# We come to address LEQZ when the emulated subleq is going to take<br \/>\n# the branch to the emulated address C.<br \/>\nLEQZ:<br \/>\n# First save the &quot;raw&quot; new PC<br \/>\n# [PC] = [C]<br \/>\nsubleq PC    PC<br \/>\nsubleq C     ZERO<br \/>\nsubleq ZERO  PC<br \/>\nsubleq ZERO  ZERO<br \/>\n# Check if [C] is less than zero. Halt if it is.<br \/>\n# We don&#039;t care about changing [C] as we&#039;ve already copied the value to [PC] above.<br \/>\nsubleq NEG1  C     -1<br \/>\n# [PC] = [PC] + [LEN]<br \/>\nsubleq NEGL  PC<br \/>\n# Go back to the start of the loop ready for the next instruction<br \/>\nsubleq ZERO  ZERO  START<br \/>\nNEGL:  data  -119   # make this == -PROG (my assembler is too primitive!)<br \/>\nNEG1:  data  -1<br \/>\nZERO:  data   0<br \/>\nC:     data   0<br \/>\nPC:    data   PROG<br \/>\n# Code for the program to be interpreted must start at the PROG address&#8230;<br \/>\nPROG:<br \/>\n[interp]: http:\/\/eigenratios.blogspot.com\/2006\/09\/mark-ii-oisc-self-interpreter.html<br \/>\n[minsky]: http:\/\/goodmath.blogspot.com\/2006\/05\/minsky-machine.html<br \/>\n[minsky-interp]: http:\/\/goodmath.blogspot.com\/2006\/05\/minsky-machine-to-play-with.html<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Expanding on last weeks theme of minimalism, this week, we&#8217;ve got OISC: the One Instruction Set Computer. This is a machine-code level primitive language with exactly one instruction. There are actually a few variants on this, but my favorite is the &#8220;subleq&#8221; OISC, which I&#8217;ll describe beneath the fold.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[92],"tags":[],"class_list":["post-154","post","type-post","status-publish","format-standard","hentry","category-pathological-programming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-2u","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/154","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/comments?post=154"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/154\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=154"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=154"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}