Jump to content
IGNORED

XB and assembly... The connection


Opry99er

Recommended Posts

In my current game development, I have discovered yet again that my XB is not quite fast or versatile enough to accomplish all of what I want to accomplish. As I have only just begun learning assembly, I will not be able to write this game in assembly, but I do feel confident that I can use it to diversify my program parameters. Whether to CALL LOAD, or take the advice if some others and embed with STSTEX... That is the question. On the list server discussion, I have learned many things and heard many more I do not understand 100%. My question here is, what precisely is the difference between the two options, and is one more effective than the other for certain tasks?

Link to comment
Share on other sites

I'm not sure what STSTEX is, do you have a link to more info?

 

As for not doing your game in Assembly, I think you should try. Maybe go for something a little more simple so you can finish. Personally I believe the best way to learn is the have a something you are working on while trying to learn a new language or whatever. Make a list of things you need to do like:

 

1. initialize

2. clear the screen

3. draw the player

4. get user input (keyboard / joystick)

5. update the player

6. check for bounds / collisions

7. check for quit / end game

8. go back to 3.

 

I saw a post you made on the TI list that you are trying to go through the Molesworth book... IMHO that is not such a great book for a beginner. The book that really helped me when I was learning assembly (back in 1984 that is) was Lottrup's book, but that is hard to find. I'm actually considering writing some assembly language tutorials, so if you have specific questions I'd be glad to try and help.

 

Matthew

  • Thanks 1
Link to comment
Share on other sites

Thank you Matthew ... I am very interested in learning to (first) write some assembly subroutines to make my XB games function better. I know that might not be the best way to learn assembly, but it is something I want to do. Tursi is helping me out and so is Marc Hull. Systex.... Not Ststex... My bad. It is apparently a way to embed assembly directly into XB code... I'll get some more info and post it when I have it. Thanks man

Link to comment
Share on other sites

You must like pain! ;-) The day I got my PEB with the E/A cart is the day I stopped writing anything in XB. It is just too painful due to the double interpretation. XB (and BASIC) hog the whole system too, so you really have to know a *lot* about the memory use and the hardware to use assembly with XB. IHMO it is harder to interface XB with assembly than to just write the whole thing straight up in assembly. Either way though, I have a lot of subroutines you could probably use. I posted a link to an integer to ASCII conversion routine on the TI list, which also has video routines to replace the stock TI ones in ROM.

 

What ever you want to do, if you need some help let me know. If you give me some idea about what you are trying to learn first, I might be able to come up with something useful to you.

 

Matthew

Link to comment
Share on other sites

Well, I tell ya... XB is the only language I know... Assembly is my nemesis... :). I bought an EA package a year ago and, to my dismay, the first line of the manual said "This is not a tutorial... You must know some assembly before this manual will help you" or some crap like that... Sad... Anyway, I bought this Molesworth book, but it is not very "beginner-friendly". I wrote my first game in XB with minor A/L support... You can DL it from my website free... Opry99er.com. You can play it and see how you like it. :). Wish that game qualified for this contest... But alas, it was finished before the contest started... I am hoping to finish a concept game I started a month or so ago... Right now I just have basic graphics done and the motion and pattern routines encoded. On the "New Game Development" page, it is listed along with other great game ideas by Keith, Filip, and Mark Wills. As for assembly, man.... It just scares the crap out of me. :). I am hoping to develop some way to create impassible borders for my main game character... For instance, I do not want the character to be able to "wrap" around the left side of the screen to get to the right, or the bottom to get to the top... Simple, right? But in XB, it is hard to do that with any precision.

Link to comment
Share on other sites

Systex is a distribution mechanism, you can't use it until the XB side of the program is completely finished. So during development, just stick to CALL LOAD().

 

What Systex does, and why it's handy, is it changes the pointers that tell the system where your XB program ends, so that they include the assembly program. This way, when you load your XB program, the assembly comes at the same time. This is useful, because CALL LOAD() is relatively slow compared to the program loader. However, once you go there, it's not safe to make a lot of changes to the XB side of the program, so you do this at the end, when you're finished development.

 

At least, if I remember correctly. I never had an official copy of it, I played with other people's loaders. ;)

Link to comment
Share on other sites

