Jump to content
IGNORED

Assembly: Problem calling GPLLNK without 32 KB memory expansion


BJGuillot

Recommended Posts

I'm a bit stuck with a problem. I want my QR Code Generator to be able to run on a non-expanded TI. It had been working until I added support for the "small character set" needed for 40-column mode. I traced the problem into the GPLLNK call that I found from TurboForth that was used to obtain the small character set.

 

For some reason, the BLWP call to GPLLNK works fine in js99er.net if the 32 KB memory expansion option is enabled, but if I turn that option off, the program causes the emulated TI to reset back to the title screen when it encounters the "bl *r4" line. When the program runs correctly, it will simply display "HELLO WORLD" and freeze.

 

I'm not sure if it's my fault in the way I've got things setup, something in the GPLLNK routine itself, something in the emulator, or if there is some fundamental reason that doesn't allow GPLLNK to work on a non-expanded TI.

 

I have attached a small sample program that demonstrates the problem. (I assemble it using "xas 99 -R -c gpltest.a99" to get an RPK that I can load with js99er.net.

 

Any assistance would be appreciated. And if there's a way to load the small character set without using GPLLNK, I'm open to using an alternate technique. This was just the only technique I'd been able to find so far.

gpltest.a99

Link to comment
Share on other sites

Bummer ... I wanted to do a quick test, but I cannot assemble this code with Editor/Assembler because you are using lowercase commands and other non-TI formatting.

 

I know this looks nice for external assemblers like xas, but it blocks any way to assemble this inside the emulation or on real iron.

Link to comment
Share on other sites

The problem with calling GPLLNK is that you need a way back to ALC. The only option I'm aware of is via the GPL XML command (>0F). If you are not writing and executing your own GPL program, you must find in an existing GROM the >0F byte followed immediately by a byte that gets you to an ALC location that contains the address of an ALC routine. The only areas over which the programmer has any control for this purpose in the present case are low RAM and cartridge ROM. The GPLLNK routine you are using (from Millers Graphics, originally) uses the only viable byte combination in GROM 0, viz., >0F27, at >176C, which translates to “XML 27”, which branches to >200E in low RAM. That is why the 32KiB expansion must be present.

 

In order to branch to cartridge space, you would need to find a GROM byte combination of >0F70 – >0F7F, which would allow branches to ROM addresses >6010 – >602E. There is no such byte combination in GROM 0. I don't know about GROM 1 or GROM 2 because I don't have a dump of those GROMs.

 

Another option would be to copy the character patterns from GROM to VRAM yourself. The small capital character set (64 patterns) starts at >06B0 in GROM 0 and the lower case character set (31 patterns) starts at >0870 in GROM 0. One fly in the ointment is that each pattern is only 7 bytes of the 8 bytes required for each character! Between the two character sets, it saved 95 bytes. You would need to zero the first byte and copy the next 7. If you are interested, I could probably cobble together a routine to do either or both sets.

 

...lee

  • Like 2
Link to comment
Share on other sites

Thanks for the help guys. It seems a lot more complicated than I expected.

 

When InsaneMultitasker pointed out I was hitting low expanded RAM at >2000, I had one of those Doh! moments, and thought it'd be a simple matter to just change that to a location in scratch RAM, but for all the reasons Lee pointed out, it seems like that was a dead end.

 

I did find a thread, http://atariage.com/forums/topic/169349-the-quest-for-the-gpl-gate, where retroclouds was trying to do something similar, but I am not following it closely enough to try to replicate it.

 

I think trying to copy the character set from GROM to VRAM will be the better approach. Thanks for the offer to cobble up a routine, but I'd like to try it first myself. I hate asking for help on things unless I get totally stuck or need to discuss options.

 

I did encounter some discussions about the danger of bypassing GPL and copying the character set from GROM is that different GROM versions may have the character set starting at different addresses. Is there any truth to that?

Link to comment
Share on other sites

OK, I went ahead and gave up on trying to use GPL to load the small character set.

 

I'm attaching a file that uses the method suggested (to read the character set out of GROM).

 

A few differences noted from what was suggested:

 

I had to use address >06B4 (instead of >06B0).

 

Also, I noticed that I could read all 95 patterns sequentially from GROM (instead of the first 64 patterns at >06B4, and then looking for the other 31 patterns at the other location). I'm not sure if this is something being caused by the js99er.net emulator or if it might be something else. (I have not tried this on a real console yet.)

grom.a99

Link to comment
Share on other sites

Also, I noticed that I could read all 95 patterns sequentially from GROM (instead of the first 64 patterns at >06B4, and then looking for the other 31 patterns at the other location). I'm not sure if this is something being caused by the js99er.net emulator or if it might be something else. (I have not tried this on a real console yet.)

 

Yes...The two sets are contiguous.

 

...lee

Link to comment
Share on other sites

I had to use address >06B4 (instead of >06B0).

 

 

Classic99's GROM 0 is, in fact, 3 bytes off in one place from Heiner Martin's dump of GROM 0. The Classic99 GROM 0 does use >06B4 for the start of the small cap char set patterns. There is an >FC byte just before the start of the table that might be useful for registration.

 

...lee

  • Like 1
Link to comment
Share on other sites

BJ...

 

I noticed in grom.a99 that you set VDPSC to >08FF, which is one byte before the pattern for 'space' (ASCII 32)—not capital 'A' as you indicate. That has the effect of shifting the characters one pixel higher than starting at >0900. It's not a problem because the zero byte of the next character pads the bottom of the current character. I just wondered whether that was your intent.

 

...lee

Link to comment
Share on other sites

Since there are a couple of GROM0's out there, I actually released code a while back that copies the lower case character set by parsing the GROM jump vector to find the code... let me see if I can find that for you. :)

  • Like 2
Link to comment
Share on other sites

GPLLNK can be used without the memory expansion. I need to know a little more about your memory usage before I can help you. It looks like your workspace is at >8300. Do you use other parts of the scratchpad? Will your assembly code be in a ROM cartridge? Let me know and I will be able to look at this tonight and come up with a solution that will work.

 

(edit) Forgot to ask if you only want to load the lower case characters or if you need the full GPLLNK for other purposes.

Edited by senior_falcon
Link to comment
Share on other sites

Since there are a couple of GROM0's out there, I actually released code a while back that copies the lower case character set by parsing the GROM jump vector to find the code... let me see if I can find that for you. :)

 

 

I think I have that. We put it as part of the 32K cart that we used with Fred's disk utility multicart, I believe.

* BANK 0-4 ROM HEADER FOR 32K BANKED
* SWITCHED CART
       DEF SFIRST,SLAST,SLOAD
       UNL
* ROM HEADER
       AORG >6000
SFIRST EQU $
SLOAD  EQU $
GRMHDR BYTE >AA,1,1,0,0,0
       DATA PROG
       BYTE 0,0,0,0,0,0,0,0
PROG   DATA 0
       DATA GOGO
       BYTE 8
       TEXT 'DM2K 2.3'
       EVEN
MINIT  EQU $
       LWPI >8300
 
* Entry point here - ideally put this code first in your ROM
* load R3 with 6 for 99/4, or 7 for 99/4A
GOGO
 CLR R0
 BL @GPLSET
 BL @GETGPL   * read GROM >0000
 LI R3,7
 CI R0,>AA01  * 99/4 is AA01, all versions of 99/4A seem to be AA02 (even 2.2!)
 JNE IS4A     * note we also assume unknown is 99/4A just to be safe
 DEC R3
 
* make a copy of the capitals for the 99/4 to 'support' lowercase
* this will be partially overwritten by the main set, but it works!
 LI R0,>0018  * GPL vector address
 LI R1,>4A00  * dest in VDP - must OR with >4000 for write
 LI R2,>0040  * how many chars
 BL @GPLVDP   * this function goes somewhere later in your ROM
 JMP MNSET
 
IS4A
* 'lowercase' letters
 LI R0,>004A  * GPL vector address (not available for 99/4)
 LI R1,>4B00  * dest in VDP - must OR with >4000 for write
 LI R2,>001F  * how many chars
 BL @GPLVDP   * this function goes somewhere later in your ROM
 
* main set
MNSET
 LI R0,>0018  * GPL vector address
 LI R1,>4900  * dest in VDP - must OR with >4000 for write
 LI R2,>0040  * how many chars
 BL @GPLVDP   * this function goes somewhere later in your ROM
 
* THIS IS THE ROUTINE THAT WILL
* SWAP BANKS TO HIGH BANK
MAIN   MOV R0,@>6000
       LI R4,>0714  * BYTES DIV 4
       LI R9,>63B0  * ADDRESS TO COPY FROM
       LI R10,>A000 * ADDRESS TO COPY TO
LP1
       MOV *R9+,*R10+
       MOV *R9+,*R10+
       DEC R4
       JNE LP1
 
* THIS IS THE ROUTINE THAT WILL
* SWAP BANKS TO NEXT BANK
MAIN2  MOV R0,@>6002
       LI R4,>0714
       LI R9,>63B0
       LI R10,>BC50
LP2
       MOV *R9+,*R10+
       MOV *R9+,*R10+
       DEC R4
       JNE LP2
 
* THIS IS THE ROUTINE THAT WILL
* SWAP BANKS TO NEXT BANK
MAIN3  MOV R0,@>6004
       LI R4,>0714
       LI R9,>63B0
       LI R10,>D8A0
LP3
       MOV *R9+,*R10+
       MOV *R9+,*R10+
       DEC R4
       JNE LP3
 
* THIS IS THE ROUTINE THAT WILL
* SWAP BANKS TO THE LOW BANK
MAIN4  MOV R0,@>6006
       LI R4,>023F
       LI R9,>7704
       LI R10,>2000
LP4
       MOV *R9+,*R10+
       MOV *R9+,*R10+
       DEC R4
       JNE LP4
 
* ALRIGHT, WE'RE DONE.  LET'S GO!
 
       B @>A000
 
* Set GROM address
GPLSET
 MOVB R0,@>9C02
 SWPB R0
 MOVB R0,@>9C02
 B *R11
 
* Get a word from GPL
GETGPL
 MOVB @>9800,R0
 SWPB R0
 MOVB @>9800,R0
 SWPB R0
 B *R11
 
* Copy R2 characters from a GPL copy function vectored at
* R0 to VDP R1. GPL vector must be a B or BR and
* the first actual instruction must be a DEST with an
* immediate operand. Set R3 to 6 for 99/4 (6 byte characters)
* or 7 for a 99/4A (7 byte characters)
GPLVDP
 MOV R11,R10    * save return address
 BL @GPLSET     * set GROM address
 BL @GETGPL     * Get branch instruction (not verified!)
 ANDI R0,>1FFF  * mask out instruction part
 AI R0,3        * skip instruction and destination
 BL @GPLSET     * set new GROM address
 BL @GETGPL     * get actual address of the table
 BL @GPLSET     * and set that GROM address - GROM is now ready!
 
 SWPB R1        * assume VDP is already prepared for write to save space
 MOVB R1,@>8C02
 SWPB R1
 MOVB R1,@>8C02 * VDP is now ready!
 
 CLR R0
 
LP8
 MOVB R0,@>8C00 * pad the top of the char with a space
 MOV R3,R0      * then copy 7 (or 6) bytes
 CI R3,6        * check for 99/4
 JNE LP9
 MOVB R0,@>8C00 * extra blank line for 99/4
 
LP9
 MOVB @>9800,@>8C00  * copy a byte (both sides autoincrement)
 DEC R0
 JNE LP9
 
 DEC R2         * next character
 JNE LP8
 
 B *R10
 
FINISH EQU $
SLAST  END
 
 
  • Like 1
Link to comment
Share on other sites

I noticed in grom.a99 that you set VDPSC to >08FF, which is one byte before the pattern for 'space' (ASCII 32)—not capital 'A' as you indicate. That has the effect of shifting the characters one pixel higher than starting at >0900. It's not a problem because the zero byte of the next character pads the bottom of the current character. I just wondered whether that was your intent.

 

Hmm... I think I probably grabbed the >08FF address from something I saw during one of my Google searches and just stuck with it. I'll need to go fix it. Still getting the hang of the memory map and other oddities of the TI. And still have a hard time thinking in hexadecimal. :-) Thanks for the help.

Link to comment
Share on other sites

GPLLNK can be used without the memory expansion. I need to know a little more about your memory usage before I can help you. It looks like your workspace is at >8300. Do you use other parts of the scratchpad? Will your assembly code be in a ROM cartridge? Let me know and I will be able to look at this tonight and come up with a solution that will work.

 

(edit) Forgot to ask if you only want to load the lower case characters or if you need the full GPLLNK for other purposes.

 

The primary purpose was just to get the character set to use for the 40- (and 80-) column modes. It looks like reading them directly from GROM may be a suitable workaround, though. For play and learning purposes, it might be fun to try calling some of the other GPL routines (like the beep/honk sounds), but I assume those can probably be done without GPL as well.

 

I'd like to be able to run my code from a ROM cartridge at some point (for non-expanded TI's), but also provide the flexibility to run it from disk using EA (for people with a PEB or NanoPEB).

