English Amiga Board

English Amiga Board (https://eab.abime.net/index.php)
-   Coders. General (https://eab.abime.net/forumdisplay.php?f=37)
-   -   Lnk/Unlnk (https://eab.abime.net/showthread.php?t=37571)

BippyM 26 June 2008 08:31

Lnk/Unlnk
 
Now I don't totally understand these commands other than they create temp workspace (Sounds like a procedure in c/basic)

If so why?

The game I am WHDloading (Croak) is a complete game of lnk/unlk. every single routine is contained in one of these.. the game was written in C!

I need lots of detailed info to understand thanks

pmc 26 June 2008 09:24

From what I understand from what I've read LINK/UNLK is there to make it easier to manage the stack in situations where subroutines call other subroutines that call other subroutines and so on where each of these subroutines needs space to store temporary data.

LINK/UNLK lets you store the temporary data on the stack itself but still maintain the integrity of the stack correctly for returns from those subroutines.

LINK allocates a frame of memory (in bytes) on the stack and sets an address register as a pointer to that stack frame.

link <address reg>,#-<value in bytes>

The negative size of the value in bytes is cos the stack grows downwards. The values in bytes is a 16 bit signed number so max size of one stack frame is 32Kb.

Each link command saves the address register used in the link command on the stack, then moves the value in the stack pointer to the address register and then subtracts the value in bytes from the stack pointer to grow the stack by that amount.

Using an example address register of a5 and an example frame size of 512 bytes, link does this:

move.l a5,-(a7)
movea.l a7,a5
addq.l #-512,a7

The frame of memory created by link is now the space between the address register used in the link command and the current value of the stack pointer.

Temporary data can be stored in this frame by moving data to where the address register is pointed to and the stack can also be used as normal without affecting this temporary frame data.

An unlk command deallocates the frame space and restores the stack pointer.

So, you can link space, call a subroutine, link more space if needed and then unlk space before returning control to the previous subroutine which can then in turn unlk its space and return from where it was called and each time the integrity of the stack is maintained.

Sounds like your game maybe has lots of subroutines that all call each other and they've used link/unlk to make the stack management easier.

Not sure if this helps in any way whatsoever but I hope it's helped you out! :great

StingRay 26 June 2008 13:26

Nothing much to understand here, LINK/UNLK are for creating local workspace so subroutines that have to be re-entrant (or are just written in C or any other high level language) work correctly. If you don't write recursive/re-entrant routines, you can safely ignore these commands as you don't need them anyway. Pus, what PMC said except for the addq.l #-512,a7 bit :D (addq only works with 3 bit values where value >0 and <=8)

pmc 10 July 2008 13:30

I've got a question about this. If I setup some variables (for want of a better word) like this:

var1: dc.w $1234
var2: dc.l $12345678
var3: dc.l $12345678
var4: dc.b $12
var5: dc.b $34
var6: dc.l $12345678
var7: dc.l $12345678

then link some space:

link a4,#-20

and move the variables into the linked space like this:

move.w var1,(a4)
move.l var2,2(a4)
move.l var3,6(a4)
move.b var4,10(a4)
move.b var5,11(a4)
move.l var6,12(a4)
move.l var7,16(a4)

is it then faster (although, admittedly, less readable) later on in my code to do things like this:

move.l $9abcdef0,2(a4)

instead of things like this:

move.l $9abcdef0,var2

Just curios - I'm trying to work out ways to make code quicker. While I'm on the subject of optimsation, is there a list of optimisations anywhere, such as "instead of clr.l d0, do a moveq.l #0,d0 cos it's faster..."?

BippyM 10 July 2008 13:32

I'm guessing it'd be the same speed as it will be using the same ram, though I guess it might be closer together

musashi5150 10 July 2008 13:59

Quote:

Originally Posted by pmc (Post 432483)
is it then faster (although, admittedly, less readable) later on in my code to do things like this:

move.l $9abcdef0,2(a4)

instead of things like this:

move.l $9abcdef0,var2

Yes, because the var2 is stored as a full 32bit address so it takes longer to fetch the instruction from memory as there is more of it... if that makes sense.

It would be saved as: move.l $9abcdef0,$xxxxxxxx with the $xxxxxxxx being filled in just before running by the AmigaDOS relocator.

Although if these instructions are outside a main loop in reality there won't be much difference of course.

StingRay 10 July 2008 14:08

musashi5150 is right! :) Use relative offsets whenever possible! Faster than using absolute 32 bit values.

Quote:

move.w var1,(a4)
move.l var2,2(a4)
move.l var3,6(a4)
move.b var4,10(a4)
move.b var5,11(a4)
move.l var6,12(a4)
move.l var7,16(a4)
You can still have readable code using that approach, just define a structure like:

Code:

        RSRESET
s_var1: rs.w 1
s_var2: rs.l 1
s_var3: rs.l 1
s_var4: rs.b 1
.... etc

then you can use: move.w var1,s_var1(a4), move.l var2,s_var2(a4) etc. :)

Toni Wilen 10 July 2008 14:20

Very simple 68000 rule: instruction takes at least "length of instruction in words" + "number of byte or word accesses, 1 byte = 1 word. 1 long = 2x word" memory cycles to complete.

(complex instructions like mul and addressing modes like -(ax) etc need more time. Or check the official 68000 pdf documentation, it includes timings.)

1 memory cycle is 1/4 of CPU clock on 68000 Amiga.

pmc 10 July 2008 14:46

@bippym: yeah, you're right they'll all still be RAM locations but I was anticipating that the increase in speed would come from referencing an offset of an address register cos it's faster to use registers than memory locations.

@mushash5150: watcha mate, good to hear from you - thanks for the confirmation. Yeah, I was aiming for these accesses to be in a main program loop hence setting them up first, and then accessing them on the offsets later.

@StingRay: OK cool, so instead of linking space on the stack to an address register and then accessing offsets from that, I can setup an rs.x structure in the assembler and do the same. I take it I have to point an address register at this rs.x structure somewhere early on in my code so I can then use the offsets from that register later?

@Toni: OK thanks for the info. If I was being very lazy though (:p), does anyone know if some kind soul has already worked all these time saving equivalents out and published a list somewhere?

musashi5150 10 July 2008 15:01

Yeah, good to see you still playing around with metal banging ;) Both of these are fairly interesting for optimising ideas - I bet Sting knows of better ones :D (Or just his voodoo 68k skills ;) )