Thanks Tursi... I am quite enamored with the AL programming guys like Marc Hull and Walid Maalouli have been doing... TI Clickety and Never-Lander are two excellent programs written by Marc Hull-- both in Assembly. I find that these games are faster and more intuitive than many games that TI programmers came out with in the 80s. I suppose it just comes with time, patience, and being able to learn from those who came before. I am going to learn Assembly. I am learning more and more every day. But I don't think I'll be able to learn it, become proficient with it, and complete a game by the deadline for this particular contest. I doubt I'll win, with an XB clunker, but I'll do my best. "Lemonade Stand" was a labor of love, and it taught me so much about XB programming that it's almost hard to let go of the format. If I had written it in TMS9900, it would most decidedly be cleaner, faster, and it would be on a cartridge right now. That's my ultimate reasoning for learning AL... I want to distribute a game on cartridge. =)

Link to comment
Share on other sites

For instance, I do not want the character to be able to "wrap" around the left side of the screen to get to the right, or the bottom to get to the top... Simple, right? But in XB, it is hard to do that with any precision.

 

Easy - don't use the auto motion - move your sprites yourself by steps, say 4 pixels at a time.

 

When you scan the keys, you only scan for a particular direction key IF the sprite is STILL in allowable bounds.

 

10 X=50 :: Y=50

20 CALL MAGNIFY(3)

30 CALL SPRITE(#1,42,5,Y,X)

40 CALL KEY(0,K,S)

50 IF X>50 THEN IF K=ASC("S") THEN X=X-4

60 IF X<100 THEN IF K=ASC("D") THEN X=X+4

70 IF Y>50 THEN IF K=ASC("E") THEN Y=Y-4

80 IF Y<100 THEN IF K=ASC("X") THEN Y=Y+4

90 GOTO 30

 

That should do it. Check I got the CALL SPRITE correct. Is it sprite number, ascii code, colour, y then x? I can't remember - been a while!

 

Also, lines 50 to 80 can be sped up by using the true ascii codes, not the ASC function - for example:

 

50 IF X>50 THEN IF K=83 THEN X=X-4

 

However, I just wrote the code so it's easy to understand for now.

 

But that is how I would do it.

 

BTW: I couldn't check this code, but I think it should work ;-)

 

Mark

Link to comment
Share on other sites

I have just implemented my JOYST function today. Took some bending and twisting of arms, and gnashing of teeth, but I got it done, thanks to Marc and Tursi. Sent you the code in eMail. Anyway, with a JOYST function, wouldn't it simplify the matter even more? There will have to be several things tied into the loop... a few CALL COINCs for SPRITE collision and such... couldn't your routine be rewritten to fit inside a JOYST loop along with the other subprograms? Or would this slow down reaction times... I know XB is slow as molasses. I just need to get this darned thing into Assembly and call it a night. In any case, I have two great books, the reading of which will put me right where I need to be in my road to "Assemblyland." Plus I have been getting excellent advice from a few folks here. Matthew has me almost convinced to stop writing in XB, throw my cart away, burn the XB manual, and get down to EA bidness.

Edited by Opry99er
Link to comment
Share on other sites

Don't be scared of assembly. It is not hard. Actually, the commands are very primitive: move data here, add two values, send a byte to the VDP, etc.. But, because of this simplicity you have a lot more commands to do something that a single statement in a high level language would do. The trade off is speed and control, and on the older computers speed is generally critical especially for games.

 

Also, things you learn about computers when working in assembly will make you a better programmer in any other language you use. I learned 9900 assembly in 1984 and the principles are still applicable today. For example when learning C, pointers are really hard for people to understand and they usually struggle with that aspect of the language. For me they were natural and easy because I understood indirect memory addressing thanks to my assembly experience. Unlike what most people think, computers have not changed in the last 40 years, they are only faster and more dense, and the OSes are more complex, but that's about it.

 

The real key to learning assembly on any computer is to understand how memory really works and how the CPU treats the bytes of data it is dealing with. That's really the secret.

 

Matthew

Link to comment
Share on other sites

Haha, that's funny, I started writing a "call clear" equivalent tutorial. There was way too much background though, and my thoughts were running all over the place. I'll try to refocus on that topic though. Ironically, clearing the screen is also one of the first examples given in the Lottrup book too.

 

Matthew

Link to comment
Share on other sites

This does not go into details for absolute beginners, but shows how I extended one of the Mini Memory system utility routines. The routine can clear the screen.

 

The Mini Memory manual has this documentation on

 

VDP Multiple Byte Write – VMBW

Format: BLWP @VMBW

 

This routine writes multiple bytes from CPU RAM to VDP RAM.

 

R0 – VDP RAM address

R1 – Starting address of CPU RAM buffer

R2 – Number of bytes to write

 

Example:

 

          LI R0,>018E      ; VDP RAM address >01BE
         LI R1,HI         ; Address of text
         LI R2,5          ; Number of bytes to write
         BLWP @WMBW       ; Display the characters
...                       
...                       
HI        TEXT "HELLO"     ; Text to be displayed

 

Now we could construct a new similar routine and document it like this ...

 

VDP Single Byte Multiple Write – VSBMW

Format: BL @VSBMW

 

This routine writes one byte multiple times to VDP RAM.

 

R0 – VDP RAM address

R1 – Byte to write (in even/high byte of word)

R2 – Number of times to writes

 

Example:

 

         CLR R0           ; VDP RAM address >0000
        LI R1,>2000      ; Byte to write (equals the space character)
        LI R2,>300       ; Number of bytes to write (equals the no. of characters on screen)
        BL @VSBMW        ; Write byte multiple times to VDP (Clear the screen)

 

 

The actual code for VSBMW could be like this

 

VSBMW    ORI R0,>4000     ; adjust for writing
        SWPB R0          ; swap
        MOVB R0,@VDPWA   ; put low byte to vdp
        SWPB R0          ; swap back
        MOVB R0,@VDPWA   ; put high byte to vdp
        NOP              ; delay
VSBMWL   MOVB R1,@VDPWD   ; put byte to vdp
        DEC R2           ; countdown
        JNE VSBMWL       ; more bytes ?
        RT               ; return from subroutine

 

:)