Link to comment
Share on other sites

 

The primary purpose was just to get the character set to use for the 40- (and 80-) column modes. It looks like reading them directly from GROM may be a suitable workaround, though. For play and learning purposes, it might be fun to try calling some of the other GPL routines (like the beep/honk sounds), but I assume those can probably be done without GPL as well.

 

I'd like to be able to run my code from a ROM cartridge at some point (for non-expanded TI's), but also provide the flexibility to run it from disk using EA (for people with a PEB or NanoPEB).

Will have it tonight for you.

Link to comment
Share on other sites

The problem with calling GPLLNK is that you need a way back to ALC. The only option I'm aware of is via the GPL XML command (>0F). If you are not writing and executing your own GPL program, you must find in an existing GROM the >0F byte followed immediately by a byte that gets you to an ALC location that contains the address of an ALC routine. The only areas over which the programmer has any control for this purpose in the present case are low RAM and cartridge ROM.

 

This last statement is wrong. The E/A manual has an incomplete list of XML table references! Thierry's site has the complete list and there are two XML table references to scratchpad RAM: >A0 – >AF and >F0 – >FF, both of which refer to >8300 – >831E. There are seven locations in GROM 0 that can be used to get you to a routine whose address is in >8300, >8306, >8316, >831C and >831E. The locations and their references are listed below:

 

