Propeller Assembly for beginners

1356729

Comments

  • edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit wrote: »
    Would you please, if I may, seriously consider opting out of this discussion.
    Sorry, I'm not opting out.

    Look, you said: "This is at least 50 times more difficult than writing in SPIN. I have to feel my way through the haze." It's not really that hard, but that is your perception because you have lots of work to do.

    You are on a big learning curve. If you are not willing to dig in and CAREFULLY read the data-sheets, manuals, and tutorials discussed at the start of this thread regarding PASM, you will FAIL.

    As for examples, there are literally hundreds of code examples out there to read. The OBEX and the Propeller Tool libraries offer wonderful examples. All you have to do is have a look.

    Why don't you move the conversation forward by posting your broken code and let us help you learn from your mistakes? Don't spend all afternoon on something without reaching out. Hopefully your learning curve will get smaller with that. Everyone has broken code from time to time. Everyone finds ways around it or just gives up.

    Regarding RES. You can use RES for uninitialized variables, but there are dangers in using it. I've already mentioned one of them below to try and save you from the grief that comes from it.
  • edited July 2011 Posts: 539Vote Up0Vote Down
    @Steve

    It truly amazes me that you have divined that I am planning to write a book on PASM for beginners without reading anything!
    What a fantastic idea. I have read, scanned and searched more pages than you can possibly imagine.
    The documentation provided by sophisticated code writers is so sparse and hard to decipher that I am left scratching my head.
    Lines upon lines are left undocumented. Often comments don't explain anything to me. The posted stuff is not for beginners. No way.
    My SPIN book has well over 120 pages of just SPIN code in it and each and ever line is carefully documented for beginners.
    My PASM book will have over a hundred of pages of PASM code in it and every line will be understood by me and every line will
    be followed by documentation that anyone can understand. There will be no short hand code that is hard to understand by beginners.

    You gave me pages of hard to understand, complicated code on how to share a variable between PASM and SPIN and I
    could not understand any of it. Hardly a way of explaining it to a beginner.
    It was I, who after reading the manuals and data sheets, who wondered if one could not read and write the same register in the two languages.
    Then...
    Kuroneko showed us all how to do it in a few lines and I could understand every line. Even a dynamic demonstration of the code on the Demo board.
    Fantastic. Crystal clear. No high flying confusing code.

    Regards
    Harprit.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit wrote: »
    Kuroneko showed us all how to do it in a few lines and I could understand every line. Even a dynamic demonstration of the code on the Demo board.
    Fantastic. Crystal clear. No high flying confusing code.
    There is little difference between the two examples. If you understand one you can understand the other.

    Why don't you make kuroneko's code your first example of variable sharing. Then move on to a more advanced version. If you want to share more than a few variables, you'll have to store multiple pointers. How you do it is up to you.
    Harprit wrote: »
    You gave me pages of hard to understand, complicated code on how to share a variable between PASM and SPIN and I could not understand any of it. Hardly a way of explaining it to a beginner.
    Considering the volume of study you have claimed to have enjoyed, my example should have been easy.
  • edited July 2011 Posts: 539Vote Up0Vote Down
    As you have suggested, my next post will indeed use K's
    code to read a pot and display the results on some LEDs.

    Harprit
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit wrote: »
    I eliminated the last two lines of your program as I could not understand what they did. I still works but I wondered of I had missed something. Did I do it right?
    No problem. The fit just makes sure that the program fits (who would have thought) into the cog user area (0..495). Not too important for just a few lines but I made it a habit. As for the trailing DAT (another habit), the propeller tool eats empty lines from the end of the file when saving. This really gets up my nose. Nothing essential ...
  • edited July 2011 Posts: 0Vote Up0Vote Down
    I feel that if you try and write a book as you learn a subject you are bound to end up including the typical misconceptions we all have as we learn. In your spin book, the section on PID is totally incorrect (I assume for this reason) and I fear this could also happen for this book. I think you need to be extremely careful when you write this book, assembly is difficult enough for those with a fear of it.

    I think you are a little unfair on the available documentation, I think that DeSilva's tutorial is pretty helpful, there is also Potatoheads which is more digestible, I made my simple set of examples for the stuff I found the hardest at the start too: http://forums.parallax.com/showthread.php?94027-Assembly-step-by-step&p=647408 which has helped a lot of people get started. But I agree there is a space for a nice book on the subject.

    Graham
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit wrote: »
    Can one say that the RES area has to list all variables that will be used in the program and that all constants have to be listed as " value long 2000" which means that these are the equivalent of the VAR and CON areas of a SPIN program?
    Important, res should always come last (every then and now I look for an exception but haven't found anything useful yet).

    As for usage, res covers uninitialised variables whereas long & Co are responsible for constants AND preset variables, e.g.
    ' initialised data and/or presets
                    
    [COLOR="orange"]addr            long    0                       ' preset variable
    mask            long    1                       ' preset variable[/COLOR]
    mono            long    -4                      ' constant
    [COLOR="orange"]dist            long    dist_preset             ' preset variable[/COLOR]
    sign            long    sign_preset             ' constant
    
    frqb_           long    frqb_preset             ' constant
    phsb_           long    frqb_preset * (-2)      ' constant
    
    ' uninitialised data and/or temporaries
    
    [COLOR="blue"]eins            res     1                       ' temporaries
    zwei            res     1                       '
    drei            res     1                       '
    vier            res     1                       '[/COLOR]
    
                    fit
    
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Using res:
    Your program will be writing a value first before it ever reads from it.

    Using res will let your assembler calculate the address it will represent
    but the data will not be included in the program itself, making it shorter.

    Though you will not gain any cog ram, so in theory you could instead use
    labelname long 0-0 , but you would make the code longer and it may also take longer time
    to set up the new cog (I'm not sure if 496 longs is always transferred even if code is shorter?)

    Using res, will force you to both iniate and reset the value for a loop etc, making for less buggy program.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    tonyp12 wrote: »
    ... but you would make the code longer and it may also take longer time
    to set up the new cog (I'm not sure if 496 longs is always transferred even if code is shorter?)
    That would be brilliant but we are stuck with 8K cycles (512 hub windows). Besides, you'd have to indicate the length somehow.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    So it always sends 512 longs, in that case can even the shadow registers be initiated?
    If code it cramped I guess you could skip: mov cnt,#5
    and have it set at start up of cog.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    tonyp12 wrote: »
    So it always sends 512 longs, in that case can even the shadow registers be initiated?
    No such luck. It goes through the motion of reading 512 longs but the SPR area is blanked.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Re: Careful.

    Yes! I think something like SPIN has some variance in what people might need to get it to "click" for them. Truth is, SPIN is pretty easy. Somebody can just jump in and do stuff and have some shot at success. It's pretty easy to poke around, change stuff, and watch what happens. That's what I did on the first day, and it was a total kick!

    I don't think PASM shares that quality, though I personally think it's one of the most fun and easy to code assembly languages I've seen. Clean. Poking around requires some playground that's setup with strong expectations set so people know what to poke around on, and how to "see what it does". Honestly, that's a significant work right there.

    I've had a work in progress for a while now, a follow on to the tutorial mentioned here. Over the few years that's been up, I've received e-mails from people saying, "I got it", or "thanks". Personally, I always thought the thing was too wordy and short on visuals. (I have found it challenging to change both, but I think I'm on a good path at present.)

    That said, just look at the number of words to introduce the very basics, and I mean basics as it's really only a primer meant to kick somebody off into exploring more PASM. Given those things, it's very easy to see that boot-strapping newbies to assembly language requires a lot of context. Assembly language is basic, and very abstract in many ways.

    And there are two kinds of people to write to, well maybe three, you tell me.

    One is the person who has dealt with assembly before somewhat successfully. The other is the person who has no assembly language experience at all.

    These are two very different user experience states to write for, which is exactly why DeSilva and I decided to break it where we did. At the time those were written, I was still coming up to speed on PASM. (Still am today, frankly --and it's a lotta fun) DeSilva had reached a nice level of mastery, and found it difficult to write for the newbie because of that. Made perfect sense for me to introduce the thing, in the hopes they could get far enough to jump into the other material out there. And the three things, including Grahams work are actually pretty good. They are just not well presented.

    I don't know where you plan to go with your effort Harpit, but I would give it some serious thought as to who you are writing for and why. Then consider scope of concepts introduced and then work from there. I'm personally going to start at "has no assembly experience", and carry through solid, basic PASM programs, as I think that's probably the most useful. Really interested people will very likely have enough competency to jump in here and get at the good stuff like the rest of us do. (another book for advanced is totally needed, and something I hope to get at for Prop II, or see somebody get done for Prop II)

    IMHO, the big problem people have with assembly language is the fundamental nature of it. Higher level language constructs can do lots of things for people, and one of the bigger ones is simply managing representations of things, the other being program flow and storage management. From there, one can easily have whole tasks abstracted to a simple command, and that is what makes the higher level languages work for people like they do.

    In assembly land, it's all up to the programmer, and when one does not understand the very basics of how computers really do things, assembly language appears as this arcane wizardry, obtuse, cryptic. That's the challenge to be met, IMHO. Context is everything, and it's not just a matter of documenting favorable commands and workflows, like it can be for a cookbook, or higher level language introduction.

    There is a third consideration too, and that is kinds of assembly language. For me, the PASM experience was favorable. It seemed to click easily enough, and it's beautiful really. I think some of that had to do with the kinds of assembly language experiences I had accumulated. There are some CPU instruction sets that are similar in concept to PASM, and there are a lot that are very different. For the "has assembly language" experience set of beginners to PASM, some relating of those concepts and establishing of common context is important, or differences in language, like "register" can really make a mess of things, doing more harm than good. I personally think this is challenging to do.

    Harpit, I'm not putting this out here to compete, or discourage. My project got slowed by "that damn day job", but it is progressing, and it will get done.

    I feel a fair amount of passion for PASM and the Propeller in general, and that's because the chip is cool, as are the people involved with it. Frankly, the whole scene has just been a lot of fun, and that counts for a lot.

    Given that, it made perfect sense to put some lessons learned out there, with a gentle push to encourage you to take the time to, "do it right", or please don't do it, as it will do more harm than good. Really. I mean that, and I mean it in the very nicest of ways.
    Do not taunt Happy Fun Ball! @opengeekorg ---> Be Excellent To One Another

    Parallax colors simplified: http://forums.parallax.com/showthread.php?123709-Commented-Graphics_Demo.spin
    PropGCC Mac OS 10.6.8 + https://www.dropbox.com/s/539urmnpemdhxra/parallax.zip?dl=0



  • edited July 2011 Posts: 0Vote Up0Vote Down
    Later today I will post my efforts to write a word in PASM and read it in SPIN.

    I wrote an article on this -- you might find it helpful as I tend to write very straightforward code.
    -- http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/prop/col/nvp10.pdf

    Note that the code listings in the PDF have the inline comments removed because this is material that goes to the magazine which prints in a two-column format; download the code for my inline comments if the article text is not enough.
    <br>
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Hi Harprit,

    I second on what potatohead wrote.

    you are taking the effort to learn PASM and writing a book for beginners. This is a big chance as you will encounter a lot of - of the same problems a beginner encounters.
    The more somebody becomes an experts the more he/she is in danger to become blind for beginner-difficulties. Until he/she focuses again on these problems through practical teaching.

    I would like to see before a book goes to printing that it is reviewed by beginners and by experts. By beginners to give it a last improvement about things the find still hard to understand.
    By experts to catch bugs that beginners or advanced users (that you will be at this stage) do not see. After that it will be a book which is worth to make its way into the hall of fame,
    because it is really easy to understand and has no bugs.


    About debuggers: let's say - for a moment - the PASM-beginner is able to use the debugger. In this situation it will be a great help just singlestep through the code watching what is happening to any byte in the RAM and how the program flows
    This is a great helpindeed.
    Without a debugger the other possabilities of debugging is to switch on/off LEDs. Inserting code for printing some debug-output is way above the head of a beginner.

    Know back to a real beginner that does not know how to use the debugger:
    If you got a lot to learn about the debugger and have to do this learning through try and error because the manual about the debugger is just "three lines long"
    I agree. It depends on how good and detailed the debugger manual is. Does the debugger-manual take the user by the hand and shows step by step screen-shot for screen-shot
    how to use it and gives information about possible reasons why something might not work (forgot to insert debug-kernel or what ever) and how to solve it it will be easy to use
    and the user will enjoy the extra-journey.

    BMA is an advanced debugger with advanced possabilities and I want to emphasise: on beginners not that easy to use for beginners. IMHO PASD is easier for beginners.
    The PASD-manual can be still improved. Now the question is who will do the work of the improvement?
    I'm in temptation do do it. I enjoy this kind of work.very much. Writing such a manual takes much more time than writing some postings.
    But I pull myself back as I know that other work that has a higher priority would suffer from that.

    Maybe something inbetween. Harprit give PASD a short try and as soon as you encounter a problem using it - don't tinker around even if yiu would like to
    tell me the problem and I will help. Maybe Ariba the author of PASD likes to help too.

    keep the questions coming
    best regards

    Stefan
    [x] <== SLAM in nail here to hook up the new screen! :lol:
  • TorTor
    edited July 2011 Posts: 0Vote Up0Vote Down
    About debuggers: I've programmed in assembler since the 6502 came along (AIM-65 in school, Apple II), 8080,Z80 (CP/M), and minicomputers (ND, VAX). I'm in camp with those who believe debuggers _are_ useful to complete beginner assembly coders. I remember when I learned my way around 8080 and Z80 assembly: I used the debugger to poke around and look at code, I wrote some code and stepped through it to see what it did. You learn very fast from that, the understanding comes much quicker than if you just code and try to run programs. Same thing when I was learning three different types of minicomputer assembly: Step through with debugger, see what every instruction does when it's doing it. And later, with 8088 and MS-DOS it was back to the debugger again.

    After a very long hiatus I'm back to re-learn CP/M and 8080 assembly, and, this time as in the past, the way in is to start the debugger (SID in this case) and fiddle with code and single-stepping.

    A couple of years back I began to write emulators for two different old minicomputer CPUs, and one of the very first things I did in both projects was to write a debugger that would let me single-step through actual code. I feel that you need to _see_ the code (and there is a one-to-one connection between assembly and code, unlike with Spin or any high level language) to get a feel for it.

    Steve: Thanks to the link for that BMADebugger, I wasn't aware of it.

    -Tor
  • edited July 2011 Posts: 539Vote Up0Vote Down
    @Graham:
    You have said this to me before and I accept your criticism.
    My explanation of PID is intended for real beginners who will never understand the digital implementation of Kallman or any other filters.
    If you read any of my books, you will see not a single equation. They are for beginners and beginners only. No complaints from beginners.
    Yes there are mistakes in my books and I maintain errata on the internet. No one else seem to for their books. I handle customer support personally.

    @Kuroneko:
    As always thank you for you great help and comments.

    @ PotatoHead:
    I have read you notes for beginners. My stuff will be may times simpler than that.
    I do not know enough the write the kind of stuff experience programmers can write
    I will give it my best shot and will decide if I want to publish or not when I am done.
    Its going to be a while
    Thanks for your comments.

    @JonnyMac:
    Your article was helpful. Thanks

    @Stephan:
    I downloaded the debugger and am trying to get an understanding of how it works.

    Harprit
  • edited July 2011 Posts: 539Vote Up0Vote Down
    Question:

    What is the short hand for changing one and a series of bits in DIRA and OUTA in PASM

    Harprit
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit wrote: »
    Question:

    What is the short hand for changing one and a series of bits in DIRA and OUTA in PASM

    Harprit

    Read about MUXC, MUXNC, MUXZ, MUXNZ, OR, ANDN, XOR etc... in the manual.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit wrote: »
    Question:

    What is the short hand for changing one and a series of bits in DIRA and OUTA in PASM

    Harprit

    If you literally mean to change, as in to change 1s to 0s and vice versa, you would use XOR along with a mask value where a 1 bit in the mask would designate a bit that you wanted changed. If you're dealing with bits 8:0 only the mask could be a literal.

    You may take offense at this, but my initial reaction when I started reading this thread was that it didn't seem like a particularly good idea to write a book about something that you're just learning about. I wouldn't want a brand new driver to write a book on driving. When I purchase a book, I tend to assume that the author knows his subject inside and out. I've been programming in PASM for about a year, and there are areas, major areas, that I haven't even touched. I visit these threads because I tend to learn new things whenever I do. And PASM is not my 1st assembly language by any means.

    If you've never programmed in assembler before, it's hard for me to believe that you wil learn enough in a reasonable amount of time to do justice to your readers. Just my 10 cents worth.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    MUX was hard to understand for me first, as I never seen this in other asms.
    And it sounded to close to Multiplication.

    What is does, it assume that you did a Test or Shift etc prior
    and therefore there is an answer in Z or C now.

    It will take this answer (can only be 0 or 1) and set the bits to this same stage of 0 or 1.
    The Mask (source field) is so you can tell what bits you want this to apply to.

    The Mask can be the pin# you want to set in Outa.

    MUXN, it will use a bit reversed answer of Z or C
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Hi Harprit,

    the mux.-commands (muxz, muxnz muxc muxnc) are the short way if the number of bits that should be changed can vary.
    example with just 8 bits
    
    
    Bit-Nr.   76543210
    Bitstate  10000001
    Bit-mask  00011000
    
    after mux-command
    Bitstate  10011001
    
    now after some loops the mask might be
    
    Bit-mask  00100111
    
    then
    Bit-Nr.   76543210
    Bitstate  00000001
    Bit-mask  00100111
    
    after mux-command
    Bitstate  00100111
    
    Of course you could use operators like and andn or etc. but they would require more commands
    copying actual state of f.e. outa to a temporal-used-long
    manipulating the temporal-used-long with a command like "AND" with zeros to clear bits,
    the command "OR" to set bits

    another "OR"-command with the temporal-used-longand outa to set the bits in outa

    With mux-commands you use one command to set or clear the Z-flag and then do the mux-command
                  mov       _dummylong,#0 wz 'execute a command that sets the z-flag   ((loading a zero will SET the z-flag if the wz-effect is specified)
                  muxz      DirA,BitMask         'set IO-Pins as Output   all bits that are set to "1" in BitMask will be set to one in DIRA
    
                  mov       _dummylong,#1 wz 'execute a command that clears the z-flag (loading a value that is non-zero will clear the z-flag if the wz-effect is specified)
                  muxz      DirA,BitMask         'set IO-Pins as Input   all bits that are set to "1" in BitMask will be set to zero in DIRA
    
    The PASD-Debug-Demo-code uses the ANDN + OR-command to set or clear bits.
    ''***************
    ''* PASD Test   *
    ''***************
    ''
    CON  'Use the following 2 lines if running on a Parallax PropDemo board        
            _clkmode        = xtal1 + pll16x
            _xinfreq        = 5_000_000
    
            'Use the following 2 lines if running on a Hydra board
            '_clkmode        = xtal1 + pll8x
            '_xinfreq        = 10_000_000
    
    VAR
      long  Cog, TestVar
    
    OBJ
      dbg   :       "PASDebug"                '<---- Add for Debugger 
    
    PUB main
    
      Cog := cognew(@entry, @TestVar) + 1
    
      dbg.start(31,30,@entry)                 '<---- Add for Debugger
    
    PUB stop
    
      if Cog
        cogstop(Cog~ -  1)
    
    DAT
                            org     0
    entry
    '  --------- Debugger Kernel add this at Entry (Addr 0) ---------
       long $34FC1202,$6CE81201,$83C120B,$8BC0E0A,$E87C0E03,$8BC0E0A
       long $EC7C0E05,$A0BC1207,$5C7C0003,$5C7C0003,$7FFC,$7FF8
    '  -------------------------------------------------------------- 
    '
    ' Test code with modify, MainRAM access, jumps, subroutine and waitcnt.
    '
    :init                   mov     dira,LEDS               ' Configure LEDs as outputs (1)
                            andn    outa,LEDS               ' Set LEDs to the 'Off' state (0)
                            mov     BlinkCounter,#0         ' Clear blink counter    
    
    :led_state_1            or      outa,LED_0              ' Turn on  LED 0  (Hydra)
                            or      outa,LED_16             ' Turn on  LED 16 (PropDemo)
                            andn    outa,LED_17             ' Turn off LED 17 (PropDemo)  
    
                            call    #wait                   ' Delay
    
    :led_state_2            andn    outa,LED_0              ' Turn off LED 0  (Hydra)
                            andn    outa,LED_16             ' Turn off LED 16 (PropDemo)
                            or      outa,LED_17             ' Turn on  LED 17 (PropDemo)
                                                    
                            call    #wait
    
                            add     BlinkCounter,#1
                            cmp     BlinkCounter,#5    wz
                  if_z      jmp     #:init
                  
                            jmp     #:led_state_1
    
    wait                    mov     WaitCounter,cnt
                            add     WaitCounter,BlinkFreq
                            waitcnt WaitCounter,BlinkFreq
    wait_ret                ret
    
    '                        
    ' VARIABLES
    '
    BlinkCounter            long    0
    LEDS                    long    $00FF_0001   ' Bits 16-23 are PropDemo board leds.  Bit 0 is Hydra LED.
    LED_0                   long    $0000_0001   ' Hydra LED.
    LED_16                  long    $0001_0000   ' PropDemo board LED.
    LED_17                  long    $0002_0000   ' PropDemo board LED.   
    BlinkFreq               long    40_000_000
    WaitCounter             res     1
    
                            fit
    
    step through this code and then modify it with mov/mux-commands to see what the commands are doing

    I also attach a file describing how to use PASD as an addition to the PASD-manual
    This manual-add-on is a short test if you find it understandable this way

    keep the questions coming
    best regards

    Stefan

    oops forgotto attach the PDF-file ! corrected now.
    [x] <== SLAM in nail here to hook up the new screen! :lol:
  • K2K2
    edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit,

    Kinda following up on what Tor said, if you want to avoid the learning curve of a debugger right now, there is still value in studying the hex code from the PropTool (produced by pressing F8). daSilva recommended this, and used values that would be easy to find. I've answered many questions this way.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    StefanL38 wrote: »
    With mux-commands you use one command to set or clear the Z-flag and then do the mux-command
    mov       _dummylong,#0 wz 'execute a command that sets the z-flag   ((loading a zero will SET the z-flag if the wz-effect is specified)
    muxz      DirA,BitMask     'set IO-Pins as Output   all bits that are set to "1" in BitMask will be set to one in DIRA
    
    mov       _dummylong,#1 wz 'execute a command that clears the z-flag (loading a value that is non-zero will clear the z-flag if the wz-effect is specified)
    muxz      DirA,BitMask     'set IO-Pins as Input   all bits that are set to "1" in BitMask will be set to zero in DIRA
    
    Maybe it 's just me but I'd argue that these examples don't really get the mux message accross.

    They way it stands now the first example is equivalent to or dira, BitMask and the second one boils down to andn dira, BitMask. So we did it in half the space (and twice the speed) and didn't have to worry about how to set flags.

    Let's assume we don't have mux & Co. Then bit propagation could be done like this:
    test    mask, ina wc
    if_c    or      outa, response
    if_nc   andn    outa, response
    
    Not exactly nice-looking but avoids jumping around the place. Now enter muxc and all we are left with is:
    test    mask, ina wc
            muxc    outa, response
    
    How does this work for you?
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Hi Kuroneko,

    thank you very much for showing how it can be coded the shortest way.

    I forgot to attach the additional PDF. Now you find it in posting #85 (two above)
    How does this work for you?
    I haven't tested it yet. But as you are an experienced programmer and there is only one type of propeller-chip
    I expect that it will work for me too :-)

    keep the improving comments coming
    best regards

    Stefan
    [x] <== SLAM in nail here to hook up the new screen! :lol:
  • edited July 2011 Posts: 0Vote Up0Vote Down
    I'm right now reading through "Programming from the Ground Up" from http://download-mirror.savannah.gnu.org/releases/pgubook/ProgrammingGroundUp-1-0-booksize.pdf which is based on IA-32 (x86), so I'm making notes on Propeller P8X32 differences.
    Pay for your free software - let the developers know how much you appreciate their work!

    Links to Propeller stuff I've done (mostly composite video)
  • edited July 2011 Posts: 539Vote Up0Vote Down
    It took me a while to get this working but I learned a lot.
    Thanks to all for the generous help provided.

    This code is listed for absolute beginners, ABSOLUTE beginners.
    You do not need to know anything about PASM or any other assembly languages. Just the desire to learn
    I made it as simple as I could as an early program to look at and study.
    I would like to know what you do not understand in this listing so I can fix it so that you can.
    I tried to avoid every short hand so its a bit bulky but its for beginners
    You need to look at the data sheet for the MCP 3208 to see what it requires.
    Page 16 is most relevant, top diagram.
    Programs runs on the development board
    Wire the first 12 pins to the first 12 LEDs.
    The 5K potentiometer goes on line 0 of the 3208 and across 5 volts.

    Here we are learning about calling subroutines
    and setting bits as we want them to be.
    And using the PAR command to share variables
    And using masks
    And most of all how to interface to a chip like the 3208.

    As always more experienced programmers are welcome to comment and criticise.
    PUB null | P_Val
      cognew(@generate, @P_Val)            ' start new cog at "generate" and read variable at P_Val
      dira[0 ..11]~~                       ' all 12 lines are outputs. 12 lines needed for 1.5 bytes
      repeat                               ' endless loop to display data
        outa[0..11] := P_Val               ' displays 1.5 bytes of data                         
       
    DAT           org       0                       'sets the starting point in Cog
    generate      mov       dira,   set_dira        'sets direction of the prop pins
                  call      #chip_sel_lo            'selects chip by pulling line low
                  call      #Clk_lo                 'START. Clock needs to be low to load data
                  call      #Din_hi                 'must start with Din high to set up 3208
                  call      #Tog_clk                'clk hi to read data
               
                  call      #Din_hi                 'SINGLE DIFF  Low to load
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
                     
                  call      #Din_lo                 'D2 Low to load input line selection sequence 000 for line 0
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
                
                  call      #Din_Lo                 'D1 Low to load input line selection sequence 000 for line 0
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
               
                  call      #Din_Lo                 'D0 Low to load input line selection sequence 000 for line 0
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
                     
                  call      #Din_lo                 'blank bit needs a clock cycle, next
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
                     
                                                    'next toggle is for the null bit, nothing read
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
              
                  mov       dat_red,  #0            'Clear register we will read data into             
                  mov       count,    #12           'Counter for number of bits we will read
    do_again      mov       temp1,    ina           'read in what is in all the input lines
                  andn      temp1,    inputmask wz  'mask off everything except Dout line. Set Z flag
            if_nz add       Dat_red,  #1            'if value is still positive add 1 to data register 
                  ror       Dat_red,  #1            'roll register right 1 bit to get ready for next bit
                  call      #Tog_Clk                'toggle clock to get next bit ready in Dout
                  sub       count,    #1 wz         'decrement the "bits read" counter. Set Z flag
            if_nz jmp       #do_again               'go up and do it again if counter not 0
                  rol       dat_red,  #12           'roll back 12 bits to get data into 12 LSBits of register
                  mov       temp,     dat_red       'get data that as read
                  wrlong    temp,   par             'put it in PAR to share it as P.Val
                  call      #Chip_Sel_Hi            'Put chip to sleep by delselecting it, for low power usage
                  jmp       #generate               'go back to do it all again
    
    'Subroutines
    Clk_Hi        mov       temp,   outa            'Get the OUTA register
                  or        outa,   clk_bit         'OR it with the Clock Bit
                  mov       outa,   temp            'put it back in OUTA register
    Clk_Hi_ret              ret
    
    Clk_Lo        mov       temp,   outa            'Get the OUTA register    
                  andn      temp,   clk_bit         'ANDN it with the Clock Bit 
                  mov       outa,   temp            'put it back in OUTA register
    Clk_Lo_ret              ret                     'return from this subroutine
    
    Tog_Clk       call      #Clk_hi                 'make clokc bit high
                  call      #clk_lo                 'make clock bit low
    Tog_Clk_ret             ret                     'return from this subroutine
                                                
    Din_Hi        mov       temp,   outa            'Get the OUTA register
                  or        temp,   din_Bit         'Make the Din high
                  mov       outa,   temp            'put it back in OUTA register
    Din_Hi_ret              ret                     'return from this subroutine
                                                  
    Din_Lo        mov       temp,   outa            'Get the OUTA register
                  andn      temp,   din_Bit         'make Din low
                  mov       outa,   temp            'put it back in OUTA register
    Din_Lo_ret              ret                     'return from this subroutine
                                                    
    Chip_Sel_Hi   mov       temp,   outa            'Get the OUTA register
                  or        temp,   chs_Bit         'Make Chip select high
                  mov       outa,   temp            'put it back in OUTA register
    Chip_Sel_Hi_ret         ret                     'return from this subroutine
                                                  
    Chip_Sel_Lo   mov       temp,   outa            'Get the OUTA register
                  andn      temp,   chs_Bit         'make chip select low
                  mov       outa,   temp            'put it back in OUTA register
    Chip_Sel_Lo_ret         ret                     'return from this subroutine
                                                  
    Read_Dout     mov       temp,   ina             'Get the INA register
    Read_Dout_ret           ret                     'return from this subroutine
                                               
    Read_Next_Bit mov       temp1,  ina             'Get the INA register
                  or        temp1,  inputmask       'mask all but Din bit
    Read_Next_Bit_ret       ret                     'return from this subroutine
    
    'Constants. This section is similar to the CON block in SPIN           
    Set_dira      long      %00001011_00000000_00000000_00000000   'Set dira byte                                     
    Chs_Bit       long      %00000001_00000000_00000000_00000000   'Chip select bit                 24
    Din_Bit       long      %00000010_00000000_00000000_00000000   'D in bit                        25
    Dout_Bit      long      %00000100_00000000_00000000_00000000   'D out bit                       26
    Clk_Bit       long      %00001000_00000000_00000000_00000000   'Clock bit                       27
    inputmask     long      %11111011_11111111_11111111_11111111   'mask for reading only the Dout bit
    
    'Variables. This section is similar to the VAR block in SPIN 
    temp          res       1       'temporary storage variable                              
    temp1         res       1       'temporary storage variable
    count         res       1       'temporary storage variable
    Dat_Red       res       1       'temporary storage variable
    
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Looks fine at a glance.

    Do you really need to set bits 0..11 set in Set_dira?
    In this example it doesn't matter, but it is confusing.
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit wrote: »
    'Subroutines
    Clk_Hi      mov     temp,    outa          'Get the OUTA register
                   or      temp,    clk_bit         'OR it with the Clock Bit
                   mov     outa,    temp          'put it back in OUTA register
    Clk_Hi_ret             ret
    
    You should really work on your formatting. Anyway, why do you use a temporary when you work on outa, just do the bit operation (or/andn). outa is one of the safe SPRs.

    Also, I think you want if_nz instead of f_nz. It still compiles because the latter is treated as a label but it's not doing what you intended. One last thing, why do you copy dat_red (a normal register) into temp (another normal register) before writing it to hub?
  • edited July 2011 Posts: 539Vote Up0Vote Down
    @Steve (Jazzed)
    I did that because if I leave that line out it would not work!
    Kuroneko left this line out in his earlier example and his example works!
    I could not figure it out so I left it in.

    @Kuroneko
    I had it formatted perfect in the Prop Tool but when I post it got all screwed up.
    Then I tried editing it but the edit does not stick.
    I am doing something wrong but I have still to figure what it is.
    Yes it was if_nz but the i got lost. I fixed it.
    I thought I had to do it but I tried it like you suggested and now I know that it is not necessary.
    I will edit it again after all the comments are in.
    I'm learning but with me it goes very slowly.

    Thanks all
    Harprit
  • edited July 2011 Posts: 0Vote Up0Vote Down
    Harprit wrote: »
    Kuroneko left this line out in his earlier example and his example works!
    I could not figure it out so I left it in.
    Before it gets confusing, which example would that be? Maybe it simply wasn't required as no I/O was performed (default is input)?
    Harprit wrote: »
    I had it formatted perfect in the Prop Tool but when I post it got all screwed up.
    Odd, never had problems with this. Then again I never use those funny editor icons. I simply type the code tags and paste in between.
Sign In or Register to comment.