Edited by sometimes99er
Link to comment
Share on other sites

 

The actual code for VSBMW could be like this

 

VSBMW    ORI R0,>4000     ; adjust for writing
        SWPB R0          ; swap
        MOVB R0,@VDPWA   ; put low byte to vdp
        SWPB R0          ; swap back
        MOVB R0,@VDPWA   ; put high byte to vdp
        NOP              ; delay
VSBMWL   MOVB R1,@VDPWD   ; put byte to vdp
        DEC R2           ; countdown
        JNE VSBMWL       ; more bytes ?
        RT               ; return from subroutine

 

:)

 

 

I know just recently we got the discussion on the TI yahoo group if the NOP (pseudo-)instructions are still required.

Somehow I lost track of the outcome. Is it safe to assume we can just remove the NOP after setting the

VDP write address ?

Link to comment
Share on other sites

I know just recently we got the discussion on the TI yahoo group if the NOP (pseudo-)instructions are still required.

Somehow I lost track of the outcome. Is it safe to assume we can just remove the NOP after setting the

VDP write address ?

I lost track also.

 

The single NOP in the above is outside the loop, so not much time to gain there if possible. The loop itself takes time with the DEC and JNE. Rolling out, moving to ScratchPad and using indirect (sort of) register access to the VDPWD should make things faster. Rolling out might then need those NOPs.

 

:D

Link to comment
Share on other sites

According to the datasheets and tracing the hardware timing:

 

After setting the address, always safe to drop the NOP.

After writing data to the VDP data port, always safe to drop the NOP.

After reading data from the VDP data port, if in scratchpad RAM and using indirect register access to the VDP (ie: MOV *Rxx,Rxx), and in bitmap mode, then a delay (NOP or otherwise) is needed. If you use any other addressing mode, are not in bitmap mode, or not in 16-bit fast RAM, then it's safe. (Note that assuming memory expansion is 8 bit RAM may cause your code not to run on modified consoles).

 

Note that not all of these assertions have been proven yet - it's based on comparing the datasheet to observed timing on the hardware

Edited by Tursi
Link to comment
Share on other sites

Unless the routines are running from the 16-bit scratchpad and you are using an unrolled loop, you pretty much cannot over run the VDP in the 99/4A.

 

Making a modified VSBW as sometimes99er did seems to be a common conclusion for those who look into making faster versions of the routines provided by TI in the ROM. This is my version of VSBW which includes a VSMW modification to write the same byte multiple times (for doing things like initializing VDP RAM, clearing the screen, etc.) To save two SWPB instructions, my routines require an equate to the address of the low byte of register 0. I also don't use BLWP because it is slower than just BL and I don't mind keeping R0, R1, R2, and R3 available for function use.

 

Matthew

 

      DEF  START

* VDP Memory Map
*
VDPRD  EQU  >8800        VDP read data
VDPSTA EQU  >8802        VDP status
VDPWD  EQU  >8C00        VDP write data
VDPWA  EQU  >8C02        VDP set read/write address
VR1CPY EQU  >83D4        Copy of VDP register 1 - see E/A manual pg. 248
VSYNC  EQU  >83D7        Vertical Sync

