Jump to content

Photo

Assembly on the 99/4A


770 replies to this topic

#726 Vorticon OFFLINE  

Vorticon

    River Patroller

  • 3,322 posts
  • Location:Eagan, MN, USA

Posted Sun May 13, 2018 7:12 AM

 
A simple resistor and capacitor on the switch tied to the LOAD input would have provided some simple hardware debounce and the software loop would probably not be necessary.
 
The problem with this approach for Vorticon's purposes is that the LOAD is being driven by a microcontroller, so the input is not bouncing.
 


If that is the case then a timeout is not going to solve this, interrupts will continue to come.  Several things come to mind:

 

1. Disable interrupts immediately upon entering the routine, and re-enable them when you are done.  Keep in mind though, that if the interrupts are coming in fast and furious, it could easily overwhelm the 99/4A.  As soon as you are done with the routine and re-enable interrupts, another could be right there waiting.

 

2. Modify the SmallyMouse code to limit the interrupt rate.  The code is available, I had to compile it myself and load it on the microcontroller.

 

3. You could put a triggered one-shot between the interrupt and the 99/4A to limit the interrupt rate.  Once an interrupt triggers the one-shot, any more interrupts are blocked until the one-shot timeout, which you could adjust to something sensible (once every 30ms or so would be a mouse update every two video frames).

 

You are absolutely correct Matt. I just thought the debouncing in software trick was neat.

Unfortunately, there is no way to disable the LOAD interrupt as it is umaskable. As for modifying the SmallyMouse code, it would be easier to just use an arduino with USB support like the Teensy++ and just decode the USB packets coming from the mouse (they have a standard format) and output direct positional data to a few pins without having to worry about quadrature encoding, phase shifts and all that messy stuff. That way a simple connection to the PIO port will work perfectly. This is actually what I want to experiment with next. The SmallyMouse was really designed to connect to vintage computers already equipped with a mouse port (Amiga, Atari ST, Electron etc...) and I have found that it's more pain than it's worth to try adapting it to mouseless systems. As to your third option, it requires additional hardware which would defeat the purpose...



#727 matthew180 OFFLINE  

matthew180

    River Patroller

  • Topic Starter
  • 2,538 posts
  • Location:Castaic, California

Posted Sun May 13, 2018 3:29 PM

Yeah, I think I was attracted to the device for coin-op purposes, since it outputs the same signals as an arcade-style track-ball.  But unless you have a system designed to accept that type of input, then it is probably more trouble than it is worth, as you pointed out.



#728 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,290 posts
  • HarmlessLion
  • Location:BUR

Posted Sun May 13, 2018 11:40 PM

The LOAD interrupt on the 9900 /is/ level triggered, but after any interrupt you get one instruction before interrupts are enabled again - so the CLR is safe.

We had a chat about this in another thread a few years ago: http://atariage.com/...t-the-side-port

Classic99 won't let you see the effects of CLRing the workspace vector, as it refuses to trigger a LOAD interrupt if the vector's not filled out, but it will still work since the first trigger happens. ;) I hadn't seen that trick before I coded support. The real console will keep re-triggering the interrupt for as long as the pin is low.

#729 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Tue Aug 14, 2018 7:41 PM

 

I think >8378 is used by the GPL RAND function to return a random byte.  I will check on that.  <--Yes, this is correct.

 

>83C0 is the console ISR’s R0 and the random number seed for the GPL RAND function used by TI Basic and RXB.  It is also the seed for the Pseudo-Random Number Generators of TI Extended Basic, TI Forth, fbForth and TurboForth (I think).  Not sure about Camel99 Forth.

 

...lee

 

 

Looking at these older posts for little Gems. 

 

Just to confirm, under the fine tuteledge found here, Camel99 Forth also uses >83C0 to pick up a PRNG seed.

 

In fact it is named "SEED" in the code. 

 

See file: https://github.com/b...B.TI/RANDOM.FTH  for details

 

B



#730 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Wed Aug 15, 2018 6:00 AM

Question for the ASM coders.

 

