Jump to content
matthew180

Assembly on the 99/4A

Recommended Posts

3 minutes ago, senior_falcon said:

VSBW, VSBR, VMBW, VMBR, VWTR are all there and can be used as usual. NUMASG, NUMREF, STRASG, STREF cannot work. They were written to pass values to and from an XB program. They would have no idea where the strings and numbers are kept in a compiled program. Since everything is integer, CFI and CIF have no purpose and are simply bypassed.

 

Got it. Thanks for the info.

  • Like 1

Share this post


Link to post
Share on other sites

TI-Net BBS took advantage of this.

 

The LOAD program is made with SYSTEX (Barry Boone) and it fills up the low memory with object code. Then it chains to BBS. 

It can chain to “Doors” programs (that is, games). When the game exits, it hangs up and runs BBS again. Assembly routines are only loaded one time. 
 


 


 

 

  • Like 2

Share this post


Link to post
Share on other sites
29 minutes ago, Vorticon said:

Got it. Thanks for the info.

I should add that this is totally transparent to the user. When you test the program in XB you can use any of the assembly support utilities as desired. When it's time to compile there is a utility called FIXAL that modifies the assembly support routines so they will work with the compiler.

If you use XB 2.8 G.E.M. you will find that loading the assembly routines for testing happens 20X faster

  • Like 2

Share this post


Link to post
Share on other sites

It has been years since I looked at it, but I seem to recall that you can force XB to use high memory (A000-FFFF) for assembly and low memory (2000-3FFF) plus VRAM for XBASIC code.  It takes some effort and probably breaks a few things.

Share this post


Link to post
Share on other sites
4 minutes ago, Jeff White said:

It has been years since I looked at it, but I seem to recall that you can force XB to use high memory (A000-FFFF) for assembly and low memory (2000-3FFF) plus VRAM for XBASIC code.  It takes some effort and probably breaks a few things.

You can AORG an ALC program into high memory, but it will have to coexist with the XB program. I am not aware you could force XB into low memory but I might be wrong there. Besides, since the idea to mix XB and assembly is to avoid the tediousness of pure assembly for complex tasks while delegating features not available in XB or too slow to assembly, restricting XB to the lower 8K would likely be too restrictive for most projects...

Share this post


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

You can AORG an ALC program into high memory, but it will have to coexist with the XB program. I am not aware you could force XB into low memory but I might be wrong there. Besides, since the idea to mix XB and assembly is to avoid the tediousness of pure assembly for complex tasks while delegating features not available in XB or too slow to assembly, restricting XB to the lower 8K would likely be too restrictive for most projects...

Actually, with some cleverness there is a great deal of flexibility in where XB can put programs. For example:

CALL INIT::CALL LOAD(-31868,0,0,0,0) Type SIZE and you'll see that the memory expansion is turned off and XB will run completely from VDP ram. But CALL LOAD didn't get the message, so you can still poke values wherever you want. Or you can CALL LOAD an object file anywhere in the memory expansion. You'll need to AORG the code to high memory, but you can use all 32K for assembly, plus about 12K for the XB program in VDP.

 

Since you can put the XB program into 12K of VDP ram, it wouldn't make much sense to put it in the 8K low memory.

 

If 24K is not large enough for your XB program, you can split the program between high and low memory and use all 32K for an XB program. In the Game Developer's Package there is a file called XB32K.OBJ which lets you do just that.

 

HMLOADER lets you embed assembly routines in an XB program and run them from high memory. This makes a neat, self contained package that contains everything in one program.

 

  • Like 1

Share this post


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

Actually, with some cleverness there is a great deal of flexibility in where XB can put programs. For example:

CALL INIT::CALL LOAD(-31868,0,0,0,0) Type SIZE and you'll see that the memory expansion is turned off and XB will run completely from VDP ram. But CALL LOAD didn't get the message, so you can still poke values wherever you want. Or you can CALL LOAD an object file anywhere in the memory expansion. You'll need to AORG the code to high memory, but you can use all 32K for assembly, plus about 12K for the XB program in VDP.

 

