Jump to content

Photo

Assembly Trick : Bit-delimited Strings

TMS9900 Assembly Development

8 replies to this topic

#1 adamantyr OFFLINE  

adamantyr

    Stargunner

  • 1,352 posts

Posted Fri Feb 9, 2018 2:22 PM

I was looking over an old game in a hex editor recently, and I noticed something interesting with the text data embedded in the program. All of the strings seemed fine until the end character, which was a byte value of 128 or greater.

 

I realized what the program was doing was using the top bit on ASCII characters to determine the string end. This lets you store strings at their exact size, rather than one byte more to store either a length byte or a null terminator byte. Very clever!

 

So I thought, how to leverage this on the TI, where I've spent a considerable amount of effort building menus and interfaces that consumed a lot of memory because of having to store strings and their addresses and lengths?

 

So I write a routine, VTEXT, and it's companion, VTEXTC. It's a subroutine that takes the address on screen into R0, and a pointer to the desired text in R1. No length needed! It writes to the screen until it encounters the eighth bit, and stops.

 

VTEXTC is the same, except it doesn't alter the VDP address. This will allow you to write concurrent strings to the screen one after the other.

 

Advantages are:

- Your text strings take up exactly their length in space

- Reduced operations for plotting text to screen

 

Disadvantages are:

- All static text in source files has to end with the top bit set, which can be aggravating to figure out the value of a given ASCII character

- Slower than a straight VMBW due to the need for a COC and copy operation on every character

- If you don't have the top bit set, it could overrun the screen buffer and the rest of VDP

 

Future expansion may include the idea of "values". Using characters 0-31 can be used as an indicator to, for example, switch to a stored numeric value in text form, so you can introduce string formatting. "%0 takes %1 damage!" for example, so it knows to plug in the 0 and 1 pre-calculated values into the string as it's writing to the screen.

TOPBIT DATA >8000                      * Top bit word
VDPWA  EQU  >8C02                      * VDP Write address port
VDPRD  EQU  >8800                      * VDP Read address port
VDPWD  EQU  >8C00                      * VDP access port (input/output)
SCRADR EQU  >0000                      * Screen address
TXTLN1 TEXT 'This is sample tex'
       BYTE 244
       TEXT 'More sample tex'
       BYTE 244
       TEXT 'Sample Tex'
       BYTE 244
       TEXT '-Sample Tex'
       BYTE 244
       
* Video Text writer, CPU to VDP
* Uses only R0 and R1 for location, length is determined by the top bit
* Sends R1 value back to calling rouine for continuous stream of text
* VTEXTC does not update position in VDP, so you can write multiple strings concurrently
VTEXT  ORI  R0,>4000                   * Set address for VDP write
       SWPB R0                         * Swap to low byte
       MOVB R0,@VDPWA                  * Move to VDP address
       SWPB R0                         * Swap
       MOVB R0,@VDPWA                  * Move to VDP address
       ANDI R0,>3FFF                   * remove extra bit so address is preserved for subsequent calls
VTEXTC MOVB *R1+,R2                    * Copy character to R2
       COC  @TOPBIT,R2                 * Check if top bit is set (end of line indicator)
       JEQ  VTEXT1                     * If so, skip to end
       MOVB R2,@VDPWD                  * Write character to screen
       JMP  VTEXTC                     * Loop
VTEXT1 ANDI R2,>7F00                   * Reset top bit on character
       MOVB R2,@VDPWD                  * Write to screen
       RT                              * return to calling program


* Example
       LI   R0,SCRADR+128              * Set R0 to SCRADR+128
       LI   R1,TXTLN1                  * Set R1 to start of text
       BL   @VTEXT                     * Write string to screen
       AI   R0,32                      * Add 32 to screen position
       BL   @VTEXT                     * Write a second line of the text
       LI   R0,SCRADR+256              * Change R0 to a different position
       BL   @VTEXT                     * Write next line to screen
       BL   @VTEXTC                    * Write the next text segment immediately after the prior