In Forth Assembler I built an integrated BLWP vector that puts the code and the vector together.  It seems a little cleaner to me. 

 

I think the code below would do this in conventional Assembler.

I am wondering if anybody else uses a structure like this or have I just stumbled upon something everybody already knows/does.

 

(code is untested so don't laugh too hard if it's all wrong)

 

Sidenote:

The reason it becomes interesting in Forth Assembler is because you can make the structure run BLWP automatically so SUB-programs like this run just by invoking the label name. Kinda cool , at least for it was for me.

WKSP1  BSS  20

PROG1  DATA WKSP1,$+2
       A    R1,R0
       A    R2,R0
       A    R3,R0
       RTWP
      
PROG2  DATA WKSP1,$+2
       S    R1,R0
       S    R2,R0
       S    R3,R0
       RTWP,
         
      BLWP  PROG1 
      BLWP  PROG2 


#731 mizapf OFFLINE  

mizapf

    River Patroller

  • 3,383 posts
  • Location:Germany

Posted Wed Aug 15, 2018 9:19 AM

In Assembler, you have to write BLWP @PROG1. Also, the BLWP lines must be part of some longer program code that is called somehow, and later returns somehow. (Note that you need to remove the comma after RTWP.)



#732 Asmusr OFFLINE  

Asmusr

    River Patroller

  • 2,892 posts
  • Location:Denmark

Posted Wed Aug 15, 2018 9:47 AM

Would, in Forth, use different workspaces for PROG1 and PROG2? Otherwise you could just use BL.



#733 mizapf OFFLINE  

mizapf

    River Patroller

  • 3,383 posts
  • Location:Germany

Posted Wed Aug 15, 2018 10:04 AM

I usually share workspaces between subprograms, not for data exchance, but for saving space. It's important though that the caller uses another one.



#734 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,765 posts
  • Location:Silver Run, Maryland

Posted Wed Aug 15, 2018 10:05 AM

WKSP1  BSS  >20

   or

WKSP1  BSS  32

 

...lee



#735 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Wed Aug 15, 2018 11:00 AM

In Assembler, you have to write BLWP @PROG1. Also, the BLWP lines must be part of some longer program code that is called somehow, and later returns somehow. (Note that you need to remove the comma after RTWP.)

 

Noted. @ required.  Comma not required.

 

This is just a code fragment to demonstrate the Vector and code being together. So yes a great deal more would be part of whatever program this was part of.



#736 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Wed Aug 15, 2018 11:06 AM

Would, in Forth, use different workspaces for PROG1 and PROG2? Otherwise you could just use BL.

These examples are more about leaving Forth and doing a sub-program in another workspace with Assembly language and then returning to Forth.

 

And in this case both sub-programs share a workspace so they can keep important information in the registers between calling PROG1 or PROG2.



#737 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Wed Aug 15, 2018 11:09 AM

WKSP1  BSS  >20

   or

WKSP1  BSS  32

 

...lee

Too many Forth programs under my belt clearly. :-)



#738 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Wed Aug 15, 2018 11:14 AM

So the only line I am actually curious about is:

PROG1  DATA  WKSP1,$+2

Does anybody use this structure?



#739 mizapf OFFLINE  

mizapf

    River Patroller

  • 3,383 posts
  • Location:Germany

Posted Wed Aug 15, 2018 11:39 AM

Me, yes. Do you mean that the vector is placed directly before the program code, or just the $+2 notation?



#740 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Wed Aug 15, 2018 3:39 PM

Yes that is what meant.

#741 apersson850 OFFLINE  

apersson850

    Dragonstomper

  • 510 posts

Posted Thu Aug 16, 2018 8:16 AM

