Jump to content
pixelpedant

Is there a minimal XB assembly subroutine implementation out there somewhere which just implements string writes to VDP memory?

Recommended Posts

XB256 implements VWRITE and VREAD as CALL LINKs for reading and writing to VDP memory. 

 

This is very nice, and more appealing to me than Mini Memory's PEEKV and POKEV since you can work with large volumes of byte data as strings. 

 

My question is, does anyone have a minimal implementation of at least this VDP write behaviour as a simple assembly subprogram?

 

Which is to say something like XB256's

 

CALL LINK("VWRITE",ADDRESS,STRING$)

 

This is specifically of interest to me since I've been doing a lot of playing with the Text-to-Speech disk's subroutines lately, and they mostly monopolise the lower 8K.  But there's space there still, or I can make some more by running the SETUP routine from high memory via HMLOADER, and/or skipping XLAT, which usually isn't necessary.  So something relatively lightweight isn't a problem.  But XB256 as a whole isn't an option. 

 

Plus, this just seems like a really fundamentally useful thing that somebody presumably implemented at some point (even if just for the sake of their own program). 

 

 

  • Like 1

Share this post


Link to post
Share on other sites

Hmmm XB has ROMs 0 and 1:

  0225            ************************************************************
  0226            * XML table number 7 for Extended Basic - must have   
  0227            *     it's origin at >6010  
  0228            ************************************************************
  0229            *           0      1      2      3      4      5     6  
  0230 6010 619C         DATA COMPCG,GETSTG,MEMCHG,CNSSEL,PARSEG,CONTG,EXECG  
       6012 61A2  
       6014 72CE  
       6016 6070  
       6018 6470  
       601A 64C4  
       601C 6500  
  0231            *           7      8    9     A    B    C      D  
  0232 601E 61BA         DATA VPUSHG,VPOP,PGMCH,SYMB,SMBB,ASSGNV,FBSYMB   
       6020 6C2A  

 99/4 ASSEMBLER
XML359                                                       PAGE 0005
       6022 6410  
       6024 61B4  
       6026 61A8  
       6028 61AE  
       602A 618C  
  0233            *             E     F   
  0234 602C 6EE2         DATA SPEED,CRNSEL  
       602E 6076  
  0235            ************************************************************
  0236            * XML table number 8 for Extended Basic - must have   
  0237            *     it's origin at >6030  
  0238            ************************************************************
  0239            *           0   1      2    3      4  5     6      7  
  0240 6030 74AA         DATA CIF,CONTIN,RTNG,SCROLL,IO,GREAD,GWRITE,DELREP   
       6032 65CC  
       6034 6630  
       6036 7ADA  
       6038 7B48  
       603A 7EB4  
       603C 7ED8  
       603E 7EF4  
  0241            *           8    9    A      B      C      D      E   
  0242 6040 7F7E         DATA MVDN,MVUP,VGWITE,GVWITE,GREAD1,GWITE1,GDTECT  
       6042 6F98  
       6044 7FC0  
       6046 7FDA  
       6048 7EA6  
       604A 7ECA  
       604C 6050  
  0243            *           F   
  0244 604E 7C56         DATA PSCAN   

XML routines MVDN, MVUP are for moving VDP to VDP.

XML routines VGWITE, GVWITE, GREAD1, GWITE1, GREAD, GWRITE are VDP or GROM read and writes.

Also VPOP and VPUSHG are stack routines in VDP.

 

XBROMS.zip

Share this post


Link to post
Share on other sites
On 12/14/2020 at 2:19 PM, pixelpedant said:

My question is, does anyone have a minimal implementation of at least this VDP write behaviour as a simple assembly subprogram?  Which is to say something like XB256's

CALL LINK("VWRITE",ADDRESS,STRING$)

. . .  So something relatively lightweight isn't a problem.

 