http://linux.cis.monroeccc.edu/~paul...c/trick68k.htm
http://www.mways.co.uk/amiga/howtoco...optimising.php

StingRay 10 July 2008 15:11

Quote:

Originally Posted by pmc (Post 432546)
@StingRay: OK cool, so instead of linking space on the stack to an address register and then accessing offsets from that, I can setup an rs.x structure in the assembler and do the same. I take it I have to point an address register at this rs.x structure somewhere early on in my code so I can then use the offsets from that register later?

Both works, you can use a base register like a5 and point it to your variable block or you can use LINK/UNLK approach.

the first approach would be something like this:
Code:

lea        VARS(pc),a5
move.l        #$08154711,BORING(a5)
move.l        #$B00BBABE,STILL_BORING(a5)
...

VARS            RSRESET
BORING                rs.l 1
STILL_BORING        rs.l 1
VARS_SIZE        rs.b 0
                ds.b VARS_SIZE    ; important! space for the variables

The LINK/UNLK method would be like this:
Code:

link        a5,#-VARS_SIZE
move.l        #$08154711,BORING(a5)
move.l        #$B00BBABE,STILL_BORING(a5)
...
unlk        a5

VARS                RSRESET
BORING                rs.l 1
STILL_BORING        rs.l 1
VARS_SIZE        rs.b 0



Notice that you don't have to reserve space for the variables here as you do that with the LINK instruction.

Using these structures has also quite a big advantage: imagine you once change your variables, f.e. you remove the BORING variable (as you are not bored anymore :P), using the structure you can just delete it and that's all you have to do as the assembler automatically calculates the right offsets. If you would have used move.l #xxx,4(a5) you would have to change that everywhere in the source as 4(a5) is now 0(a5) for obvious reasons. :) I hope that was somewhat understandable. :)

pmc 10 July 2008 15:21

@musashi5150: nice one mate, I'll check those out. :great

@StingRay: Top man. Yeah, it was definitely understandable - and very timely, I was only looking at my code and thinking "if I ended up in a situation where I was having to change all those offsets it would be a pain in the arse!" and here you come posting the solution. :D

StingRay 10 July 2008 15:27

Perfect timing then. :D Happy coding =)


All times are GMT +2. The time now is 10:58.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.

Page generated in 0.04635 seconds with 11 queries