Since you can put the XB program into 12K of VDP ram, it wouldn't make much sense to put it in the 8K low memory.

 

If 24K is not large enough for your XB program, you can split the program between high and low memory and use all 32K for an XB program. In the Game Developer's Package there is a file called XB32K.OBJ which lets you do just that.

 

HMLOADER lets you embed assembly routines in an XB program and run them from high memory. This makes a neat, self contained package that contains everything in one program.

 

This is the realm of black magic! I am only but a poor accolyte...

 

Share this post


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

Actually, with some cleverness there is a great deal of flexibility in where XB can put programs. For example:

CALL INIT::CALL LOAD(-31868,0,0,0,0) Type SIZE and you'll see that the memory expansion is turned off and XB will run completely from VDP ram. But CALL LOAD didn't get the message, so you can still poke values wherever you want. Or you can CALL LOAD an object file anywhere in the memory expansion. You'll need to AORG the code to high memory, but you can use all 32K for assembly, plus about 12K for the XB program in VDP.

 

Since you can put the XB program into 12K of VDP ram, it wouldn't make much sense to put it in the 8K low memory.

 

If 24K is not large enough for your XB program, you can split the program between high and low memory and use all 32K for an XB program. In the Game Developer's Package there is a file called XB32K.OBJ which lets you do just that.

 

HMLOADER lets you embed assembly routines in an XB program and run them from high memory. This makes a neat, self contained package that contains everything in one program.

 

I think that CALL LOAD is just clearing the values for first free address (FFA) and last free address (LFA) of 24K to make it “disappear”.  I am pretty sure that I was able to point the FFA and LFA using values in the range 2000-3FFF and manipulated some other values to CALL LOAD object code into 24K without using AORG.  I had limited success.

 

It made sense to do it at the time.

 

I could be misremembering.  

Share this post


Link to post
Share on other sites
23 hours ago, Vorticon said:

You can AORG an ALC program into high memory, but it will have to coexist with the XB program. I am not aware you could force XB into low memory but I might be wrong there. Besides, since the idea to mix XB and assembly is to avoid the tediousness of pure assembly for complex tasks while delegating features not available in XB or too slow to assembly, restricting XB to the lower 8K would likely be too restrictive for most projects...

Check out RXB 2020 it has

CALL PRAM(start low memory address, end high memory address) ! for XB programs in upper 24K where XB programs reside

CALL VDPSTACK(VDP stack memory location) ! for XB  to change location of VDP Stack in VDP so changes VDP RAM use and control

CALL PLOAD(memory address boundary ,"DSK#.filename") ! will load at any 32K location 4K file into memory (i.e. example >B000 )

CALL SAMS(memory address boundary , page number) ! changes SAMS page number at boundary address (i.e. example >A000)

 

  • Like 1

Share this post


Link to post
Share on other sites

Hi. Does anyone know if the CFI function (XMLLNK) trashes R5? It seems to be the case but I want to make sure. There is no mention of that in the EA manual...

Share this post


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

Hi. Does anyone know if the CFI function (XMLLNK) trashes R5? It seems to be the case but I want to make sure. There is no mention of that in the EA manual...

 

Not unless you are using FAC as your workspace. When you

       BLWP @XMLLNK
       DATA >1200

the workspace is changed to >2094. The return is then changed to the instruction following the DATA directive and the workspace is again changed to the GPLWS (>83E0) before BLing to the CFI routine. After CFI returns, the workspace is reverted to >2094 and the RTWP, of course, reverts to your workspace, continuing execution with the instruction following the DATA directive. No register in your workspace is touched unless it overlaps FAC, >2094, or GPLWS.

 

...lee

  • Like 1

Share this post


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

 

Not unless you are using FAC as your workspace. When you


       BLWP @XMLLNK
       DATA >1200