GROM 0 Address XML Cmd Vector Address
-------------- ------- --------------
>00E8 XML >FF >831E
>034C XML >FF >831E
>0379 XML >F0 >8300
>0DBB XML >F3 >8306
>0EDE XML >FB >8316
>1264 XML >F0 >8300
>1675 XML >FE >831C

...lee

Link to comment
Share on other sites

I think I have that. We put it as part of the 32K cart that we used with Fred's disk utility multicart, I believe.

That's it, thanks. GPLVDP is the function in question in there, and it's called twice (once for uppercase, once for lowercase).

Link to comment
Share on other sites

Hoo-boy! :-o In revisiting my last post with an eye to comparing the two GROM 0's I now know about, they only agree on the last address!! At least, there appears to be one invariant—unless there's a third one out there that could scramble this. Here's the result for the GROM 0 used by Classis99 compared to the one dumped by Heiner Martin:

 

GROM 0 Address XML Cmd Vector Address
(Classic99) (Martin) (Classic99) (Martin) (Classic99) (Martin)
-------------------- -------------------- --------------------
>00E8 >00E5 XML >FF XML >FF >831E >831E
>034C >0349 XML >FF XML >FF >831E >831E
>0379 >0376 XML >F0 XML >F0 >8300 >8300
>0DBB >0DB7 XML >F3 XML >EF >8306 >D01E
>0EDE >0EDA XML >FB XML >F7 >8316 >830E
>1264 >1260 XML >F0 XML >F0 >8300 >8300
>1675 >1675 XML >FE XML >FE >831C >831C