I presume that STRING$ is an XB string, meaning that it resides in VRAM, and that ADDRESS is also in VRAM, so that implementing the above VWRITE routine is actually moving a string from one VRAM location to another. If so, there are a couple of ways to do this. One is much more “lightweight” than the other. The light one would require only 50 – 60 bytes beyond the CALL overhead. The heavy one, which should be a good bit faster (unless the CALL overwhelms its time), would require an additional 256-byte RAM buffer to hold the largest possible XB string. I will probably attempt both routines just for grins, but do you have a preference?

 

...lee

  • Like 1

Share this post


Link to post
Share on other sites
39 minutes ago, Lee Stewart said:

 

I presume that STRING$ is an XB string, meaning that it resides in VRAM, and that ADDRESS is also in VRAM, so that implementing the above VWRITE routine is actually moving a string from one VRAM location to another. If so, there are a couple of ways to do this. One is much more “lightweight” than the other. The light one would require only 50 – 60 bytes beyond the CALL overhead. The heavy one, which should be a good bit faster (unless the CALL overwhelms its time), would require an additional 256-byte RAM buffer to hold the largest possible XB string. I will probably attempt both routines just for grins, but do you have a preference?

 

...lee

GREAD

* (RAM to RAM)
* Read data from ERAM 
* @GSRC  : Source address on ERAM
* @DEST  : Destination address in CPU
*           Where the data stored after read from ERAM

 

GWRITE

* (RAM to RAM) 
* Write the data whcih is stored in CPU to ERAM
* @GDST  : Destination address on ERAM where data is going
*           to be stored
* @CSRC  : Source address on CPU where data stored

 

MVDN

* (VDP to VDP) or (RAM to RAM) 
* WITHOUT ERAM : Move the contents in VDP RAM from a lower
*                address to a higher address avoiding a
*                possible over-write of data
* >835C          ARG    : byte count
* >8300          VAR0   : source address
* >8306          VARY2  : destination address
* WITH ERAM    Same as above except moves ERAM to ERAM

 

MVUP

* (RAM to RAM) 
* WITH ERAM    : Move the contents in ERAM FROM a higher
*                 address to a lower address
*                ARG    : byte count
*                VAR9   : source address
*                VAR0   : destination address

 

VGWITE

* (VDP to RAM) >834C=ADDR1,>8350=ADDR2,>834E=BCNT1
* Move data from VDP to ERAM
* @ADDR1 : Source address where the data stored on VDP
* @ADDR2 : Destination address on ERAM
* @BCNT1 : byte count

 

GVWITE

* Move data from ERAM to VDP (RAM to VDP)
* @GSRC  : Source address where the data stored on ERAM
* @DEST  : Destination address on VDP
* @BCNT3 : byte count

 

I do use use GPL MOVE instead it takes less bytes to do same thing and speed wise is just slightly slower then the XML versions.

Depends on amount moved, the larger the amount to move the slower GPL MOVE is in comparison.

 

 

 

Edited by RXB

Share this post


Link to post
Share on other sites

 

44 minutes ago, Lee Stewart said:

 

I presume that STRING$ is an XB string, meaning that it resides in VRAM, and that ADDRESS is also in VRAM, so that implementing the above VWRITE routine is actually moving a string from one VRAM location to another. If so, there are a couple of ways to do this. One is much more “lightweight” than the other. The light one would require only 50 – 60 bytes beyond the CALL overhead. The heavy one, which should be a good bit faster (unless the CALL overwhelms its time), would require an additional 256-byte RAM buffer to hold the largest possible XB string. I will probably attempt both routines just for grins, but do you have a preference?

 

 

That'd be awesome, Lee.  I figure the buffered one's the one I'd use the most.  But it sure doesn't hurt to have options!

 

I suppose on reflection it's not surprising that this doesn't exist somewhere as just a support routine sitting on a disk for some relatively elaborate legacy XB program (like the XB RPGs). 

 