the workspace is changed to >2094. The return is then changed to the instruction following the DATA directive and the workspace is again changed to the GPLWS (>83E0) before BLing to the CFI routine. After CFI returns, the workspace is reverted to >2094 and the RTWP, of course, reverts to your workspace, continuing execution with the instruction following the DATA directive. No register in your workspace is touched unless it overlaps FAC, >2094, or GPLWS.

 

...lee

Well, I have this nasty habit of not creating my own workspace and just using the default registers, so I don't think that's it...

I really should stop doing that regardless 😄

In the mean time, I just replaced R5 with a different register until I figure this out. I would never have guessef was it not for the Classic99 debugger...

Share this post


Link to post
Share on other sites

I'm working on a mixed XB and assembly project. Below is an excerpt of an ALC routine called from XB. It worked fine without using a dedicated user space. But when I added the LWPI instruction it crashed. I have never bothered to create my own register user space in the past (I know, heresy...) but that's been causing issues here with the XB assembly support utilities which seem to modify certain registers when used. Any hints?

 

       DEF  RSTMAP,UPDMAP,WINDOW,MODMAP
       DEF  ADDUNT
	   
VMBW   EQU  >2024
NUMREF EQU  >200C
XMLLNK EQU  >2018
CFI    EQU  >12B8
FAC    EQU  >834A
WSPREG EQU  >8300
RETADR BSS  8

RSTMAP MOV  R11,@RETADR
       MOV  R13,@RETADR+2
       MOV  R14,@RETADR+4
       MOV  R15,@RETADR+6
       LWPI WSPREG
       CLR  @MAPPTR
       MOV  @RETADR,R11
       MOV  @RETADR+2,R13
       MOV  @RETADR+4,R14
       MOV  @RETADR+6,R15
       RT
etc...

 

  • Like 1

Share this post


Link to post
Share on other sites
24 minutes ago, Vorticon said:

I'm working on a mixed XB and assembly project. Below is an excerpt of an ALC routine called from XB. It worked fine without using a dedicated user space. But when I added the LWPI instruction it crashed. I have never bothered to create my own register user space in the past (I know, heresy...) but that's been causing issues here with the XB assembly support utilities which seem to modify certain registers when used. Any hints?

 


       DEF  RSTMAP,UPDMAP,WINDOW,MODMAP
       DEF  ADDUNT
	   
VMBW   EQU  >2024
NUMREF EQU  >200C
XMLLNK EQU  >2018
CFI    EQU  >12B8
FAC    EQU  >834A
WSPREG EQU  >8300
RETADR BSS  8

RSTMAP MOV  R11,@RETADR
       MOV  R13,@RETADR+2
       MOV  R14,@RETADR+4
       MOV  R15,@RETADR+6
       LWPI WSPREG
       CLR  @MAPPTR
       MOV  @RETADR,R11
       MOV  @RETADR+2,R13
       MOV  @RETADR+4,R14
       MOV  @RETADR+6,R15
       RT
etc...

How about changing

 

WSPREG EQU >8300 

 

to

 

WSPREG BSS 32

 

That way, you create the workspace within your code.  I think that works with XB assembly, but not 100% certain.

 

 

 

Share this post


Link to post
Share on other sites

The problem with this is that it slows things down quite a bit. It's recommended to keep the user space in the scratchpad RAM for maximum performance.

Share this post


Link to post
Share on other sites

I believe XB drops you into a shared WP.

 

You can use your own workspace but you need to restore it before returning from your code. 

 

There is STWP, I don't remember if that has general addressing or must go to a "register". If necessary move it to a well known address so you can get at it later.

 

Then before return the only way I could figure out was to MOV the desired return WS address into the parameter address of the LWPI code.. 

 

  mov @wpstash, @8(WPRT)

WPRT LWPI >0000 ; dummy value for assembler

  rt

 

 

something like that... Or, use a BLWP to get to your code that wants its own WP, and return from it with RTWP

  • Like 2

Share this post


Link to post
Share on other sites

