Mike Green said...
Interestingly, someone just pointed out that these, and the JMP instruction, are all the same instruction except for the NR flag.
Anyway, the storing of the return address happens at execution time (it has to ... think about it).
Call and return are "macros" in that they're shortcuts that are handled by the assembler for convenience. The Call is really just a JmpRet and the Return is just a Jmp. When the assembler sees a "Call #Routine", it produces a "JmpRet Routine_ret,#Routine".
When the assembler sees a "Ret", it produces a "Jmp #0".
·That's what I was seeing in the F8 show hex --·more zeros than I expected.·The actual address loading is·done when the JmpRet is executed.
The assembler does no checking of what's at the "Routine_ret" label. It's normally not the job of an assembler to enforce good coding habits. It might be useful as an option for an assembler to issue warning messages, but this assembler/compiler has no provision for warning messages.
·It does (expletive) (and stop) if your return label lacks "_ret". But it didn't care about a NOP.
Thanks Mike. So now all I have to do is figure what could be made useful by changing the second byte (or so) of a register.
Mike Green said...
Yep, if you use "Call #Routine", the assembler generates a reference to "Routine_ret" and you better have a label like that somewhere in your program.
So what's this about the 2nd byte (or so) of a register?
Bad joke maybe, or worse, an attempt to figure how to misuse JmpRet for my own purposes. Which is, I think, figuring which 9 bits are changed in
the _ret address. Any cog address can be viewed as part of just another 'register'. My best guess was that it was·the second byte·of the target; the·second word is $.c 5c, if it·is in fact a jmp.
Turns out it's a little endian value with the least significant 8 bits in the first byte and the ninth bit·as the least significant of·the second byte.
$ff·01·for the last location in cog space, for example. That's what I think I am seeing in the hex dump.
It seems to be a way to set a flag or to stash up to $1ff in another address·as you jmp to a routine*. Assuming that you take care of the routine's exit yourself.
* or on exit of a routine,·perhaps. Of course that just might·give the assembler the sniffles.
(Parenthetical why consider this stuff? Answer: bent on rolling my own forth and still dumb enough to chase up the wrong tree[noparse][[/noparse]s] for a time.·I never have programmed a RiSC with memory issues before....)
Fred,
It's really simple ... the JMPRET stores the return address in the source field of the long word whose address is in the destination field of the JMPRET. The layout of the instruction is documented in all sorts of places ... the Propeller Manual, the Propeller datasheet. As is true of RISCs, the format of the instruction is always the same.
Digging up an old thread...
My demo board (nice build quality, btw), has LED's from pins 16-23. I want to do timed animations on them. I thought I could define the paterns;
DAT
Pattern1 BYTE %1111_0000
Pattern2 BYTE %0000_0000
Pattern3 BYTE %1100_0000
and go thru the patterns by writing that byte to outa starting at bit 16. Is there a way I can address the outa register 'mid byte' like that? It does work if I make the patterns longs.
another question;
can't I do;
waitcnt cnt, #300
to pause the cog for 300 clocks? Doesn't seem to work.
For your first question, use "shl·pattern, #16". this will shift the data to start at pin 16.
For your second question, in assembly you must provide the clock tick to wait for in the destination field. The instruction will add the source to the destination, but only after the instruction has executed (so its good for establishing the next wait period, but not this one). You only specified cnt, which means it will wait until the counter is equal to the count again which is ~54 seconds later. You need to do something like the following:
mov val, cnt
add val, #300
waitcnt val, #300 'the increment value (300) only needs to be included when you need to wait the same period again
PUB main
cognew(@begin,0)
DAT
begin
ORG 0 '
shl dirs, #16 'shift sixteen bits
mov dira,dirs 'make pin 16 output
mov outa,dirs 'make the output high
:loop
mov time,cnt 'take current system counter, move to time long
add time,waitper 'add wait period to time
waitcnt time,#1 'wait until cnt == time plus waitper. Add #1 to time, but time will get rewritten
shl dirs,#1 'shift to pin 17
mov dira,dirs 'Make pin 17 output
mov outa,dirs 'Make that 17th pin high
jmp #:loop 'repeat forever
time RES 1
dirs LONG 1
waitper LONG 10_000
I would expect it to display LED #16, wait 10_000 clocks or so, and shift to pin 17. Instead, when I run this, pins 18, 21 & 22 go high, it pauses for about a minute and pins 19, 22 & 23 go high. then 23 & 20. then just 21.
res should be last. time with be overlayed on dirs
I would move the set of outa before dira. In your case doesn't matter much but its better to set the output before you enable the output
@ Nick : Yes, a Cog is loaded with longs sequentially from Hub, but RES isn't stored in
Hub by the compiler. Thus what's loaded from Hub just before your code comes to be
executed is ...
jmp #:loop 'repeat forever
time LONG 1
dirs LONG 10_000
waitper LONG ???? ' <--- Probably wrong value
Bringing up an old thread because I never really spent time on PASM like I planned to..
I'm trying to understand MOVD,MOVI etc
Looking at Mike Green's Code
'' Here's a simple example of table lookup in assembly.
'' This particular example takes a table index in "ptr"
'' and sets the "data" to the word value from the table.
'' There's no range checking. If you want long values,
'' just eliminate the shifts and masks (*). You can use
'' the same kind of logic for byte values.
DAT
org 0
test mov ptr,#2 ' for an example, get third value
call #look ' note table indices are 0 to n-1
:stop jmp #:stop ' no checking for out of range
look mov data,ptr ' ptr is a table index (0 to n-1)
shr data,#1 ' divide input value by 2 to get (*)
add data,#table ' long word index, add table address
movs :inline,data ' have to use instruction modification
nop ' need pause here for pipelining
:inline mov data,0-0 ' get long value from table
test ptr,#1 wz ' do we want odd or even half (*)
if_z and data,mask ' if even, take lower 16 bits (*)
if_nz shr data,#16 ' if odd, take upper 16 bits (*)
look_ret ret
table word $0000
word $C0C1
word $C181
word $0140
word $C301
word $03C0
word $0280
mask long $FFFF
data res 1
ptr res 1
I have some questions actually many but I will start with a beginners question...
movs :inline,data ' have to use instruction modification
nop ' need pause here for pipelining
:inline mov data,0-0
I thought
:inline
was a label to jump to.. can you explain in beginner lingo how
movs :inline,data
works.
Also..
0-0
what does this mean.
If you have time I'd really like to pick apart this litte code snipet
Remember I'm still after 3 years a real beginner... I have written some ASM programs on my own.. but I'm trying to get my head around this stuff.
The "0-0" is a place holder for something in the code that will be modified at run time. It really means nothing until you, or the Propeller, parses the program. In the COG, there are just longs. Each long could be an instruction. If the program ends up executing it, then it is an instruction. If not, then it's data. Makes no difference to the COG.
Instructions have some pieces, or elements encoded into bit-fields:
There is the instruction opcode, and it's impacted by the MOVI instruction. These bits detail what the instruction actually does.
There is the instruction source, and it's impacted by the MOVS instruction. These bits detail the source data value or location(address).
The instruction destination is impacted by the MOVD instruction. These bits detail the destination address.
Instructions have some other bits, like the conditional bits, if_Z, if_NOT_C, etc... (Whether or not the thing is actually executed)
Finally there is the address mode bit, either literal, or not literal. --->the octothorpe '#' as in 'JMP #label' being different from 'JMP label' (literal, or indirect addressing mode)
The last two can be modified, but you have to do it with a bitmask operation. I don't think there is any way to do it with an official instruction opcode.
About that #....
I find it easiest to explain this using the case of the JMP instruction. The # means the value in the instruction bits is the value that will be loaded into the program counter when the JMP is executed. If you leave off the # then the value in the instruction bits is the address of the COG memory location that contains the value that will be loaded into the program counter. The former is literal, the latter is indirect. This little bit of info is valuable when considering the MOVS instruction to modify another instruction before it is loaded and executed.
So, let's say you want to load a register with some element of a table contained in the COG. That would look like this right?
MOV destination, #55
Let's also say the table exists from COG memory 50 to 60. Then the value at COG 55 would be copied into the long referenced by the label destination. So far so good. Now, let's say that you want to do some math, and reference the table location that equals the result of that math. Now you need the MOVS instruction!
So you do the math, and let's say that the result is 7. Add 7 to 50, yielding 57. Do a MOVS on the MOV instruction above, and the #55 would change to a #57. Since this happens at run time, you would have code that looks like the following:
[noparse][[/noparse]some math that puts a value into result]
add result, #table 'calculate table + index into table = table element address!
MOVS loadtable, result 'this instruction modifies the source field to contain the desired table element address
nop 'for the pipeline
loadtable MOV destination, #0-0 'source gets self-modified
result LONG 0
table LONG $ffeeddaa element 0
LONG $DDEEFFAA element 1
LONG $0000FFFF element 2
etc.....
When doing this, you have to keep an eye out for the pipeline. Instructions take 6 cycles, but execute in 4. An instruction gets loaded before it's executed. If the instruction is loaded, then you modify something, it won't impact the instruction. The nop shows this. You have to have just one instruction between a self modify instruction, and the instruction that it actually modified.
To sum up then:
You use MOVi to change the instruction itself. So, a MOV could be NOP, for example. Some part of your code ahead of the MOV, could decide that it's not needed, and change it to a NOP. I know the conditionals are there for that, but it's an example I could think of quickly.
You use a MOVs when you want to change the source address, or value of a given instruction. That's the table index load example above. Be careful of the # and what it means. IMHO, you want the # more often than not with MOVs. We will see what the real pros here say about that, but that's been my experience. BTW, I don't think you can change this in a self modify. The addressing mode form of an instruction is set when you compile, and the self-modify instructions don't change it, they change only the value the instruction operates with.
You use a MOVd, when you want to change the destination address an instruction is working with. That might be writing values back to a table, for example.
Absolutely it can be changed. I didn't mean to imply it couldn't. I was trying to get at it being easiest if the instruction has the right addressing mode, before modifying it with MOVd and MOVs...
Wow... my head is still spinning..... [noparse]:)[/noparse] Where is 0-0 in the Assembly manual.
So LoadTable is an Instruction in this case not a label.. Since I'm new be easy on me. [noparse]:)[/noparse] I thought that these Were labels for like jump returns and things of that nature.
So in order to use commands like MOVS, MOVD and MOVI
The Line must have a "label" to refer to it from the MOVS.. right?
So if Result == 2
add result,#table 'Result is now 2+#table
MOVS loadtable, result ' Points to element 2 Value $0000FFFF
Nop
loadtable Mov destination,0-0 gets replaced by the value of Result(element 2 Value $0000FFFF)
0-0 is a convention carried over from other systems. It's a nice placeholder that doesn't flag an error. Truth is, you can put whatever you want there. Why?
Because your program will modify it at run time.
On the matter of labels, a label is a label. If you JMP to it, it's a JMP label. If you self-modify it, it's a instruction label. All one and the same.
All a label really does is equate a cog memory address with some word that's easier for us to remember and work with.
Yes, the value 2 will end up as the source in the instruction labeled loadtable. That would look like MOV destination, 2, and behave the same way.
Just noticing where this thread has gone, I'd like to put in a quick note about books for learning assembly.· The best books for this are OLD books written for 8 bit CPU's in the late 1970's and early 1980's.· These books generally start with binary/hex math, explain addressing, and go through the instruction functional groups in a clear and accessible manner.· Not that I refer to them much any more, but dear to my heart (and within easy reach) are...
Programmer's Guide to the 1802 by Tom Swan, Hayden Press, 1981
The 8080A BugBook (my personal gateway guide) by Rony, Larsen, and Titus for Radio Shack, SAMs Press 1977
Z80 User's Manual by Joseph J. Carr, Reston Publishing, 1980
The Z-80 microcomputer Handbook by William Barden, Jr., SAMS Press, 1978
The Complete Timex TS1000/Sinclair ZX81 ROM Disassembly by Dr. Ian Logan and Dr. Frank O'Hara, Melbourne House, 1982
If you don't know assembly at all, books of this vintage are much easier to comprehend than later books because the processors they document are much simpler and more straightforward, so more time is spent explaining and demonstrating concepts (nearly all of which scale to the prop, which despite its bit width is a fairly simple processor too by modern standards) and much less on enumerating a zoo of instruction types in different bit widths, addressing modes, and so on.· In those days you had to learn assembly to make the machine do anything useful, so there were books on the subject that really were meant to be comprehensible by kids (or at least teenagers).· There were also books specifically about the Commodore 64 (including a full system manual) and Apple ][noparse][[/noparse], which I don't have because I didn't have those then relatively expensive systems back in the day.
I update it from time to time. This kind of stuff is just a bit beyond it, but there are a lot of basics covered. Maybe a read through might shake you off of BASIC!
No worries on time. If I have some, I'll contribute here. Don't always get it perfect, but somebody else usually steps in and the end result is all good!
PotatoHead... Yep I read it... Very helpful... I think it's great that people take the time to contribute so much.
I wrote this little ASM code... Basically it just counts down from whatever is in counter... Each time It reaches zero it sends that data to LEDs attached to Pins 0-7.. and is supposed to read the next countdown value from a table.
The first time though it counts down from 255.
The next iteration it reads the table ... It is suppose to start at $0f but it starts at $1b, then $36 then $51 etc... I'm not sure what I'm doing wrong can someone take a quick peek? It should pick the 1st Long in the table.
Thanks in advance for any help you can offer.
Eric
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
OBJ
Debug: "TV_Text"
Num: "Numbers"
Var
Long Index
PUB Main
Debug.Start(12)
Num.Init
Index:=$FF
cognew(@Entry, @Index) 'Launch new cog
Repeat
Debug.Out($01)
Debug.Str(Num.ToStr(Index,Num#Hex))
Debug.Str(String(" "))
DAT
org 0
Entry Mov Count,Par 'Count = Index=255
RdLong Counter,Count
Mov DIRA,#$ff 'Pins 0-7 OutPuts
Mov OUTA,#$00 'Pins 0-7 Low
Mov OutPut,#0
Mov TableIndex,#Table
Add Time, cnt 'Calculate delay time
Add Time, #500 'Set minimum delay here
:Loop
WrLong Counter,Count
Waitcnt Time, Delay 'Wait
Sub Counter,#1
TJNZ Counter,#:Loop
Add Output,#1
Mov OutA,OutPut 'Send OutOut to Pins
Call #GetCount 'Get Next CountDown
JMP #:loop
GetCount MOVS :loadtable, TableIndex 'this instruction modifies the source field to contain the desired table element address
nop
:loadtable MOV Destination, 0-0 'source gets self-modified
Mov Counter,Destination
Add TableIndex,#1 ' Increment TableIndex- no checking for end of table...Should still run 6 interations.
GetCount_Ret Ret
Fit 496
Delay long 10_000_000
Count Long 0
Counter Long 0
TableIndex Long 0
Table Long $0F,$0E,$0D,$0E,$0B,$0A
Time Res 1
OutPut Res 1
Destination Res 1
Post Edited (SailerMan) : 9/30/2009 12:53:33 AM GMT
I removed the FIT496 and Changed the Add to a MOV.. --- < dumb mistake...now the program continues to countdown from $1D... I'll figure this out eventually. Thanks! [noparse]:)[/noparse]
SailerMan said...
I removed the FIT496 and Changed the Add to a MOV.. --- < dumb mistake...now the program continues to countdown from $1D... I'll figure this out eventually. Thanks! [noparse]:)[/noparse]
The problem is this line:
MOV Destination, #0-0
In your initial code example $1B is the address of Table. This gets correctly inserted into the mov instruction. However, you specified # which means load the immediate value $1B into Destination. What you want is the register location $1B. So just remove the offending #. The immediate-or-not bit is located somewhere else in the instruction and not modified by e.g. movs. Be careful what you wish for [noparse]:)[/noparse]
Last night I ran this program through a debugger and noticed the table was @ $1D (Light Bulb) ... I was going to troubleshoot this tonight when I got home...Thanks! for your help.
SailerMan said...
I just updated The above code and is the most recent.
In the Entry section set TableIndex to #table, not #0. And in GetCount remove/skip the first line, first instruction should be movs. Otherwise you keep adding the base address for the table.
With those changes I have it working on the demo board. That just leaves the end-of-table check.
SailerMan, I started with BASIC myself and an infamous comment by Djikstra notwithstanding, I think BASIC is a much better place to start than other high-level languages if you want to progress to ASM and an understanding of how the machine works. And the Prop is an EXCELLENT machine to start with, giving you some relatively modern capabilities with underpinnings that would have felt very natural to my teenaged ca. 1980 self.
Comments
So what's this about the 2nd byte (or so) of a register?
the _ret address. Any cog address can be viewed as part of just another 'register'. My best guess was that it was·the second byte·of the target; the·second word is $.c 5c, if it·is in fact a jmp.
Turns out it's a little endian value with the least significant 8 bits in the first byte and the ninth bit·as the least significant of·the second byte.
$ff·01·for the last location in cog space, for example. That's what I think I am seeing in the hex dump.
It seems to be a way to set a flag or to stash up to $1ff in another address·as you jmp to a routine*. Assuming that you take care of the routine's exit yourself.
* or on exit of a routine,·perhaps. Of course that just might·give the assembler the sniffles.
(Parenthetical why consider this stuff? Answer: bent on rolling my own forth and still dumb enough to chase up the wrong tree[noparse][[/noparse]s] for a time.·I never have programmed a RiSC with memory issues before....)
It's really simple ... the JMPRET stores the return address in the source field of the long word whose address is in the destination field of the JMPRET. The layout of the instruction is documented in all sorts of places ... the Propeller Manual, the Propeller datasheet. As is true of RISCs, the format of the instruction is always the same.
My demo board (nice build quality, btw), has LED's from pins 16-23. I want to do timed animations on them. I thought I could define the paterns;
and go thru the patterns by writing that byte to outa starting at bit 16. Is there a way I can address the outa register 'mid byte' like that? It does work if I make the patterns longs.
another question;
can't I do;
to pause the cog for 300 clocks? Doesn't seem to work.
For your second question, in assembly you must provide the clock tick to wait for in the destination field. The instruction will add the source to the destination, but only after the instruction has executed (so its good for establishing the next wait period, but not this one). You only specified cnt, which means it will wait until the counter is equal to the count again which is ~54 seconds later. You need to do something like the following:
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
I would expect it to display LED #16, wait 10_000 clocks or so, and shift to pin 17. Instead, when I run this, pins 18, 21 & 22 go high, it pauses for about a minute and pins 19, 22 & 23 go high. then 23 & 20. then just 21.
I would move the set of outa before dira. In your case doesn't matter much but its better to set the output before you enable the output
Hub by the compiler. Thus what's loaded from Hub just before your code comes to be
executed is ...
I'm trying to understand MOVD,MOVI etc
Looking at Mike Green's Code
I have some questions actually many but I will start with a beginners question...
I thought
was a label to jump to.. can you explain in beginner lingo how
works.
Also..
what does this mean.
If you have time I'd really like to pick apart this litte code snipet
Remember I'm still after 3 years a real beginner... I have written some ASM programs on my own.. but I'm trying to get my head around this stuff.
Thank,
Eric
Instructions have some pieces, or elements encoded into bit-fields:
There is the instruction opcode, and it's impacted by the MOVI instruction. These bits detail what the instruction actually does.
There is the instruction source, and it's impacted by the MOVS instruction. These bits detail the source data value or location(address).
The instruction destination is impacted by the MOVD instruction. These bits detail the destination address.
Instructions have some other bits, like the conditional bits, if_Z, if_NOT_C, etc... (Whether or not the thing is actually executed)
Finally there is the address mode bit, either literal, or not literal. --->the octothorpe '#' as in 'JMP #label' being different from 'JMP label' (literal, or indirect addressing mode)
The last two can be modified, but you have to do it with a bitmask operation. I don't think there is any way to do it with an official instruction opcode.
About that #....
I find it easiest to explain this using the case of the JMP instruction. The # means the value in the instruction bits is the value that will be loaded into the program counter when the JMP is executed. If you leave off the # then the value in the instruction bits is the address of the COG memory location that contains the value that will be loaded into the program counter. The former is literal, the latter is indirect. This little bit of info is valuable when considering the MOVS instruction to modify another instruction before it is loaded and executed.
So, let's say you want to load a register with some element of a table contained in the COG. That would look like this right?
MOV destination, #55
Let's also say the table exists from COG memory 50 to 60. Then the value at COG 55 would be copied into the long referenced by the label destination. So far so good. Now, let's say that you want to do some math, and reference the table location that equals the result of that math. Now you need the MOVS instruction!
So you do the math, and let's say that the result is 7. Add 7 to 50, yielding 57. Do a MOVS on the MOV instruction above, and the #55 would change to a #57. Since this happens at run time, you would have code that looks like the following:
When doing this, you have to keep an eye out for the pipeline. Instructions take 6 cycles, but execute in 4. An instruction gets loaded before it's executed. If the instruction is loaded, then you modify something, it won't impact the instruction. The nop shows this. You have to have just one instruction between a self modify instruction, and the instruction that it actually modified.
To sum up then:
You use MOVi to change the instruction itself. So, a MOV could be NOP, for example. Some part of your code ahead of the MOV, could decide that it's not needed, and change it to a NOP. I know the conditionals are there for that, but it's an example I could think of quickly.
You use a MOVs when you want to change the source address, or value of a given instruction. That's the table index load example above. Be careful of the # and what it means. IMHO, you want the # more often than not with MOVs. We will see what the real pros here say about that, but that's been my experience. BTW, I don't think you can change this in a self modify. The addressing mode form of an instruction is set when you compile, and the self-modify instructions don't change it, they change only the value the instruction operates with.
You use a MOVd, when you want to change the destination address an instruction is working with. That might be writing values back to a table, for example.
Hope this helps some!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
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!
Post Edited (potatohead) : 9/28/2009 2:40:09 PM GMT
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
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!
So LoadTable is an Instruction in this case not a label.. Since I'm new be easy on me. [noparse]:)[/noparse] I thought that these Were labels for like jump returns and things of that nature.
So in order to use commands like MOVS, MOVD and MOVI
The Line must have a "label" to refer to it from the MOVS.. right?
So if Result == 2
Am I thinking in the right direction?
Eric
Because your program will modify it at run time.
On the matter of labels, a label is a label. If you JMP to it, it's a JMP label. If you self-modify it, it's a instruction label. All one and the same.
All a label really does is equate a cog memory address with some word that's easier for us to remember and work with.
Yes, the value 2 will end up as the source in the instruction labeled loadtable. That would look like MOV destination, 2, and behave the same way.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
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!
Programmer's Guide to the 1802 by Tom Swan, Hayden Press, 1981
The 8080A BugBook (my personal gateway guide) by Rony, Larsen, and Titus for Radio Shack, SAMs Press 1977
Z80 User's Manual by Joseph J. Carr, Reston Publishing, 1980
The Z-80 microcomputer Handbook by William Barden, Jr., SAMS Press, 1978
The Complete Timex TS1000/Sinclair ZX81 ROM Disassembly by Dr. Ian Logan and Dr. Frank O'Hara, Melbourne House, 1982
If you don't know assembly at all, books of this vintage are much easier to comprehend than later books because the processors they document are much simpler and more straightforward, so more time is spent explaining and demonstrating concepts (nearly all of which scale to the prop, which despite its bit width is a fairly simple processor too by modern standards) and much less on enumerating a zoo of instruction types in different bit widths, addressing modes, and so on.· In those days you had to learn assembly to make the machine do anything useful, so there were books on the subject that really were meant to be comprehensible by kids (or at least teenagers).· There were also books specifically about the Commodore 64 (including a full system manual) and Apple ][noparse][[/noparse], which I don't have because I didn't have those then relatively expensive systems back in the day.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
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!
My biggest problem is that my brain is stuck in "BASIC" and thinking in ASM has been a little bit of a struggle.
By the way potatohead... Thanks for taking the time to explain. It's appreciated.
It's really basic and has some of the assembly mindset expressed in simple and friendly terms.
http://forums.parallax.com/forums/attach.aspx?a=28716
I update it from time to time. This kind of stuff is just a bit beyond it, but there are a lot of basics covered. Maybe a read through might shake you off of BASIC!
No worries on time. If I have some, I'll contribute here. Don't always get it perfect, but somebody else usually steps in and the end result is all good!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
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!
I wrote this little ASM code... Basically it just counts down from whatever is in counter... Each time It reaches zero it sends that data to LEDs attached to Pins 0-7.. and is supposed to read the next countdown value from a table.
The first time though it counts down from 255.
The next iteration it reads the table ... It is suppose to start at $0f but it starts at $1b, then $36 then $51 etc... I'm not sure what I'm doing wrong can someone take a quick peek? It should pick the 1st Long in the table.
Thanks in advance for any help you can offer.
Eric
Post Edited (SailerMan) : 9/30/2009 12:53:33 AM GMT
In your initial code example $1B is the address of Table. This gets correctly inserted into the mov instruction. However, you specified # which means load the immediate value $1B into Destination. What you want is the register location $1B. So just remove the offending #. The immediate-or-not bit is located somewhere else in the instruction and not modified by e.g. movs. Be careful what you wish for [noparse]:)[/noparse]
With those changes I have it working on the demo board. That just leaves the end-of-table check.
Also
can be more conveniently written as