More machine code problems
I am trying to access the pub but cant seem to do it right.
I need to get the value of Stack in pub second
Any ideas?
VAR
Long cog
Long Second
PUB Start : okay
okay := cog := Cognew(@Main, 0) + 1
Pub Seconds
Return Stack
Dat
ORG 0
Main
Mov Stack, #0
Mov time, Cnt
:Loop Waitcnt time, Delay
Add Stack, time
jmp #:loop
Stack res 1
time res 1
delay long 80_000_000
Fit 496
I need to get the value of Stack in pub second
Any ideas?
Comments
VAR Long cog Long Second Long Stack PUB Start : okay okay := cog := Cognew(@Main, @Stack) + 1 Pub Seconds Return Stack Dat ORG 0 Main Mov StackPtr, par Mov StackVal, #0 WRLong StackVal, StackPtr Mov time, Cnt :Loop Waitcnt time, Delay Add StackVal, time WRLong StackVal, StackPtr jmp #:loop delay long 80_000_000 StackPtr res 1 ' Pointer to "Stack" hub ram location StackVal res 1 ' Value to put into "Stack" time res 1 Fit 496
Bean
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134
Post Edited (Bean (Hitt Consulting)) : 1/4/2010 7:26:56 PM GMT
Dat ORG 0
Needed to be
Dat ORG
Since I am using the following line of code.
okay := cog := Cognew(@Main, @Stack) + 1
and not
okay := cog := Cognew(@Main, 0) + 1
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
okay := cog := Cognew(@Main, @Stack) + 1
@stack is address $00 ?
-Phil
-Phil
Post Edited (Phil Pilgrim (PhiPi)) : 1/4/2010 6:25:49 PM GMT
VAR Long cog Long Second PUB Start : okay okay := cog := Cognew(@Main, @Second) + 1 Pub Seconds Return Second Dat ORG 0 Main Mov Stack, Par Mov time, Cnt :Loop Waitcnt time, Delay WrLong Stack,Stack++ jmp #:loop Stack res 1 time res 1 delay long 80_000_000 Fit 496
Here is what I think is going on.
okay := cog := Cognew(@Main, @Second) + 1
This is starting a new cog with the memory located at Second
Mov Stack, Par
This moves the contents of the PAR (address $00) into Stack that I have defined below using Stack Res 1
Mov time, Cnt
This moves the counter register in to the register time that I also defined below using Time Res 1
:Loop Waitcnt time, Delay
This waits here until delay register (defined below as 80_000_000) is equal to time
WrLong Stack,Stack++
This increment stack and writes to the register Stack
Is this working as I think it should? It sure is not working in real life
Edited :By the way all the code should do is add 1 every second
Post Edited (Zap-o) : 1/4/2010 6:42:16 PM GMT
-Phil
Post Edited (Phil Pilgrim (PhiPi)) : 1/4/2010 6:58:16 PM GMT
Phil I have done this and it still is not working. Thanks for the help I will keep reading the manual - not much help in that book in my opinion until the lights come on.
":Loop waitcnt time,delay" won't work the way you expect. You've set time to the contents of cnt. When the waitcnt executes, that time has passed by and the waitcnt will wait about 50 seconds until cnt wraps around 32 bits and is equal to the value in time.
"wrlong stack,stack++" won't do what you expect. "stack++" doesn't increment "stack" in assembly, only in Spin. The assembler will probably assume you meant "wrlong stack,stack".
A simple assembly routine to increment a memory location once a second would look like:
' you'd start this with "cognew(@main,@secondCounter)" DAT org 0 main rdlong sec1,#$0 ' hub location $0 contains the CLKFREQ value mov time,sec1 add time,cnt ' set the initial time to one second in the future :loop waitcnt time,sec1 ' wait 1 second and increment the wait time rdlong temp,par ' read the location in hub memory add temp,#1 ' increment it wrlong temp,par ' write it back jmp #:loop sec1 res 1 time res 1 temp res 1
MOV temp,0 ' Move the value that is in address zero into temp
MOV temp,#0 ' Move the value zero into temp
Bean
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
main rdlong sec1, #$0 ' hub location $0 contains the CLKFREQ value
I don't see how this has anything to do with hub 0 and clkfreq?
Please understand -should be obvious- I am new and trying to understand the "machine code".
That first instruction just makes use of a Spin convention to get the number of clock ticks in one second by reading the long stored in hub location zero.
When you wrote this line of code
:loop waitcnt time, sec1 ' wait 1 second and increment the wait time
How did you know it only takes 1 sec. Seems that your code (works great by the way) would run faster than a second.
I like to think of hub memory as an I/O device. You need to use special instructions to access it and it has its own rules (like it's byte, word, and long accessible and works on its own time schedule).
·
I looked at your code and I may be too late and all the other GREAT people have helped enough already.
·
But here is my two bits worth......In your original code I saw·Four problems.
·
VAR Long cog Long Second PUB Start : okay okay := cog := Cognew(@Main, [b][color=red]0[/color][/b]) + 1 Pub Seconds [b][color=red]Return Stack[/color][/b] Dat ORG 0 Main Mov Stack, #0 [b][color=red]Mov time, Cnt[/color][/b] :Loop [b][color=red]Waitcnt time, Delay[/color][/b] Add Stack, [b][color=red]time [/color][/b] jmp #:loop [b][color=red]Stack res 1 [/color][/b]time res 1 [b][color=red]delay long 80_000_000[/color][/b] Fit 496
1- You were confusing Hub and Cog Ram.....especially in the DAT section
Even though you have a DAT variable that within the SPIN code is a valid variable and is accessible to the SPIN methods
it is NOT the same variable when the DAT section is copied to the COG as part of the PASM code.
So when you had the Stack Res 1 variable there were three problems with it... It is a RES so it never got created in the HUB ram
in the first place..... Even if it were, when it gets copied to the Cog as part of the PASM code it becomes a COG ram variable
and that is NOT the same as the Hub ram one.....So when you update that variable in the PASM code it is not going to update
the one in the DAT area in the HUB ram.
This is all confusing due to the DAT variables being of the same name as the Cog and Hub.....that is why it is not a good idea to share
DAT variables of the same names as the Hub and Cog....use different stuff like VARs.
·
2- You were putting LONGs AFTER RESs
all LONGs in the DAT section that will be copied to the PASM code should be BEFORE any RESs....always put RESs as the last thing.
3- Instead of Counting Seconds you are counting the Clock Ticks
When you Add Stack, time.... you are adding the clock ticks count not incrementing the seconds count. It should be
Add Stack, #1 .....but any way see later for a working program.
4- Wrong use of the WaitCnt command.
When you moved the Cnt to the time variable and then WaiteCnt time,Delay you will be waiting for a long long time before the waitcnt will
actually time out....this is because the value in time is already LESS than the new Cnt value and WaitCnt will have to wait until Cnt
rolls over again and become less than the original Cnt value you stored in time.
So what you need is to INCREMENT the time value BEFORE you use it in the WaitCnt command.....but only the first time since in the
PASM version once WaitCnt times out it also increments the time variable by the delay (nice feature should have been also in SPIN).
·
Anyway..... I have "corrected" your code and PRESERVED as much as possible your original code. This way you can compare the
working program to the original one and can observe the corrections and how they apply.
Here it is.. I added some DEBUGGING code to see what is happenning........pay attention to bolded stuff
·
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 Var Long cog Long Seconds OBJ Debug : "FullDuplexSerialPlus" '....added this to do sum debugging PUB Start : okay Debug.Start(31,30,0,115200) ' start the debugger waitcnt(ClkFreq+cnt) 'wait a bit to give time to activate the Serial terminal okay := cog := Cognew(@Main, [b]@Seconds[/b]) + 1 'changed here to pass the address of Seconds to the cog repeat '...this is just some debugging code to print out the results Debug.Dec(GetSeconds) Debug.Tx(2) Debug.Tx(0) Debug.Tx(0) Pub GetSeconds 'renamed your original method to make more sense [b]Return Seconds[/b] 'changed here to return the Seconds value Dat ORG 0 Main [b]Mov SecondsPtr, Par 'save the address of the Seconds variable [/b] Mov time, Cnt [b]Add time, Delay 'make sure that time is Delay ahead as a start[/b] :Loop Waitcnt time, Delay [b]Add SecondsValue, #1 'increment the seconds by 1 [/b] [b]WrLong SecondsValue, SecondsPtr ' copy the value to the Hub Ram variable[/b] jmp #:loop [b]delay long 80_000_000 'moved this here since all LONGs have to be before RESs[/b] SecondsValue Long 0 'renamed the variables to make more sense 'also made the SecondValue as a Long to be able to initialize it 'here instead of in the PASM code...it needs to be a zero to start with. SecondsPtr res 1 time res 1 Fit 496
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Samuel
www.RobotBASIC.com
Post Edited (SamMishal) : 1/4/2010 11:48:36 PM GMT
So I cant seem to grasp the memory mapping of the hub. for example
okay := cog := Cognew(@Main, @Seconds) + 1
This starts a cog at the label @Main with memory @seconds
Then in the Assembly code how does it know? Nowhere is it mentioned again / Also what if I want to use more memory how can I be sure to read / write the correct one? I feel like there should be an addressing mechanism or stack pointer or something.
The @Seconds value gets put into the "par" register (read-only, must be LONG alined). This is the address (in HUB ram) of your parameters.
I think you are getting confused between HUB ram addresses and COG ram addresses. It might help to think of HUB ram as like a hard drive, and COG ram as RAM. You need to "load" a program from the hard drive (HUB ram) into ram (COG ram) to run it. @Main is where the program is located on the hard drive, and @Seconds is where some data is located on the hard drive.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
·
You are welcome.....
·
I think you are confusing the CogNew() when it is used to start a SPIN code and when it is used to start a PASM code.
·
When CogNew() is used to start a SPIN code you give it the name of the METHOD and (you are right) an address for an area
in the HUB ram to use as a STACK for doing pushing and popping for when other methods are called with parameters and for
doing MATH (adding multiplying etc).
·
HOWEVER......when you use CogNew() to LOAD a PASM code you give it two things
·
1- The area in the DAT section where the PASM code is.
·
Nothing to do with the Org 0 or anything....the compiler knows where to get the PASM code from the name you
gave for the·area in the DAT section. And it does not matter what you give it in the next parameter it ALWAYS
loads 496 Longs into the Cog and then starts the cog running from the 0th address.
·
The Org 0 is a directive that tells the compiler to start loading the code at the 0th ram or a different place
in the very rare situation you might want to do so (ie other than 0).....but just forget about Org 0 now.....
just put it there and one day you will see why you might want to put a number other than 0....by the way
Org without the 0 will do the same thing as if there is a zero there.
·
2- An ADDRESS of an area in HUB ram.
·
The address in the hub ram is not a STACK address. It is just that.... an address. How you use it in the PASM code
is up to you. If you do not want to pass an address then you just put a 0.
·
In this case we used it to POINT to the Seconds variable. We then used that address to COPY a long from COG
RAM to that address in the HUB RAM but which also happened to be WHERE the Variable Seconds is and thus the
SPIN program which OWNS the variable can see the variable and its new value.
·
Of course this address could also be used to be a POINTER to the start of a CHUNK of Hub RAM or to the
HEAD ELEMENT of and ARRAY or to the first character of a string and so on and so forth............
·
So do not confuse how the Cognew() is used to start a SPIN METHOD and to start a PASM CODE.
The two are·related actions but DIFFERENT.
·
By the way....the line
········ Mov· SecondsPtr, Par
·
is there to copy the address passed in the 2nd parameter of Cognew() to the register SecondsPtr.
When you say CogNew(@Main,@Seconds) the·2nd parameter is saved in the PAR register of the cog.
·
We really do not STRICTLY NEED to save that value in another register if all we do is use it and never want
to INDEX into it, since it is already saved in the Par register.
·
HOWEVER....it is a good practice to do so and it becomes a necessity when you need to INDEX into it
.....but this is another complexity you do not need to worry about (for now).
·
Just remember.....when we called the CogNew() we give it the address of the area in the Dat section where
the PASM code is and the compiler will load 496 longs to the Cog. The second thing we give it is an
ADDRESS to some place in Hub ram again and that is given to the Cog by putting it in the PAR register for the
cog.
·
Now how·you use this value in the PAR register DEPENDS on what you want to do....in your case you wanted
to copy a value from the Cog RAM to that place in the HUB ram and since it just happened to also be where
the Seconds variable is then you effectively managed to pass a value from the cog to the SPIN code
which is actually running in another cog.
I hope·I explained this clearly.....·
·
·
·
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Samuel
www.RobotBASIC.com
Post Edited (SamMishal) : 1/5/2010 1:19:41 PM GMT
Note: PAR is a read only register. Thus if you want to RDLONG the second element you need to copy PAR to another register.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Composite NTSC sprite driver: Forum
NTSC & PAL driver templates: ObEx Forum
OnePinTVText driver: ObEx Forum
CON
· _clkmode = xtal1 + pll16x
· _xinfreq = 5_000_000
Var
······· Long cog
······· Long Seconds······
······· Long SecondsUp
······· Long SecondsDown
·······
OBJ
· Debug··· : "FullDuplexSerialPlus"······· '....added this to do sum debugging
PUB Start :· okay·
· Debug.Start(31,30,0,115200)·········· ' start the debugger
· waitcnt(ClkFreq * 5 + cnt)··············'wait a bit to give time to activate the Serial terminal···········································
· Seconds···· := 1234567890············· ' Set some obvious values
· SecondsUp := 0
· SecondsDown := 0
· okay := cog := Cognew(@Main, @Seconds) + 1·· 'changed here to pass the address of Seconds to the cog
· repeat··························································'...this is just some debugging code to print out the results
··· Debug.Dec(SecondsUp)
··· Debug.tx(13)
··· Debug.Dec(SecondsDown)
··· Debug.Tx(13)
··· waitcnt(ClkFreq/10 + cnt)····························· 'wait a bit to display the values in Serial terminal···········································
··· Debug.tx(16)
Dat
······· ORG············ 0
Main·······
······· Mov············ SecondsPtr, Par··················· 'save the address of the Seconds variable
······· Rdlong········· SecondsValue, SecondsPtr····· 'Read Seconds in Cog 0 into SecondsValue in this cog
······· Add············ SecondsPtr, #4···················· 'Move the pointer 4 byte (1 long) to point to SecondsUp in cog 0
······· Mov············ time,······ Cnt······················ 'Make time equal to current counter value
······· Add············ time,······ Delay·····················'Add the delay to the counter value
:loop
······· Add············ Delta, #1····························· 'Adding one to temp
······· Add············ SecondsValue, Delta·············· 'Adding temp to the SecondsValue
······· WrLong········· SecondsValue, SecondsPtr·····'Copy the value to the Hub Ram variable and thus to SecondsUp
······· Sub············ SecondsValue, Delta·············· 'Set value to the Seconds value copied from cog 0
······· Sub············ SecondsValue, Delta·············· 'Substract temp to the SecondsValue
······· Add············ SecondsPtr, #4····················· 'Move the pointer 4 byte (1 long) to point to SecondsDown in cog 0
······· WrLong········· SecondsValue, SecondsPtr····· 'Copy the value to the Hub Ram variable and thus to SecondsDown
······· Add············ SecondsValue, Delta··············· 'Set value to the Seconds value copied from cog 0
······· Sub············ SecondsPtr, #4····················· 'Move the pointer 4 byte (1 long) to point to SecondsUp in cog 0 again
·······
······· Waitcnt········ time,········ Delay··················'Wait a second (note time is added to delay at the end of waitcnt so it is on auto)
······· jmp············ #:loop································· 'Start over.
delay········· long 80_000_000······ '1 second of counts at this clock mode and x-stal
SecondsValue·· long 0················· 'Time valiable
Delta·········· long 0···················· 'Difference from start time in seconds
SecondsPtr···· res 1··················· 'Memory location
time·········· res 1······················· 'Counts of time
······· Fit············ 496
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