Jump to content
IGNORED

Assembly routines in XB


Vorticon

Recommended Posts

Welp, I am still having the same BAD ARGUMENT error as before even when R0 is set to 1... Here's the code. Ignore that it does not actually return to XB yet but just loops around. The 256th element of the array contains the number of valid elements in that array.

EDIT: I missed your correction regarding R0, but the issue remains

** XB PIO LOW LEVEL DATA OUT ROUTINE **
**          AUGUST 2017              **
**       BY WALID MAALOULI           **
 
       DEF  DATOUT
PIO    EQU  >5000             PIO PORT DATA ADDRESS
FAC    EQU  >834A             FLOATING POINT ACCUMULATOR ADDRESS
XMLLNK EQU  >2018
NUMREF EQU  >200C
REGSTR BSS  8                 STORAGE FOR RETURN REGISTERS
 
** GET NUMBER OF VERTICES
DATOUT MOV  R11,@REGSTR       SAVE RETURN REGISTERS
       MOV  R13,@REGSTR+2
       MOV  R14,@REGSTR+4
       MOV  R15,@REGSTR+6
       LI   R0,256            SELECT 256TH ELEMENT OF VERTEX ARRAY (# OF VERTICES)
       LI   R1,1              SELECT ARGUMENT 1 FROM XB CALL
       BLWP @NUMREF           FETCH ARGUMENT AND PLACE IN FAC
       BLWP @XMLLNK
       DATA >12B8             CONVERT VALUE TO INTEGER
       MOV  @FAC,R4           SAVE COUNTER INTO R4
       INC  R4                ARRAY ZERO BASED. CONVERT TO 1 BASED

** SEND BYTE ARRAY VALUES TO PIO PORT
       BL   @PIOINI           INITIALIZE PIO PORT
REDO   LI   R0,1              POINT TO FIRST ELEMENT OF VERTEX ARRAY
       LI   R1,1              SELECT ARGUMENT 1 FROM XB CALL
LOOP   BLWP @NUMREF           FETCH VERTEX
       BLWP @XMLLNK
       DATA >12B8             CONVERT TO INTEGER
       MOVB @FAC+1,@PIO       SEND BYTE TO PIO PORT
       INC  R0                POINT TO NEXT VERTEX ARRAY ELEMENT
       C    R0,R4             CHECK IF LAST ELEMENT REACHED
       JLE  LOOP
       JMP  REDO
 
** INITIALIZE RS232 CARD
PIOINI LI   R12,>1300         PLACE RS232 CARD CRU ADDRESS IN R12
       SBO  0                 ACTIVATE CARD
       SBO  7                 TURN CARD LED ON
       SBZ  1                 SET THE PIO PORT TO OUTPUT
       RT
 
** RETURN TO XB
RETURN MOV  @REGSTR,R11
       MOV  @REGSTR+2,R13
       MOV  @REGSTR+4,R14
       MOV  @REGSTR+6,R15
       SBZ  0                 INACTIVATE RS232 CARD
       SBZ  7                 TURN LED OFF
       RT
 
       END
Link to comment
Share on other sites

So I tried Anders' suggestion and I'm not having much luck there either unfortunately.

 

XB code:

100 CALL CLEAR
101 CALL INIT :: CALL LOAD("DSK5.PIOOUTA")
105 DIM VERTEX(256),POINT(16,16)
...
330 REM SEND ARRAY TO PIO PORT
350 CALL LINK("ARYLOC",MEMADR)
355 CALL LOAD(MEMADR,VPOINTER) :: MEMADR=MEMADR+1
360 FOR I=0 TO VPOINTER :: CALL LOAD(MEMADR+I,VERTEX(I)) :: NEXT I
370 CALL LINK("DATOUT")
390 GOTO 160

ALC code:

** XB PIO LOW LEVEL DATA OUT ROUTINE **
**          AUGUST 2017              **
**       BY WALID MAALOULI           **
 
       DEF  DATOUT,ARYLOC
PIO    EQU  >5000             PIO PORT DATA ADDRESS
FAC    EQU  >834A             FLOATING POINT ACCUMULATOR ADDRESS
XMLLNK EQU  >2018
NUMREF EQU  >200C
NUMASG EQU  >2008
REGSTR BSS  8                 STORAGE FOR RETURN REGISTERS
VERTEX BSS  128               STORAGE FOR VERTICES
 
** SEND ADDRESS OF VERTICES STORAGE LOCATION IN MEMORY
ARYLOC MOV  R11,@REGSTR       SAVE RETURN REGISTERS
       MOV  R13,@REGSTR+2
       MOV  R14,@REGSTR+4
       MOV  R15,@REGSTR+6
       CLR  @FAC
       LI   R0,VERTEX
       MOV  R0,@FAC       PLACE STORAGE ADDRESS IN FAC
       BLWP @XMLLNK
       DATA >0020             CONVERT TO FLOATING POINT
       CLR  R0
       LI   R1,1              SELECT ARGUMENT 1 OF XB CALL
       BLWP @NUMASG
       B    @RETURN
 
** SEND ARRAY TO PIO PORT
DATOUT MOV  R11,@REGSTR       SAVE RETURN REGISTERS
       MOV  R13,@REGSTR+2
       MOV  R14,@REGSTR+4
       MOV  R15,@REGSTR+6
       BL   @PIOINI           INITIALIZE PIO PORT
       CLR  R3
       MOVB @VERTEX,R3        GET NUMBER OF VERTICES IN ARRAY
       SWPB R3
REDO   LI   R1,1
LOOP   MOVB @VERTEX(R1),@PIO  SEND ARRAY BYTE TO PIO
       INC  R1
       C    R1,R3
       JLE  LOOP
       JMP  REDO
                
** INITIALIZE RS232 CARD
PIOINI LI   R12,>1300         PLACE RS232 CARD CRU ADDRESS IN R12
       SBO  0                 ACTIVATE CARD
       SBO  7                 TURN CARD LED ON
       SBZ  1                 SET THE PIO PORT TO OUTPUT
       RT
 
** RETURN TO XB
RETURN MOV  @REGSTR,R11
       MOV  @REGSTR+2,R13
       MOV  @REGSTR+4,R14
       MOV  @REGSTR+6,R15
       SBZ  0                 INACTIVATE RS232 CARD
       SBZ  7                 TURN LED OFF
       RT
 
       END

I'm sure I'm missing something here...

Link to comment
Share on other sites

I am guessing your Basic program is something like

 

100 DIM PIO(256)

110 PIO(256) = 256

120 REM

130 REM Set up elements 0..255 with values for DATAOUT

140 REM

150 CALL INIT

160 CALL LOAD("DSK1.DATAOUT")

170 CALL LINK("DATAOUT",PIO())

180 ...

 

Your ALC to read PIO(256) should work, setting R4 to 256. Subsequently setting R4 to 257 with “INC R4”, however, will read outside your array bounds. You should, in fact, decrement R4 because it is a zero-based array.

 

REDO LI R0,1” should be “REDO CLR R0” to start at the first element. The loop will now read 256 elements from PIO(0..255).

 

If you change the program to “OPTION BASE 1”, you should change the Basic program to

 

90 OPTION BASE 1

100 DIM PIO(257)

110 PIO(257) = 256

120 REM

130 REM Set up elements 1..256 with values for DATAOUT

140 REM

150 CALL INIT

160 CALL LOAD("DSK1.DATAOUT")

170 CALL LINK("DATAOUT",PIO())

180 ...

You would now not decrement R4, leaving it at 256. You would also restore the statement, “REDO LI R0,1”.

 

I think that should do it.

 

...lee

  • Like 1
Link to comment
Share on other sites

Lee, R4 will contain the number of data elements to read from the array which I save in element 255 in the XB program. Given that you have confirmed that R0 can be 0 for an array starting with a 0 index, then the program will need to be modified back to my original design where R4 is not incremented by 1, and that did not work either (here's the original code)

** XB PIO LOW LEVEL DATA OUT ROUTINE **
**          AUGUST 2017              **
**       BY WALID MAALOULI           **
 
       DEF  DATOUT
PIO    EQU  >5000             PIO PORT DATA ADDRESS
FAC    EQU  >834A             FLOATING POINT ACCUMULATOR ADDRESS
XMLLNK EQU  >2018
NUMREF EQU  >200C
REGSTR BSS  8                 STORAGE FOR RETURN REGISTERS
 
** GET NUMBER OF VERTICES
DATOUT MOV  R11,@REGSTR       SAVE RETURN REGISTERS
       MOV  R13,@REGSTR+2
       MOV  R14,@REGSTR+4
       MOV  R15,@REGSTR+6
       LI   R0,255            SELECT 256TH ELEMENT OF VERTEX ARRAY (# OF VERTICES)
       LI   R1,1              SELECT ARGUMENT 1 FROM XB CALL
       BLWP @NUMREF           FETCH ARGUMENT AND PLACE IN FAC
       BLWP @XMLLNK
       DATA >12B8             CONVERT VALUE TO INTEGER
       MOV  @FAC,R4           SAVE COUNTER INTO R4

** SEND BYTE ARRAY VALUES TO PIO PORT
       BL   @PIOINI           INITIALIZE PIO PORT. 
REDO   LI   R0,0              POINT TO FIRST ELEMENT OF VERTEX ARRAY
       LI   R1,1              SELECT ARGUMENT 1 FROM XB CALL
LOOP   BLWP @NUMREF           FETCH VERTEX
       BLWP @XMLLNK
       DATA >12B8             CONVERT TO INTEGER
       MOVB @FAC+1,@PIO       SEND BYTE TO PIO PORT
       INC  R0                POINT TO NEXT VERTEX ARRAY ELEMENT
       C    R0,R4             CHECK IF LAST ELEMENT REACHED
       JLE  LOOP
       JMP  REDO
 
** INITIALIZE RS232 CARD
PIOINI LI   R12,>1300         PLACE RS232 CARD CRU ADDRESS IN R12
       SBO  0                 ACTIVATE CARD
       SBO  7                 TURN CARD LED ON
       SBZ  1                 SET THE PIO PORT TO OUTPUT
       RT
 
** RETURN TO XB
RETURN MOV  @REGSTR,R11
       MOV  @REGSTR+2,R13
       MOV  @REGSTR+4,R14
       MOV  @REGSTR+6,R15
       SBZ  0                 INACTIVATE RS232 CARD
       SBZ  7                 TURN LED OFF
       RT
 
       END 

Would you mind posting the code snippet you used to test your access to the array elements?

Link to comment
Share on other sites

So I tried Anders' suggestion and I'm not having much luck there either unfortunately.

 

XB code: <snip>

ALC code: <snip>

 

I'm sure I'm missing something here...

 

I presume you initialized VPOINTER to the number of vertices, which must be less than 128, unless you make the ALC VERTEX array larger than 128 bytes. Also, with the first byte of the array a count byte, you can only address 255 bytes—any larger number takes more than 1 byte to store.

 

Line 360 should start storage at MEMADR+1 to avoid stepping on the vertex count. It should be either

 

360 FOR I=1 TO VPOINTER :: CALL LOAD(MEMADR+I,VERTEX(I)) :: NEXT I
or
360 FOR I=0 TO VPOINTER :: CALL LOAD(MEMADR+I+1,VERTEX(I)) :: NEXT I
I think I would change the loop to
REDO CLR R3
MOVB @VERTEX,R3 GET NUMBER OF VERTICES IN ARRAY
SWPB R3
LI R2,VERTEX+1
LOOP MOVB *R2+,@PIO SEND ARRAY BYTE TO PIO
DEC R3
JNE LOOP
JMP REDO
...lee
Link to comment
Share on other sites

...

Would you mind posting the code snippet you used to test your access to the array elements?

** TEST OF NUMREF FOR ARRAYS          **
**          AUGUST 2017               **
**       BY LEE STEWART               **
 
       DEF  SPIN
FAC    EQU  >834A             FLOATING POINT ACCUMULATOR ADDRESS
ARG    EQU  >835C             ARGUMENT REGISTER
XMLLNK EQU  >2018
NUMASG EQU  >2008
NUMREF EQU  >200C
CFI    EQU  >12B8
CIF    EQU  >0020


** SPIN WHILE WE CHECK THE DEBUGGER
SPIN   CLR  R0
       LI   R1,1
       BLWP @NUMREF
       LI   R0,1
       BLWP @NUMREF    <---just overwrites FAC with second value
       INCT @FAC
       CLR  R0
       BLWP @NUMASG
       INCT @FAC
       INC  R0
       BLWP @NUMASG
       RT
 
       END

I called it “SPIN” because that was what I was going to let it do. Instead, I just read the first two elements of the array and added 2 to the second FAC byte and returned that value to the first element, then did it again for the second.

 

Here is the Basic program:

100 CALL INIT
110 CALL LOAD("DSK1.TEST_ARRAY.OBJ")
120 DIM A(10)
130 FOR I = 0 TO 10
140 A(I) = I+1
150 NEXT I
160 CALL LINK("SPIN",A())
170 FOR I = 0 TO 10
180 PRINT A(I)
190 NEXT I
200 GOTO 200

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

Lee, R4 will contain the number of data elements to read from the array which I save in element 255 in the XB program. Given that you have confirmed that R0 can be 0 for an array starting with a 0 index, then the program will need to be modified back to my original design where R4 is not incremented by 1, and that did not work either (here's the original code)

...

 

I can't find anything wrong with it—assuming that VERTEX(255) is 254 or less (unless you don't care that it might send the count to @PIO.

 

The only thing besides setting breakpoints in the debugger might be to use your own workspace as Anders suggested.

 

...lee

Link to comment
Share on other sites

Generally, when passing an array like this, it's better to store the number of relevant elements in the first element of the array. If you store that in array(0), then you don't have to know in advance how large the array is. That's good, since it implies that the same assembly routine can handle any size of array. You know that you always have array(0), so you can always look there to find out if there are seven elements in the array, or 389 or whatever.

 

With the byte array method I suggested, you have to send the byte count as a 16-bit value (two bytes), if you need an array larger than 255 bytes. But again, sending the size first will allow you to know how far down the array you should index.

Link to comment
Share on other sites

This is why TI Basic and TI Extended Basic are better than other Basic Languages.

 

Strings store the SIZE of the String so you use as a index. Other Basics make you count the string to the end to find end of string, huge waste of processing time.

 

Even TI Basic and TI Extended Basic stores the size of numbers also when tokenized i.e. Address:Line#:type:length:token:number stored.

  • Like 1
Link to comment
Share on other sites

 

 

I presume you initialized VPOINTER to the number of vertices, which must be less than 128, unless you make the ALC VERTEX array larger than 128 bytes. Also, with the first byte of the array a count byte, you can only address 255 bytes—any larger number takes more than 1 byte to store.

 

Line 360 should start storage at MEMADR+1 to avoid stepping on the vertex count. It should be either

 

360 FOR I=1 TO VPOINTER :: CALL LOAD(MEMADR+I,VERTEX(I)) :: NEXT I
or
360 FOR I=0 TO VPOINTER :: CALL LOAD(MEMADR+I+1,VERTEX(I)) :: NEXT I
Yes, line 355 of the XB program already does that
I think I would change the loop to
REDO CLR R3
MOVB @VERTEX,R3 GET NUMBER OF VERTICES IN ARRAY
SWPB R3
LI R2,VERTEX+1
LOOP MOVB *R2+,@PIO SEND ARRAY BYTE TO PIO
DEC R3
JNE LOOP
JMP REDO
Lee, what is the benefit in using your loop format as compared to my original one since they both achieve the same thing?

 

Link to comment
Share on other sites

Generally, when passing an array like this, it's better to store the number of relevant elements in the first element of the array. If you store that in array(0), then you don't have to know in advance how large the array is. That's good, since it implies that the same assembly routine can handle any size of array. You know that you always have array(0), so you can always look there to find out if there are seven elements in the array, or 389 or whatever.

 

With the byte array method I suggested, you have to send the byte count as a 16-bit value (two bytes), if you need an array larger than 255 bytes. But again, sending the size first will allow you to know how far down the array you should index.

 

I actually did that with your version of the program where the first element of the array is the element count.

Question: with the expansion memory on, XB reserves the lower 8K of RAM from >2000 to >3FFF for ALC subroutines. Per my program, the Vertex storage location should be at >2008 (confirmed by creating a list file when assembling), and yet the address returned to XB for it is somewhere in the >2300 range (I'm not at the TI currently and don't have the exact value). When run, the program gets the Vertex address, loads it with the array values, and then just hangs...

I need to whip out the debugger tonight and see what the heck is going on here...

Link to comment
Share on other sites

** TEST OF NUMREF FOR ARRAYS          **
**          AUGUST 2017               **
**       BY LEE STEWART               **
 
       DEF  SPIN
FAC    EQU  >834A             FLOATING POINT ACCUMULATOR ADDRESS
ARG    EQU  >835C             ARGUMENT REGISTER
XMLLNK EQU  >2018
NUMASG EQU  >2008
NUMREF EQU  >200C
CFI    EQU  >12B8
CIF    EQU  >0020


** SPIN WHILE WE CHECK THE DEBUGGER
SPIN   CLR  R0
       LI   R1,1
       BLWP @NUMREF
       LI   R0,1
       BLWP @NUMREF    <---just overwrites FAC with second value
       INCT @FAC
       CLR  R0
       BLWP @NUMASG
       INCT @FAC
       INC  R0
       BLWP @NUMASG
       RT
 
       END

I called it “SPIN” because that was what I was going to let it do. Instead, I just read the first two elements of the array and added 2 to the second FAC byte and returned that value to the first element, then did it again for the second.

 

Here is the Basic program:

100 CALL INIT
110 CALL LOAD("DSK1.TEST_ARRAY.OBJ")
120 DIM A(10)
130 FOR I = 0 TO 10
140 A(I) = I+1
150 NEXT I
160 CALL LINK("SPIN",A())
170 FOR I = 0 TO 10
180 PRINT A(I)
190 NEXT I
200 GOTO 200

...lee

 

 

I'll test out your code tonight. At first look, it does not seem to be doing anything different than what I have been doing... Puzzling...

Link to comment
Share on other sites

 

...
Lee, what is the benefit in using your loop format as compared to my original one since they both achieve the same thing?

 

You are right. I always like countdown loops because it usually makes the compare instruction unnecessary. It only saves one instruction, though. I should have sat on my hands a little longer. :P

 

...lee

Link to comment
Share on other sites

 

You are right. I always like countdown loops because it usually makes the compare instruction unnecessary. It only saves one instruction, though. I should have sat on my hands a little longer. :P

 

...lee

 

Actually saving one instruction could be significant when processing large arrays. I'll keep that in mind :)

Link to comment
Share on other sites

Question: with the expansion memory on, XB reserves the lower 8K of RAM from >2000 to >3FFF for ALC subroutines. Per my program, the Vertex storage location should be at >2008 (confirmed by creating a list file when assembling), and yet the address returned to XB for it is somewhere in the >2300 range (I'm not at the TI currently and don't have the exact value). When run, the program gets the Vertex address, loads it with the array values, and then just hangs...

 

Ehh, this was a long time ago, but doesn't XB also store some data/code in low RAM when you do CALL INIT? Or is that Editor/Assembler only?

Link to comment
Share on other sites

Yes. All the way to >25FF (to my surprise).

When doing CALL INIT XB copies >600 bytes out of GROM, but what is from >2538 to >2600 (and probably a little before that) is just extra stuff. If I remember right, after CALL INIT the value at >2002 is the first free address. The assembly support routines only go from >2000 to the address in >2002. Unlike XB, RXB does not copy those extra bytes.

 

(edit) assembly support routines are from >2000 to >24F4 and the assembly code is loaded starting at >24F4

 

Edited by senior_falcon
Link to comment
Share on other sites

When doing CALL INIT XB copies >600 bytes out of GROM, but what is from >2538 to >2600 (and probably a little before that) is just extra stuff. If I remember right, after CALL INIT the value at >2002 is the first free address. The assembly support routines only go from >2000 to the address in >2002. Unlike XB, RXB does not copy those extra bytes.

 

 

So the user ALC routines would start at >2600 then?

  • Like 1
Link to comment
Share on other sites

Quick update:

The version based on apersson850's array access method is fully functional now. Actually, it was never broken to start with, but rather the PIO throughput was much lower than I had expected and it was not being adequately picked up by my connected equipment. The culprit was the compare instruction when cycling through the array elements

       CLR  R3
       MOVB @VERTEX,R3        GET NUMBER OF VERTICES IN ARRAY
       SWPB R3
REDO   LI   R1,1
LOOP   MOVB @VERTEX(R1),@PIO  SEND ARRAY BYTE TO PIO
       INC  R1
       C    R1,R3
       JLE  LOOP
       JMP  REDO

At Lee's suggestion, I changed it to a decrementing loop instead, thus eliminating the compare instruction alltogether

REDO   CLR  R3
       MOVB @VERTEX,R3        GET NUMBER OF VERTICES IN ARRAY
       SWPB R3
       LI   R2,VERTEX+1
LOOP   MOVB *R2+,@PIO  SEND ARRAY BYTE TO PIO
       DEC  R3
       JNE  LOOP
       JMP  REDO

and now the array is cycled through much faster. I had no idea Compare executed that slowly...

At that point, I'm not going to even bother to use the NUMREF utility function given that I will have to issue a BLWP call for each array element in that case, which is going to be even slower.

Fascinating...

Link to comment
Share on other sites

When accessing bytes (MOVB), indexed access is slightly slower than indirect with auto-increment as well.

Then INC or DEC and a JMP are roughly like 1½ MOV, but C is like a MOV. So you reduce the loop time to roughly 5/7 by counting downwards instead.

 

Accessing array times one by one will be much slower, that's correct.

 

Perhaps you want the output to cycle through as fast as possible. Otherwise you may have dual arrays, either after each other or interleaved. The second data item could be the duration you want the output to hold the same data.

 

Here's the original function (just slightly modified)

GPLWS  EQU  >83E0

* Bla, bla...

       LI   R5,PIO
REDO   CLR  R3
       LI   R2,VERTEX
       MOVB *R2+,@GPLWS+7        GET NUMBER OF VERTICES IN ARRAY
LOOP   MOVB *R2+,*R5   SEND ARRAY BYTE TO PIO
       DEC  R3
       JNE  LOOP
       JMP  REDO

And here assuming a delay count (byte) follows each data item.

GPLWS  EQU  >83E0

* Bla, bla...

       LI   R5,PIO
REDO   CLR  R3
       CLR  R4
       LI   R2,VERTEX
       MOVB *R2+,@GPLWS+7        GET NUMBER OF VERTICES IN ARRAY
LOOP   MOVB *R2+,*R5  SEND ARRAY BYTE TO PIO
       MOVB *R2+,@GPLWS+9    Fetch delay count
DELAY  DEC  R4
       JNE  DELAY
       DEC  R3
       JNE  LOOP
       JMP  REDO
Edited by apersson850
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...