Calling assembly routines

General discussion on mikroPascal PRO for PIC32.
Post Reply
Author
Message
tormod
Posts: 57
Joined: 29 Nov 2004 16:31

Calling assembly routines

#1 Post by tormod » 09 Jun 2020 11:09

I am designing a library of assemblycoded routines serving a lot of features. I am testing this routines with separate testprograms and they work to satisfaction giving correct result. But I have run into a problem. I am trying to include this libraries into a very large project but it seems that something is going wrong when I let an assembly routine call another assembly routines within same unit. I am using registers for transferring data at optimization level 4. The assembly routines does not use stackpointer.
By simplified testprogram the same routines works perfectly, and in general calling assembly routines that does not call other assembly routines works OK even in the larger project. Simplified this is how it should work:

XCTR := __SkrASMCollectString(@XStr,@RStr+18,65-18); where XStr and RStr is global string variables and XStr is a global word variable. These routine calls __SkrASMMemMove(Dest,Source : ^byte; len : word) : word; for actual moving of data. Both assemblyroutines are in the same unit. The call is initially from an other unit. Added files both basic files and compiled files for reference. What is the problem? linker? registers? settings? or? The compilers add SP and RA where it is needed.

function __SkrASMMemMove(Destination,Source : ^byte; Len : word) : word;

// ====================================================================================================================
//
// function __SkrASMMemMove(Destination,Source : ^byte; Len : word) : word;
//
// This routine moves data between memory locations; from <Source> to <Destination>. No of bytes to be moved is given
// by <Len>. Routine tries to move data in bulk of 4 bytes, if any remaining bytes, these are moved as single
// bytes (max 3). The function returns bytes moved (== <Len>) for practical purposes so caller can use it as a
// function or procedure by selection. Routine is written in MIPS assembler for maximum speed. No overlap checks are
// done.
//
// No stack is used
// Input registers : R25,R26,R27
// Registers used : R2,R3,R6
// Result register : R27
//
// work started 25.09.2018
//
// ====================================================================================================================

begin
asm
srl R2,R27,2 ; no of double words in R2
andi R3,R27,3 ; no of remaining bytes in R3

L___SkrASMMemMove01:

beq R2, R0, L___SkrASMMemMove02
NOP
lw R6, 0(R26) ; load first word from source
sw R6, 0(R25) ; write first word to destination
addi R2, R2, -1
addiu R25, R25, 4 ; advance source address with 4 bytes
addiu R26, R26, 4 ; advance destination address with 4 bytes
beq R0, R0, L___SkrASMMemMove01
NOP

L___SkrASMMemMove02:

beq R3, R0, L___SkrASMMemMove03 ; beqz R3, L___SkrASMMemMove03
NOP
lb R6, 0(R26) ; load byte from source
sb R6, 0(R25) ; store byte to destination
addiu R25, R25, 1 ; add one to source address to get right start point
addiu R26, R26, 1
addi R3, R3, -1 ; subtract loop counter
beq R0, R0, L___SkrASMMemMove02 ; jump unconditionally
NOP

L___SkrASMMemMove03:

end;
result := R27;
end;



function __SkrASMCollectStr(Str,Source : ^byte; SLen : word) : word;
// ====================================================================================================================
//
// function __SkrASMCollectStr(Str,Source : ^byte; SLen : word) : word;
//
// This routine moves <SLen> bytes from <Source> to <Str>. The routine returns bytes moved.
//
// Added: 29.05.2020
// ====================================================================================================================

begin
asm
jal ___SkrASMMemMove // move data
NOP
sb R0,0(R25) // set terminator
end;
result := R2;
end;

//-------------------------------------------
// CALLING SEQUENCE

Pos := __SkrASMFindFirstByte(@RStr,RCtr,'$')+1; // OK
XCtr := __SkrASMCollectStr(@XStr,@RStr+Pos,RCtr-Pos); // ?????????

Pos is a local variable, XStr,RStr are global string varaiable (String[300]), XCtr,RCtr is string length

Compiled versions:
------------------