* Program continues...



#2 mizapf OFFLINE  

mizapf

    River Patroller

  • 3,360 posts
  • Location:Germany

Posted Fri Feb 9, 2018 2:37 PM

Usually, one would use an additional null character to terminate; this is also used in MDOS on the Geneve. So the effect of this approach is to save one byte per string, right?



#3 apersson850 OFFLINE  

apersson850

    Dragonstomper

  • 501 posts

Posted Fri Feb 9, 2018 2:44 PM

Yes, this is to remove the need for a text length byte or a terminator byte. Which is one byte per string, unless you allow strings longer than 255 bytes, in which case the leading length byte has to be a leadning length word.



#4 mizapf OFFLINE  

mizapf

    River Patroller

  • 3,360 posts
  • Location:Germany

Posted Fri Feb 9, 2018 3:08 PM

Is it worth it? A null terminator would allow using the remaining 128 characters after ASCII 127. Also, it would perform better, because you could simply check for null when fetching the character.



#5 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,241 posts
  • HarmlessLion
  • Location:BUR

Posted Fri Feb 9, 2018 3:21 PM

Nice! This is how many Apple2 programs handled their text strings (maybe the ROMs, I don't recall).

 

You can optimize your test a little bit:

 

COC  @TOPBIT,R2                 * Check if top bit is set (end of line indicator)
JEQ  VTEXT1                     * If so, skip to end

 

Can be replaced with "JLT VTEXT1"... since a byte with the MSB set is a negative value, and the MOVB will set the flags. Saves you the COC, which is one of the more expensive parts of that loop.



#6 Stuart OFFLINE  

Stuart

    Dragonstomper

  • 776 posts
  • Location:Southampton, UK

Posted Fri Feb 9, 2018 3:45 PM

A similar trick is used with the error message strings in Cortex BASIC, but it negates the final byte in each string (which sets the MS bit so JLT/JGT jumps can be used). The required character is recovered by negating the value again.



#7 adamantyr OFFLINE  

adamantyr

    Stargunner

  • Topic Starter
  • 1,352 posts

Posted Fri Feb 9, 2018 4:33 PM

Nice! This is how many Apple2 programs handled their text strings (maybe the ROMs, I don't recall).

 

You can optimize your test a little bit:

COC  @TOPBIT,R2                 * Check if top bit is set (end of line indicator)
JEQ  VTEXT1                     * If so, skip to end

Can be replaced with "JLT VTEXT1"... since a byte with the MSB set is a negative value, and the MOVB will set the flags. Saves you the COC, which is one of the more expensive parts of that loop.

 

Very nice optimization, that does save some bytes and a costly memory to register comparison!



#8 adamantyr OFFLINE  

adamantyr

    Stargunner

  • Topic Starter
  • 1,352 posts

Posted Fri Feb 9, 2018 4:33 PM

Is it worth it? A null terminator would allow using the remaining 128 characters after ASCII 127. Also, it would perform better, because you could simply check for null when fetching the character.

Well  if you are participating in, for example, a 4K RAM contest, every byte counts. ;)



#9 adamantyr OFFLINE  

adamantyr

    Stargunner

  • Topic Starter
  • 1,352 posts

Posted Sat Feb 10, 2018 3:48 PM

I think a big part of why I like this particular technique is that using a whole byte as a null terminator for text is SUCH a waste.

 

I'd written a lot of my CRPG interface code using the standard VMBW technique with three registers, but now I look at that and just think "That's FOUR BYTES i'm wasting every time I write a single line of text." Yes, I'm using AMS but I'm still trying to keep my modules to a fixed size. My Start module now has less than a kilobyte of space, and I still have to write up the opening introduction code. So optimization techniques like this are still useful.







Also tagged with one or more of these keywords: TMS9900, Assembly, Development

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users