Assembly help
Klap
Posts: 65
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
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.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,
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
...
I am have problems getting it to work right.
I am not sure what I am doing wrong.
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.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 4/2/2009 4:47:28 AM GMT
(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.
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?
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
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.
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.
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
(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.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
--Steve
Propalyzer: Propeller PC Logic Analyzer
http://forums.parallax.com/showthread.php?p=788230
(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
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:
to get this:
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?
(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.
#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.
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
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
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!
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:
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