* Workspaces
*
WRKSP0 EQU  >8300        Workspace 0
WRKSP1 EQU  >8320        Workspace 1
R0LB   EQU  WRKSP0+1     R0 low byte for VDP routines


* Set up workspace.
*
START  LIMI 0            Disable interrupts
      LWPI WRKSP0       Set workspace pointer

* Clear the screen.
*
      LI   R0,0         Upper left corner of screen
      LI   R1,>2000     Character >20 (32) = space
      LI   R2,>300      Number to write (768)
      BL   @VSMW        Write to VDP

      LIMI 2
LOOP1  JMP  LOOP1


**
* VDP Routines
**

* General register use is:
* R0   VDP RAM starting address.
* R1   MSB contains the value to write or to receive a value
*      when reading.  For multiple byte reads/writes, contains
*      the CPU buffer address.
* R2   Counter (counts down) for multiple reads/writes.

**
* VDP Single Byte Write and Single Byte Multiple Write
*
* Writes the value in the most-significant byte of R1 to the
* VDP RAM address indicated in R0.  For VSMW, the value in R2
* determines how many times to write the byte.  This is very
* useful when initializing large amounts of VDP RAM for things
* such as clearing the screen or setting up bitmap mode.
*
VSBW   LI   R2,1         Force the byte count to 1 for single byte write
VSMW   MOVB @R0LB,@VDPWA Send low byte of VDP RAM write address
      ORI  R0,>4000     Set read/write bits 14 and 15 to write (01)
      MOVB R0,@VDPWA    Send high byte of VDP RAM write address
      ANDI R0,>3FFF     Restore R0 to be as nondestructive as possible
VSMWLP MOVB R1,@VDPWD    Write byte to VDP RAM
      DEC  R2           Byte counter
      JNE  VSMWLP       Check if done
      RT

**
* VDP Multiple Byte Write
*
* Writes the number of bytes indicated in R2 from the CPU RAM
* starting at the address indicated by R1 and places them in
* the VDP RAM starting at the address indicated by R0.
*
VMBW   MOVB @R0LB,@VDPWA Send low byte of VDP RAM write address
      ORI  R0,>4000     Set read/write bits 14 and 15 to write (01)
      MOVB R0,@VDPWA    Send high byte of VDP RAM write address
      ANDI R0,>3FFF     Restore R0 to be as nondestructive as possible
VMBWLP MOVB *R1+,@VDPWD  Write byte to VDP RAM
      DEC  R2           Byte counter
      JNE  VMBWLP       Check if done
      RT

**
* VDP Single Byte Read
*
* Reads a byte from VDP RAM address indicated in R0 and places
* it in the most-significant byte of R1.
*
VSBR   MOVB @R0LB,@VDPWA Send low byte of VDP RAM write address
      ANDI R0,>3FFF     Set read/write bits 14 and 15 to read (00)
      MOVB R0,@VDPWA    Send high byte of VDP RAM write address
      MOVB @VDPRD,R1    Read byte from VDP RAM
      RT

**
* VDP Multiple Byte Read
*
* Reads the number of bytes indicated in R2 from the VDP RAM
* starting at the address indicated by R0 and places them in
* the CPU RAM starting at the address indicated by R1.
*
VMBR   MOVB @R0LB,@VDPWA Send low byte of VDP RAM write address
      ANDI R0,>3FFF     Set read/write bits 14 and 15 to read (00)
      MOVB R0,@VDPWA    Send high byte of VDP RAM write address
VMBRLP MOVB @VDPRD,*R1+  Read byte from VDP RAM
      DEC  R2           Byte counter
      JNE  VMBRLP       Check if finished
      RT

**
* VDP Write To Register
*
* Writes the value in the least-significant byte of R0 to the
* VDP register indicated in the most-significant byte of R0.
*
VWTR   MOVB @R0LB,@VDPWA Send low byte (value) to write to VDP register
      ORI  R0,>8000     Set up a VDP register write operation
      MOVB R0,@VDPWA    Send high byte (address) of VDP register
      RT

      END

Edited by matthew180
Link to comment
Share on other sites

Yup, Lottrup's book will defiantly get you going. You still have to take a lot of things on faith though. I'm working on two "chapters" right now, one on understanding memory and another is an in depth explanation of a clear screen function. Both are about 5 pages long so far and about half done based on what I still have in my head to write down.

 

Matthew

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