In my opinion, the advantage of the vectored addressing is that you can group the vectors together, for easy overview. It means that if you want to write a new implementation of one subroutine, you can place that anywhere, and then, at your central vector pack location, just change the pointer to the new version, or the old version, for testing that they both work (or that the new one doesn't have the same bug as the old one). You don't need to scout around for the different routines to find their vectors.

Especially if the actual code is in different include files, due to total code size, this is valuable.



#742 InsaneMultitasker OFFLINE  

InsaneMultitasker

    River Patroller

  • 2,237 posts

Posted Thu Aug 16, 2018 1:40 PM

So the only line I am actually curious about is:

PROG1  DATA  WKSP1,$+2

Does anybody use this structure?

I learned this exact approach from another programmer during when I first started dabbling in assembly.  It wasn't until years later that I came upon some code that used the vector/label, and it dawned on me that I could place that vector "anywhere".



#743 FarmerPotato OFFLINE  

FarmerPotato

    Chopper Commander

  • 122 posts
  • Location:Austin, TX

Posted Thu Aug 16, 2018 4:52 PM

A variation on BLWP (from FORTI's interrupt service routine)

LI R1,$+8
MOV *SP,R0
BLWP R0
* PC continues here:

BLWP takes WP from R0, PC from R1, 

This gets a workspace pointer from the FORTH stack and performs an approximation of LWP, a TMS9995 instruction, on the TMS9900.

 

It's used to run the same routine on different workspace contexts.

 

Afterward you can put a return address in R14.

CLR *SP     set status
LI R14,NEXT
RTWP


#744 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Thu Aug 16, 2018 5:34 PM

In my opinion, the advantage of the vectored addressing is that you can group the vectors together, for easy overview. It means that if you want to write a new implementation of one subroutine, you can place that anywhere, and then, at your central vector pack location, just change the pointer to the new version, or the old version, for testing that they both work (or that the new one doesn't have the same bug as the old one). You don't need to scout around for the different routines to find their vectors.

Especially if the actual code is in different include files, due to total code size, this is valuable.

 

 

I learned this exact approach from another programmer during when I first started dabbling in assembly.  It wasn't until years later that I came upon some code that used the vector/label, and it dawned on me that I could place that vector "anywhere".

 

And course making a table of vectors let's you call them by index which is cool too.

So I guess the moral is  that "one size does not fit all".



#745 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Thu Aug 16, 2018 5:44 PM

 

A variation on BLWP (from FORTI's interrupt service routine)

LI R1,$+8
MOV *SP,R0
BLWP R0
* PC continues here:

BLWP takes WP from R0, PC from R1, 

This gets a workspace pointer from the FORTH stack and performs an approximation of LWP, a TMS9995 instruction, on the TMS9900.

 

It's used to run the same routine on different workspace contexts.

 

Afterward you can put a return address in R14.

CLR *SP     set status
LI R14,NEXT
RTWP

 

OH! That is very clever.   So by doing BLWP R0  (as opposed to  BLWP @R0)  you can use the registers as vector addresses.   

 

So since my Forth keeps TOS in R4, all I need to do in Forth assembler is...

CODE CALLPROG  (code_address workspace -- )
              *SP+ R5 MOV,
                  R4 BLWP,
                     NEXT,

How cool!  I gotta try that right now.

 

Thanks!



#746 TheBF OFFLINE  

TheBF

    Dragonstomper

  • 754 posts
  • Location:The Great White North

Posted Thu Aug 16, 2018 6:56 PM

This code worked just as you described. 

 

Thanks again FarmerPotato!  ;)

\ BLWP direct test

INCLUDE DSK1.TOOLS.F
INCLUDE DSK1.ASM9900.F

HEX
CREATE WKSP2  20 ALLOT

CREATE TEST
       R0 DEAD LI,
       R1 BEEF LI,
       R2 DEAD LI,
       R3 BEEF LI,
       RTWP,

CODE BLWP() ( addr wksp -- )
    *SP+ R5 MOV,  \ pop addr into R5 (temp register in CAMEL99) 
     R4 BLWP,     \ BLWP direct to wksp in TOS cache register
     TOS POP,     \ refill TOS register (R4)
     NEXT,        \ return to Forth 
     ENDCODE

EDIT: I should add

 

Called like this: 

TEST WKSP2 BLWP() 

Edited by TheBF, Thu Aug 16, 2018 7:33 PM.


#747 Asmusr OFFLINE  

Asmusr

    River Patroller

  • 2,892 posts
  • Location:Denmark

Posted Wed Aug 22, 2018 1:19 PM

On this page:

 

http://ti99-geek.nl/.../c99c/c99c.html

 

there are several code examples like this:

MOV @YPOS,8
BL 15
LI 8,1
BL 15
BL *12
DATA LOCATE
AI 14,4

BL *12 is the same as BL *R12, of course, but I have never seen BL 15 before. Is it the same as BL *R15, or what does it mean?



#748 RXB OFFLINE  

RXB

    River Patroller

  • 3,320 posts
  • Location:Vancouver, Washington, USA

Posted Wed Aug 22, 2018 2:39 PM

In XB ROMs this is the standard use of Registers

  2801            ************************************************************
  2802            * CALL - STATEMENT EXECUTION  
  2803            * Finds the subprogram specified in the subprogram table,   
  2804            * evaluates and assigns any arguments to the formal   
  2805            * parameters, builds the stack block, and transfers control 
  2806            * into the subprogram.  
  2807            *  General register usage:  
  2808            *     R0 - R6 Temporaries   
  2809            *     R7      Pointer into formals in subprogram name entry 
  2810            *     R8      Character returned by PGMCHR  
  2811            *     R9      Subroutine stack  
  2812            *     R10     Temporary   
  2813            *     R11     Return link   
  2814            *     R12     Temporary   
  2815            *     R13     GROM read-data address  
  2816            *     R14     Interpreter flags   
  2817            *     R15     VDP write-address address   
  2818            ************************************************************ 

The only time you see R15 or *R15 is like MOVB  is

  2830 7528 D7E0         MOVB @R0LB,*R15        Load out the VDP write address
       752A 83E1  
  2831 752C 0260         ORI  R0,WRVDP          Enable the VDP write  
       752E 4000  
  2832 7530 D7C0         MOVB R0,*R15           Second byte of VDP write   

R10 is used mostly for a copy of stack or stack pointer.

R12 is used mostly for a copy of R11 or a secondary return pointer like R11

 

That is the standard approach Texas Instruments had for Register usage you see in many programs that TI wrote.


Edited by RXB, Wed Aug 22, 2018 2:40 PM.


#749 PeteE OFFLINE  

PeteE

    Chopper Commander

  • 163 posts
  • Location:Beaverton, OR

Posted Wed Aug 22, 2018 3:22 PM

BL *12 is the same as BL *R12, of course, but I have never seen BL 15 before. Is it the same as BL *R15, or what does it mean?

 

It is valid, but not the same.  If your workspace pointer is set to >8300, "BL R15" is the same as "BL @>831E" (branching to the assembly code in memory at the same address as R15.)

 

I wonder what the the C99 compiler was using it for?  Maybe a breakpoint or tracepoint where R15 could easily be changed between "B *R11" or "something else" to cause compiled code to do something different dynamically at runtime?  Just a guess...



#750 mizapf OFFLINE  

mizapf

    River Patroller

  • 3,383 posts
  • Location:Germany

Posted Wed Aug 22, 2018 5:59 PM

Fun fact: The B/BL addressing introduces a minor inconsistency in the TMS9900 microarchitecture. Normally, the operand (source, destination) is first fetched from the given address, whichever mode is used (register, indirect, symbolic, indexed, indirect-increment).

 

In the book "9900 Family System Design", chapter 4, the microprocessing of the commands is explained; I needed that information for implementing the cycle-precise emulation of the 99xx CPUs in MAME and thus stumbled over that comment for B and BL (page 4-96):

 

Note: The source data is fetched, although it is not used.

 

This actually means that when you do a B @>A000, the CPU indeed first fetches the word from >A000, then sets the program counter to >A000 and continues execution. It would have been more logical to interpret "B R15" as "branch to the address in R15". But instead, it means "branch to the address of R15".

 

The TMS9995 kept the interpretation as in the 9900, of course (would have been incompatible otherwise); but to improve the situation, the previously used "data derivation sequence" was modified to be an "address derivation sequence", which could avoid to fetch unneeded data.






0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users