+Vorticon Posted May 13, 2018 Share Posted May 13, 2018 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... Quote Link to comment Share on other sites More sharing options...
matthew180 Posted May 13, 2018 Author Share Posted May 13, 2018 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. Quote Link to comment Share on other sites More sharing options...
Tursi Posted May 14, 2018 Share Posted May 14, 2018 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/forums/topic/260870-does-anything-use-load-and-iaq-at-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. Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 15, 2018 Share Posted August 15, 2018 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/bfox9900/CAMEL99-V2/blob/master/LIB.TI/RANDOM.FTH for details B 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 15, 2018 Share Posted August 15, 2018 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 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted August 15, 2018 Share Posted August 15, 2018 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.) Quote Link to comment Share on other sites More sharing options...
Asmusr Posted August 15, 2018 Share Posted August 15, 2018 Would, in Forth, use different workspaces for PROG1 and PROG2? Otherwise you could just use BL. Quote Link to comment Share on other sites More sharing options...
+mizapf Posted August 15, 2018 Share Posted August 15, 2018 I usually share workspaces between subprograms, not for data exchance, but for saving space. It's important though that the caller uses another one. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted August 15, 2018 Share Posted August 15, 2018 WKSP1 BSS >20 or WKSP1 BSS 32 ...lee 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 15, 2018 Share Posted August 15, 2018 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. Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 15, 2018 Share Posted August 15, 2018 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. Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 15, 2018 Share Posted August 15, 2018 WKSP1 BSS >20 or WKSP1 BSS 32 ...lee Too many Forth programs under my belt clearly. :-) Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 15, 2018 Share Posted August 15, 2018 So the only line I am actually curious about is: PROG1 DATA WKSP1,$+2 Does anybody use this structure? Quote Link to comment Share on other sites More sharing options...
+mizapf Posted August 15, 2018 Share Posted August 15, 2018 Me, yes. Do you mean that the vector is placed directly before the program code, or just the $+2 notation? Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 15, 2018 Share Posted August 15, 2018 Yes that is what meant. Quote Link to comment Share on other sites More sharing options...
apersson850 Posted August 16, 2018 Share Posted August 16, 2018 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. Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted August 16, 2018 Share Posted August 16, 2018 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". Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted August 16, 2018 Share Posted August 16, 2018 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 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 16, 2018 Share Posted August 16, 2018 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". Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 16, 2018 Share Posted August 16, 2018 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! Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 17, 2018 Share Posted August 17, 2018 (edited) 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 August 17, 2018 by TheBF Quote Link to comment Share on other sites More sharing options...
Asmusr Posted August 22, 2018 Share Posted August 22, 2018 On this page: http://ti99-geek.nl/Projects/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? Quote Link to comment Share on other sites More sharing options...
RXB Posted August 22, 2018 Share Posted August 22, 2018 (edited) 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 August 22, 2018 by RXB Quote Link to comment Share on other sites More sharing options...
PeteE Posted August 22, 2018 Share Posted August 22, 2018 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... 2 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted August 22, 2018 Share Posted August 22, 2018 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. 3 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.