Jump to content
IGNORED

Can you help me with ASM?


Sergioz82

Recommended Posts

Hello, 

I'm working on my first game entirely in ASM and I'm using Compute's! Beginner's Guide to Assembly Language.

 

It's nothing innovative, just your everyday Pacman clone, however I think I need to work first on something tried and tested by generations of programmers before dedicating myself to the games I have in mind.

I've already set up a labyrinth, the ghosts and the Pacman which can also eat the pills, however I'm kinda stuck at making the sprites detect walls and act accordingly.  I found the source code for Munch Man and it gave me some enlightenment but I can't figure out how the programmers implemented the detection. 

 

So my question is: how can I do it? 

My idea is: since I already have a routine to read the character under the sprite (for eating the pill) I could also use it to check a character ahead the one the sprite is on according to the direction.. however, even if I can't figure it out I've got the suspect that Munch Man uses something more efficient in terms of lines of code and the theory behind.  

 

Thanks in advance.

 

PS: the sprites have a 2X magnification, in collision detection between Pacman and ghosts I already keep it into account (add 16 pixels for boundaries, I suppose I'll have to do the same with wall collision.

  • Like 2
Link to comment
Share on other sites

I'm not saying this would be the most efficient, etc, but if you are in a graphics mode, read the graphics data at the point of interest in the direction of travel and test the color if the walls are of a different color from other items.

 

 

  • Like 2
Link to comment
Share on other sites

Some ideas that I have used. 

Disclaimer: I do this in Forth but the ideas are the same for Assembly Language. Someone here will no doubt school me on things. :)

 

 

To convert a pixel coordinate to a character coordinate you divide the pixel value in a register by 8. This is best done using a shift right instruction.

* with pixel value in R1 we can divide by 8 like this
* Each bit shift right divides by 2. So shifting 3 bits divides by 8 

     SRA R1,3    

 

Conversely to convert a character coordinate to a pixel coordinate, multiply by 8 by using a shift left instruction     

* With a character coordinate in R2, multiply by 8 like this

            SLA R2,3

With this knowledge you can convert to the appropriate units and compare graphics coords. to pixels coords. 

 

---

You get the sprite's coordinates by reading the data from the sprite attribute table.

IMPORTANT: This table is in VDP RAM so you have to read the bytes with VSBR and write bytes with VSBW

My setup has the table at VDP address >300. Yours may be set to some other location.  VDP register settings in your program startup code determine this.

 

There are 4 bytes in the table for each sprite:

col,row,char,color

So to get the column location (in pixels) of sprite #0 

  • read the byte at >300 (with BLWP @VSBR)
  • Read the row location at >301
  • The ASCII character at >302 
  • and the color at >303.

 

To get the 4 byte location in the table, of any sprite, you can take the sprite# (option base 0)  and multiply by 4  (just use SLA R?,2) :)

and add the result to the base address of the sprite attribute table. 

 

 

Hope that helps and also I hope I didn't tell you things you already knew.

 

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

Sprite to character collision detection is a pain in the butt. ;)

 

You do have an advantage on your side - you know that the characters are every 8 pixels. So if you check correctly on 8 pixel boundaries, you know you should be okay in-between them. You can simply read the joystick at 8 pixel boundaries for new motion, and continue moving between them. (Probably want to allow for instant reversal though).

 

A technique I see a lot of titles used is to choose collision points for a sprite, and just check those. For instance, you could just check the center pixel on each side of the character. If the pixel is in a wall, nudge the character out of it.

 

https://www.gamedeveloper.com/design/the-pac-man-dossier

 

Pac Man appears to use this technique, while continuing the previous direction until reaching the 8 pixel boundary (though it's hard to be sure - there's a LOT more written about the ghosts than the player). This allows the 'cornering' effect and suggests that the game checks and remembers x and y movement separately. It seems to be pretty robust, at least with the defined mazes!

 

 

 

Edited by Tursi
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

18 hours ago, Sergioz82 said:

My idea is: since I already have a routine to read the character under the sprite (for eating the pill) I could also use it to check a character ahead the one the sprite is on according to the direction.

That's what I would do, and it usually works very well as long as your walls fill out the characters. If you have corners with only a few pixels you want to skip those. So you need to arrange your characters to make it easy to know which numbers to check for. I don't think you need to worry about performance for this, since you only need to do it a few times every frame. But as mentioned, if you require 32K anyway, it's more efficient to check a map in CPU RAM/ROM than to check the VDP RAM. 

Edited by Asmusr
  • Thanks 1
Link to comment
Share on other sites

I don't think I would read the screen at all. Why not have a simple array in memory which represents the directions a sprite can move in. There would be one byte per screen location (though since you only need four bits, you could pack two locations into a single byte).

 

bit 0 = can move left

bit 1 = can move right

bit 2 = can move up

bit 3 = can move down

 

As the character moves eight pixels right (for example) you increase your array pointer by 1, read the array, and the value tells you which directions the character can move in. If the character is moving left, you decrease your array pointer by 1 and read. For moving up, decrease array pointer by 32, for down, increase array pointer by 32.

 

Something like that.:thumbsup:

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

It sounds like you're trying to save memory, but most likely you will have a copy of the map in CPU RAM/ROM already, and I don't see why checking an alternative representation would be easier or faster?

 

Also remember that a 16x16 sprite can partially cover up to 9 8x8 characters, so it's not always in one location, unless it can only change direction on 16 pixel boundaries. If you use the method to check characters in the direction you're moving, you need to check at least two points, e.g. top-left and bottom-left if you're moving left, or you could end up moving part of the sprite into a wall.   

Edited by Asmusr
  • Like 3
  • Thanks 1
Link to comment
Share on other sites

21 hours ago, 9640News said:

I'm not saying this would be the most efficient, etc, but if you are in a graphics mode, read the graphics data at the point of interest in the direction of travel and test the color if the walls are of a different color from other items.

 

 

At the moment I'm not  venturing into bitmap mode, however it's an interesting solution, I'll keep it in mind for the future.

 

@TheBF

I solved that part, however I keep forgetting that in ASM I can use register shifts so I used simple address pointers and increments to reach the various sprites but your solution seems better. 

 

@LostCause @Asmusr

Yes, using an array would save me a lot of calls to VDP routines. For the moment I'm not aiming to save memory so, why not!

 

@Tursi 

I really like your suggestion of checking the collision every 8 pixels. My idea instead was of doing it at each position increment and I already had doubts about aligning the sprite with the corridors (the player would have to make pixel-perfect turns). Your way will facilitate me a lot of things

 

 

@Willsy

This is another interesting suggestion

 

Thank you very much to all!

 

  • Like 6
Link to comment
Share on other sites

@Asmusr

 

