Shop OBEX P1 Docs P2 Docs Learn Events
Assembly help — Parallax Forums

Assembly help

KlapKlap Posts: 65
edited 2009-04-03 07:35 in Propeller 1
I have never used assembly before. I have searched through a lot of assembly help threads but have found none that could help me. Is there a very SIMPLE tutorial that goes over assembly? As in it explains every little step in minute detail? Any help would be much appreciated.

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-01 04:33
    Any assembly language is just a convenient way of writing the computer's instructions. Generally, you need to start with understanding the instructions and how they work. The Hydra Manual, chapter 13 is probably the best introduction to the Propeller's instruction set. You have to pay for it, but the manual is worth it for explaining the hardware and both Spin and assembly. You can also start with the Propeller Manual. Neither will provide you with the sort of tutorial you're asking for.

    The sticky thread "Propeller: Getting Started and Key Thread Index" is about all there is in terms of tutorials. If you haven't, try deSilva's tutorial.
  • KlapKlap Posts: 65
    edited 2009-04-01 05:01
    You are probably right. I will have to get the Hydra Manual eventually. Perhaps a few months from now when I can afford the manual I will start trying assembly.
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-01 05:11
    Again, if you haven't, try deSilva's tutorial and potatohead's assembly introduction, both in the thread I mentioned.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-01 08:17
    If I were you, I'd not wait for a book. You have the prop manual and you can use the documents mentioned by Mike. And you'll find a lot of helping hands here in the forum. You find a lot of assembly examples in the obEx and in the forum. Just do some printouts and try to understand what's done. Of course there is bad style and good style programming, but if you post your results here I'm sure there will be a lot of lessons posted for you on how to do it different or better ;O)
  • KyeKye Posts: 2,200
    edited 2009-04-01 14:58
    The best way to learn is to modify an already prewrtitten asm file for your needs, take one of parrallax's drivers and modify it, see what you can do.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Chris_DChris_D Posts: 305
    edited 2009-04-01 22:53
    Hi fellow "want to learn ASM" guy!!!!

    I am in the same boat you are!· I want to do some stuff on the prop that requires more processing than SPIN can handle which takes me into the world of ASM.· I have been programming computers in BASIC since the very early 80's and it is still my preferred language.·

    I am taking my baby steps right now with ASM on the prop and it isn't easy going.· The Prop manual is a reference manual and no where near capable of getting me going with ASM.· The tutorials mentioned by others in this thread are good reading and helpful, but again, for me they fall way short of what I need to get going.· I don't want this to sound like an insult to any of the authors of those tutorials - writing a tutorial akin to "ASM for idiots" would be a substanital undertaking!!!!!

    That's the "doom and gloom" of it.· Now onto the solution....

    As other have suggested, you have to dive in and start somewhere.· Take one of the "simple" blink an LED example programs and work through it.· Reference the various tutorials mentioned and try your hardest to figure out what is going on.· Give it your best shot, and when all else fails, ask questions here.· There are a lot of very helpful people here and far more guys that know ASM than you might expect!·

    Do not expect perfect answers to all your questions. Sometimes people answer with what they believe is correct based on their application of a function or command.·This does not mean they understand every little detail and very well could be missinforming you without any ill intent.

    Luckily, the Prop software allows for good-ole-fashioned "hacking and trying" things if you have a development board or similar.· There are also some other tools that are helpful such as GEAR·which is free and referenced in one of the tutorials.·

    I guess·my point is this..

    Don't expect this to be easy.· There isn't yet a·step-by-step, all inclusive guide to learning ASM on the prop.··If you are like me, you are·attempting to achieve the highest possible performance from·the prop and you are willing to·put in the effort to get there.··I was hoping to figure it out in a few days of hacking and quickly realized it is going to require a·lot more than that!· But the results in the end should be worth it, I will have gained the knowledge of another programming language and have gotten the most performance I can from·the Prop!

    Hang in there!

    Chris
  • KlapKlap Posts: 65
    edited 2009-04-01 23:33
    Alright, I guess I will try a simple LED blink routine then.

    ...

    I am have problems getting it to work right.

    
    {
    ────────────────────────────────────────────────────────────────────────────────────────
    File: 1_FirstProgram.spin
    Programmer: Aaron Klapheck
    Source: TJHJ Parallax Forum Member
    Date: 1-Apr-09                
    
    Blinks an LED repeatedly 5 times
    
    Code that may need to be changed is bracketed by "***" and is located in
    the CON section only. In the PUB init block the speaker code may be deleated
    if a speaker is not being used.
    ────────────────────────────────────────────────────────────────────────────────────────
    
    }
    
    
    CON ' These are constants I include in most code I write because of there universality and usefulness.
    
    'Clock ***May need to change this section depending on crystal being used***
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
                                           
    
    'Timing
    
       clockfreq = ((_CLKMODE - XTAL1) >> 6) * _XINFREQ 
       _1uS  = clockfreq / 1_000_000      'Divisor for  1 uS
       _1mS  = clockfreq /     1_000      'Divisor for  1 mS
       _1S   = clockfreq /         1      'Divisor for  1 S
       
    
    'Serial Terminal
    
      STrxpin  = 31
      STtxpin  = 30
      STmode   = 0
      STbaud   = 9600  '***may need to change***
    
      
    'Speaker ***Can Delete this section if not using piezospeaker*** 
    
      frequency_audible  = 2093    ' 2093Hz. C7 note
      piezospeaker       = 0       '***may need to change***
    
    CON ProgramSpecific  ' These are constants that change depending on the rest of the program. 
    
    'LED pin
    
      PinLED = 10  '***may need to change***
    
    obj
    
       ' General routines
      Debug           : "FullDuplexSerialPlus"
      SqrWave         : "SquareWave"
    
       
    var
    
      long stack[noparse][[/noparse]10]
    
    PUB init ' Initialization Routine
    
      ' Piezospeaker Beeps for 2s then waits for 1/4s.
      '***Start of Piezospeaker code***
      SqrWave.Freq(0, piezospeaker, frequency_audible)
      waitcnt(_1S*2 + cnt)
      dira[noparse][[/noparse]piezospeaker] := outa[noparse][[/noparse]piezospeaker] := frqa := ctra := 0
      waitcnt(_1S/4 + cnt)
      '***End of Piezospeaker code***
    
      ' Activate and clear Serial Terminal
      Debug.start(STrxpin, STtxpin, STmode, STbaud)
      Debug.tx(Debug#CLS)
    
      BlinkLED
       
    pub BlinkLED 
    
      cognew(StartBlinking, @stack)  'Start a new cog w/ the asm program
    
    
    
    DAT 
    
    StartBlinking    xor      Dira, LEDMask ' Set LEDMask as output
                     xor      Outa, LEDMask ' Set LEDMask high
    
    
    BlinkOnOff       waitcnt  Timing, Second 'Wait one second
                     xor      Dira, LEDMask ' Toggle LEDMask
    
                     jmp       BlinkOnOff  'Jump back up to BlinkOnOff 
    
    
    Timing           res      1     ' Reserve on long for variable
    Second           long     _1S   ' not sure what this does
    LEDMask          long     |< PinLED 
    '                      &#61600;&#61600;
    '                      &#9492;&#9531;&#9472; Bitwise Decode: Takes the number following it and formats it
    '                          as a 32-bit long with a single high bit at PinLED location
    
    
    



    I am not sure what I am doing wrong.
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-04-02 04:39
    Klap,

    You're really close... I indicated the differences. ... Also your program will work, but it might be a better practice to use 'or' instead of 'xor' to set the initial 'Dira' and 'Outa' state. use 'or' to set a bit, and use 'andn' to clear a bit.


    DAT 
    
    StartBlinking    xor      Dira, LEDMask ' Set LEDMask as output
                     xor      Outa, LEDMask ' Set LEDMask high
    
                     
    [color=#009900]
                     mov    Timing, cnt    ' move current value of cnt into Timing variable                             '<----Added line by Beau Schwabe
                     add    Timing, Second    ' offset timing variable by a future event of 1 second                   '<----Added line by Beau Schwabe
    [/color]
    
    
    BlinkOnOff       waitcnt  Timing, Second 'Wait one second
                     xor      Dira, LEDMask ' Toggle LEDMask
    
                     jmp       [color=#009900]#[/color]BlinkOnOff  'Jump back up to BlinkOnOff                               '<----Added '#' by Beau Schwabe
    
    
    'Timing           res      1     ' Reserve on long for variable                                                             '<----Remarked line by Beau Schwabe
    Second           long     _1S   ' not sure what this does
    LEDMask          long     |< PinLED 
    '                      &#61600;&#61600;
    '                      &#9492;&#9531;&#9472; Bitwise Decode: Takes the number following it and formats it
    '                          as a 32-bit long with a single high bit at PinLED location
    
    [color=#009900]
    Timing           res      1     ' Reserve on long for variable ... place all 'res' below 'byte', 'word', and 'long' declarations.               '<----Added line by Beau Schwabe
    [/color]
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 4/2/2009 4:47:28 AM GMT
  • KlapKlap Posts: 65
    edited 2009-04-02 07:15
    I just have a few questions.

    (1) why do you have to use a # in front of BlinkOnOff (I think I have seen it not used before).
    (2) why does this work "Second long _1S" I thought that _1S was declared by the other cog (cog not running DAT) so if that is true then wouldn't _1S have to be passed to the cog as a parameter?
    (3) why is or better than xor in this case?
    (4) why would you use andn? Wouldn't xor be doing the same thing? It would seem like using xor would be much more efficient use of code than to use or followed by andn to toggle a pin on and off (it would at least make it run faster by eliminating and extra command).
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-02 07:40
    Klap said...
    (1) why do you have to use a # in front of BlinkOnOff (I think I have seen it not used before).
    (2) why does this work "Second long _1S" I thought that _1S was declared by the other cog (cog not running DAT) so if that is true then wouldn't _1S have to be passed to the cog as a parameter?
    (3) why is or better than xor in this case?
    (4) why would you use andn? Wouldn't xor be doing the same thing? It would seem like using xor would be much more efficient use of code than to use or followed by andn to toggle a pin on and off (it would at least make it run faster by eliminating and extra command).

    1. Because you want to jump to the label BlinkOnOff, not the content of the location named BlinkOnOff. JMP sets the PC to bits 8..0 of the source register. If you use BlinkOnOff without # then PC is set to bits 8..0 of location/register BlinkOnOff which is 7 I believe (source argument for waitcnt).
    2. Pass. AFAICS it's a constant devlared in the CON section. Nothing sinister.
    3. It isn't. If you want to use XOR that's fine but it requires that you have a known state. OR will always set a bit, XOR just toggles what's there already. FWIW, you could use ADD & Co.
    4. See 3. ANDN definitly resets a bit, as does XOR provided that the bit is 1. As for efficiency, to get a single pulse (pin is 0) you can use XOR/XOR or OR/ANDN. There is no penalty.
  • KlapKlap Posts: 65
    edited 2009-04-02 07:58
    Few more questions.

    1. What does content of location name mean? Is BlinkOnOff stored in main ram like a variable? Can other programs access BlinkOnOff like a variable?
    2. Ohh, I got confused there. But can a cog use constants started in other cogs? I thought that if a cog wanted to use a constant that it didn't declare itself then that constant had to be passed to it?
    3. Ohh. I see how if I didn't know the states of the pins ahead of time that OR would be the better option because it always sets the pins high, while ANDN would always set them low.

    I copied this program line for line in my code and it still didn't work. I did the same thing in spin in less than a minute and it worked just fine. I never could have imagined that programing an LED to turn on and off in assembly could be so difficult. Perhaps there is some out there who has written this complicated assembly code before?
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-02 08:21
    Klap said...
    1. What does content of location name mean? Is BlinkOnOff stored in main ram like a variable? Can other programs access BlinkOnOff like a variable?
    2. Ohh, I got confused there. But can a cog use constants started in other cogs? I thought that if a cog wanted to use a constant that it didn't declare itself then that constant had to be passed to it?
    3. Ohh. I see how if I didn't know the states of the pins ahead of time that OR would be the better option because it always sets the pins high, while ANDN would always set them low.

    Initially your program code sits in hub memory, once you start a cog running PASM, 512 longs from a given address are copied into cog RAM (even if your program is shorter).

    1. Imagine the cog memory as either 512 registers or 512 addresses. BlinkOnOff is just an alias for register/address 4. Stored at this location is the waitcnt instruction, i.e. the content (see Beau's example). As this location is in cog memory, no other cog can access it directly.
    2. Constants are not started or anything. They just are. IIRC if the proptool can access them at compile time, everyone has access to them. Then again, SPIN isn't exactly my cup of tea, I only use it to start PASM [noparse]:)[/noparse]

    HTH
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-02 08:29
    Just noticed why the program doesn't work. Inside the loop you toggle the DIRA bit when it should be OUTA.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-02 08:33
    (1) without # the command (whatever command it is) reads the content of BlinkOnOff and uses this as adress to jump to.
    With # jmp really uses BlinkOnOff as jump-adress - which is what you want to do here

    (2) Constants are definitions inside of one spin-file. The compiler will replace these with the values during compile-time. There is no need to pass it as parameter because it will never change. That's why they are called constants. You are on a pretty good track with your programming style. Often you see calculations inside of SPIN-code which in real are never changing. SPIN does not know that and calculates the value every time. Of course this makes the code bigger and slower.

    E.G.: you often read
    waitcnt( clockfreq / 1_000_000 +cnt )
    So, each time clockfreq / 1_000_000 will be calculated by spin.

    Your approach is very sophisticated. Alternatively you could write:
    waitcnt( constant( clockfreq/1_000_000 ) + cnt )

    (3) See the truth - table of xor
    0 xor 0 => 0
    0 xor 1 => 1
    1 xor 0 => 1
    1 xor 1 => 0
    assuming the first operand is a bitmask. In case the bitmask is 0 the result is equal to the second operand. In case it is 1, the result will be the inverse of the second operand. This is also known as a progammable inverter.
    So, the difference is that if you definitely know the previous state of the second operand -> none. But if the state is unknown you might think it's doing something else than it's really doing.
    It's simply better to use OR if you definitely want to set bits and ANDN if you want to clear bits.

    (4) See (3). It would not be faster. XOR has the same runtime as ANDN or OR. It would be 2 longs shorter. (one additional waitcnt).
    If you want to toggle it's OK.


    One more thing about your code (only for understanding):
    In your code you reserved some longs as STACK. Of course it's just a name here, but stack usually is a concept for passing parameters and store values temporary in a First in, First out manner. But to point that out clearly: SPIN interpreter needs a real stack, PASM does not need a stack!
    I would call that a parameter buffer.
  • KlapKlap Posts: 65
    edited 2009-04-02 08:47
    Thank you.

    I see what you mean about the registers now. That makes a whole lot of sense.
    I didn't know that constants were accessible by every cog; that is cool!
    What is PASM?

    I changed DIRA to OUTA. I even changed the first two XOR's with OR's as mentioned above. The program still doesn't work. This is getting ridiculous. I think I will be sticking with spin for the time being. Assembly looks nightmare-ish to debug.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-02 09:00
    To find the paradise you have to go through hell! ;o)

    You should not give up. Post your new code and we'll find the problem and explain. Best way to learn things is the hard way because you'll always remember.

    PASM means propeller assembler.

    Constants are not accessible as such. The constant is encoded into the assembler command during compile-time. A variable is accessed, as you read the content of it during runtime.

    Post Edited (MagIO2) : 4/2/2009 9:08:09 AM GMT
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-02 09:40
    Klap said...
    The program still doesn't work. This is getting ridiculous.
    This minimal program definitely works on my Hydra (LED on pin 5/6). Give it a try and go from there.

    CON
                                           
      PinLED = 6
    
    pub BlinkLED 
      cognew(@StartBlinking, 0)
    
    DAT             org
    
    StartBlinking   xor     dira, LEDMask
    
                    rdlong  delay, #0
                    mov     timing, cnt
                    add     timing, #9  ' this is the minimal delay so the first waitcnt returns immediately
                    
    BlinkOnOff      waitcnt timing, delay
                    xor     outa, LEDMask
    
                    jmp     #BlinkOnOff                               
    
    LEDMask         long      1 << PinLED
    delay           res       1
    timing          res       1
    
    DAT
    
  • KlapKlap Posts: 65
    edited 2009-04-02 20:21
    Hurray! The LED is now blinking on and off.
    (Thank you MagIO2 for the going through hell comment, I feel that right about now).

    Lots more questions:
    (1) I then tired to put this code in my original program and it didn't work. Any spin code I inserted into this program behaved exactly the same as it does when it is executed by itself; why is PASM any different?
    (2) Is 1 << PinLED the same as |< PinLED in this case (I think thy are).
    (3) What is a "#number" does it behave like a regular number?
    (4) What is org? I know it is a compile time address pointer, but why would a person ever need to use one?
    (5) Why does delay need to be a variable? And why does it have to be read from memory? Can't it be set as a constant (its not like it is changing at anytime in the program); so why not set it equal to one second or something?
    (6) Why does there even need to be an LEDMask? Shouldn't you be able to xor dira directly with PinLED ?

    Any help appreciated.
  • KlapKlap Posts: 65
    edited 2009-04-02 20:39
    I read through some of deSilva tutorial which was sort of helpful. But I have a lot more questions now. Perhaps I should just hold off on them until I get the Hydra Manual.
  • jazzedjazzed Posts: 11,803
    edited 2009-04-02 20:51
    Klap said...
    Hurray! The LED is now blinking on and off.
    (Thank you MagIO2 for the going through hell comment, I feel that right about now).

    Lots more questions:
    (1) I then tired to put this code in my original program and it didn't work. Any spin code I inserted into this program behaved exactly the same as it does when it is executed by itself; why is PASM any different?
    (2) Is 1 << PinLED the same as |< PinLED in this case (I think thy are).
    (3) What is a "#number" does it behave like a regular number?
    (4) What is org? I know it is a compile time address pointer, but why would a person ever need to use one?
    (5) Why does delay need to be a variable? And why does it have to be read from memory? Can't it be set as a constant (its not like it is changing at anytime in the program); so why not set it equal to one second or something?
    (6) Why does there even need to be an LEDMask? Shouldn't you be able to xor dira directly with PinLED ?

    Any help appreciated.
    1. no idea what this question means
    2. yes
    3. #number references the address of the memory location (also called register) that keeps "number" value
    4. org tells the assembler "code to execute starts here" and will be 0
    5. delay is a target location for the rdlong instruction
    6. LEDMask allows you to conveniently set a 32 bit value with mov, or, xor, etc ... you can only set up to 9 bits within an instruction without a separate location.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-02 21:30
    (1) ???
    (2) yep
    (4) org sets an compiler internal counter to the value you give behind org or defaults it to 0. The thing is, that microcontrollers work with adresses and not with labels. Each line of code will be placed at a certain place in memory. The compiler counts these lines/adresses. Whenever you jump to a certain label, the compiler will replace this by the adress where the target can be found.
    In propeller the adressing stuff is a little bit more complicated, because you have two adress-spaces. The first adress space it the HUB RAM. Here you have byte adresses. This means each byte of this memory has it's own adress.
    The second adress space is the COG RAM. Here you have long adresses. So not each byte, but each long has it's own adress.
    ORG simply tells the compiler the adress with which the next section starts. For PASM-routines that you want to load into the COG you have to set the adress to 0. If you don't do that, all the jumps, calls and COG RAM memory access will use the wrong adresses.

    (3) let's see
    dat
    org
    mov reg1, #1
    mov reg2, 1
    ...

    reg1 long 0
    reg2 long 0

    The difference is: #1 is directly encoded into the sssssssss bits of the assembly command. (That's why a immediate can only be in range of 0-511) So, the first command stores the number 1 in the memory with adress reg1. (Assuming we have no additional code this would be 2). Command 2 treats the 1 as an adress, reads the content of that memory and stores that value in reg2.

    (5) I don't know the hydra demos, but I'd guess that they work with a little trick. They read from HUB RAM adress 0. If you click on "Object Info" in the PropTool, you see that adress 0 is reserved for some initialisation stuff. So, I think that you find the clkfreq in this adress. That would mean that the demo should blink with 1Hz.
    You can not add the value of clkfreq directly with # because it's bigger than 511.
    Even constants need to be stored somwhere if used in the program. For constants smaller than 512 you can do that directly in the assembler command, for bigger constants you need a full 32 bit long. A constant is only a hint for the compiler. You tell the compiler that this value is never changed.

    (6) Same problem. # works as long as your LED is connected to one of the pins 0-8. To keep the code flexible it's better to have the value in a full 32 bit long. So the LEDpin constant can really be defined freely for every pin. The constant LEDpin itslef is just the pin number to make things easier. Of course you could as well define the constant as

    CON
    PINled = %00000000000000000001000000000000

    then you don't need the |=.

    Post Edited (MagIO2) : 4/2/2009 9:39:17 PM GMT
  • KlapKlap Posts: 65
    edited 2009-04-02 21:47
    Sorry, this is my original program:

    {
    &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;
    File: 1_FirstProgram.spin
    Programmer: Aaron Klapheck
    Source: TJHJ Parallax Forum Member
    Date: 1-Apr-09                
    
    Blinks an LED repeatedly 5 times
    
    Code that may need to be changed is bracketed by "***" and is located in
    the CON section only. In the PUB init block the speaker code may be deleated
    if a speaker is not being used.
    &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;
    
    }
    
    
    CON ' These are constants I include in most code I write because of there universality and usefulness.
    
    'Clock ***May need to change this section depending on crystal being used***
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
                                           
    
    'Timing
    
       clockfreq = ((_CLKMODE - XTAL1) >> 6) * _XINFREQ 
       _1uS  = clockfreq / 1_000_000      'Divisor for  1 uS
       _1mS  = clockfreq /     1_000      'Divisor for  1 mS
       _1S   = clockfreq /         1      'Divisor for  1 S
       
    
    'Serial Terminal
    
      STrxpin  = 31
      STtxpin  = 30
      STmode   = 0
      STbaud   = 9600  '***may need to change***
    
      
    'Speaker ***Can Delete this section if not using piezospeaker*** 
    
      frequency_audible  = 2093    ' 2093Hz. C7 note
      piezospeaker       = 0       '***may need to change***
    
    CON ProgramSpecific  ' These are constants that change depending on the rest of the program. 
    
    'LED pin
    
      PinLED = 10  '***may need to change***
    
    obj
    
       ' General routines
      Debug           : "FullDuplexSerialPlus"
      SqrWave         : "SquareWave"
    
       
    var
    
      long stack[noparse][[/noparse]10]
    
    PUB init ' Initialization Routine
    
      ' Piezospeaker Beeps for 2s then waits for 1/4s.
      '***Start of Piezospeaker code***
      SqrWave.Freq(0, piezospeaker, frequency_audible)
      waitcnt(_1S*2 + cnt)
      dira[noparse][[/noparse]piezospeaker] := outa[noparse][[/noparse]piezospeaker] := frqa := ctra := 0
      waitcnt(_1S/4 + cnt)
      '***End of Piezospeaker code***
    
      ' Activate and clear Serial Terminal
      Debug.start(STrxpin, STtxpin, STmode, STbaud)
      Debug.tx(Debug#CLS)
    
      BlinkLED
       
    pub BlinkLED 
    
      cognew(StartBlinking, @stack)  'Start a new cog w/ the asm program
    
    
    
    DAT 
    
    StartBlinking    xor      Dira, LEDMask ' Set LEDMask as output
                     xor      Outa, LEDMask ' Set LEDMask high
    
    
    BlinkOnOff       waitcnt  Timing, Second 'Wait one second
                     xor      Dira, LEDMask ' Toggle LEDMask
    
                     jmp       BlinkOnOff  'Jump back up to BlinkOnOff 
    
    
    Timing           res      1     ' Reserve on long for variable
    Second           long     _1S   ' not sure what this does
    LEDMask          long     |< PinLED 
    
    
    




    What I meant to say is that if I replace the "DAT" and "pub BlinkLED" sections above with equivalent spin code for blinking the LED on and off it works but If I replace the "DAT" section with above with the DAT section that actually did work:

    
    pub BlinkLED 
      cognew(@StartBlinking, 0)
    
    DAT             org
    
    StartBlinking   xor     dira, LEDMask
    
                    rdlong  delay, #0
                    mov     timing, cnt
                    add     timing, #9  ' this is the minimal delay so the first waitcnt returns immediately
                    
    BlinkOnOff      waitcnt timing, delay
                    xor     outa, LEDMask
    
                    jmp     #BlinkOnOff                               
    
    LEDMask         long      1 << PinLED
    delay           res       1
    timing          res       1
    
    DAT
    
    
    



    to get this:


    
    CON ' These are constants I include in most code I write because of there universality and usefulness.
    
    'Clock ***May need to change this section depending on crystal being used***
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
                                           
    
    'Timing
    
       clockfreq = ((_CLKMODE - XTAL1) >> 6) * _XINFREQ 
       _1uS  = clockfreq / 1_000_000      'Divisor for  1 uS
       _1mS  = clockfreq /     1_000      'Divisor for  1 mS
       _1S   = clockfreq /         1      'Divisor for  1 S
       
    
    'Serial Terminal
    
      STrxpin  = 31
      STtxpin  = 30
      STmode   = 0
      STbaud   = 9600  '***may need to change***
    
      
    'Speaker ***Can Delete this section if not using piezospeaker*** 
    
      frequency_audible  = 2093    ' 2093Hz. C7 note
      piezospeaker       = 0       '***may need to change***
    
    CON ProgramSpecific  ' These are constants that change depending on the rest of the program. 
    
    'LED pin
    
      PinLED = 10  '***may need to change***
    
    obj
    
       ' General routines
      Debug           : "FullDuplexSerialPlus"
      SqrWave         : "SquareWave"
    
       
    var
    
      long stack[noparse][[/noparse]10]
    
    PUB init ' Initialization Routine
    
      ' Piezospeaker Beeps for 2s then waits for 1/4s.
      '***Start of Piezospeaker code***
      SqrWave.Freq(0, piezospeaker, frequency_audible)
      waitcnt(_1S*2 + cnt)
      dira[noparse][[/noparse]piezospeaker] := outa[noparse][[/noparse]piezospeaker] := frqa := ctra := 0
      waitcnt(_1S/4 + cnt)
      '***End of Piezospeaker code***
    
      ' Activate and clear Serial Terminal
      Debug.start(STrxpin, STtxpin, STmode, STbaud)
      Debug.tx(Debug#CLS)
    
      BlinkLED
    
    pub BlinkLED 
      cognew(@StartBlinking, 0)
    
    DAT             org
    
    StartBlinking   xor     dira, LEDMask
    
                    rdlong  delay, #0
                    mov     timing, cnt
                    add     timing, #9  ' this is the minimal delay so the first waitcnt returns immediately
                    
    BlinkOnOff      waitcnt timing, delay
                    xor     outa, LEDMask
    
                    jmp     #BlinkOnOff                               
    
    LEDMask         long      1 << PinLED
    delay           res       1
    timing          res       1
    
    
    



    Then the program still doesn't work. Even though the DAT section by itself works, why doesn't it work with my my original spin code above it?
  • KlapKlap Posts: 65
    edited 2009-04-02 22:25
    I think I am starting to understand this now.

    (3) #1 refers to the actual number 1
    while 1 refers to the value stored at memory location 1.

    (4) org is used to point the program to cog RAM instead of main RAM, because long values can't be stored in main RAM only cog RAM.

    (5) Constants can't be used if they are long sized because they don't load into main RAM.

    (6) The pin number can't be used directly just in case it is lager than 8 and cant' fit into main RAM.

    Please tell me if I am thinking about this the right way.
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-02 23:16
    #4 and #5: Long values can indeed be stored and fetched from main RAM. You have to use addresses that are multiples of 4 and you have to use RDLONG or WRLONG. Even though main RAM is byte oriented, words and longs are accessed as single items with the appropriate instructions.

    #6: The pin # is only used directly (as an immediate operand mask) when it fits in the 9 bit immediate source field of the instruction. This limits immediate access to pins 0-8. It has nothing to do with main RAM. It has to do with the number of bits in the instruction available for an immediate value.
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-02 23:50
    For the record, hub location #0 is clkfreq so the LED actually blinks with 2Hz (1sec on, 1sec off).

    Furthermore, I had trouble getting it to work initially due to the 5Mhz/PLL16 setting until I remembered that the Hydra uses 10MHz/PLL8.

    Anyway, that still doesn't explain why SPIN works and PASM doesn't.

    1. Can you put the BlinkLED method first (so it gets run instead of init), or start BlinkLED earlier in init.
    2. Is there an LED at pin 10?
    3. Is anything in your extra objects using pin 10 in an incompatible way?

    Post Edited (kuroneko) : 4/3/2009 12:37:09 AM GMT
  • jazzedjazzed Posts: 11,803
    edited 2009-04-03 00:43
    Klap said...
    I think I am starting to understand this now.

    (3) #1 refers to the actual number 1
    while 1 refers to the value stored at memory location 1.

    (4) org is used to point the program to cog RAM instead of main RAM, because long values can't be stored in main RAM only cog RAM.

    (5) Constants can't be used if they are long sized because they don't load into main RAM.

    (6) The pin number can't be used directly just in case it is lager than 8 and cant' fit into main RAM.

    Please tell me if I am thinking about this the right way.
    3. Yes.

    4. All code is saved to main hub ram. The cognew(@program, @parameters)·statement for asm says copy and run 520 longs starting at the address of program (@ and # are cousins) and put the address of parameters into the PAR register at startup.

    5. It doesn't matter what size constants are ... the compiler will handle that. You can use·different variable sizes in DAT sections to create initialized variables; normally cog variables are longs though.

    6. A pin number can be any value, but a given bit represents a given pin in DIRA, INA, and OUTA. There are 32 bits in a long and 32 pins. Only 9 pins can be specified with a command like mov outa, #$100; 32 pins can be specified using a long: dat·pinmask long 1 << 31 ...·mov outa, pinmask.

    Generally if you have trouble integrating code, start over and integrate things one at a time. Try removing all the spin code with comments for example except the things you know will work independently such as the serial port and led blinker. Even the most experienced programmer can have non-functional code if they add 100 things and don't keep track of key items. For example, having two serial port drivers running using the same pins all at the same time will cause trouble because of the "wired OR" nature of the output pins.

    BTW assuming xor "dira, #1" will set dira bit 0 is bad practice. "or dira, #1" should be used to guarantee the pin becomes an output for the cog that will set the output ... there are exceptions of course if you know what you're doing.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • potatoheadpotatohead Posts: 10,261
    edited 2009-04-03 02:42
    The easy way to sort out xor vs or.

    or is stateless. It will set the bit to a 1, period. xor has a state, meaning it conditionally sets the bit, depending on the state of the bit.

    Every new state introduced is something you have to manage, and the source of a bug you will have to find!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
    Safety Tip: Life is as good as YOU think it is!
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-03 07:32
    @kuroneko: I see my mistake, but you are wrong as well: 1 sec on and one sec off is 0.5Hz. (Neither 1 nor 2 Hz;o)

    Ok ... let's try a better explanation of this org.
    As I told earlier the code is compiled and then you'll find a PASM command on a certain place in HUB RAM. So, let's play compiler and add the adresses:
    $0000 Initialization
    
    pub Main                        ' this is just a compiler statement. It adds this name to a symbol-table together with the adress of the 
                                    ' following code. (compiler internal table) (Main, $0010)
    $0010 cognew(@demo,0)           ' this is compiled to some bytecode. So, there is no 1:1 relation between number of SPIN commands and the
                                    ' number if longs needed in HUB-RAM this COGNEW for example seems to need 2 longs
    dat org 0
    demo                            ' this is a symbol as well. So the name together with the HUB-RAM adress are stored in a table inside of 
                                    ' the compiler (demo, $0018)
    $0018 mov dira, #1              ' dira is only an alias of a special register in COG-RAM. You could write $1F6 here as well 
                                    ' (see page 23 of Prop Manual)
    $001C rdlong waittime, #0       ' Here is the first place where ORG effects the resulting machine-code. If we don't have ORG 0 the compiler
                                    ' would replace waittime with $034/4. But cognew loads the code into COG-RAM. And there the demo will start
                                    ' at adress $000 ! You see the problem? As the compiler can not guess which PASM-labels are the beginning of
                                    ' code loaded to COG-RAM you have to adjust the adresses with the ORG by yourself. So, the compiler simply
                                    ' subtracts the offset you defined with the ORG statement from the HUB-RAM adress (and divides it by 4) -> $007
    
    $0020 mov time, cnt             ' time -> $008, cnt is a special register with adress $1F1
    $0024 add time, waittime        ' time -> $008, waittime -> $007
    
    loop                            ' again a symbol for the symbol table ( loop, $0028 )
    $0028 xor outa,#1               ' ... I guess the rest is pretty clear now ...
    $002C waitcnt time, waittime
    $0030 jmp #loop 
    
    $0034 waittime long 0
    $0038 time long 0
    
    
    


    Some words about the /4: Remember we have 2 independend adress-spaces, HUB-RAM and COG-RAM. HUB ram has byteadresses, COG ram has long adresses. So byte $0000, $0001, $0002 and $0003 copied from HUB RAM to COG RAM only have one adress as all 4 bytes fit into one long.


    Post Edited (MagIO2) : 4/3/2009 7:49:34 AM GMT
  • kuronekokuroneko Posts: 3,623
    edited 2009-04-03 07:35
    MagIO2 said...
    @kuroneko: I see my mistake, but you are wrong as well: 1 sec on and one sec off is 0.5Hz. (Neither 1 nor 2 Hz;o)
    Shame on me! But I just got up and didn't have any coffee yet.
Sign In or Register to comment.