___SkrASMMemMove:
;SkrASM.mpas,249 :: begin
;SkrASM.mpas,251 :: srl R2,R27,2 ; no of double words in R2
SRL R2, R27, 2
;SkrASM.mpas,252 :: andi R3,R27,3 ; no of remaining bytes in R3
ANDI R3, R27, 3
;SkrASM.mpas,254 :: L___SkrASMMemMove01:
L___SkrASMMemMove01:
;SkrASM.mpas,256 :: beq R2, R0, L___SkrASMMemMove02
BEQ R2, R0, L___SkrASMMemMove02
;SkrASM.mpas,257 :: NOP
NOP
;SkrASM.mpas,258 :: lw R6, 0(R26) ; load first word from source
LW R6, 0(R26)
;SkrASM.mpas,259 :: sw R6, 0(R25) ; write first word to destination
SW R6, 0(R25)
;SkrASM.mpas,260 :: addi R2, R2, -1
ADDI R2, R2, -1
;SkrASM.mpas,261 :: addiu R25, R25, 4 ; advance source address with 4 bytes
ADDIU R25, R25, 4
;SkrASM.mpas,262 :: addiu R26, R26, 4 ; advance destination address with 4 bytes
ADDIU R26, R26, 4
;SkrASM.mpas,263 :: beq R0, R0, L___SkrASMMemMove01
BEQ R0, R0, L___SkrASMMemMove01
;SkrASM.mpas,264 :: NOP
NOP
;SkrASM.mpas,266 :: L___SkrASMMemMove02:
L___SkrASMMemMove02:
;SkrASM.mpas,268 :: beq R3, R0, L___SkrASMMemMove03 ; beqz R3, L___SkrASMMemMove03
BEQ R3, R0, L___SkrASMMemMove03
;SkrASM.mpas,269 :: NOP
NOP
;SkrASM.mpas,270 :: lb R6, 0(R26) ; load byte from source
LB R6, 0(R26)
;SkrASM.mpas,271 :: sb R6, 0(R25) ; store byte to destination
SB R6, 0(R25)
;SkrASM.mpas,272 :: addiu R25, R25, 1 ; add one to source address to get right start point
ADDIU R25, R25, 1
;SkrASM.mpas,273 :: addiu R26, R26, 1
ADDIU R26, R26, 1
;SkrASM.mpas,274 :: addi R3, R3, -1 ; subtract loop counter
ADDI R3, R3, -1
;SkrASM.mpas,275 :: beq R0, R0, L___SkrASMMemMove02 ; jump unconditionally
BEQ R0, R0, L___SkrASMMemMove02
;SkrASM.mpas,276 :: NOP
NOP
;SkrASM.mpas,278 :: L___SkrASMMemMove03:
L___SkrASMMemMove03:
;SkrASM.mpas,282 :: result := R27; // movz R2,R27,R0 jr RA
; Result start address is: 8 (R2)
MOVZ R2, R27, R0
;SkrASM.mpas,283 :: end;
; Result end address is: 8 (R2)
L_end___SkrASMMemMove:
JR RA
NOP
; end of ___SkrASMMemMove

CALLING ROUTINE
------------------
___SkrASMCollectStr:
;SkrASM.mpas,1530 :: begin
ADDIU SP, SP, -4
SW RA, 0(SP)
;SkrASM.mpas,1532 :: jal ___SkrASMMemMove // move data
JAL ___SkrASMMemMove+0
;SkrASM.mpas,1533 :: NOP
NOP
;SkrASM.mpas,1534 :: sb R0,0(R25) // set terminator
SB R0, 0(R25)
;SkrASM.mpas,1536 :: result := R2;
; Result start address is: 8 (R2)
;SkrASM.mpas,1537 :: end;
; Result end address is: 8 (R2)
L_end___SkrASMCollectStr:
LW RA, 0(SP)
ADDIU SP, SP, 4
JR RA
NOP
; end of ___SkrASMCollectStr

INITIAL CALLING ROUTINE
------------------------
;SkrReceivedMsg.mpas,692 :: XCtr := __SkrASMCollectStr(@XStr,@RStr+Pos,RCtr-Pos);
ANDI R3, R6, 65535
LUI R2, hi_addr(_RStr+0)
ORI R2, R2, lo_addr(_RStr+0)
ADDU R3, R2, R3
LHU R2, Offset(_RCtr+0)(GP)
SUBU R2, R2, R6
; Pos end address is: 24 (R6)
ANDI R27, R2, 65535
MOVZ R26, R3, R0
LUI R25, hi_addr(_XStr+0)
ORI R25, R25, lo_addr(_XStr+0)
JAL ___SkrASMCollectStr+0
NOP
SH R2, Offset(_XCtr+0)(GP)


definition of parametre within this calling unit:

RStr : string[300]; external;
RCtr : word; external;
RPos : word; external;
XStr : string[300]; external;
XCtr : word; external;
XPos : word; external;

tormod
Posts: 57
Joined: 29 Nov 2004 16:31

Re: Calling assembly routines

#2 Post by tormod » 17 Jun 2020 11:22

I have done the following:

Rewritten the __SkrASMMemMove to avoid subsequent load and save:


function __SkrASMMemMove(Destination,Source : ^byte; Len : word) : word;

// ====================================================================================================================
//
// function __SkrASMMemMove(Destination,Source : ^byte; Len : word) : word;
//
// This routine moves data between memory locations; from <Source> to <Destination>. No of bytes to be moved is given
// by <Len>. Routine tries to move data in bulk of 4 bytes, if any remaining bytes, these are moved as single
// bytes (max 3). The function returns bytes moved (== <Len>) for practical purposes so caller can use it as a
// function or procedure by selection. Routine is written in MIPS assembler for maximum speed. No overlap checks are
// done.
//
// No stack is used
// Input registers : R25,R26,R27
// Registers used : R2,R3,R6
// Result register : R27
//
// work started 25.09.2018
//
// ====================================================================================================================