I started in the 80`s with a Commodore Vic-20 and Atari 800XL. I have only been using the Classic99 Emulator for a few Months now and Assembly on the TI for maybe a couple weeks. So, I had to give this some thought.

 

After loading a VDP RAM Dump of Pacman in Magellan the only answer to your question I can come up with is simplicity. Pixel perfect collision on any system is ridiculously over complicated. Since Pacman moves in between the character grid checking any map in RAM seems like a lot of different characters to check collision against.

 

The array does not need to be based on 8x8 or 16x16 it can be anything as long as the horizontal and vertical distances are a multiple of some constant. The Pacman sprite is actually - 11x11. Slicing up the screen dimensions to create the array and using known offsets to position the sprites no actual sprite collision needs to be performed. Just increment the X or Y index to the array after the sprite has moved that constant distance check if the next index in the direction contains either a 0 or 1. if it contains a zero the sprite can continue or otherwise stop.
 

Edited by LostCause
  • Like 2
Link to comment
Share on other sites

  • 1 month later...

 

Hello, the development is going on but I got stuck with an apparently simple task.

Below it's the movement routine called with BLWP from the game loop.

 

A quick explanation: JREAD is the joystick read routine which puts into LASTI the input when it's not zero (only when game starts pacman has zero direction and stands still)

R5 and R6 contain the characters of pacman sprites (it's made of 2 sprites to give it some color) according to direction, the Jx labels do this: load new sprite pattern , load *R3 with the appropriate position increment (00FF,0100 etc).

R9 sets the offset for collision detection that must happen 16 pixels ahead whan going right and down.

MOVE does the temporary operation with offset for detecting the pattern of character in front of pacman.

If it's not a wall then the routine will update the sprites attributes in VDP.

 

My problem now is: how the hell do I tell it to change direction only each 16 pixels (sprites are 2x magnified)?I tried some solution: COC the position with 0F  and allow direction change only when it's true, set up a counter that counts up to 0F and allow direction change only when it's over and so on but each solution messes up with the movement. 

 

Second question: with the current code, when the pacman is going let's say right and it's going through a horizontal corridor, if the player moves up the pacman stops, instead I'd like it to keep going in the original direction, ignoring the input.

 

Can you guys help me? 

 

Thank you very much

 

 

Quote

TMPWP1 BSS 32                                                                   
MOVPAC DATA TMPWP1                                                              
       DATA ENTPT1                                                              
ENTPT1 LI R3,PACDIR                                                             
       MOV @PACYX+2,R5                                                          
       MOV @BANYX+2,R6                                                          
       CLR R9                                                                   
       BL @JREAD                                                                
       MOV @LASTI,R10                                                           
       CI R10,0                                                                 
       JEQ NOMOVE                                                               
J0     CI R10,SX                                                                
       JNE J1                                                                   
       MOV @DSX,*R3                                                             
       LI  R5,PSXA                                                              
       LI  R6,BANSX                                                             
       JMP MOVE                                                                 
J1     CI R10,DX                                                                
       JNE J2                                                                   
       MOV @DDX,*R3                                                             
       LI R9,>000F                                                              
       LI R5,PDXA                                                               
       LI R6,BANDX                                                              
       JMP MOVE                                                                 
J2     CI R10,SU                                                                
       JNE J3                                                                   
       MOV @DSU,*R3                                                             
       LI R5,PSUA                                                               
       LI R6,BANSU                                                              
       JMP MOVE                                                                 
J3     CI R10,GIU                                                               
       JNE MOVE                                                                 
       MOV @DGIU,*R3                                                            
       LI R9,>0F00                                                              
       LI R5,PGUA                                                               
       LI R6,BANGU                                                              
                                                                                
MOVE   MOV @PACYX,@TMPVAR                                                       
       AB *R3,@TMPVAR                                                           
       AB @1(R3),@TMPVAR+1                                                      
       MOV @TMPVAR,R4                                                           
       AB R9,@TMPVAR                                                            
       SWPB R9                                                                  
       AB R9,@TMPVAR+1                                                          
       BLWP @RDCHAR                                                             
       MOV @TMPVAR,R9                                                           
       CI R9,>1100                                                              
       JLT NOMOVE                                                               
                                                                                
       MOV R4,@PACYX                                                            
       MOV R4,@BANYX                                                            
       MOVB R5,@PACYX+2                                                         
       MOVB R6,@BANYX+2                                                         
       LI R7,>0500                                                              
       MOVB @PACYX+2,R6 *3 RIGHE PER CAMBIO CARATTERE                           
       XOR R6,R7                                                                
       MOVB R7,@PACYX+2                                                         
       LI R0,>0300                                                              
       LI R1,PACYX                                                              
       LI R2,8                                                                  
       BLWP @VMBW                                                               
NOMOVE RTWP          

 

Link to comment
Share on other sites

1 hour ago, Sergioz82 said:

My problem now is: how the hell do I tell it to change direction only each 16 pixels (sprites are 2x magnified)?I tried some solution: COC the position with 0F  and allow direction change only when it's true, set up a counter that counts up to 0F and allow direction change only when it's over and so on but each solution messes up with the movement. 

For the first issue, maybe you need to use CZC instead of COC? For the second issue, maybe you don't want to change the direction variables until you know that the passage is free? It would help us to understand the issue if you comment each line of your source.

  • Like 1
Link to comment
Share on other sites

2 hours ago, Sergioz82 said:

Hello, the development is going on but I got stuck with an apparently simple task.  

Below it's the movement routine called with BLWP from the game loop.

 

A quick explanation: JREAD is the joystick read routine which puts into LASTI the input when it's not zero (only when game starts pacman has zero direction and stands still)

R5 and R6 contain the characters of pacman sprites (it's made of 2 sprites to give it some color) according to direction, the Jx labels do this: load new sprite pattern , load *R3 with the appropriate position increment (00FF,0100 etc).

R9 sets the offset for collision detection that must happen 16 pixels ahead whan going right and down.

MOVE does the temporary operation with offset for detecting the pattern of character in front of pacman.

If it's not a wall then the routine will update the sprites attributes in VDP.

 

My problem now is: how the hell do I tell it to change direction only each 16 pixels (sprites are 2x magnified)?I tried some solution: COC the position with 0F  and allow direction change only when it's true, set up a counter that counts up to 0F and allow direction change only when it's over and so on but each solution messes up with the movement. 

 

Second question: with the current code, when the pacman is going let's say right and it's going through a horizontal corridor, if the player moves up the pacman stops, instead I'd like it to keep going in the original direction, ignoring the input.

 

Can you guys help me?          Thank you very much

 

As @Asmusr indicated, “Comments, please.”

 

Is it correct for me to presume that JREAD defines, via EQU, the constants (DX,SX,...) used in the “CI R10,...” instructions?

 

An aside: This code,

       MOV  @LASTI,R10
       CI   R10,0         <---unnecessary instruction
       JEQ  NOMOVE

does not need the CI instruction because the MOV will have already set the EQ status bit if the value copied to R10 was 0.

 

...lee

  • Like 2
Link to comment
Share on other sites

@Asmusr

I'll try CZC.
For the second question, I don't know how to implement this behavior: keep going and check collision forward, but if I change direction toward a wall check collision in the new direction then keep going to original direction.

Maybe I could store the original direction before the R10 check for joystick and switch back to this value if the path is blocked?

 

@Lee Stewart

 

Yes indeed, SX,DX etc.. are defined with EQU. Please see the commented code below.

 

Quote

does not need the CI instruction because the MOV will have already set the EQ status bit if the value copied to R10 was 0.

 

True! I keep forgetting that each operation alters the status register, I still think in terms of high level language, I just wanted to translate an IF instruction.

Thank you for the tip!

 

About the code, here's my comments:

 

First four lines set up the worskpace and registers for BLWP (I use labels because I compile with Relative option, so I leave the memory allocation to the compiler, I don't know what address is associated to labels)

 

Quote

TMPWP1 BSS 32                                                                   
MOVPAC DATA TMPWP1                                                              
       DATA ENTPT1                                                              
ENTPT1 LI R3,PACDIR                 R3 points to word with pacman direction (the increment I need).                                            
       MOV @PACYX+2,R5            2 lines: pre-load R5 and R6 with the character containing the actual pattern for representing the direction: face left, right, up and down.                                              
       MOV @BANYX+2,R6            PACYX and BANYX points to each sprite's position in attribute list. +2 for pointing to the character.                                              
       CLR R9                               I get sure 16 pixels offset for collision detection is 0 by default                                    
       BL @JREAD                         read joystick input. In the sub the value in LASTI is updated with the joystick position value only if such value is not zero                                       
       MOV @LASTI,R10                move the value in R10 for immediate comparison                                           
       CI R10,0                             If input is zero skip the routine (when game starts pacman stands still, @LASTI start value is zero)                                    
       JEQ NOMOVE                                                               
J0     CI R10,SX                         SX,DX,SU,GIU (left,right etc..) are constants, EQU to joystick values I get from @KSCAN                                       
       JNE J1                                                                   
       MOV @DSX,*R3                  DSX,DDX,DSU,DGIU contains the increment (0001 for right, 00FF for left, 0100 for down and FF00 for up).                                            
       LI  R5,PSXA                         for main sprite load the "face left-open mouth" character (PSXA, PDXA,BANSX,BANDX etc.. defined with EQU)
       LI  R6,BANSX                       for secondary sprite load the "face left" character                                    
       JMP MOVE                            ok, go to position update part
J1     CI R10,DX                                                                
       JNE J2                                                                   
       MOV @DDX,*R3                                                             
       LI R9,>000F                        J1,J2,J3 do the same things in J0, however in J1 and J3 I load in R9 the 16 pixels offset for right and down collision detection
       LI R5,PDXA                                                               
       LI R6,BANDX                                                              
       JMP MOVE                                                                 
J2     CI R10,SU                                                                
       JNE J3                                                                   
       MOV @DSU,*R3                                                             
       LI R5,PSUA                                                               
       LI R6,BANSU                                                              
       JMP MOVE                                                                 
J3     CI R10,GIU                                                               
       JNE MOVE                                                                 
       MOV @DGIU,*R3                                                            
       LI R9,>0F00                                                              
       LI R5,PGUA                                                               
       LI R6,BANGU                                                              
                                                                                
MOVE   MOV @PACYX,@TMPVAR   I copy the actual pacman position in a temporary variable for collision detection (characters, collision between sprites is managed in another routine)                                                    
       AB *R3,@TMPVAR                 *R3 is loaded with the increment, now I add Y value  (yy00)                                        
       AB @1(R3),@TMPVAR+1        add the X value (00xx)                                             
       MOV @TMPVAR,R4                 I store the updated position in R4                                          
       AB R9,@TMPVAR                    I add the potential Y offset, if zero nothing changes                                         
       SWPB R9                                                                  
       AB R9,@TMPVAR+1                I add the potential X offset, if zero nothing changes                                       
       BLWP @RDCHAR                    go to "read the character under the sprite" routine, for the moment I recycle TMPVAR, RDCHAR will get X and Y from it and then store in it the value of the detected character                                   
       MOV @TMPVAR,R9                 move the read value in register 9 for immediate comparison                                         
       CI R9,>1100                                                              
       JLT NOMOVE                          below 11 (pill character) there are the walls characters, so stop (this part will be expanded, will recognize energizers, bonus, replace H11 with H20 (space) when pacman eats the pill etc..                                                                                
       MOV R4,@PACYX                  2 lines:  ok I can move, copy the updated position to attributes of sprite 1 and 2 of pacman                                         
       MOV R4,@BANYX                                                            
       MOVB R5,@PACYX+2            2 lines: update the sprites character according to the direction                                             
       MOVB R6,@BANYX+2                                                         
       LI R7,>0500                        4 lines: with XOR I can swap each cycle the character of sprite 1 with open or close mouth                                      
       MOVB @PACYX+2,R6  
       XOR R6,R7                                                                
       MOVB R7,@PACYX+2                                                         
       LI R0,>0300                       4 lines: write in VDP the updated attributes for sprite 1 and 2.                                       
       LI R1,PACYX                                                              
       LI R2,8                                                                  
       BLWP @VMBW                                                               
NOMOVE RTWP

 

Edited by Sergioz82
  • Like 1
Link to comment
Share on other sites

For the first issue, would adding something like this at the top work?

        MOV @PACYX,R0   ; Get Y and X coordinates
        AI  R0,>0100    ; Normalize Y
        LI  R1,>0F0F    ; Mask for checking position
        CZC R1,R0       ; Check that X and Y are multiples of 16          
        JNE MOVE        ; Skip read joystick

In addition, I guess you also need to save the direction (R9) between calls to MOVPAC.

  • Like 1
Link to comment
Share on other sites

On 5/18/2022 at 2:15 PM, TheBF said:

Some ideas that I have used. 

Disclaimer: I do this in Forth but the ideas are the same for Assembly Language. Someone here will no doubt school me on things. :)

 

 

To convert a pixel coordinate to a character coordinate you divide the pixel value in a register by 8. This is best done using a shift right instruction.


* with pixel value in R1 we can divide by 8 like this
* Each bit shift right divides by 2. So shifting 3 bits divides by 8 

     SRA R1,3    

 

Conversely to convert a character coordinate to a pixel coordinate, multiply by 8 by using a shift left instruction     


* With a character coordinate in R2, multiply by 8 like this

            SLA R2,3

With this knowledge you can convert to the appropriate units and compare graphics coords. to pixels coords. 

 

---

You get the sprite's coordinates by reading the data from the sprite attribute table.

IMPORTANT: This table is in VDP RAM so you have to read the bytes with VSBR and write bytes with VSBW

My setup has the table at VDP address >300. Yours may be set to some other location.  VDP register settings in your program startup code determine this.

 

There are 4 bytes in the table for each sprite:


col,row,char,color

So to get the column location (in pixels) of sprite #0 

  • read the byte at >300 (with BLWP @VSBR)
  • Read the row location at >301
  • The ASCII character at >302 
  • and the color at >303.

 

To get the 4 byte location in the table, of any sprite, you can take the sprite# (option base 0)  and multiply by 4  (just use SLA R?,2) :)

and add the result to the base address of the sprite attribute table. 

 

 

Hope that helps and also I hope I didn't tell you things you already knew.

 

RXB 2022E has CALL COLLIDE and Lee Stewart helped me write the ROM 3 for it.

Here is the source if it helps:

Spoiler

************************************************************
       AORG >6000
       TITL 'RXB ROM3'
************************************************************
* EQUATES
BIAS   EQU  >6000
PAD    EQU  >8300       * TEMP
PAD1   EQU  >8301       * TEMP
PAD2   EQU  >8302       * VDP ADDRESS
PAD3   EQU  >8303       * TEMP
PAD4   EQU  >8304       * TEMP
PAD5   EQU  >8305       * TEMP
PAD6   EQU  >8306       * TEMP BUFFER FOR COINSP
PAD8   EQU  >8308       * SPRITE 1
PADA   EQU  >830A       * SPRITE 2
BYTES  EQU  >830C       * STRING LENGTH
SREF   EQU  >831C       * STRING POINTER
FAC    EQU  >834A       * RAM line buffer
FAC1   EQU  >834B       * GCHAR buffer
FAC4   EQU  >834E       * String Address
FAC6   EQU  >8350       * String Length
ARG    EQU  >835C       * ARGUMENT FOR ERRORS
STATUS EQU  >837C       * GPL STATUS BYTE
ISR    EQU  >83C4       * ISR INTERUPT HOOK
GR0LB  EQU  >83E1       * GPLWS R0 LSB
GR4LB  EQU  >83E9       * GPLWS R4 LSB
VDPRD  EQU  >8800       * VDP Read Data address
VDPWD  EQU  >8C00       * VDP Write Data address
************************************************************
* VDP EQUATES
VBUFF  EQU  >03C0       * line buffer in VRAM
************************************************************
UNUSED DATA >0000,>0000,>0000,>0000
       DATA >0000,>0000,>0000,>0000
******************************************************************
* XML table number 7 for RXB ROM3 - must have                    *
*     it's origin at >6010                                       *
******************************************************************
*             0     1     2     3     4     5     6
       DATA RROLL,LROLL,UROLL,DROLL,HCHAR,VCHAR,ASCHEX
*             7    8    9     A     B     C     D
       DATA HPUT,VPUT,CLEARP,>0000,>0000,>0000,>0000
*             E     F
       DATA ALPHA,CHRLDR
*****************************************************************
* XML table number 8 for RXB ROM3 - must have                   *
*     it's origin at >6030                                      *
*****************************************************************
*             0      1     2     3     4     5     6     7
       DATA COLLSP,>0000,>0000,>0000,>0000,>0000,>0000,>0000
*             8     9     A     B     C      D      E     F
       DATA >0000,>0000,>0000,CINIT,XISRON,XISROF,>0000,>0000
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Write VRAM address
*     Expects address in R0
*
* BL here for writing data
*
VWADD  ORI  R0,>4000    * set to write VRAM data
*
* BL here for reading data
*
VWADDA MOVB @GR0LB,*R15 * write LSB of R0 to VDPWA
       MOVB R0,*R15     * write MSB of R0 to VDPWA
       ANDI R0,>3FFF    * ensure R0 returned intact
       RT
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* The following utilities expect 
*     R0 = VRAM address of row
*     R1 = RAM buffer address
*
* R2 and R10 will be destroyed

* Copy 1 row of 32 bytes from VDP (R0) to RAM (R1)
*
VRROW  MOV  R11,R10   * save return
       BL   @VWADDA   * write out VDP read address
       LI   R2,32     * read 1 row
       LI   R8,VDPRD  * Register faster then address
VRROW1 MOVB *R8,*R1+  * read next VDP byte to RAM
       MOVB *R8,*R1+  * read next VDP byte to RAM
       DECT R2        * dec count by 2
       JNE  VRROW1    * repeat if not done
       B    *R10      * return to caller

* Copy 1 row of 32 bytes from RAM (R1) to VDP (R0)
*
VWROW  MOV  R11,R10   * save return
       BL   @VWADD    * write out VDP write address
       LI   R2,32     * write one row
       LI   R8,VDPWD  * Register faster then address
VWROW1 MOVB *R1+,*R8  * write next VDP byte from RAM
       MOVB *R1+,*R8  * write next VDP byte from RAM
       DECT R2        * dec count by 2
       JNE  VWROW1    * repeat if not done
       B    *R10      * return to caller
*********************************************************
* CALL ROLLRIGHT(repetion,...)                          *
*********************************************************
RROLL  MOV  R11,R9    * save return address
       CLR  R0        * set to screen start
       LI   R3,24     * rows to roll
* Write row to RAM buffer
RROLLP LI   R1,FAC+1  * RAM buffer+1 for roll-right positions
       BL   @VRROW    * copy row to RAM buffer 2 bytes at a time
* Copy last column before first in RAM buffer
       MOVB @FAC+32,@FAC * copy roll-out byte to roll-in position
* Copy rolled row back to screen (R0 still has correct location)
       LI   R1,FAC    * reset RAM buffer pointer
       BL   @VWROW    * copy rolled line          
* Process next row
       AI   R0,32     * next row                   
       DEC  R3        * dec row count
       JNE  RROLLP    * roll next row if not done
       B    @PAGER     * return to XB
*********************************************************
* CALL ROLLLEFT(repetion,...)                           *
*********************************************************
LROLL  MOV  R11,R9    * save return address
       CLR  R0        * set to screen start
       LI   R3,24     * rows to roll
* Write row to RAM buffer
LROLLP LI   R1,FAC    * RAM buffer+1 for roll-left positions
       BL   @VRROW    * copy row to RAM buffer 2 bytes at a time
* Copy first column after last in RAM buffer
       MOVB @FAC,@FAC+32 * copy roll-out byte to roll-in position
* Copy rolled row back to screen (R0 still has correct location)
       LI   R1,FAC+1  * reset RAM buffer pointer
       BL   @VWROW    * copy rolled line 2 bytes at a time
* Process next row
       AI   R0,32     * next row                   
       DEC  R3        * dec row count
       JNE  LROLLP    * roll next row if not done
       B    @PAGER     * return to XB
*********************************************************
* CALL ROLLUP(repetion,...)                             *
*********************************************************
UROLL  MOV  R11,R9    * save return address
       CLR  R0        * set to screen start
       LI   R3,23     * rows to roll (all but 1st)
* Write first row to RAM buffer
       LI   R1,FAC    * set RAM buffer
       BL   @VRROW    * copy row to RAM buffer 2 bytes at a time
* Copy RAM buffer to VRAM buffer
       LI   R0,VBUFF  * set VRAM dest to VBUFF
       LI   R1,FAC    * set RAM buffer
       BL   @VWROW    * copy row to VBUFF 2 bytes at a time
* Start copy loop at 2nd row
       LI   R0,32     * point to 2nd row
* Write row to RAM buffer
UROLLP LI   R1,FAC    * set RAM buffer
       BL   @VRROW    * copy row to RAM buffer 2 bytes at a time
* Copy to previous row
       AI   R0,-32    * back up 1 row
       LI   R1,FAC    * reset RAM buffer pointer
       BL   @VWROW    * copy to previous row 2 bytes at a time
* Process next row
       AI   R0,64     * next row
       DEC  R3        * dec row count
       JNE  UROLLP    * roll next row if not done
* Copy saved row to RAM
       LI   R0,VBUFF  * set VRAM source
       LI   R1,FAC    * set RAM buffer
       BL   @VRROW    * copy row to RAM buffer 2 bytes at a time
* Copy saved row to last row
       LI   R0,736    * point to last row
       LI   R1,FAC    * reset RAM buffer pointer
       BL   @VWROW    * copy to last row 2 bytes at a time
       B    @PAGER     * return to XB
*********************************************************
* CALL ROLLDOWN(repetion,...)                           *
*********************************************************
DROLL  MOV  R11,R9    * save return address
       LI   R0,736    * set to last row
       LI   R3,23     * rows to roll (all but last)
* Write last row to RAM buffer
       LI   R1,FAC    * set RAM buffer
       BL   @VRROW    * copy row to RAM buffer 2 bytes at a time
* Copy RAM buffer to VRAM buffer
       LI   R0,VBUFF  * set VRAM dest to VBUFF
       LI   R1,FAC    * set RAM buffer
       BL   @VWROW    * copy row to VBUFF 2 bytes at a time
* Start copy loop at 2nd-to-last row
       LI   R0,704    *  point to row 22
* Write row to RAM buffer
DROLLP LI   R1,FAC    * set RAM buffer
       BL   @VRROW    * copy row to RAM buffer 2 bytes at a time
* Copy to next row
       AI   R0,32     * down 1 row
       LI   R1,FAC    * reset RAM buffer pointer
       BL   @VWROW    * copy to next row 2 bytes at a time
* Process next row
       AI   R0,-64    * back up 2 rows
       DEC  R3        * dec row count
       JNE  DROLLP    * roll next row if not done
* Copy saved row to RAM
       LI   R0,VBUFF  * set VRAM source
       LI   R1,FAC    * set RAM buffer
       BL   @VRROW    * copy row to RAM buffer 
*                     *  2 bytes at a time
* Copy saved row to first row
       CLR  R0        * point to first row
       LI   R1,FAC    * reset RAM buffer pointer
       BL   @VWROW    * copy to first row 2 bytes at a time
       B    @PAGER    * return to caller
***********************************************************
* CALL HCHAR(row,column,character#,repetition[,...])      *
***********************************************************
* CALL HCHAR(row,column,character#,repetition)
* R0 VDP ADDRESS = PAD2
* R1 CHARACTER   = PAD 
* R3 COUNTER     - FAC
*
HCHAR  MOV  R11,R9      * save return address
       LI   R8,VDPWD    * put VDPWD in R8 for faster loop
       MOV  @PAD2,R0    * VRAM start address for HCHAR4
       MOV  @PAD,R1     * ASCII char code is in MSB
       AI   R1,>6000    * Add screen offset (96) to char in MSB
       MOV  @FAC,R3     * repetition to R3..
       MOV  R3,R7       * .. and to R4 for manipulation
       LI   R5,768      * get screen end = 768 to a register..
       MOV  R5,R6       * ..and to R6 for screen size
       C    R6,R7       * scrn_size > cnt, i.e., cnt OK?
       JGT  HCHAR1      * yes; jump
       MOV  R6,R7       * no; cnt = scrn_size
HCHAR1 C    R0,R5       * VRAM address outside screen?
       JHE  HCHARX      * error if so..just exit
       S    R0,R5       * bytes to end of screen
HCHAR2 MOV  R7,R3       * put cnt in R3 for HCHAR4
       JGT  HCHAR3      * are we done?
       JMP  HCHARX      * yup; we're outta here!
HCHAR3 S    R5,R7       * no; do we wrap to screen start?
       JLT  HCHAR4      * no
       MOV  R5,R3       * yes, just go to screen end
HCHAR4 BL   @VWADD      * write out VRAM write address
       LI   R8,VDPWD    * put VDPWD in R8 for faster loop
HCHAR5 MOVB R1,*R8      * Write a byte to next VRAM location
       DEC  R3          * decrement count
       JNE  HCHAR5      * Not done, fill another
       CLR  R0          * wrap for next round
       MOV  R6,R5       * scrn_size to bytes-to-end-of-screen
       JMP  HCHAR2      * see if more
HCHARX B    @PAGER      * return to caller
***********************************************************
* CALL VCHAR(row,column,character#,repetition[,...])      *
***********************************************************
* CALL VCHAR(row,column,character#,repetition)
* R0 VDP ADDRESS = PAD2
* R1 CHARACTER   = PAD 
* R3 COUNTER     = FAC
VCHAR   MOV  R11,R9     * save return address
        MOV  @PAD2,R0   * VDP ADDRESS 
        MOV  R0,R7      * Copy VDP ADDRESS
VCHART  CI   R7,31      * VDP ADDRESS>=31 top?
        JLE  VCHARD     * column<=31 top found
        AI   R7,-32     * VDP ADDRESS-32
        JMP  VCHART     * Loop
VCHARD  CI   R7,31      * column=31?
        JNE  VCHARR     * 0 to 30
        CLR  R7         * Reset column to 0
        JMP  VCHARZ
VCHARR  INC  R7         * column+1
VCHARZ  MOV  @PAD,R1    * Character to display
        AI   R1,BIAS    * Screen offset 96 
        MOV  @FAC,R3    * Repetition  
VCHAR1  BL   @VWADD     * write out VRAM write address
        LI   R8,VDPWD   * Register faster then @
        MOVB R1,*R8     * write next VRAM byte from R1
        CI   R0,768     * End of screen?
        JEQ  VCHARE     * Yes
        CI   R0,735     * next to last ROW?
        JLE  VCHAR3     * Yes
VCHARE  MOV  R7,R0      * VDP ADDRESS=COPY VDP ADDRESS 
        INC  R7         * column+1 
        CI   R7,31      * Next row past last column? 
        JLE  VCHAR2     * No
        CLR  R7         * Wrap Column back
VCHAR2  DEC  R3         * repetition-1
        JNE  VCHAR1     * No done yet
        JMP  VCHAR4     * Exit
VCHAR3  AI   R0,32      * ROW+1
        CI   R0,768     * Off screen?
        JHE  VCHARE     * Yes reset
        DEC  R3         * REPETITION-1
        JNE  VCHAR1     * No loop
VCHAR4  B    @PAGER     * RETURN TO XB
**********************************************************
* CALL HPUT(row,column,$variable,...)                    *
* CALL HPUT(row,column,number-variable,...)              *
**********************************************************
* CALL HPUT(row,column,string or number)
* R0 VDP SCREEN ADDRESS = PAD2 R5,R0
* R4 VDP STRING ADDRESS = FAC4 R4,R0
* R3 COUNTER            = FAC6 R3
*
HPUT    MOV  R11,R9     * save return address
        MOV  @PAD2,R5   * VDP SCREEN ADDRESS
        MOV  @FAC4,R4   * String address or number
        MOV  @FAC6,R3   * Length
        LI   R7,BIAS    * Get Screen bias off set 
        LI   R1,VDPWD   * Register faster then @
        LI   R8,VDPRD   * Register faster then @
        CI   R3,0       * Length=0? 
        JEQ  HPUT2      * Yes
HPUT0   MOV  R4,R0      * Get String/number address
        BL   @VWADDA    * read out VDP address R4
        MOVB *R8,R6     * Get $/# from R4 byte into R6
        AB   R7,R6      * Add bias
        MOV  R0,R4      * Get new update into R4
        INC  R4         * STRING ADDRESS+1
        MOV  R5,R0      * Get SCREEN ADDRESS
        BL   @VWADD     * write out VDP write address R5
        MOVB R6,*R1     * Put R6 onto screen address R0 
        MOV  R0,R5      * Get new update into R5
        INC  R5         * SCREEN ADDRESS+1
        CI   R5,768     * Last row:col?
        JNE  HPUT1      * No, so continue loop
        CLR  R5         * Reset back to top row:col
        DEC  R3         * count by -1
        JNE  HPUT0      * count=0? Restart at top row:col
        JMP  HPUT2      * return to caller
HPUT1   DEC  R3         * count by -1
        JNE  HPUT0      * count=0?
HPUT2   B    @PAGER     * return to caller
**********************************************************
* CALL VPUT(row,column,$variable,...)                    *
* CALL VPUT(row,column,number-variable,...)              *
**********************************************************
* CALL VPUT(row,column,string or number)
* R0 VDP SCREEN ADDRESS = PAD2 R5,R0
* R4 VDP STRING ADDRESS = FAC4 R4,R0
* R3 COUNTER            = FAC6 R3
*
VPUT    MOV  R11,R9     * save return address
        MOV  @PAD2,R5   * VDP ADDRESS
        MOV  @FAC4,R4   * String address or number
        MOV  @FAC6,R3   * Length
        LI   R7,BIAS    * Get Screen bias off set 
        LI   R1,VDPWD   * Register faster then @
        LI   R8,VDPRD   * Register faster then @
        CI   R3,0       * Length=0? 
        JEQ  VPUT2      * Yes
VPUT0   MOV  R4,R0      * Get String/number address
        BL   @VWADDA    * read out VDP address R4
        MOVB *R8,R6     * Get $/# from R4 byte into R6
        AB   R7,R6      * Add bias
        MOV  R0,R4      * Get new update into R4
        INC  R4         * STRING ADDRESS+1
        MOV  R5,R0      * Get SCREEN ADDRESS
        BL   @VWADD     * write out VDP write address R5
        MOVB R6,*R1     * Put R6 onto screen address R0 
        MOV  R0,R5      * Get new update into R5
        CI   R5,767     * OFF SCREEN?
        JEQ  VPUT3      * Yes
        CI   R5,735     * Last ROW?
        JGT  VPUT4      * Yes
        AI   R5,32      * ROW+1
VPUT1   DEC  R3         * Length-1
        JNE  VPUT0      * No loop
VPUT2   B    @PAGER     * return to XB
VPUT3   CLR  R5         * RESET TO TOP LEFT CHARACTER
        JMP  VPUT1      * Always loop
VPUT4   INC  R5         * COL+1
        S    @PAD2,R5   * Original address-screen address    
        JMP  VPUT1      * Always loop
**********************************************************
* CALL INVERSE(chr#,...)                                 *
* CALL INVERSE(ALL,...)                                  *
**********************************************************
* R0 TEMP VDP   
* R1 CHARACTER ADDRESS  = FAC
* R2 NUMBER CHAR COUNT  = PAD 
* R3 ADDRESS OF R4 TO R7
INVERS  MOV  R11,R9    * save return address
        MOV  @FAC,R1   * CHARACTER ADDRESS
        CI   R1,0      * ALL flag?
        JNE  INV1      * No single character defintion
        LI   R1,>03F0  * Cursor first character
        LI   R2,129    * Load number of characters
        JMP  INV2      * Go do ALL
INV1    LI   R2,1      * Load 1 character 
* Get 4 bytes of character definition
INV2    LI   R3,>83E8 * BUFFER in R4 to R7 
        MOV  R1,R0    * Copy VDP Char Address
        BL   @VWADDA  * read out VDP address                 
        LI   R8,VDPRD * Register faster then address
        MOVB *R8,*R3+ * read next VDP byte to RAM
        MOVB *R8,*R3+ * read next VDP byte to RAM
        MOVB *R8,*R3+ * read next VDP byte to RAM
        MOVB *R8,*R3+ * read next VDP byte to RAM
        MOVB *R8,*R3+ * read next VDP byte to RAM
        MOVB *R8,*R3+ * read next VDP byte to RAM
        MOVB *R8,*R3+ * read next VDP byte to RAM
        MOVB *R8,*R3+ * read next VDP byte to RAM
        INV  R4       * INVERT BITS
        INV  R5       * INVERT BITS
        INV  R6       * INVERT BITS
        INV  R7       * INVERT BITS
        LI   R3,>83E8 * BUFFER in R4 to R7 
        MOV  R1,R0    * Copy VDP Char Address
        BL   @VWADD   * write out VDP address
        LI   R8,VDPWD * Register faster then address
        MOVB *R3+,*R8 * write next VDP byte from RAM
        MOVB *R3+,*R8 * write next VDP byte from RAM
        MOVB *R3+,*R8 * write next VDP byte from RAM
        MOVB *R3+,*R8 * write next VDP byte from RAM
        MOVB *R3+,*R8 * write next VDP byte from RAM
        MOVB *R3+,*R8 * write next VDP byte from RAM
        MOVB *R3+,*R8 * write next VDP byte from RAM
        MOVB *R3+,*R8 * write next VDP byte from RAM
        AI   R1,8     * Next Character Definition  
        DEC  R2       * Character counter -1
        JNE  INV2     * 0? No keep looping
        B    @PAGER     * return to XB
*************************************************************
* CALL COLLIDE(#SPR,#SPR,TOLERANCE,DOTROW,DOTCOL)           *
*************************************************************
* PAD  = SPRITE 1 RETURN=ROW
* PAD2 = SPRITE 2 RETURN=COLUMN
* FAC  = TOLERANCE
COLLSP MOV  R11,R9     * save return address
* LOOK FOR SPRITE COINCIDENCE
COLL   LI   R8,PAD     * PAD
       CLR  R0         * ZERO OUT
       MOVB *R8+,R0    * Sprite #1 ROW in high byte
       CLR  R4         * ZERO OUT
       MOVB *R8+,R4    * Sprite #1 COL in high byte
       CLR  R1         * ZERO OUT 
       MOVB *R8+,R1    * Sprite #2 ROW in high byte
       CLR  R5         * ZERO OUT
       MOVB *R8+,R5    * Sprite #2 COL in high byte
       MOV  @FAC,R7    * TOLERANCE
       SWPB R7         * Put into high byte
       CLR  @PAD       * zero out 
       CLR  @PAD2      * zero out 
*** CHECK FOR OFF SCREEN       
       LI   R6,>C000   * Off screen value
       C    R0,R6      * To Sprite #1 ROW to high?
       JHE  COLL       * Yes defualt zero 
       C    R1,R6      * To Sprite #2 ROW to high?
       JHE  COLL       * Yes defualt zero 
*** Row comparison
       MOV  R1,R8
       S    R0,R8      * Sprite #2 ROW-Sprite #1 ROW
       ABS  R8         * No negative value
       C    R8,R7      * Within tolerance?
       JGT  COLL       * No defualt zero       
*** Column comparison 
       MOV  R5,R8
       S    R4,R8      * Sprite #2 COL-Sprite #1 COL
       ABS  R8         * No negative value
       C    R8,R7      * Within tolerance?
       JGT  COLLO      * No defualt zero 
       SWPB R0         * Sprite #1 ROW in low byte
       MOV  R0,@PAD    * Save Sprite #1 ROW to XB
       SWPB R4         * Sprite #1 COL in low byte
       MOV  R4,@PAD2   * Save Sprite #1 COL to XB
COLLO  B    @PAGER     * return to XB  
***********************************************************
* CALL CLEARPRINT                                         *
***********************************************************
CLEARP MOV  R11,R9     * save return address
       LI   R0,2       * Screen address start COL 3
       LI   R1,>8000   * Space Character
       LI   R3,24      * ROW counter
       LI   R4,2       * COL copy
       LI   R8,VDPWD   * put VDPWD in R8 for faster loop
CLEARL BL   @VWADD     * write out VRAM write address
       LI   R2,28      * Count COL 28
CLEARR MOVB R1,*R8     * Write a byte to next VRAM location
       DEC  R2         * COUNT-1
       JNE  CLEARR     * No loop
       AI   R4,32      * Start COL copy +32
       MOV  R4,R0      * Get new ROW:COL
       DEC  R3         * ROW-1
       JEQ  COLLO      * On zero done
       JMP  CLEARL     * LOOP forever
***********************************************************
* RXB CALL INIT ASSEMBLY ROUTINE
*
CINIT   MOV  R11,R9    * save return address
        LI   R0,>2000  * RAM destination address
        LI   R1,ALCEND * ROM source address 
        LI   R2,>0274  * COUNT
INITLP  MOV  *R1+,*R0+ * Write next RAM word 1
        MOV  *R1+,*R0+ * Write next RAM word 2
        MOV  *R1+,*R0+ * Write next RAM word 3
        MOV  *R1+,*R0+ * Write next RAM word 4 
        MOV  *R1+,*R0+ * Write next RAM word 5
        MOV  *R1+,*R0+ * Write next RAM word 6
        MOV  *R1+,*R0+ * Write next RAM word 7
        MOV  *R1+,*R0+ * Write next RAM word 8
        DEC  R2        * COUNT-1
        JNE  INITLP    * Repeat if not done
        MOV  *R1+,*R0+ * Last word to load
        B    @PAGER       * DONE RETURN TO XB 
***********************************************************
ALCEND  DATA >205A,>24F4,>4000,>AA55
        DATA >2038,>2096,>2038,>217E
        DATA >2038,>21E2,>2038,>234C
        DATA >2038,>2432,>2038,>246E
        DATA >2038,>2484,>2038,>2490
        DATA >2038,>249E,>2038,>24AA
        DATA >2038,>24B8,>2038,>2090
        DATA >0000,>0000,>0000,>0000
        DATA >0000,>0000,>0000,>0000
        DATA >0000,>0000,>0000,>0000
        DATA >0000,>0000,>0000,>0000
        DATA >6520,>C060,>2004,>0281
        DATA >4000,>130E,>C001,>0202
        DATA >834A,>8CB0,>1606,>8CB0
        DATA >1604,>8CB0,>1602,>C030
        DATA >0450,>0221,>0008,>10EF
        DATA >0200,>2500,>C800,>8322
        DATA >02E0,>83E0,>0460,>00CE
        DATA >C81D,>8322,>10F9,>C01D
        DATA >C06D,>0002,>06A0,>20DC
        DATA >C0C1,>0603,>0223,>8300
        DATA >D0D3,>1361,>0983,>0643
        DATA >1612,>C000,>165C,>C0C5
        DATA >05C3,>06A0,>2406,>1653
        DATA >05C3,>06A0,>23CA,>0204
        DATA >834A,>0202,>0008,>DC74
        DATA >0602,>15FD,>0380,>06A0
        DATA >20F8,>10F5,>C041,>1347
        DATA >0A81,>9060,>8312,>1143
        DATA >0981,>C141,>0A35,>0225
        DATA >0008,>A160,>8310,>045B
        DATA >C24B,>0643,>1634,>C0C5
        DATA >06A0,>23CA,>C0C1,>06A0
        DATA >2406,>112D,>06A0,>211C
        DATA >06A0,>23CA,>6004,>0A30
        DATA >A040,>0459,>C28B,>0A51
        DATA >09D1,>C201,>D120,>8343
        DATA >0984,>1303,>0600,>1123
        DATA >0580,>0206,>0001,>C0C5
        DATA >0223,>0004,>06A0,>23CA
        DATA >C0C1,>0643,>05C3,>06A0
        DATA >23CA,>0581,>6044,>3981
        DATA >C186,>1611,>C187,>0608
        DATA >15F5,>0606,>A184,>8180
        DATA >150A,>05C3,>045A,>0200
        DATA >0700,>0460,>2084,>0200
        DATA >1C00,>0460,>2084,>0200
        DATA >1400,>0460,>2084,>C01D
        DATA >C06D,>0002,>06A0,>20DC
        DATA >C0C1,>0603,>0223,>8300
        DATA >D0D3,>0983,>160E,>C000
        DATA >1622,>0202,>0008,>0204
        DATA >834A,>C0C5,>06A0,>23CA
        DATA >CD01,>05C3,>0642,>15FA
        DATA >0380,>0643,>160F,>C000
        DATA >1612,>C0C5,>05C3,>06A0
        DATA >2406,>160B,>05C3,>06A0
        DATA >23CA,>C101,>0201,>834A
        DATA >0460,>20CA,>06A0,>20F8
        DATA >10F8,>0460,>2166,>0460
        DATA >216E,>C81D,>2038,>C82D
        DATA >0002,>83E2,>C82D,>0004
        DATA >2044,>02E0,>83E0,>C80B
        DATA >2040,>C020,>2044,>06A0
        DATA >20DC,>C0C1,>0603,>0223
        DATA >8300,>D0D3,>0983,>0603
        DATA >1332,>0643,>164A,>C2A0
        DATA >2038,>162D,>C0C5,>05C3
        DATA >06A0,>2406,>9801,>2058
        DATA >1620,>0206,>0008,>0204
        DATA >834A,>C0C5,>06A0,>23CA
        DATA >CD01,>05C3,>0646,>15FA
        DATA >06A0,>22DA,>0225,>0004
        DATA >C105,>C046,>06A0,>23E6
        DATA >05C4,>D050,>0981,>06A0
        DATA >23E6,>C2E0,>2040,>C820
        DATA >203E,>830C,>02E0,>2038
        DATA >0380,>0200,>0700,>C2E0
        DATA >2040,>0460,>2084,>0200
        DATA >1C00,>0460,>226E,>C08B
        DATA >0643,>16F3,>C0C5,>06A0
        DATA >23CA,>C0C1,>06A0,>2406
        DATA >1102,>0460,>226A,>C020
        DATA >2038,>06A0,>211C,>6004
        DATA >0A10,>A0C0,>06A0,>23CA
        DATA >0452,>06A0,>227E,>0206
        DATA >834A,>CD83,>DDA0,>2058
        DATA >DD84,>CD81,>C0C1,>1602
        DATA >04D6,>1005,>0603,>06A0
        DATA >2406,>0981,>C581,>C020
        DATA >2044,>06A0,>22DA,>0460
        DATA >225A,>C80B,>203A,>C805
        DATA >203C,>C2E0,>601E,>069B
        DATA >C020,>2044,>C160,>203C
        DATA >D190,>0986,>C820,>830C
        DATA >203E,>C806,>830C,>C806
        DATA >8350,>C2E0,>6012,>069B
        DATA >C020,>2044,>0206,>834A
        DATA >0204,>001C,>CD84,>DDA0
        DATA >2058,>DD84,>C5A0,>831C
        DATA >C0A0,>830C,>1309,>C116
        DATA >C0C0,>0583,>D073,>06A0
        DATA >241A,>0584,>0602,>15FA
        DATA >C2E0,>6028,>069B,>C020
        DATA >2044,>C160,>203C,>C2E0
        DATA >203A,>045B,>C01D,>C06D
        DATA >0002,>06A0,>20DC,>C0C1
        DATA >0603,>0223,>8300,>D0D3
        DATA >0983,>0603,>1302,>0643
        DATA >1623,>C000,>1628,>C02D
        DATA >0004,>C0C5,>05C3,>06A0
        DATA >2406,>9801,>2058,>161D
        DATA >05C3,>06A0,>23CA,>C041
        DATA >1307,>C181,>0601,>C0C1
        DATA >06A0,>2406,>9050,>1A15
        DATA >DC01,>1309,>C0C6,>0981
        DATA >C141,>06A0,>2406,>DC01
        DATA >0583,>0605,>15FA,>0380
        DATA >06A0,>227E,>C02D,>0004
        DATA >10E6,>0460,>2166,>0460
        DATA >216E,>0200,>1300,>0460
        DATA >2084,>06C3,>D803,>8C02
        DATA >06C3,>D803,>8C02,>1000
        DATA >D060,>8800,>06C1,>D060
        DATA >8800,>06C1,>045B,>06C4
        DATA >D804,>8C02,>06C4,>0264
        DATA >4000,>D804,>8C02,>1000
        DATA >D801,>8C00,>06C1,>D801
        DATA >8C00,>06C1,>045B,>06C3
        DATA >D803,>8C02,>06C3,>D803
        DATA >8C02,>1000,>D060,>8800
        DATA >045B,>06C4,>D804,>8C02
        DATA >06C4,>0264,>4000,>D804
        DATA >8C02,>1000,>D801,>8C00
        DATA >045B,>C83E,>83E2,>02E0
        DATA >83E0,>C80B,>204E,>C081
        DATA >0281,>0040,>1B0A,>C0A1
        DATA >6010,>0281,>0004,>1605
        DATA >C0A2,>0002,>0692,>2466
        DATA >1001,>0692,>02E0,>2038
        DATA >C80B,>83F6,>0380,>0200
        DATA >0B00,>0460,>2084,>02E0
        DATA >83E0,>C80B,>204E,>06A0
        DATA >000E,>02E0,>2038,>C80B
        DATA >83F6,>0380,>06A0,>24CA
        DATA >D82D,>0002,>8C00,>0380
        DATA >06A0,>24CA,>D831,>8C00
        DATA >0602,>16FC,>0380,>06A0
        DATA >24D0,>DB60,>8800,>0002
        DATA >0380,>06A0,>24D0,>DC60
        DATA >8800,>0602,>16FC,>0380
        DATA >C05D,>D82D,>0001,>8C02
        DATA >0261,>8000,>D801,>8C02
        DATA >0380,>0201,>4000,>1001
        DATA >04C1,>C09D,>D820,>203D
        DATA >8C02,>E081,>D802,>8C02
        DATA >C06D,>0002,>C0AD,>0004
        DATA >045B
**********************************************************
EAINIT  MOV  R11,R9    * save return address
        CLR  R0        * ZERO OUT R0
        LI   R1,>2000  * Start address
        LI   R2,8192   * Counter
CLRINT  MOV  R0,*R1+   * CLEAR WORD 
        DECT R2        * Counter-2
        JNE  CLRINT    * ZERO?
        LI   R0,LOW1   * FOUR WORDS
        LI   R1,>2000  * Set up init
        BL   @FOURWS   * LOAD IT
        LI   R0,LOW2   * FOUR WORDS
        LI   R1,>2024  * Set up list 
        BL   @FOURWS   * LOAD IT
        LI   R0,LOW3   * Routines
        LI   R1,>20FA  * Set up routines
        LI   R2,1404   * Counter
SLOW3   MOV  *R0+,*R1+ * LOAD IT
        DECT R2        * Counter-2
        JNE  SLOW3     * ZERO? 
        LI   R0,LOW4   * Name List
        LI   R1,>3F38  * NAMES & Address
        LI   R2,200    * Counter
SLOW4   MOV  *R0+,*R1+ * LOAD IT
        DECT R2        * Counter-2
        JNE  SLOW4     * ZERO?
        B    @PAGER     * return to XB
************************
FOURWS  MOV  R11,R10
        MOV  *R0+,*R1+
        MOV  *R0+,*R1+
        MOV  *R0+,*R1+
        MOV  *R0+,*R1+
        B    *R10
**********************************************************
* EDITOR ASSEMBLER LOWER 8K SUPPORT
* Data for Initialization of
* Memory Expansion
***********************************
LOW1  DATA  >A55A,>2128,>2398,>225A
LOW2  DATA  >A000,>FFD7,>2676,>3F38
LOW3  DATA  >0064,>2000,>2EAA,>2094
      DATA  >21C4,>2094,>2196,>2094,>21DE,>2094,>21F4
      DATA  >2094,>2200,>2094,>220E,>2094,>221A,>2094,>2228
      DATA  >209A,>22B2,>20DA,>23BA,>C80B,>2030,>D060
      DATA  >8349,>2060,>20FC,>132A,>C020,>8350,>1311,>06A0
      DATA  >2646,>101E,>0281,>3F38,>1319,>C001,>0202
      DATA  >834A,>8CB0,>1611,>8CB0,>160F,>8CB0,>160D,>C810
      DATA  >2022,>02E0,>20BA,>C020,>2022,>1309,>0690
      DATA  >02E0,>83E0,>C2E0,>2030,>045B,>0221,>0008,>10E4
      DATA  >0200,>0F00,>D800,>8322,>02E0,>83E0,>0460
      DATA  >00CE,>5820,>20FC,>8349,>02E0,>2094,>0380,>C83E
      DATA  >83E2,>02E0,>83E0,>C80B,>20AA,>C081,>0281
      DATA  >8000,>1B07,>09C1,>0A11,>0A42,>09B2,>A0A1,>0CFA
      DATA  >C092,>0692,>02E0,>2094,>C80B,>83F6,>0380
      DATA  >D060,>8373,>0981,>C87E,>8304,>F820,>20FC,>8349
      DATA  >02E0,>83E0,>C2E0,>2030,>045B,>02E0,>83E0
      DATA  >C80B,>20AA,>06A0,>000E,>02E0,>2094,>C80B,>83F6
      DATA  >0380,>06A0,>223A,>D82D,>0002,>8C00,>0380
      DATA  >06A0,>223A,>D831,>8C00,>0602,>16FC,>0380,>06A0
      DATA  >2240,>DB60,>8800,>0002,>0380,>06A0,>2240
      DATA  >DC60,>8800,>0602,>16FC,>0380,>C05D,>D82D,>0001
      DATA  >8C02,>0261,>8000,>D801,>8C02,>0380,>0201
      DATA  >4000,>1001,>04C1,>C09D,>D820,>2099,>8C02,>E081
      DATA  >D802,>8C02,>C06D,>0002,>C0AD,>0004,>045B
      DATA  >0204,>834A,>C014,>C184,>04F6,>04F6,>C140,>1323
      DATA  >0740,>0203,>0040,>04F6,>04D6,>0280,>0064
      DATA  >1A13,>0280,>2710,>1A08,>0583,>C040,>04C0,>3C20
      DATA  >20FA,>D920,>83E3,>0003,>0583,>C040,>04C0
      DATA  >3C20,>20FA,>D920,>83E3,>0002,>D920,>83E1,>0001
      DATA  >D520,>83E7,>0545,>1101,>0514,>045B,>C17E
      DATA  >53E0,>20FC,>C020,>8356,>C240,>0229,>FFF8,>0420
      DATA  >2114,>D0C1,>0983,>0704,>0202,>208C,>0580
      DATA  >0584,>80C4,>1306,>0420,>2114,>DC81,>9801,>20FE
      DATA  >16F6,>C104,>1352,>0284,>0007,>154F,>04E0
      DATA  >83D0,>C804,>8354,>C804,>2036,>0584,>A804,>8356
      DATA  >C820,>8356,>2038,>02E0,>83E0,>04C1,>020C
      DATA  >0F00,>C30C,>1301,>1E00,>022C,>0100,>04E0,>83D0
      DATA  >028C,>2000,>1332,>C80C,>83D0,>1D00,>0202
      DATA  >4000,>9812,>20FF,>16EE,>A0A0,>20A4,>1003,>C0A0
      DATA  >83D2,>1D00,>C092,>13E6,>C802,>83D2,>05C2
      DATA  >C272,>D160,>8355,>1309,>9C85,>16F2,>0985,>0206
      DATA  >208C,>9CB6,>16ED,>0605,>16FC,>0581,>C801
      DATA  >203A,>C809,>2034,>C80C,>2032,>0699,>10E2,>1E00
      DATA  >02E0,>209A,>C009,>0420,>2114,>09D1,>1604
      DATA  >0380,>02E0,>209A,>04C1,>06C1,>D741,>F3E0,>20FC
      DATA  >0380,>C80B,>2030,>02E0,>20BA,>0420,>2124
      DATA  >02E0,>83E0,>1303,>C2E0,>2030,>045B,>D820,>20BA
      DATA  >8322,>0460,>00CE,>04E0,>2022,>53E0,>20FC
      DATA  >C020,>8356,>0420,>2120,>0008,>1332,>0220,>FFF7
      DATA  >0201,>0200,>0420,>210C,>0580,>C800,>202E
      DATA  >C1E0,>2024,>C147,>04CC,>06A0,>25E0,>0283,>0001
      DATA  >1624,>058C,>04C3,>1023,>0283,>0046,>161E
      DATA  >04C2,>06A0,>262E,>0283,>003A,>16F7,>C020,>202E
      DATA  >0600,>0201,>0100,>0420,>210C,>06A0,>25E0
      DATA  >C020,>2022,>1307,>06A0,>2646,>1005,>CB4E,>0016
      DATA  >C3A0,>2022,>0380,>D740,>F3E0,>20FC,>0380
      DATA  >06A0,>25C2,>04C4,>D123,>2662,>0974,>C808,>202C
      DATA  >06A0,>2594,>0464,>23F8,>0580,>0240,>FFFE
      DATA  >C120,>2024,>A100,>1808,>8804,>2026,>1B05,>C160
      DATA  >2024,>C804,>2024,>100A,>C120,>2028,>A100
      DATA  >8804,>202A,>140C,>C160,>2028,>C804,>2028,>C1C5
      DATA  >0209,>0008,>06A0,>262E,>0609,>16FC,>10B6
      DATA  >0200,>0800,>10CC,>A005,>C800,>2022,>10AF,>A800
      DATA  >202C,>13AC,>0200,>0B00,>10C2,>A005,>C1C0
      DATA  >10A6,>A005,>DDC0,>DDE0,>20DB,>10A1,>A005,>06A0
      DATA  >2566,>C000,>1316,>0226,>FFF8,>8106,>1B02
      DATA  >0514,>1096,>8594,>16F8,>89A4,>0002,>0002,>16F4
      DATA  >89A4,>0004,>0004,>16F0,>C0E6,>0006,>C250
      DATA  >C403,>C009,>16FC,>0224,>0008,>C804,>202A,>10EA
      DATA  >A005,>06A0,>2566,>0226,>FFF8,>8106,>13E3
      DATA  >C296,>1501,>050A,>8294,>16F7,>89A4,>0002,>0002
      DATA  >16F3,>89A4,>0004,>0004,>16EF,>C296,>1516
      DATA  >C0E6,>0006,>C253,>C4C0,>C0C9,>16FC,>C246,>6244
      DATA  >C286,>022A,>0008,>C0C6,>0643,>064A,>C693
      DATA  >0649,>16FB,>0224,>0008,>C804,>202A,>10D9,>CB44
      DATA  >0002,>0200,>0C00,>0460,>2432,>0460,>2494
      DATA  >C28B,>0209,>0006,>C1A0,>202A,>0226,>FFF8,>C106
      DATA  >8806,>2028,>1AF3,>C806,>202A,>06A0,>262E
      DATA  >DDA0,>20E1,>0609,>16FA,>C580,>0206,>4000,>045A
      DATA  >C28B,>04C0,>C30C,>1308,>06A0,>262E,>D020
      DATA  >20E1,>06A0,>262E,>A003,>045A,>0209,>0004,>06A0
      DATA  >262E,>06A0,>25C2,>0A40,>A003,>0609,>16F8
      DATA  >045A,>0223,>FFD0,>0283,>000A,>1A05,>0223,>FFF9
      DATA  >0283,>0019,>1B01,>045B,>0200,>0A00,>0460
      DATA  >2432,>02E0,>83E0,>0200,>2032,>C330,>C270,>C830
      DATA  >8354,>C830,>8356,>C050,>1D00,>9820,>4000
      DATA  >20FF,>161D,>0699,>101B,>1E00,>02E0,>20DA,>C020
      DATA  >202E,>0201,>20DB,>0202,>0004,>0420,>2118
      DATA  >7000,>0950,>1610,>0982,>C001,>0201,>203C,>0420
      DATA  >2118,>04C8,>0602,>11D7,>D0F1,>0983,>A203
      DATA  >045B,>02E0,>20DA,>04C0,>06C0,>0460,>2432,>0201
      DATA  >3F40,>0221,>FFF8,>C011,>1105,>8060,>202A
      DATA  >16F9,>05CB,>045B,>0200,>0D00,>045B,>2D52,>5163
      DATA  >6483,>8455,>045C,>5B5F,>5EF0,>F003,>F0F0
      DATA  >4700,>00C8,>3F38
LOW4  DATA  >5554,>4C54,>4142,>2022,>5041,>4420,>2020,>8300
      DATA  >4750,>4C57,>5320,>83E0,>534F,>554E,>4420
      DATA  >8400,>5644,>5052,>4420,>8800,>5644,>5053,>5441
      DATA  >8802,>5644,>5057,>4420,>8C00,>5644,>5057
      DATA  >4120,>8C02,>5350,>4348,>5244,>9000,>5350,>4348
      DATA  >5754,>9400,>4752,>4D52,>4420,>9800,>4752
      DATA  >4D52,>4120,>9802,>4752,>4D57,>4420,>9C00,>4752
      DATA  >4D57,>4120,>9C02,>5343,>414E,>2020,>000E
      DATA  >584D,>4C4C,>4E4B,>2104,>4B53,>4341,>4E20,>2108
      DATA  >5653,>4257,>2020,>210C,>564D,>4257,>2020
      DATA  >2110,>5653,>4252,>2020,>2114,>564D,>4252,>2020
      DATA  >2118,>5657,>5452,>2020,>211C,>4453,>524C
      DATA  >4E4B,>2120,>4C4F,>4144,>4552,>2124,>4750,>4C4C
      DATA  >4E4B,>2100
***********************************************************
* RXB Character set 
***********************************************************
CHRLDR MOV  R11,R9    * save return address
       LI   R0,>03F8  * VDP destination address
       BL   @VWADD    * write out VDP write address
       LI   R1,CHARS  * CHARACTER LIST
       LI   R2,96     * COUNT
       LI   R8,VDPWD  * Register faster then address
CHRLP  MOVB *R1+,*R8  * write next VDP byte from ROM 1
       MOVB *R1+,*R8  * write next VDP byte from ROM 2
       MOVB *R1+,*R8  * write next VDP byte from ROM 3
       MOVB *R1+,*R8  * write next VDP byte from ROM 4
       MOVB *R1+,*R8  * write next VDP byte from ROM 5
       MOVB *R1+,*R8  * write next VDP byte from ROM 6
       MOVB *R1+,*R8  * write next VDP byte from ROM 7
       MOVB *R1+,*R8  * write next VDP byte from ROM 8
       DEC  R2        * COUNT-1
       JNE  CHRLP     * Repeat if not done 
       B    @PAGER    * DONE
**************************************************
CHARS  BYTE >00,>00,>00,>00,>00,>00,>00,>00 *   31
       BYTE >00,>00,>00,>00,>00,>00,>00,>00 *   32
       BYTE >00,>10,>10,>10,>10,>00,>10,>00 * ! 33 
       BYTE >00,>28,>28,>28,>00,>00,>00,>00 * " 34
       BYTE >00,>28,>7C,>28,>28,>7C,>28,>00 * # 35
       BYTE >00,>38,>54,>30,>18,>54,>38,>00 * $ 36
       BYTE >00,>44,>4C,>18,>30,>64,>44,>00 * % 37
       BYTE >00,>20,>50,>20,>54,>48,>34,>00 * & 38
       BYTE >00,>08,>10,>20,>00,>00,>00,>00 * ' 39
       BYTE >00,>08,>10,>10,>10,>10,>08,>00 * ( 40
       BYTE >00,>20,>10,>10,>10,>10,>20,>00 * ) 41
       BYTE >00,>00,>28,>10,>7C,>10,>28,>00 * * 42
       BYTE >00,>10,>10,>7C,>10,>10,>00,>00 * + 43
       BYTE >00,>00,>00,>00,>00,>30,>10,>20 * , 44
       BYTE >00,>00,>00,>7C,>00,>00,>00,>00 * - 45
       BYTE >00,>00,>00,>00,>00,>30,>30,>00 * . 46
       BYTE >00,>04,>08,>10,>20,>40,>00,>00 * / 47
       BYTE >00,>3C,>4C,>54,>64,>44,>38,>00 * 0 48
       BYTE >00,>10,>30,>10,>10,>10,>38,>00 * 1 49
       BYTE >00,>38,>44,>08,>10,>20,>7C,>00 * 2 50
       BYTE >00,>38,>44,>18,>04,>44,>38,>00 * 3 51
       BYTE >00,>08,>18,>28,>48,>7C,>08,>00 * 4 52
       BYTE >00,>78,>40,>78,>04,>44,>38,>00 * 5 53
       BYTE >00,>38,>40,>78,>44,>44,>38,>00 * 6 54
       BYTE >00,>7C,>04,>08,>10,>20,>20,>00 * 7 55
       BYTE >00,>38,>44,>38,>44,>44,>38,>00 * 8 56
       BYTE >00,>38,>44,>44,>3C,>04,>78,>00 * 9 57
       BYTE >00,>00,>30,>30,>00,>30,>30,>00 * : 58
       BYTE >00,>00,>30,>30,>00,>30,>10,>20 * ; 59
       BYTE >00,>00,>10,>20,>40,>20,>10,>00 * < 60
       BYTE >00,>00,>00,>7C,>00,>7C,>00,>00 * = 61
       BYTE >00,>00,>10,>08,>04,>08,>10,>00 * > 62
       BYTE >00,>38,>44,>08,>10,>00,>10,>00 * ? 63
       BYTE >00,>38,>44,>54,>58,>40,>3C,>00 * @ 64
       BYTE >00,>38,>44,>44,>7C,>44,>44,>00 * A 65
       BYTE >00,>78,>24,>38,>24,>24,>78,>00 * B 66
       BYTE >00,>38,>44,>40,>40,>44,>38,>00 * C 67
       BYTE >00,>78,>24,>24,>24,>24,>78,>00 * D 68
       BYTE >00,>7C,>40,>78,>40,>40,>7C,>00 * E 69
       BYTE >00,>7C,>40,>78,>40,>40,>40,>00 * F 70
       BYTE >00,>38,>44,>40,>4C,>44,>38,>00 * G 71
       BYTE >00,>44,>44,>7C,>44,>44,>44,>00 * H 72
       BYTE >00,>38,>10,>10,>10,>10,>38,>00 * I 73
       BYTE >00,>04,>04,>04,>04,>44,>38,>00 * J 74
       BYTE >00,>44,>48,>50,>70,>48,>44,>00 * K 75
       BYTE >00,>40,>40,>40,>40,>40,>7C,>00 * L 76
       BYTE >00,>44,>6C,>54,>44,>44,>44,>00 * M 77
       BYTE >00,>44,>64,>54,>54,>4C,>44,>00 * N 78
       BYTE >00,>38,>44,>44,>44,>44,>38,>00 * O 79 
       BYTE >00,>78,>44,>44,>78,>40,>40,>00 * P 80
       BYTE >00,>38,>44,>44,>54,>4C,>3C,>00 * Q 81
       BYTE >00,>78,>44,>44,>78,>48,>44,>00 * R 82
       BYTE >00,>38,>44,>30,>08,>44,>38,>00 * S 83
       BYTE >00,>7C,>10,>10,>10,>10,>10,>00 * T 84
       BYTE >00,>44,>44,>44,>44,>44,>38,>00 * U 85
       BYTE >00,>44,>44,>44,>44,>28,>10,>00 * V 86
       BYTE >00,>44,>44,>44,>54,>54,>28,>00 * W 87
       BYTE >00,>44,>28,>10,>10,>28,>44,>00 * X 88
       BYTE >00,>44,>44,>28,>10,>10,>10,>00 * Y 89
       BYTE >00,>7C,>08,>10,>20,>40,>7C,>00 * Z 90
       BYTE >00,>38,>20,>20,>20,>20,>38,>00 * [ 91
       BYTE >00,>00,>40,>20,>10,>08,>04,>00 * \ 92
       BYTE >00,>38,>08,>08,>08,>08,>38,>00 * ] 93
       BYTE >00,>10,>38,>54,>10,>10,>10,>00 * ^ 94
       BYTE >00,>00,>00,>00,>00,>00,>7C,>00 * _ 95
       BYTE >00,>20,>10,>08,>00,>00,>00,>00 * ` 96
       BYTE >00,>00,>00,>38,>48,>48,>3C,>00 * a 97
       BYTE >00,>20,>20,>38,>24,>24,>38,>00 * b 98
       BYTE >00,>00,>00,>1C,>20,>20,>1C,>00 * c 99
       BYTE >00,>04,>04,>1C,>24,>24,>1C,>00 * d 100
       BYTE >00,>00,>00,>1C,>28,>30,>1C,>00 * e 101
       BYTE >00,>0C,>10,>38,>10,>10,>10,>00 * f 102
       BYTE >00,>00,>00,>1C,>24,>1C,>04,>38 * g 103
       BYTE >00,>20,>20,>38,>24,>24,>24,>00 * h 104
       BYTE >00,>10,>00,>30,>10,>10,>38,>00 * i 105
       BYTE >00,>08,>00,>08,>08,>08,>48,>30 * j 106
       BYTE >00,>20,>20,>24,>38,>28,>24,>00 * k 107
       BYTE >00,>30,>10,>10,>10,>10,>38,>00 * l 108
       BYTE >00,>00,>00,>78,>54,>54,>54,>00 * m 109
       BYTE >00,>00,>00,>38,>24,>24,>24,>00 * n 110
       BYTE >00,>00,>00,>18,>24,>24,>18,>00 * o 111
       BYTE >00,>00,>00,>38,>24,>38,>20,>20 * p 112
       BYTE >00,>00,>00,>1C,>24,>1C,>04,>04 * q 113
       BYTE >00,>00,>00,>28,>34,>20,>20,>00 * r 114
       BYTE >00,>00,>00,>1C,>30,>0C,>38,>00 * s 115
       BYTE >00,>10,>10,>38,>10,>10,>0C,>00 * t 116
       BYTE >00,>00,>00,>24,>24,>24,>1C,>00 * u 117 
       BYTE >00,>00,>00,>44,>28,>28,>10,>00 * v 118
       BYTE >00,>00,>00,>44,>54,>54,>28,>00 * w 119
       BYTE >00,>00,>00,>24,>18,>18,>24,>00 * x 120
       BYTE >00,>00,>00,>24,>24,>1C,>04,>38 * y 121
       BYTE >00,>00,>00,>3C,>08,>10,>3C,>00 * z 122
       BYTE >00,>0C,>10,>10,>20,>10,>10,>0C * { 123
       BYTE >00,>10,>10,>10,>00,>10,>10,>10 * | 124
       BYTE >00,>60,>10,>10,>08,>10,>10,>60 * } 125
       BYTE >00,>00,>20,>54,>08,>00,>00,>00 * ~ 126