...lee

  • Like 1
Link to comment
Share on other sites

I haven't tested it, but this should do the trick: (edited per Lee's suggestion below)

********************************************************************************
*GPLLNK AND DSRLINK FROM THE SMART PROGRAMMER
*adapted to use scratchpad RAM only
*Uses >8320 as a workspace
********************************************************************************
 
GPLWS  EQU >83E0
GLNKWS EQU >8320
GR4    EQU GPLWS+8
GR6    EQU GPLWS+12
LDGADD EQU >60
XTABFE EQU >831C
GETSTK EQU >166C

 
GPLLNK DATA GLNKWS
       DATA GLINK1
 
GXMLAD DATA >1675
        
GLINK1	MOV @>0050,@GR4
       MOV *R14+,@GR6
       MOV @XTABFE,R12
	LI R9,XMLRTN
       MOV R9,@XTABFE
       LWPI GPLWS
       BL *R4
       MOV @GXMLAD,@>8302(R4)
       INCT @>8373
       B @LDGADD
 
XMLRTN MOV @GETSTK,R4
       BL *R4
       LWPI GLNKWS
       MOV R12,@XTABFE
       RTWP
Edited by senior_falcon
  • Like 3
Link to comment
Share on other sites

  • 2 years later...

Heh, I arrived almost at the same code, but what's the relation of XTABFE and GXMLAD? AFAIK the original routine uses >200E and >176C, but both >1675 and >176C don't make any sense address-wise.

 