begin
asm
srl R2,R27,2 // no of double words in R2
andi R3,R27,3 // no of remaining bytes in R3

MM_01:
beq R2,R0,MM_02 // if all words done, go to bytes
NOP
lw R4, 0(R26) // load first word from source
addiu R26,R26,4 // advance source address with 4 bytes
addiU R2,R2,-1 // loop counter
sw R4, 0(R25) // write first word to destination
addiu R25,R25,4 // advance destination address with 4 bytes
b MM_01 // loop until done
NOP

MM_02:
beq R3,R0,MM_03 // test if we are done
NOP
lb R4,0(R26) // load byte from source
addiu R26,R26,1 // increment source
addiU R3,R3,-1 // subtract loop counter
sb R4,0(R25) // store byte to destination
addiu R25,R25,1 // increment destination
b MM_02 // jump unconditionally
NOP

MM_03:
end;
result := R27;
end;

Calling this routine directly rather than using __SkrASMCollectStr adding a NUL to resulting string, the following result was gained:

Testcase no 1: call to __SkrASMMemMove copying RStr to XStr, everything OK.
----------------------------------------------------------------------------
CALLING SEQUENCE:

if RCtr > 15 then begin

__SKruartsendtext('RStr1: '+RStr);

RPos := __SkrASMFindFirstByte(@RStr,RCtr,'$')+1; /// giving RPos = 18 which is correct !!!

inttostr(RPos,output);
__skruartsendtext('POS: '+output);
longwordtohex(@RStr,output);
__Skruartsendtext('ADDRRSTR: '+output);
longwordtohex(@XStr,output);
__Skruartsendtext('ADDRXSTR: '+output);
//RStr := 'tormod';

//__SkrASMGetTermStr(@XStr,@RStr,RCtr,0);

// __SkrStringCollectAStr(@RStr+Pos,RCtr-Pos,XStr);
// XCtr := __SkrASMCollectStr(@XStr,@RStR,RCtr);
//RPos := __SkrASMMemCalc(@RStr,RPos);
//longwordtohex(RPos,output);
//__Skruartsendtext('ADDRRP: '+output);
//RStr := 'tormod';
XCtr := __SkrASMMemMove(@xsTR,@RsTR,rcTR);
inttostr(xctr,output);
__skruartsendtext('xctr: '+output+#13+#10);

xstr[XCtr] := #0;


inttostr(length(xstr),output);
__skruartsendtext('xctrinternlength: '+output+#13+#10);


longwordtohex(@XStr,output);

__Skruartsendtext('ADDRXSTR: '+output+#13+#10);
__skruartsendtext('Xstr: '+Xstr+#13+#10);

longwordtohex(@rStr,output);
__skruartsendtext('ADDRrstr: '+OUTPUT);





RStr1: +CXGPSLR: 0,1,2,$GPRMC,103921.00,A,5956.86856,N,01046.12625,E,0.520,,151118,,,A*79POS: 18ADDRRSTR: A0003500ADDRXSTR: A00033D0xctr: 83

xctrinternlength: 83 --- same length as RSTr

ADDRXSTR: A00033D0

Xstr: +CXGPSLR: 0,1,2,$GPRMC,103921.00,A,5956.86856,N,01046.12625,E,0.520,,151118,,,A*79 --- same as RSTr

ADDRrstr: A0003500

Test2: setting expected length of Xstr equal to 60 characters:
--------------------------------------------------------------
RStr1: +CXGPSLR: 0,1,2,$GPRMC,103921.00,A,5956.86856,N,01046.12625,E,0.520,,151118,,,A*79POS: 18ADDRRSTR: A0003500ADDRXSTR: A00033D0xctr: 60

xctrinternlength: 60

ADDRXSTR: A00033D0

Xstr: +CXGPSLR: 0,1,2,$GPRMC,103921.00,A,5956.86856,N,01046.12625 --- XStr shortened as expected

ADDRrstr: A0003500

Test3: adding a value to Rstr address = 18:
-------------------------------------------
XCtr := __SkrASMMemMove(@xsTR,@RsTR+18,60);

result:
RStr1: +CXGPSLR: 0,1,2,$GPRMC,103921.00,A,5956.86856,N,01046.12625,E,0.520,,151118,,,A*79POS: 18ADDRRSTR: A0003500ADDRXSTR: A00033D0 --------CRASHING, why????

Left with the following question:
----------------------------------------
Compiler linker can not handle the @Rstr+18 parameter why??
Trying to use the __SkrASMCollectStr failes in all cases, itonly should add the stringterminator. Running the same procedures in a dedicated testprogram with debugging everything is working as it should !!!!

Post Reply

Return to “mikroPascal PRO for PIC32 General”