**********************************************************
* CALL HEX($variable,variable,...)                       *
* CALL HEX(variable,$variable,...)                       *
* CALL HEX(">####",variable,...)                         *
**********************************************************
* HEX VDP to RAM (String to Address) LES version
* R0 TEMP ASC TO HEX    
* R1 HEX ADDRESS        = FAC
* R2 STRING             = PAD 
* R3 COUNTER            = R3
ASCHEX MOV  R11,R9      * save return address
       CLR  R1          * clear result reg
       LI   R2,PAD      * assume 4-bytes in PAD-PAD3
       LI   R3,4        * load counter
HEX01  CLR  R0          * zero out work reg
       MOVB *R2+,R0     * Get ASC byte
       SWPB R0          * get byte to LSB
* ASC CHECK VALUE
       CI   R0,103      * g ?
       JHE  ERROR       * ERROR BAD ARGUMENT
       CI   R0,97       * a ?
       JHE  HEX02       * Valid
       CI   R0,71       * G ?
       JHE  ERROR       * ERROR BAD ARGUMENT 
       CI   R0,65       * A ?
       JHE  HEX02       * Valid
       CI   R0,58       * : ?
       JHE  ERROR       * ERROR BAD ARGUMENT
       CI   R0,47       * / ?
       JLE  ERROR       * ERROR BAD ARGUMENT