Your example is nearly implementing BLWP and RTWP except it is missing the part that restores WP. I'd just use the actual instructions... 

  • Like 3

Share this post


Link to post
Share on other sites
32 minutes ago, Vorticon said:

The problem with this is that it slows things down quite a bit. It's recommended to keep the user space in the scratchpad RAM for maximum performance.

There are not a lot of safe places in the scratchpad ram when doing CALL LINK. When LINK is performed, it starts with the GPLWS at >83E0. You can use some of this workspace. R0 to maybe R10.  Other places might be OK for a workspace if you store the contents and restore them. But using STRREF, NUMASG, etc might interfere with that.

Remember, you are interfacing with Extended BASIC which is not exactly a speed demon. Even the most poorly written assembly code will give stellar performance compared to XB.

  • Like 3

Share this post


Link to post
Share on other sites
On 6/28/2021 at 4:04 PM, Jeff White said:

It has been years since I looked at it, but I seem to recall that you can force XB to use high memory (A000-FFFF) for assembly and low memory (2000-3FFF) plus VRAM for XBASIC code.  It takes some effort and probably breaks a few things.

RXB 2020 has this built in using CALL PRAM(address-low,address-high) for location of XB program space.

And CALL VDPSTACK(address) for location of VDP STACK ADDRESS.

Also CALL PLOAD(address-boundry,"DSK#.FILENAME") for loading memory image 4K sized files into any area of memory in 32K.

This works like CALL SAMS(address-boundry,RAM-page) for address of RAM and what page to use.

 

And no RXB did not break anything in the process.

  • Like 1

Share this post


Link to post
Share on other sites

I think I'm just going to forgo setting up my own user space in the context of XB and ALC. Seems like more trouble than it's worth. It works fine without it as long as I am careful about my register use choices.

Thanks for the pointers guys.

 

  • Like 3

Share this post


Link to post
Share on other sites

I'm not sure I understand what's going on here...

MOV	@WORKSV,@$+8	; this writes WP into next instruction, first param, as though it was literal
LWPI	>AAAA

Aren't you overwriting the recovered WP address with >AAAA?

Share this post


Link to post
Share on other sites

The assembler produces the LWPI >AAAA instruction, which is 2 words in the binary. But at runtime, the MOV before it rewrites that instruction for the desired value of the immediate operand. 

 

That move instruction is using @$ which in xas99 is the address of the current instruction. So +8 gets the address of the parameter to LWPI. 

  • Like 1

Share this post


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

I'm not sure I understand what's going on here...


MOV	@WORKSV,@$+8	; this writes WP into next instruction, first param, as though it was literal
LWPI	>AAAA

Aren't you overwriting the recovered WP address with >AAAA?

 

No. It is quite the other way around. This is self-modifying code that replaces the placeholder, >AAAA, with the contents of WORKSV at execution time.

 

...lee

  • Like 5

Share this post


Link to post
Share on other sites

I checked my BBS assembly code (just to be sure I was remembering correctly) and I am using GPLWS >83E0 registers for many of the routines, including those that pass parameters via CALL LINK.  If I need to BL to another routine, I save R11 then restore prior to exiting to XB.  I also save R12 if I modify it, though it probably isn't necessary. 

 

One of my go-to references is the Millers Graphics "The Smart Programmer", August 1986, which contains a comprehensive overview of XB scratchpad usage. [MG also published VDP RAM and CPU ram and scratchpad ram usage for XB/EA/MiniMem, in other issues].

 

The snip below details the >83E0 workspace bytes; the keyscan and interrupt routines use some of the registers, meaning you may want to disable interrupts (LIMI 0) and/or account for any potential changes to registers. 

 

image.thumb.png.774ba253b602fb304ff919cd9c56b795.png

 

Note: the typical DSRLNK routine starts (and in some cases the peripheral DSR expects) execution of the DSR ROM routines with the workspace pointer set to >83E0, so it is usually best to set up your own workspace in some manner when calling IO routines.

 

 

  • Like 3

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