My thinking being that the current appeal of speeding things up or simplifying matters by just dumping large chunks of pregenerated sprite/screen/pattern/colour data into relevant VDP locations as bytes is substantially contingent on two things, neither of which is true in an 80s context: namely, disk access is fast and convenient, and storage is arbitrarily large.  And more importantly, handling and generating assets as VDP RAM dumps is easy, and is supported by various cross-platform development tools.  Such that it's tempting to just "cut out the middle man" as far as some of that data goes, even when using XB for the broader program logic. 

 

Share this post


Link to post
Share on other sites
52 minutes ago, pixelpedant said:

 

 

That'd be awesome, Lee.  I figure the buffered one's the one I'd use the most.  But it sure doesn't hurt to have options!

 

I suppose on reflection it's not surprising that this doesn't exist somewhere as just a support routine sitting on a disk for some relatively elaborate legacy XB program (like the XB RPGs). 

 

My thinking being that the current appeal of speeding things up or simplifying matters by just dumping large chunks of pregenerated sprite/screen/pattern/colour data into relevant VDP locations as bytes is substantially contingent on two things, neither of which is true in an 80s context: namely, disk access is fast and convenient, and storage is arbitrarily large.  And more importantly, handling and generating assets as VDP RAM dumps is easy, and is supported by various cross-platform development tools.  Such that it's tempting to just "cut out the middle man" as far as some of that data goes, even when using XB for the broader program logic. 

 

I agree, RXB does this with my commands like CALL PLOAD("DSK1.FILE") and CALL MOVE("RV",2079,8192,0) from RAM to VDP screen.

Edited by RXB
Spelling

Share this post


Link to post
Share on other sites
2 hours ago, pixelpedant said:

 

 

That'd be awesome, Lee.  I figure the buffered one's the one I'd use the most.  But it sure doesn't hurt to have options!

 

I suppose on reflection it's not surprising that this doesn't exist somewhere as just a support routine sitting on a disk for some relatively elaborate legacy XB program (like the XB RPGs). 

 

My thinking being that the current appeal of speeding things up or simplifying matters by just dumping large chunks of pregenerated sprite/screen/pattern/colour data into relevant VDP locations as bytes is substantially contingent on two things, neither of which is true in an 80s context: namely, disk access is fast and convenient, and storage is arbitrarily large.  And more importantly, handling and generating assets as VDP RAM dumps is easy, and is supported by various cross-platform development tools.  Such that it's tempting to just "cut out the middle man" as far as some of that data goes, even when using XB for the broader program logic. 

 

I agree with considering what is 80s spirit (even if you run it on emulation).

 

I think your issues can be reasonably addressed.   It comes down to how much data and how often?

 

Load from disk

 

Give yourself a budget of 90K of assets as a minimum. Also compress it! Let the assembly routine unpack it. Require just a few records of data for each update in the game. Cache the most recently used (maybe just 2 screens worth.)

 

90K is enough for a hundred screenshots (in chars), a couple of charsets (48-64 characters each). The killer is text. At one extreme, an Infocom data file takes the whole disk.

 

TI-Runner periodically loads 1 screen from disk (albeit from all assembly.)


Loading a screenful of chars from strings is reasonable: 6 records of DF128, less with RLE compression. I used this technique to initialize screen data into a 4K buffer in low RAM, 8 screens for a level, each 16x32. One assembly routine to blit a section to the screen.

 

Initializing your charset is another: one  DF128 record is 16 char definitions. 

 

Rule out loading a full bitmap picture. It's beyond XB VDP capacity.

 

Data hiding

 

Put the data into your program to make it faster. Hiding it in the 24K RAM as lines, locatable only by routines aware of it.

 

I'm rusty on this technique. But I think you load your data into 24K, change the first free address, then MERGE the XB program. Then at runtime, your assembly routines can grab from it. Barry Boone's SYSTEX was one example of this technique (it creates a program in the 24K, that hides your 8K, and restores it the next time you run.)

 