* Convert ASC to value
HEX02  AI   R0,>FFD0    * correct for 0-9 in LSB
       CI   R0,>000A    * LSB < 10?
       JLT  HEX03       * we're good
       AI   R0,>FFF9    * correct LSB for A-F
* Add digit and shift if not done
HEX03  A    R0,R1       * add hex digit to result reg LSB
       DEC  R3          * decrement counter
       JEQ  HEX04       * return if done
       SLA  R1,4        * shift hex digit left 1 nybble
       JMP  HEX01       * get another hex digit
HEX04  MOV  R1,@FAC     * get result to FAC for CIF
       B    @PAGER      * return to XB
ERROR  LI   R1,>994A    * ERROR CODE FLAG
NERROR MOV  R1,@ARG     * LOAD ERROR CODE FLAG
       B    @PAGER      * return to XB
***********************************************************
* CALL ALPHALOCK(numeric-variable)                        *
***********************************************************
ALPHA  MOV  R11,R9     * save return address
       MOV  R12,R8     * save R12 value for later
       CLR  R12        * ZERO OUT R12
       SBZ  21         * PUT ALPHA LOCK STROBE
       SRC  R12,14     * WAIT
       TB   7          * ALPHA LOCK DOWN?
       SBO  21         * RESET ALPHA LOCK STROBE
       JEQ  ALPHAF     * RETURN ALPHA LOCK OFF 
       LI   R1,>994A   * ALPHA LOCK ON     