How are those values used? I might want to move XTABFE somewhere else.

Link to comment
Share on other sites

Heh, I arrived almost at the same code, but what's the relation of XTABFE and GXMLAD? AFAIK the original routine uses >200E and >176C, but both >1675 and >176C don't make any sense address-wise.

 

How are those values used? I might want to move XTABFE somewhere else.

 

The following probably contains a lot of what you already know, but, hopefully, it answers your questions and may help the casual reader with other details:
XTABFE contains the address of the 15th vector (16 possible) in the 16th XML vector table (16 possible) referenced by the GPL code: “XML >FE”. The two-byte, hex code for this is >0FFE. The XML table:element refrence is >FE, with >Fx referencing the table starting at >8300 and >xE referencing element >1C—hence >831C as the value of XTABFE.
GXMLAD contains the address of the GPL XML instruction (>0FFE) we wish the GPL interpreter to execute, which is located at GROM0 address >1675.
Regarding the GROM0 addresses >1675 and >176C, GPL instructions are on byte boundaries, not word boundaries as with ALC. The GPL XML instruction opcode (>0F) appears at both locations. The XML table:vector byte that follows it in the first reference (>1675) is >FE, which is explained above. In the Heiner Martin GROM0 dump, the byte following >0F at >176C is >27, which points to the 8th vector (>200E) in the 3rd XML vector table, starting at >2000 in low RAM. Because the GPL interpreter is byte oriented, it does not matter that the GPL “instructions” at >1675 and >176C are data and never normally executed. It is sufficient that they happen, fortuitously, to be the actual instructions we need to serve our ends.
...lee
  • Like 2
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...