Shop OBEX P1 Docs P2 Docs Learn Events
Purpose of 0-0 — Parallax Forums

Purpose of 0-0

Hi

Please see the example code (ex07C) at http://www.cp.eng.chula.ac.th/~piak/project/propeller/machinelanguage.pdf under the section 'Enter self modifying code!'.

In there, it covers how to do indexed addressing.

I can see that the MOVS :access, #X stores the address of the 'array' into the ADDS sum, 0-0 instruction.

It looks like the ADD :access, #1 instruction moves the pointer into the array to the next value.

However, although the ADDS sum, 0-0 instruction must be the one to add the next array value to the total, what does the 0-0 mean ?

Thanks

Comments

  • Heater.Heater. Posts: 21,230
    In school we learned that

    0 - 0 = 0

    so

    ADDS sum, 0-0

    means

    ADDS sum, 0

    The use of 0-0 is just a convention. It's purpose is to indicate that the source field of the instruction will be modified by some other code. That is, it's a warning to the reader that this is self modifying code they are looking at.


  • evanhevanh Posts: 15,916
    edited 2016-02-25 10:29
    When I first saw that in a source file I went cross-eyed (pun can be taken). 0-0 didn't register as an equation to me, I was thinking what symbol is that? It looks like a smiley attempt. I had to read one of heater's explanations and it was a real doh! moment. Once you know it's just a filler then it is a smiley! :)
  • Ok thanks.

    I can see that the long at :access (which is where the ADDS lives) is being incremented by the ADD :access, #1
    I know that this is to allow the next long to be read.

    However ...

    sum isn't even declared so how does the assembler know where to store the zero in the initial MOV sum, #0 ?

    Why even add 0 ? The code is meant to be adding up the numbers as it goes round the loop. In the example above this one, the ADDS sum, r is very clearly adding the values in the longs to sum. In this case though, it's only seems to be adding the zero and doesn't seem to be keeping that running total.

    Thanks again.

  • Again, the 0-0 is a temporary legal value that is used by the programmer to indicate to others that the field will be modified in code. I used this in code for accessing arrays in PASM -- like this:
    ' basepntr = address of array/table
    ' idx = index of element to read
    ' value = value that is read
    
    read                    mov     r1, basepntr
                            add     r1, idx
                            movs    :rdval, r1
                            nop
    :rdval                  mov     value, 0-0
    read_ret                ret
    
    
    ' basepntr = address of array/table
    ' idx = index of element to write
    ' value = value to write
    
    write                   mov     r1, basepntr
                            add     r1, idx
                            movd    :wrval, r1
                            nop
    :wrval                  mov     0-0, value
    write_ret               ret
    

  • ErNaErNa Posts: 1,752
    That is funny! I never realized, it is 0 minus 0, I always saw it as 0_0, eyes wide open, so I also learned a lesson here ;-)
  • This convention arose before Chip's assembler included the singleton $ to indicate the current value of the instruction pointer. Had it been in there from the beginning, 0-0 would probably have been $-$ instead.

    -Phil
  • JonnyMacJonnyMac Posts: 9,105
    edited 2016-02-25 18:24
    That is funny! I never realized, it is 0 minus 0, I always saw it as 0_0, eyes wide open, so I also learned a lesson here ;-)
    0_0 works, too, because the Spin/PASM compiler allows the underscore separator in numbers.
  • Cluso99Cluso99 Posts: 18,069
    In JonnyMac's example above...
    read                    mov     r1, basepntr
                            add     r1, idx
                            movs    :rdval, r1
                            nop
    :rdval                  mov     value, 0-0
    read_ret                ret
    
    The effect of the movs instruction is to replace the source operand (the 0-0 operand) with the source in the movs instruction in the instruction declared in the destination (the :rdval operand/instruction) of the movs instruction.

    Once the movs :rdval,r1 is executed the code becomes...
    read                    mov     r1, basepntr
                            add     r1, idx
                            movs    :rdval, r1
                            nop
    :rdval                  mov     value, r1
    read_ret                ret
    
    The nop is required because modifying an instruction requires an instruction in between the modification and executing it (due to the pipelining in the cpu).

    The second example replaces the 0-0 in the destination with r1.

    BTW you will often see an "add dest,h200" instruction when looping. This adds a constant $200 (binary 10_0000_0000) to the instruction pointed to in the destination. This is adding 1 to the destination of the instruction because the first 9 bits are all 0's and are added to the source, and where the 10th bit is a 1 and added to the destination part. h200 will be declared as a long $200.
  • I've always thought it is better to just put 0 along with a comment that the source or destination will be modified by other instructions. The 0-0 is confusing to most people when they first see it, but it does serve the purpose of making people question what the **** is going on.
  • Heater.Heater. Posts: 21,230
    This very thread shows that 0-0 works as intended. The opening poster saw that, stopped in his tracks and had to ask.

    Much better than some long winded and non-standard comments at that point in the code.

    "This zero is not really a zero, it's actually whatever value is written to the source field of this instruction by some other code before this instruction is run."

    Nah.

  • Cluso99 wrote: »
    Once the movs :rdval,r1 is executed the code becomes...
    read                    mov     r1, basepntr
                            add     r1, idx
                            movs    :rdval, r1
                            nop
    :rdval                  mov     value, r1
    read_ret                ret
    

    That's not correct. It becomes:
    read                    mov     r1, basepntr
                            add     r1, idx
                            movs    :rdval, r1
                            nop
    :rdval                  mov     value, basepntr+idx
    read_ret                ret
    
  • Heater. wrote: »
    This very thread shows that 0-0 works as intended. The opening poster saw that, stopped in his tracks and had to ask.

    Much better than some long winded and non-standard comments at that point in the code.

    "This zero is not really a zero, it's actually whatever value is written to the source field of this instruction by some other code before this instruction is run."

    Nah.

    The comment doesn't need to be long winded. It could just say "Source field modified at execution time". However, it is probably more fun to just put 0-0 and mystify the novice instead. After all, why should we bother using comments, or even documenting the code at all. It's much more rewarding to write obfuscated code.

  • JonnyMacJonnyMac Posts: 9,105
    edited 2016-02-26 02:04
    Can't we all just get along?... :)

    Why not do both? Use 0-0, then add a short comment like: Source field modified by code
  • Heater.Heater. Posts: 21,230
    I'm all for comments. There is nothing worse than coming back to a piece of code one has written a while ago I finding one has totally forgotten what it does, why it is there or how it does it. "What damn idiot wrote this gibberish"...."Ah, oops, it was me".

    On the other hand comments can be clutter that just gets in the way and wastes time and mental energy:
    add x,  #11    ' Add 11 to x
    
    Comments need maintenance and often end up being confusing when they done get it properly, thus making them worse than no comment at all.
    add x,  #29    ' Add 11 to x
    
    The level of commenting called for may well depend on the intended audience. For example when I first discovered Javascript I might write:
    (function f () {
    .....
    }())              // Self invoking function 
    
    Because it's a kind of weird JS language feature that I was not used to. Later on I get used to it and such comments become annoying.




  • AribaAriba Posts: 2,690
    Here is the example from the tutorial:
    'ex07C 
    ' we assume X to X+19 contain 20 longs to be added up 
         MOVS :access, #X  ' this instruction modifies a COG cell (*)        
         MOV sum, #0 
         MOV count, #20 
    :loop 
    :access  
         ADDS sum, 0-0     ' the lower 9 bits of this instruction... 
                           ' ... will be modified by (*)  
         ADD :access, #1   ' modify a cell to point to the next number 
         DJNZ count, #:loop 
         ...   
    X:   RES 20
    
    as you can see beside the 0-0 also the comments are there. And there is a text that describes the idea.
    retromicro wrote: »
    Ok thanks.

    I can see that the long at :access (which is where the ADDS lives) is being incremented by the ADD :access, #1
    I know that this is to allow the next long to be read.

    However ...

    sum isn't even declared so how does the assembler know where to store the zero in the initial MOV sum, #0 ?

    This is just a code snippet, that not will compile (assemble) as it is. For sure you need to declare a register sum, start the cog from Spin and so on.
    retromicro wrote: »
    Why even add 0 ? The code is meant to be adding up the numbers as it goes round the loop. In the example above this one, the ADDS sum, r is very clearly adding the values in the longs to sum. In this case though, it's only seems to be adding the zero and doesn't seem to be keeping that running total.

    I does not add 0, it would add the content of register 0, but this register address get replaced by the address of the register X, and later the address gets incremented to X+1, X+2 and so on.

    Andy
  • Cluso99Cluso99 Posts: 18,069
    edited 2016-02-26 04:37
    Seairth wrote: »
    Cluso99 wrote: »
    Once the movs :rdval,r1 is executed the code becomes...
    read                    mov     r1, basepntr
                            add     r1, idx
                            movs    :rdval, r1
                            nop
    :rdval                  mov     value, r1
    read_ret                ret
    

    That's not correct. It becomes:
    read                    mov     r1, basepntr
                            add     r1, idx
                            movs    :rdval, r1
                            nop
    :rdval                  mov     value, basepntr+idx
    read_ret                ret
    
    Yes, of course you are correct.
    I was thinking of movs :rdval,#r1 which I believe to be more common.
    The gotch with the example is that only the lower 9 bits of the contents of r1 will be moved and this may very well not be what is required.

    The result is more correctly
    read                    mov     r1, basepntr
                            add     r1, idx
                            movs    :rdval, r1
                            nop
    :rdval                  mov     value, (basepntr+idx & $1FF)
    read_ret                ret
    
  • ErNaErNa Posts: 1,752
    Now that I realized, 0-0 = 0, I remember that ones I discovered 0 is not 0, but is 8-8. or even 1-0-1. And now we come closer to motor control. ;-)
  • Heater. wrote: »
    The level of commenting called for may well depend on the intended audience. For example when I first discovered Javascript I might write:
    (function f () {
    .....
    }())              // Self invoking function 
    
    Because it's a kind of weird JS language feature that I was not used to. Later on I get used to it and such comments become annoying.
    That's not self-invoking, its a lambda (anonymous function) that gets called immediately. The one thing
    anonymous functions can't do is self-invoke since they don't have a name bound to them to allow a recursive call
    (unless the language provides some sort of "recurse" syntax to allow this)
  • Heater.Heater. Posts: 21,230
    edited 2016-02-26 14:51
    Mark_T,
    That's not self-invoking...
    I'm afraid many would disagree with you, including http://www.w3schools.com/js/js_function_definition.asp and many others.

    Mind you I tend to prefer referring to these things with the more common "Immediately-Invoked Function Expression" or "IIFE" : http://benalman.com/news/2010/11/immediately-invoked-function-expression which seems more accurate to me.
    ...its a lambda (anonymous function) t
    It is not an anonymous function. It has a name "f". See below. We can call it a "lambda" but there is more to the lambda idea than being anonymous.
    The one thing anonymous functions can't do is self-invoke since they don't have a name bound to them to allow a recursive call
    (unless the language provides some sort of "recurse" syntax to allow this)
    Anonymous functions can indeed call themselves:
    (function () {
        console.log("Hello! I am anonymous, and I can call myself anyway !");
        arguments.callee();
    }());
    
    Mind you that is not allowed in ES5 strict mode. My example is not anonymous so it can, either directly or indirectly, like so:
    "use strict";
    (function f(count) {
        if (count === 1) {
            console.log("Hello! I am not anonymous, I call myself f");
            setTimeout(f, 1000);
        } else {
            console.log("See?");
        }
    }(1));              // Self invoking function 
    










  • Hmm...my first reaction to JavaScript 15 years ago was, "Nothing here for me."
    This discussion and the included referrences are conclusive proof that my initial assessment was correct. :)
  • Heater.Heater. Posts: 21,230
    User Name,

    I had the same reaction 15 years ago.

    We were so wrong!

    JS is amazing. It's has features that Java and C++ are only recently catching up with.

    This discussion and the included references only show that people don't understand the language.

    It's OK that people don't understand JS. Nobody understands C++ either. But apparently that's OK.

    In my experience so far JS can match C++ and Java, performance wise, for server tasks.

    End of story really. Why suffer all that compiler Smile when you can, you know, get the job done.



  • Something I read recently described JS as the assembly language of browsers, apparently referring both to its speed and its degree of control. This is intriguing.

    Perhaps the primary reason I passed on it back-in-the-day was because everything I did involved driving I/O lines according to strict timing requirements. JS seemed the furthest thing from what was needed. But I'm at least a tad more eclectic in my programming nowadays. Perhaps there is a place for JS.
  • Heater.Heater. Posts: 21,230
    User Name
    Perhaps the primary reason I passed on it back-in-the-day was because everything I did involved driving I/O lines according to strict timing requirements. JS seemed the furthest thing from what was needed.Perhaps the primary reason I passed on it back-in-the-day was because everything I did involved driving I/O lines according to strict timing requirements. JS seemed the furthest thing from what was needed.
    I totally understand that. I was in much the same boat. As far as I was concerned if a language did not compile down to half decent decent machine code it was not a "real" language. Such things were toys. Far too slow and the run times far too big. Blech. No use for that.

    My eyes started to open a few years back when webgl in the browser was just becoming available. As an experiment the company I worked for let me put up a 3D, real-time, data visualization. Incredible, I found I can do blazing fast 3D scene rendering in the browser with a few lines of simple JS.

    To make that thing work I had to create some server side code to parse a bunch of XML data streams, extract and filter this and that data and send it down to connected browsers. I had something of a shock when I found that JS running under node.js on the server could do all that with a performance almost matching similar server side code we had in C++ !

    webgl and node.js were all very new at the time. So this whole project was a big gamble. I only had 4 weeks to pull it off. Including learning JS, node, and all the libraries from scratch. I don't think it would have happened on time if it was C++ I was learning from scratch.

    A major factor in all this is that modern JS engines are no dumb interpreters they JIT the code achieve impressive performance.

    But what about tweaking those I/O lines and typical MCU stuff? Well, there is JS on very small machines no a days. On a Raspberry Pi you can do some useful bit banging at quite a rate: https://www.npmjs.com/package/pigpio

    But what about tiny MCUs? Well we have JS on those to: http://www.espruino.com/
    Something I read recently described JS as the assembly language of browsers, apparently referring both to its speed and its degree of control. This is intriguing.
    Yep. Take C/C++ code. Compile it into JS with Emscripten: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Emscripten

    A while back msrobots and I did exactly that. We got the open source Spin compiler to run in the browser. It's amazing that this actually works at a usable speed. Sorry I don't have the demo of that on line just now.

    There are a bunch of other languages that "transpile" to JS as well now a days.
    Perhaps there is a place for JS.
    The bottom line here is that times have changed. Performance is cheap, memory is cheap, why not luxuriate an a language that is dead easy to use? Whilst being very well standardized and available on pretty much anything.

    Ease of use trumps raw performance much of the time. That is why we have Spin on the Prop right?

    We still have C/C++ for the really tough stuff.
  • True it happens not to be anonymous, I failed to see the 'f', but 'f' isn't used, and the function does not call itself,
    the expression in which the function declaration occurs calls the function. Trust me I written enough compiler
    back-ends to know how these things work. The callee thing is JS is exactly what I meant by
    unless the language provides some sort of "recurse" syntax to allow this
  • Heater.Heater. Posts: 21,230
    Mark_T,

    I trust you. It's only that the terminology we are using "Self invoking function", "Immediately-Invoked Function Expression", "IIFE" is used and abused, even by the "experts". Like a lot of other terminology.

    The "callee" thing is an error in ES5 strict mode. So far I have failed to find an alternative way to have an anonymous function call itself. It's probably not something one should want to be doing :)

  • Thanks for the info guys. Things are now clear and the code worked first time.
Sign In or Register to comment.