ALPHAO MOV  R8,R12     * Restore R12 
       MOV  R1,@FAC    * Save value to FAC
       B    @PAGER     * return to XB
ALPHAF CLR  R1         * ZERO OUT FLAG
       JMP  ALPHAO     * ALPHA LOCK OFF
***********************************************************
* CALL ISRON(variable)                                    *
***********************************************************
XISRON MOV  R11,R9       * save return address
       MOV  @FAC,@ISR    * Put FAC into ISR Interupt hook
       JMP  NEXIT        * exit
***********************************************************
* CALL ISROFF(variable)                                   *  
***********************************************************
XISROF MOV  R11,R9       * save return address
       MOV  @ISR,@ISR    * Compare if new ISR HOOK
       JEQ  NHOOK        * No 
       MOV  @ISR,@FAC    * Put ISR Hook into FAC
NHOOK  CLR  @ISR         * Clear ISR Hook
NEXIT  CLR  @STATUS      * Clear GPL stuse byte
       B    @PAGER       * return to XB
************************
SPRLP  MOVB R1,*R8     * Write a byte to next VRAM location
       DEC  R2         * COUNT-1  
       JNE  SPRLP      * LOOP
       RT
***********************************************************
       AORG >7FFA
PAGER  CLR  @>6000       * RESTORE PAGE ONE
       B    *R9          * return to caller   
