What does @ do in PASM ?
heater
Posts: 3,370
What does @ do in PASM ?
I've got a program that uses a simple Large Memory Model Virtual Machine. So I have to set the LMM's program counter to the start of the LMM program. Obvious thing for me is to just have a LONG that holds the address of the LMM program and then move that into the program counter "mov lmm_pc, target". So now the adress long (target) needs initializing so I write "target long @lmm_prog".
This does not work. The @ does not seem to give the correct address.
If I initialize target from spin prior to launching the PASM into the cog all is well "target := @lmm_prog". Here the @ works as expected.
This is OK if there is only one LMM program but a pain if there are many small LMM functions in a table driven system. A table of targets.
Below is an out line of what I'm trying to do (Notice how posting this screws up the indentation which is why I dislike the use of indenting for code structuring)
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
I've got a program that uses a simple Large Memory Model Virtual Machine. So I have to set the LMM's program counter to the start of the LMM program. Obvious thing for me is to just have a LONG that holds the address of the LMM program and then move that into the program counter "mov lmm_pc, target". So now the adress long (target) needs initializing so I write "target long @lmm_prog".
This does not work. The @ does not seem to give the correct address.
If I initialize target from spin prior to launching the PASM into the cog all is well "target := @lmm_prog". Here the @ works as expected.
This is OK if there is only one LMM program but a pain if there are many small LMM functions in a table driven system. A table of targets.
Below is an out line of what I'm trying to do (Notice how posting this screws up the indentation which is why I dislike the use of indenting for code structuring)
DAT org 0 enter . . some code here . mov lmm_pc, target 'Set LMM's program counter to some program address jmp #lmm_start 'Start the LMM virtual machine . .more code here . ' This is a reversed execution order LMM virtual machine (Which, of course, starts near the bottom:) lmm_ins_0 nop rdlong lmm_ins_1, lmm_pc sub lmm_pc, #7 lmm_ins_1 nop lmm_start rdlong lmm_ins_0, lmm_pc djnz lmm_pc, #lmm_ins_0 lmm_pc long 0 target long @lmm_prog '<--------- THIS DOES NOT WORK AS I EXPECT this long 0 that long 0 fit lmm_prog mov this, that 'Lage memory model program . . more LMM code here . jmp #some_instruction_in_native_code
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
Comments
When used in PASM the address put in the long is the hub address of 'somewhere'
minus the base address of the object the PASM code is included with. For a top-level
object the base address is $0010, for others ... it has to be calculated ( brain too
warped at present to even start describing that ).
Changing ...
mov lmm_pc, target
jmp #lmm_start
To ...
mov lmm_pc, target
add lmm_pc,#$10
jmp #lmm_start
should fix this one. I find the easiest way is to pass the address of the LMM code
to execute in via the PAR in the CogNew because that way PAR points to the
genuine start address.
If you have "long @somewhere" and "CogNew(@enter,@somewhere)", the difference
should give the base address, but normally I wouldn't have the "long @somewhere"
within the LMM.
And a big hint : Don't try reverse LMM operations until you've got the traditional LMM
working as it's a nightmare to debug -- trust me, I speak with experience !
My opcode dispatch table entries contain either the COG address of the native PASM handlers or the HUB address of the LMM handlers, these are indicated by having the top bit of the address set. The main instruction dispatch loop checks that top bit and jumps to a native handler or sets the LMM PC and jumps to the VMM accordingly.
So there are 17 addresses in the dispatch table that need initializing from SPIN (would not like to do it from PASM as it eats COG space) something like this:
do_daa_addr := @do_daa | $8000
do_xchg_addr := @do_xchg | $8000
etc
etc
This is a pain. Given that there is only one DAT section per object the compiler knows the address at compile time so @ should work fine or perhaps @@.
Anyway way from what you say I'm stuck with this run time setting. I guess I could calculate the difference as you show but then I would still have to add it to all entries at start up - no gain.
Atually I'm using a reverse LMM and its no more problem than the forward one BUT only because my handlers are short simple straight line code, no jumps or calls within LMM code, only calls to native functions. I just write the handler after the fit statement just like normal code.
The code revesal is done in spin at start up and the dispatch table set up goes like this:
do_daa_addr := (@lmm_end + @lmm_begin - @do_daa) | $8000
It's easy to move handlers from PASM to LMM and vice-versa.
Thanx.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
1. Get constants in CON blocks
2. Compile sub objects (could be first)
3. Make the method table with blank entries? (this may be done later, not sure, but needs to be before 6)
4. Assemble code in DAT block
5. Allocate VAR space? (this could be done before this, not sure, but needs to be before 6)
6. Compile PUB and PRI blocks including constant expressions in these
7. Fixup method table
8. Put sub objects in binary file in order
So, the compiler can only know the address of a dat variable if it is in the first object and the method table is done before assembling the DAT block.
hippy, how are DAT variables accessed, as an offset from the object base?
the opcodes requiring LMM will run slower so an extra instruction probably won't make
a lot of difference, none at all if you're lucky and it doesn't delay the subsequent rdlong
which gets the LMM opcode. I was quite surprised how little effect adding instructions
into my VM's had.
Another thought on patching up the offset; if there is a "long @somewhere" in the PASM,
Spin can read that, subtract its own "@something" and write the offset into Cog before
launching. That gets it down to just one update to handle.
pass @@0 via PAR one could write it to the Cog image before loading using something
like this ( untested ) ....
"hub_address_something := @something" or "cognew(@enter, param)" and it works just fine. I see no reason why it should not work the same in ASM statements and DAT definitions.
hippy, these adress fixups whether done in spin or asm (using the @00 trick) whatever will never slow down the LMM or 8080 emulator as they are only done once prior to launching the cog. Currently I have a bunch spin statements like below to fix up the dispatch table addreses prior to coginit:
do_daa_addr := (@lmm_end + @lmm_begin - @do_daa) | $8000
N.B. This caters for the reverse execution order of the LMM.
I'd rather just write "do_daa_addr word (@lmm_end + @lmm_begin - @do_daa) | $8000" into my dispatch table.
I'm sure your "offset := @@0" would work just fine as I do similar already with other things.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
of compilation it only knows the address offset to its start, and every module is compiled
individually and only at linking ( done invisibly ) is the real address known. The "@" and
"@@" for Spin provide the magic in the background for that.
As to why Spin and PASM get different results, that's AIUI because both store this offset,
then once linked and at runtime the values differ; in Spin "@" is a unary operator, in PASM
it's a compile time directive.
It's annoying, but that's the way it is. And probably too late to change it if it could be as
doing so would break a lot of existing code.
When used in a DAT section the @ only knows the offset from the start of the object so that is all it can provide.
It is what it is so let it rest there. I'm sure Parallax had a good reason for this.
Anyway I'm very happy thanks to hippy and stevenmess I now have an opcode dispatch table that initializes it's own entries, all be it to an offset address, and a LMM virtual machine that adds the required offset as it runs.
Turns out, hippy, as you said the extra instruction in starting the LMM does not show up but wow I saved 50 longs by not initializing things in spin !!
Current execution rate of 8080/5 opcodes is 323KIPS running FIBO and 352KIPS running the EX8080 test prog.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.