asm memory and stack question
I am currently trying to learn assembly and it is going well. The thing I'm having a tough time wrapping my brain around is how to set data in an array in global memory.
hear is my test code:
i am incrementing the on_time by #1 until it hits fun. then I mov fun_2 into the on_time and repeat. I then wrlong on_time to the par address and display it in terminal. this works but how do I select what index of the array I put it into? also I was looking at float32 for an example and I think I somewhat understand how it works but not really how to implement it. it has the command in the first spot in the array and then sets it to 0 and returns the result to the second slot of the array. I think, not realy clear on this writing to the address thing.
What I am looking for is to be able to set a flag in the first var of the array to 1 when the data has been changed in the second var of the array and then cleared by spin to 0 to acknowledge it was read, and spin would put 3 in the flag var to pass data to the cog and in asm it would take the data to a local var and clear the flag again.
so...
how do I put data in stack[1] from asm?
how do I check stack[0] my flag in asm for 2 and then read the data in stack[1], stack[2] ect.. to local variables in the cog?
I am not asking for a finished program, I am just wanting clarification on how passing to and from the hub memory works in a bit more detail. I have read the tips and pitfalls pdf and 2 asm tutorials but this is the thing I am mostly getting hung up on.
hear is my test code:
con _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 timeat = 45000 VAR long cog ' This is in hub ram long cog2 long stack[10] obj DEBUG : "FullDuplexSerialPlusRH" PUB LedOnOff | t dira[4] := 1 start(0) DEBUG.start(31, 30, 0, 9600) 'cog := cognew(Counterdebug, @stack) + 1 t := cnt repeat waitcnt(t += timeat) outa[4] := 1 waitcnt(t += timeat) outa[4] := 0 Counterdebug PUB start(pin) : okay pinmask := |<pin ' This can be done because pinmask(cog ram) is filled before the data is loaded into ' the cog, notice pinmask is declared a long not a res. After the cog is loaded ' the value cannot be modified in this way. ' Now to start the cog, notice the @entry, look at the assembly, you can see where it will begin okay := cog := cognew(@entry, @stack[0]) + 1 PUB stop '' Stop flashing - frees a cog if cog cogstop(cog~ - 1) pub Counterdebug | t t := cnt repeat 'waitcnt(t += timeat) 'waitcnt(clkfreq/1 + cnt) DEBUG.str(string("fun: ")) DEBUG.dec(stack[0]) DEBUG.tx(Debug#CR) DAT org ' Sets the origin at zero for this point entry or DIRA,pinmask ' Sets relevant pin to an output or OUTA,pinmask ' Make pin high mov time,CNT ' Current clock loaded into time add time,on_time ' on_time added to time :loop waitcnt time,off_time ' waits for time to pass, off_time added to time automatically xor OUTA,pinmask ' toggles pin add on_time,#1 cmp on_time,fun wz if_z mov on_time, fun_2 waitcnt time,on_time ' waits for time to pass, on_time added to time automatically xor OUTA,pinmask wrlong on_time,par ' toggles pin jmp #:loop ' loop, the # means that :loop is a literal (something typed into program ' rather than a register). ' These variables are in cog ram! ' Initialized data on_time long 4000 ' on time in clock cycles, 500 * 80000 (cycles per millisecond) off_time long 4000 ' off time, also 500 milliseconds pinmask long 0 ' pinmask can be changed when the program is in HUB RAM fun long 16000 fun_2 long 1000 limit long 100 '**** ATTENTION, all res variables MUST come after other variables ************ ' Uninitialized data time res 1 ' res is used only to create the label, so no code or other variables ' except more res can be placed here, because no real space is used
i am incrementing the on_time by #1 until it hits fun. then I mov fun_2 into the on_time and repeat. I then wrlong on_time to the par address and display it in terminal. this works but how do I select what index of the array I put it into? also I was looking at float32 for an example and I think I somewhat understand how it works but not really how to implement it. it has the command in the first spot in the array and then sets it to 0 and returns the result to the second slot of the array. I think, not realy clear on this writing to the address thing.
What I am looking for is to be able to set a flag in the first var of the array to 1 when the data has been changed in the second var of the array and then cleared by spin to 0 to acknowledge it was read, and spin would put 3 in the flag var to pass data to the cog and in asm it would take the data to a local var and clear the flag again.
so...
how do I put data in stack[1] from asm?
how do I check stack[0] my flag in asm for 2 and then read the data in stack[1], stack[2] ect.. to local variables in the cog?
I am not asking for a finished program, I am just wanting clarification on how passing to and from the hub memory works in a bit more detail. I have read the tips and pitfalls pdf and 2 asm tutorials but this is the thing I am mostly getting hung up on.
Comments
Depending on who you ask you'll get a different solution
same thing in the next example but you already have 4 and 8 in the variables so it auto indexes, correct?
Yes, if you need the addresses more often (while the cog is running) it makes sense to have them pre-calculated, otherwise you'd have to calculate them every time you need them based on par.
Because. Address-wise result is followed by the function parameters which are followed by the local variables (all are of type long). It may be documented somewhere but that's the assumed order.
Thank you for clarifying that. I see where that was added to the manual now.
There ought to be a compressed one-page summary of the most critical programming aspects of the Prop - especially the things that are not obvious and not conventional. Maybe this winter (northern hemisphere) I'll put together a cheat sheet like that.
I sympathize with you on this issue re: "result is followed by the function parameters which are followed by the local variables". As I have just seen it myself for the first time looking at float32.
Problem is this is a detail of the internal operation of the compiled Spin byte codes which I don't think Parallax wants to document for the user. Reason being that it is liable to change. (OK the interpreter is cast in ROM but bear with me). What if the compiler is changed and it passes params to methods in a different order or some other way. What if the results are returned differently. What if local variables get put somewhere else?
Now it happens that things are done in a particular way now and objects like float32 have taken advantage of that, but it is not 100% reliable for all time. Parallax could change the compiler in ways that it still behaves as documented but breaks such objects as float32.
So it's really down to us users to discover, use and document these "features".
That is food for thought. The paucity of programming particulars on anything other than SPIN may have stemmed from a desire not to lock themselves into one way of doing things. At this point, I think the die is cast on Prop I. The new amplifications and elaborations in the Prop Manual may be a sign of that.
I still maintain, though, that having users discover secrets about your product has historically been viewed as a negative thing. Most of the discoveries were unfavorable anyway. Actually expecting your customers to uncover and document features would have been viewed as really odd.
But with the ever increasing complexity of hardware, the ever increasing number of devices, and the generally more open and friendly (i.e. less adversarial) relationship between producer and consumer, perhaps it's not such a big deal.
On the other hand, when you're anxious for results or under a lot of pressure to deliver, having to 'discover' your processor can be VERY frustrating!
Having users discover secrets about your product has historically been normal:)
As an example the Z80 had a pile of undocumented opcodes and flag settings. Most were not of much use but others were discovered and used.
But they were rightly undocumented. They were not intended to be used, just a by product of the way the Z80 was built. With no guarantee that they would still be there in later revisions.
Whether this business about Spin results, parameters and local variables on the stack and other unwritten Spin/PASM/Prop features comes in the same category is open to question I guess.
The bug that permitted so-called "synthetic programming" on the HP-41C calculator was entirely an oversight on the part of HP and its use was discouraged by HP in the strongest terms. It took 10 or 20 years for them to warm up to it in the least.
More generally, most products have some sort of protection that, at a minimum, voids their warranty if breached. Other products have dire warnings about using them for anything other than their intended use - at least that's how it is in the Land of the Free, and the Home of the Brave.
Speaking specifically of chips, using undocumented features in a professional setting is viewed as a grave mistake for the very reasons you've articulated previously. Data sheets are viewed as gospel. Deviating from them is heretical. At least that's the way it has been in every company and organization for whom I've worked.
In the case of Parallax, it has been difficult to distinguish between intended features that simply fell between the documentation cracks, and unintended associations that have been discovered and exploited, but which may change or disappear at any time.