***********************************************************
       END
 

 

Link to comment
Share on other sites

3 hours ago, Sergioz82 said:

. . . each operation alters the status register . . .

 

Actually, some operations have no effect on the status register. For example, you can do multiple conditional jumps on the same status result because none of the jump instructions changes the status register. The same is true of the branch instructions.

 

...lee

  • Like 2
Link to comment
Share on other sites

The one that I found about late was the CLR instruction.

 

You can do a MOV and set the flags.

Then CLR  another register, Rx,   and NOT affect the flags.

 

Then you can JEQ or JNE to set Rx based on the previous MOV.

Much handier when you have to return true/false in a language. 

 

 

  • Like 1
Link to comment
Share on other sites

20 hours ago, Asmusr said:

For the first issue, would adding something like this at the top work?


        MOV @PACYX,R0   ; Get Y and X coordinates
        AI  R0,>0100    ; Normalize Y
        LI  R1,>0F0F    ; Mask for checking position
        CZC R1,R0       ; Check that X and Y are multiples of 16          
        JNE MOVE        ; Skip read joystick

In addition, I guess you also need to save the direction (R9) between calls to MOVPAC.

I added your code between JREAD and MOV @LASTI,R10. I like Senior Falcon's idea of keeping the command memorized while during the step-16 movement so it will turn on its own.

 