Uses

 

For an RPG, assume you update the charset infrequently (like entering new terrain.) Then suppose a screen is static and composed of tiles. Say you want to fill 2/3 of the screen with map. It's  512 bytes or four records of chars.

 

If you have 2x2 tiles, then only 128 bytes are needed to fill the screen.

 

My first XB-assembly hybrid was a routine that took 81 bytes from a XB string and drew a 9x9 map of 2x2 tiles. I was pretty happy with that (when it was debugged...)

 

If you have a list of bigger objects to draw, you can compose it of 3 byte chunks for row, column, object number.

 

I'm talking about loading compressed data in pieces, not always a VDP dump. (Tunnels of Doom has the whole VDP image in its 52K: pattern table, colors, + data.)

 

When you are comfortable with DSRLNK in assembly, move the loading (and saving!) out of XB code for another big speedup. 

 

 

 

Sprites

 

Another technique I used is to store the sprite attribute table in low RAM. XB program updates a sprite location in a buffer with CALL LOAD(9472+S*4,Y,X) instead of CALL LOCATE(#S,Y,X). Pattern and color too. One CALL LINK("SPTBL") copies the whole thing to VDP. Instantly updated positions and frames. Combine same technique for the motion table. A substitute for turning the sprite motion bit off, looping across CALL MOTION, turning motion back on.. the assembly routine can set all the sprite attributes together.

 

Code

 

I doubt I can find any of my code for these things. So. It requires knowledge of XB argument processing, which is harder than VDP access. 

 

Hope this adds to the idea pool!

 

Share this post


Link to post
Share on other sites

Thanks for the ideas!  I think it's definitely worth considering how contemporary tools imply big changes for how we think about TI game development, XB or otherwise. 

 

Just given that it is relatively trivial to rapidly generate VDP assets, in the present day. 

 

And so this makes certain types of game which would have been extremely arduous to create, at one point in time, some of the easiest to create, now. 

 

A Myst-clone (slideshow) style adventure, for example.  Crazily arduous to develop graphical assets for, using original era tools.  Pretty easy, in the days of Magellan and Convert9918. 

 

A TIPI mouse driver for XB is another thing that encourages thinking differently about what genres and designs the platform might now encourage, which once it didn't so much, and gestures in the direction of point and click graphical adventure games.

Share this post


Link to post
Share on other sites
On 12/14/2020 at 2:19 PM, pixelpedant said:

XB256 implements VWRITE and VREAD as CALL LINKs for reading and writing to VDP memory. 

 

This is very nice, and more appealing to me than Mini Memory's PEEKV and POKEV since you can work with large volumes of byte data as strings. 

 

My question is, does anyone have a minimal implementation of at least this VDP write behaviour as a simple assembly subprogram?

 

Which is to say something like XB256's

 

CALL LINK("VWRITE",ADDRESS,STRING$)

 

This is specifically of interest to me since I've been doing a lot of playing with the Text-to-Speech disk's subroutines lately, and they mostly monopolise the lower 8K.  But there's space there still, or I can make some more by running the SETUP routine from high memory via HMLOADER, and/or skipping XLAT, which usually isn't necessary.  So something relatively lightweight isn't a problem.  But XB256 as a whole isn't an option. 

 

Plus, this just seems like a really fundamentally useful thing that somebody presumably implemented at some point (even if just for the sake of their own program). 

 

 

CALL LINK("VWRITE",address,string) is short and simple. (And VREAD as well) If you are thinking of doing this project in XB I can post the code for those.

  • Like 1

Share this post


Link to post
Share on other sites

This is some code I wrote to do the job. In 1988. It is mixed in with some 9938 command code for LINE and PSET and all the graphics modes including 80 column. I don't think XB likes that. But here is XB CALL LINK("WRITE", vaddr, string$). There is also a FILL in there.

 

I can't test it right now.

 

The key source. If there are undefineds, I have attached the whole file.

xbs

 DEF WRITE

FAC    EQU >834A
XMLLNK EQU >2018
CFI    EQU >12B8
NUMASG EQU >2008
NUMREF EQU >200C
STRASG EQU >2010
STRREF EQU >2014

VDPRD  EQU >8800
VDPSTA EQU >8802
VDPWD  EQU >8C00
VDPWA  EQU >8C02


* CALL LINK("WRITE", vaddr, string)
WRITE
 LIMI 0
 MOV  R11,R12
* Get argument 1, a number
 LI   R1,1
 BL   @GET
 MOV  R0,R3
* Get argument 2, a string
 BL   @GET$
 MOV  R2,R2
 JEQ  WRT
 MOV  R3,R0
 BLWP @VMBW
WRT
 BL   @SETB0
 B    *R12

* STRREF, R1=STRBUF R2=LEN
GET$
 CLR  R0
 LI   R2,STRBUF
 SETO *R2
 BLWP @STRREF
 MOV  R2,R1
 MOVB *R1+,R2
 SRL  R2,8
 RT

GET
 CLR  R0
 BLWP @NUMREF
 BLWP @XMLLNK
 DATA CFI
 MOV  @FAC,R0
 INC  R1
 RT

VMBW   DATA VWS,V4
V4
 LIMI 0
 MOV  *R13,R0
 BL   @WRV
 MOV  @2(R13),R1
 MOV  @4(R13),R2
 JEQ  V4X
V4A
 MOVB *R1+,@VDPWD
 DEC  R2
 JNE  V4A
V4X
 RTWP

VWTR   DATA VWS,V5
V5
 LIMI 0
 MOV  *R13,R0
 ORI  R0,>8000
 SWPB R0
 MOVB R0,@VDPWA
 SWPB R0
 MOVB R0,@VDPWA
 RTWP

SETB0
 LI   R0,>0E00
 BLWP @VWTR
 RT

 

  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, pixelpedant said:

A Myst-clone (slideshow) style adventure, for example.  Crazily arduous to develop graphical assets for, using original era tools.  Pretty easy, in the days of Magellan and Convert9918. 

I don't agree. Drawing a few characters and sprites for a homebrew game is doable for a single developer. Drawing new graphics on a larger scale is still a huge task. Unless you convert existing graphics, which can still be a big task, but then you run into issues with copyright and credits.

  • Like 1

Share this post


Link to post
Share on other sites
 4112            ************************************************************
  4113                
  4114 7FC0              AORG >7FC0   
  4116                
  4117            * (VDP to RAM) >834C=ADDR1,>8350=ADDR2,>834E=BCNT1  
  4118            * Move data from VDP to ERAM  
  4119            * @ADDR1 : Source address where the data stored on VDP  
  4120            * @ADDR2 : Destination address on ERAM  
  4121            * @BCNT1 : byte count   
  4122                
  4123      7FC0  VGWITE EQU  $   
  4124 7FC0 D7E0         MOVB @ADDR11,*R15      LSB of VDP address  
       7FC2 834D  
  4125 7FC4 C0A0         MOV  @ADDR2,R2         Address in ERAM   
       7FC6 8350  
  4126 7FC8 D7E0         MOVB @ADDR1,*R15       MSB of VDP address  
       7FCA 834C  
  4127 7FCC 1000         NOP  
  4128 7FCE DCA0  VGZ1   MOVB @XVDPRD,*R2+      Move a byte   
       7FD0 8800  
  4129 7FD2 0620         DEC  @BCNT1            One less to move  
       7FD4 834E  
  4130 7FD6 16FB         JNE  VGZ1              If not done, loop for more  
  4131 7FD8 045B         RT                     Return  
  4132            ************************************************************
1 hour ago, senior_falcon said:

CALL LINK("VWRITE",address,string) is short and simple. (And VREAD as well) If you are thinking of doing this project in XB I can post the code for those.

You are talking about using the XB ROMs or using your own routines?

Edited by RXB
comment added

Share this post


Link to post
Share on other sites
1 hour ago, Asmusr said:

I don't agree. Drawing a few characters and sprites for a homebrew game is doable for a single developer. Drawing new graphics on a larger scale is still a huge task. Unless you convert existing graphics, which can still be a big task, but then you run into issues with copyright and credits.

Oh, indeed, art doesn't create itself.  But having a pretty much immediate route from Photoshop/Illustrator to 9918A bitmap graphics certainly is a tantalising reality, when it comes to certain fairly specific categories of game, and of game art which can benefit from this approach. 

 

And I have a personal bias which feeds my interest in this reality.  After the TI-99, I think I'm most nostalgic about the early CD-ROM era.  Because it created so much bizarre, idiosyncratic, and wildly varied outsider art on the back of the newfound reality that there was a cheap and widely supported medium (and sufficient supporting technologies) for distributing large volumes of more or less platform-agnostic image and/or video clip content as game media.  With HyperCard and Macromedia Director games feeding into the phenomenon. 

 

Suddenly, here were are in 2020 (well, not for long), and playing video clips on a TI-99 and conveniently converting generic popular image formats for use on the TI-99 is a viable reality. 

 

Most of the time, I come back to the TI-99/4A precisely because a platform whose art styles are more so dictated and motivated by specific hardware parameters has a natural appeal.  But an avenue (however limited) into the exact opposite category of game art, which makes the dangerous and somewhat dubious assumption that (with the right algorithms) the 9918A's bitmap mode can be treated as if it were a straightforward colour bitmap mode - I find that rather tantalising. 

 

Share this post


Link to post
Share on other sites

This is from XB256. I haven't tested to see that everything is there. I think it is, but there might be unresolved references or missing code.

	DEF VWRITE
	DEF VREAD

NUMREF	EQU >200C
XMLLNK	EQU >2018
ERR	EQU >2034
VMBW	EQU >2024
VMBR	EQU >202C
STRREF	EQU >2014
STRASG	EQU >2010


GETNUM  INC R1 
GETNU1	CLR R0
	BLWP @NUMREF  
	BLWP @XMLLNK
	DATA >12B8		CFI
	C @>834A,*R11+
	JLT GTNERR
	C @>834A,*R11+
	JGT GTNERR
	B *R11  
	
GTNERR	LI R0,>1E00
	BLWP @ERR

VWRITE LWPI WKSP  
	MOV @>8312,R8  
	SRL R8,8  
	CLR R1  
VWRIT1	BL @GETNUM  
	DATA 0
	DATA >3FFF
	MOV @>834A,R9  		address into r9
	INC R1  
	LI R2,BUFFER
	SETO *R2  
	BLWP @STRREF  		get the string
	MOV R1,R7  
	MOV R2,R1  
	MOVB *R1+,R2  
	SRL R2,8 		length to r2 
	MOV R9,R0  		VDP addr. to r0	
	BLWP @VMBW  		write it
	C R7,R8  
	JHE BK2XB	
	MOV R7,R1  
	JMP VWRIT1	

VREAD  	LWPI WKSP  
	MOV @>8312,R8  
	SRL R8,8  		# arguments in r8
	CLR R1  
VREAD1	BL @GETNUM 
	DATA 0
	DATA >3FFF
	MOV @>834A,R9  
	BL @GETNUM 
	DATA 1
	DATA 255
	MOV @>834A,R2  
	MOV R9,R0  
	MOV R1,R7  
	LI R1,BUFFER  
	MOVB @>834B,*R1+  
	BLWP @VMBR
	CLR R0  
	MOV R7,R1  
	INC R1  
	LI R2,BUFFER
	BLWP @STRASG
	C R1,R8  
	JLT VREAD1	
	
BK2XB 	LWPI >83E0  
	B @>006A  

BUFFER	BSS 256
WKSP	BSS 32

 

  • Like 4

Share this post


Link to post
Share on other sites

Awesome.  Thanks so much.  And for all your work in empowering XB programmers. 

 

That is indeed doing the trick as a lightweight implementation of VREAD and VWRITE in XB, based on the expected (XB256-equivalent) functionality, compiled as follows. 

 

VDPRW

 

Such that the following has the expected observed effect:

 

image.thumb.png.dede25ed84b50fd28c49d81b112e9088.png

 

Description of VREAD and VWRITE from the XB256 manual being (for the sake of completeness):

 

CALL LINK(“VREAD”, memory address, # bytes, string[ , . . .])
VREAD reads the specified number of bytes from the VDP ram into a string variable of up
to 255 bytes. Up to 5 strings can read with one call to VREAD.


CALL LINK (“VWRITE”,memory address, string[ , . . .])
VWRITE writes a string to the VDP ram starting at the specified memory address. Up to 8
strings can be written with one call to VWRITE.

 

  • Like 2

Share this post


Link to post
Share on other sites
On 12/15/2020 at 4:47 PM, Lee Stewart said:

I presume that STRING$ is an XB string, meaning that it resides in VRAM, and that ADDRESS is also in VRAM, so that implementing the above VWRITE routine is actually moving a string from one VRAM location to another. If so, there are a couple of ways to do this. One is much more “lightweight” than the other. The light one would require only 50 – 60 bytes beyond the CALL overhead. The heavy one, which should be a good bit faster (unless the CALL overwhelms its time), would require an additional 256-byte RAM buffer to hold the largest possible XB string. I will probably attempt both routines just for grins, but do you have a preference?           ...lee

 

A couple of other folks beat me to the buffered VWRITE. I will still do the unbuffered routine [unless someone beats me to it 🙂], which requires carnal knowledge of XB’s CALL LINK(). Here is how TI Forth and fbForth do a VRAM-to-VRAM  unbuffered copy:

*
** necessary EQUates
*
UTILWS EQU  >????       ; set to an appropriate workspace address
VDPRD  EQU  >8800       ; VRAM read data register
VDPWD  EQU  >8C00       ; VRAM write data register
VDPWA  EQU  >8C02       ; VRAM write address register
*
** VRAM-to-VRAM unbuffered move 
**    R0: count
**    R1: VRAM source
**    R2: VRAM destination
*
VMOVE  DATA UTILWS,VMOVEN        ; VMOVE vector for BLWP

VMOVEN                           ; VMOVE entry point
       LIMI 0
       MOV  *R13,R1              ; get count to R1
       MOV  @2(R13),R2           ; get VRAM source to R2
       MOV  @4(R13),R3           ; get VRAM destination to R3
       ORI  R3,>4000             ; prepare for VDP write

** copy count bytes from VRAM source to VRAM destination
VMVMOR MOVB @UTILWS+5,@VDPWA     ; write LSB of VDP read address
       MOVB R2,@VDPWA            ; write MSB of VDP read address
       INC  R2                   ; next VDP read address
       MOVB @VDPRD,R0            ; read VDP byte
       MOVB @UTILWS+7,@VDPWA     ; write LSB of VDP write address
       MOVB R3,@VDPWA            ; write MSB of VDP write address
       INC  R3                   ; next VDP write address
       MOVB R0,@VDPWD            ; write VDP byte
       DEC  R1                   ; decrement count
       JNE  VMVMOR               ; repeat if not done
       RTWP                      ; return to calling program

This will need to be BLWPed from the CALLed routine, which should be pretty small.

 

...lee

  • Like 1

Share this post


Link to post
Share on other sites

You have glossed over an important detail. If 10 A$="hello world" then where in the VDP memory is "hello world"? You cannot move it unless you know where it is.

Share this post


Link to post
Share on other sites
31 minutes ago, senior_falcon said:

You have glossed over an important detail. If 10 A$="hello world" then where in the VDP memory is "hello world"? You cannot move it unless you know where it is.

 

I guess I was not very clear. I really have not glossed over that important detail because I have not yet written the routine to be CALLed from XB. That routine (VWRITU, perhaps) will get the location of said string from the passed argument list as it will the VRAM destination address. It just will not copy it to a RAM buffer as STRREF does. The routine I shared is the one that VWRITU will call.

 

...lee

Share this post


Link to post
Share on other sites
1 hour ago, senior_falcon said:

You have glossed over an important detail. If 10 A$="hello world" then where in the VDP memory is "hello world"? You cannot move it unless you know where it is.

Just so you know RXB 2020 shows with SIZE where the first free memory is in VDP and RAM along with Lower 8K.

If you type in A$="Hello World" and then SIZE it shows the First Free address is in VDP and that would be address of string A$

then Length byte then that string ending in a >0B

Use Classic99 debugger to look at VDP from SIZE says >37CD and there is that string.

Type in B$="Goodbye Word" and it shows less memory and >37C3 and always shows end of that string as the address.

So it always shows the last address used and Free.

Might be a useful tool.

Share this post


Link to post
Share on other sites
18 hours ago, Lee Stewart said:

 

I guess I was not very clear. I really have not glossed over that important detail because I have not yet written the routine to be CALLed from XB. That routine (VWRITU, perhaps) will get the location of said string from the passed argument list as it will the VRAM destination address. It just will not copy it to a RAM buffer as STRREF does. The routine I shared is the one that VWRITU will call.

 

...lee

You will probably use STRREF as the starting point for your code. You will be surprised to see how inefficient XB STRREF is. They could have set up the address to read from, then done a standard loop like this:

LOOP  MOVB @>8800,*R1+

          DEC R2

          JNE LOOP

 

Instead there is a sub to set the address for every read:

  SWPB R3  
  MOVB R3,@>8C02  
  SWPB R3  
  MOVB R3,@>8C02  
  NOP 
  MOVB @>8800,R1  
  B *R11

And after returning R1 is stored in the buffer.

 

After seeing I feel better about some of the sloppy code I write.

  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, senior_falcon said:

You will probably use STRREF as the starting point for your code. You will be surprised to see how inefficient XB STRREF is.

 

No, I will be using the pointers XB uses in scratchpad RAM. Like I said, it requires carnal knowledge of CALL LINK()’s innards. I just need to grab the time to write it and test it. Soon....

 

...lee

  • Like 2

Share this post


Link to post
Share on other sites

I found a way to modify STRREF to eliminate the slow subroutine at >2406. Here are the pertinent lines of code currently:

H239C MOV R6,R3

          SRL R1,8

          MOV R1,R5                change to MOV R1,R2    (number of bytes to move)

H23A2 BL @H2406

          MOVB R1,*R0+

          INC R3                     MOV R0,R1       H24AE   MOVB @>8800,*R1+   (this is part of VMBR)

          DEC R5                    B @H24B2        ----->   DEC R2

          JGT H23A2                                                   JNE H24AE 

          RTWP                                                           RTWP

Then the sub is:

H2406 SWPB R3

          MOVB R3,@>8C02

          SWPB R3

          MOVB R3,@>8C02

          JMP H2414

          MOVB @>8800,R1

          B *R11

 

You can see that once the loop has started there are only 3 instructions to move a byte vs. 12 instructions. That should really speed things up, right?

Not so much, as it turns out.

It takes 37 seconds to read a 255 byte long string 500 times in XB

It takes 25 seconds to read a 255 byte long string 500 times with the modified routine.

This is the best case scenario. Most strings will be less than 255 bytes long, and of course you would want to do something with the string after reading it to the buffer. So in the real world you would probably not see any detectable improvement.

  • Like 1

Share this post


Link to post
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.

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...