Problem is, now pacman moves diagonally and then stops :? 

I have no idea why it happens, it seems I'm not altering other registers except R0..

Another problem is that in a scenario of stop for collision detection + ignore input for step-16 the Pacman gets stuck

  • Like 1
Link to comment
Share on other sites

18 hours ago, TheBF said:

You can do a MOV and set the flags.

Then CLR  another register, Rx,   and NOT affect the flags.

 

Then you can JEQ or JNE to set Rx based on the previous MOV.

Much handier when you have to return true/false in a language. 

That's true. The opponent of CLR, SETO doesn't change any status bits either. Not too surprising, since the result here is obvious, as you set the destination to contain a pre-defined value. Thus you know already if it's zero or not, for example.

Slightly more surprising is that SWPB doesn't modify and status bits. Instructions like LWPI, LIMI and STWP together with SBZ and SBO are also executed without affecting any status bits.

  • Like 2
Link to comment
Share on other sites

3 hours ago, Sergioz82 said:

I added your code between JREAD and MOV @LASTI,R10. I like Senior Falcon's idea of keeping the command memorized while during the step-16 movement so it will turn on its own.

 

Problem is, now pacman moves diagonally and then stops :? 

I have no idea why it happens, it seems I'm not altering other registers except R0..

Another problem is that in a scenario of stop for collision detection + ignore input for step-16 the Pacman gets stuck

If it moves diagonally it sounds like you need to clear the movement in X when it finds a free passage in Y and vice versa. Have you to inspect what happens using a debugger?

  • Like 2
Link to comment
Share on other sites

14 hours ago, Asmusr said:

If it moves diagonally it sounds like you need to clear the movement in X when it finds a free passage in Y and vice versa. Have you to inspect what happens using a debugger?

 It's a strange thing.. I used the debugger but since I don't manage the addresses It's quite intricate to set the appropriate breakpoints. 

I start the game by moving right: pacman goes in that direction but also increments its y

(If I move to the left it moves one pixel left then it gets stuck). Can't go up or down because there are walls.

For what it seems, it's like if moving @pacyx to R0 and manipulating R0 also alters the content of pacyx itself (I double checked I didn't forget @) because with debugger I can see row byte in VDP >0300 is incremented as if AI R0,>0100 affected the actual position. 

In facts, if I comment your lines the Pacman moves correctly. I have no idea, I only use R0 for CZC and for VMBW.. now I'm going to check the sequence of jumps, maybe implementing the 16 pixels step makes it skip some register valorization.

Edited by Sergioz82
  • Like 1
Link to comment
Share on other sites

@Asmusr

Never mind, found the problem:

I decided to not use indirect addressing for R3, therefore when I update position in TMPVAR I had to use SWPB for MOVB R3,@TMPVAR+1 but I forgo to restore the original order before updating @PACYX, so with CZC it used a wrong @PACYX.. 

 

Easier done than said ?

 

Now I have to avoid pacman getting stuck when in front of a wall with CZC EQ=0

  • Like 4
Link to comment
Share on other sites

Finally it works :)

Well, kinda works, there are still a couple of issues (I need a 2 characters read for 2x magnification because as you can see in some turns pacman gets inside walls and same problem for eating some pills) to solve but it's taking shape.

 

Here's the updated movement routine:

 

Quote

TMPWP1 BSS 32                                                                   
MOVPAC DATA TMPWP1                                                              
       DATA ENTPT1                                                              
ENTPT1 BL @INIT loading pacman sprite attributes (+offset) in registers is now a subroutine                                                                 
       BL @JREAD   read keyboard                                                             
       CB @HALT,@HFF is pacman in front of a wall?  HALT byte is FF when true                                                           
       JEQ JL  yes, check new direction                                                                   
       MOV @PACYX,R0 pacman is moving, HALT is 00. Next  3 lines check a step 8 before accepting input                                                            
       AI R0,>0100                                                              
       LI R1,>0707                                                              
       CZC R1,R0                                                                
       JNE MOVE  sprite position is not multiple of 8. Ignore input, keep going                                                               
                                                                                
JL     MOV @LASTI,R10                                                           
       JEQ NOMOVE                                                               
                                                                                
J0     CI R10,SX                                                                
       JNE J1                                                                   
       MOV @DSX,R3                                                              
       LI R5,PSXA                                                               
       LI R6,BANSX                                                              
       CLR R9                                                                   
       JMP MOVE                                                                 
J1     CI R10,DX                                                                
       JNE J2                                                                   
       MOV @DDX,R3                                                              
       LI R9,>000F                                                              
       LI R5,PDXA                                                               
       LI R6,BANDX                                                              
       JMP MOVE                                                                 
J2     CI R10,SU                                                                
       JNE J3                                                                   
       MOV @DSU,R3                                                              
       LI R5,PSUA                                                               
       LI R6,BANSU                                                              
       CLR R9                                                                   
       JMP MOVE                                                                 
J3     CI R10,GIU                                                               
       JNE MOVE                                                                 
       MOV @DGIU,R3                                                             
       LI R9,>0F00                                                              
       LI R5,PGUA                                                               
       LI R6,BANGU                                                              
                                                                                
MOVE   MOV @PACYX,@TMPYX   use a temporary variant to check if in next pixel there isn't a wall                                                     
       AB R3,@TMPYX                                                             
       SWPB R3                                                                  
       AB R3,@TMPYX+1                                                           
       SWPB R3                                                                  
       MOV @TMPYX,R4  one pixel increment according to direction in R3. Store in R4                                                           
       MOV R9,@OFFSF save the new offset                                                           
       AB R9,@TMPYX                                                             
       SWPB R9                                                                  
       AB R9,@TMPYX+1                                                            
       BLWP @RDCHAR  offset +16 for right and down sprite on character detection is added to TEMPYX (used inside RDCHAR)                                                           
       MOV @RCHVAL,R9 move in r9 the value of the character in front of pacman                                                           
       CI R9,>1100  is not a wall or a pill?                                                             
       JGT C2 then go on                                                                   
       CI R9,>1100 is it a wall?                                                             
       JLT C1 then go check if pacman must stop or maintain the direction                                                                   
       MOV @RCHPOS,R0 if read value is 11 (pill) then use character position returned from RDCHAR to VSBW a space character                                                          
       LI R1,>2000                                                              
       BLWP @VSBW                                                               
       JMP C2                                                                   
C1     C @PACDIR,R3 at TMPYX there's a wall. Did pacman changed direction?                                                              
       JEQ C3 no, then stop                                                                   
       BL @INIT yes, restore the original position and repeat the move procedure                                                                 
       JMP MOVE                                                                 
C3     SETO @HALT set HALT flag
       CLR @LASTI    set joystick input to zero                                                           
       JMP NOMOVE   exit movpac                                                            
C2     CLR @HALT pacman can move, set HALT flag to zero                                                                
       MOV R3,@PACDIR       update pacman sprite attributes and copy them to VDP                                                    
       MOV R4,@PACYX                                                            
       MOV R4,@BANYX                                                            
       MOVB R6,@BANYX+2                                                         
       LI R7,>0500               3 lines for animation (open-close mouth)                                               
       XOR R5,R7                                                                
       MOVB R7,@PACYX+2                                                         
       LI R0,>0300                                                              
       LI R1,PACYX                                                              
       LI R2,8                                                                  
       BLWP @VMBW                                                               
NOMOVE RTWP                                                                     
                                                                                
INIT                                                                            
       MOV @PACDIR,R3                                                           
       MOV @PACYX+2,R5                                                          
       MOV @BANYX+2,R6                                                          
       MOV @OFFSF,R9 read the saved offset                                                           
       B *R11  

 

Spacm.gif

Edited by Sergioz82
  • Like 4
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...