apersson850 Posted February 7 Share Posted February 7 That's correct. CRU addresses in TMS 9900 systems are only 15 bits long. This is due to the fact that the CPU addresses memory word by word, so for 65536 bytes of addressing space, you only need 32768 word addresses, and that's done with 15 bits. So when you increment a CRU address by one in hardware you increment it by two in software. Then there aren't 32768 CRU bits available either, because the three top bits are used to encode the external instructions (LREX, CKON,CKOF, RSET and IDLE). Which of them is executed is signaled by the three top bits, leaving 4096 possible CRU addresses. The TMS 9995 does it differently, so there you have up to 32768 CRU bits. An external instruction behaves like a CRU instruction minus that the signal CRUCLK is not active. 4 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted February 7 Share Posted February 7 1 hour ago, Vorticon said: So it is a kosher way of doing things after all... It's usually best to consult a Rabbi for these decisions, but I think Lee will do in a pinch I totally forgot about that oddity in CRU addresses. 4 Quote Link to comment Share on other sites More sharing options...
+dhe Posted February 8 Share Posted February 8 @TheBF could you put up a correct code fragment to illustrate this point? 1 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted February 8 Share Posted February 8 1 hour ago, dhe said: @TheBF could you put up a correct code fragment to illustrate this point? Let's say I want to activate the first RS232 card in my system, which is at the base CRU address of >1300: LI R12,>1300 ;LOAD CRU BASE IN R12 SBO 0 ;ACTIVATE CARD AI R12,14 ;I NEED TO ACCESS CRU BIT 7 TO TURN THE CARD LED ON. 7*2=14. OFFSET THE CRU BASE BY THAT AMOUNT SBO 0 ;CARD LED TURNED ON 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted February 8 Share Posted February 8 2 hours ago, Vorticon said: Let's say I want to activate the first RS232 card in my system, which is at the base CRU address of >1300: LI R12,>1300 ;LOAD CRU BASE IN R12 SBO 0 ;ACTIVATE CARD AI R12,14 ;I NEED TO ACCESS CRU BIT 7 TO TURN THE CARD LED ON. 7*2=14. OFFSET THE CRU BASE BY THAT AMOUNT SBO 0 ;CARD LED TURNED ON If you know this information at assembly time, tighter code is simply LI R12,>1300 ;LOAD CRU BASE IN R12 SBO 0 ;ACTIVATE CARD SBO 7 ;TURN ON CARD LED Manipulating R12 becomes useful when you don’t know this information at assembly time. Such an example might be a program that gets CRU bits to turn on/off from the user. ...lee 3 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted February 8 Share Posted February 8 55 minutes ago, Lee Stewart said: Manipulating R12 becomes useful when you don’t know this information at assembly time. Such an example might be a program that gets CRU bits to turn on/off from the user. Yup. That's exactly what I'm doing. 3 Quote Link to comment Share on other sites More sharing options...
Stuart Posted February 8 Share Posted February 8 2 hours ago, Vorticon said: Yup. That's exactly what I'm doing. If the program is running from RAM, you could of course rewrite the SBO/SBZ/TB opcodes to reference different CRU bits. Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted February 8 Share Posted February 8 33 minutes ago, Stuart said: If the program is running from RAM, you could of course rewrite the SBO/SBZ/TB opcodes to reference different CRU bits. How would one do that? Quote Link to comment Share on other sites More sharing options...
+TheBF Posted February 8 Share Posted February 8 22 minutes ago, Vorticon said: How would one do that? Stuart is referring to something you can do in ASM or Forth or C (perhaps). This is where you make a function with the SBO instruction in it and your language lets you get the address of that function and lets you change the value in memory right after the instruction. (which you might get to with an offset) Self modifying code in other words. Not taken to be good form in modern times, but done by ASM coders to overcome shortcomings in the instruction set like you have found. 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted February 8 Share Posted February 8 Correction: In the case of SBO etc. You change the byte in the instruction. For reference I make these instructions manually with HEX code, You can see where I only change one number for go from SBO 0 to SBO 1 CODE 0SBO ( -- ) 1D00 , NEXT, ENDCODE CODE 0SBZ ( -- ) 1E00 , NEXT, ENDCODE CODE 1SBO ( -- ) 1D01 , NEXT, ENDCODE CODE 1SBZ ( -- ) 1E01 , NEXT, ENDCODE 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted February 9 Share Posted February 9 4 hours ago, Vorticon said: How would one do that? Here is one way: *++ Set CRU Bits (these two instructions must be in RAM so they can be modified!) SBOBIT SBO 0 SBZBIT SBZ 0 *++ Set specified CRU bit (1). R0 has bit to set in MSB. R12 must be set to appropriate CRU. MOVB R0,@SBOBIT+1 ;set up SBO instruction for appropriate CRU bit X @SBOBIT ;execute SBO for bit in R0 MSB *++ Reset specified CRU bit (0). R0 has bit to reset (clear) in MSB. R12 must be set to appropriate CRU. MOVB R0,@SBZBIT+1 ;set up SBZ instruction for appropriate CRU bit X @SBZBIT ;execute SBZ for bit in R0 MSB ...lee 4 1 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted February 9 Share Posted February 9 Got it. So what's the advantage of doing it that way? Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted February 9 Share Posted February 9 (edited) 23 hours ago, Vorticon said: Got it. So what's the advantage of doing it that way? Maybe nothing more than a way to manage changing the CRU bit from ROM or an alternate way to organize the code. If all relevant code is in RAM, the following would be shorter and quicker for SBO (and similar for SBZ😞 *++ Set specified CRU bit (1). R0 has bit to set in MSB MOVB R0,@SBOBIT+1 ;set up SBO instruction for appropriate CRU bit SBOBIT SBO 0 ;execute SBO for bit in R0 MSB A good way to use the X instruction is on a table of instructions of constant length, which SBO and SBZ instructions are. This method is probably not useful for setting and clearing CRU bits because it would be larger than desirable, but, if most of the CRU bits between 0 and 7 needed attention, then the following might be useful for setting the bits: *++ Table of 1-word SBO instructions for successive CRU bits SBOTBL SBO 0 SBO 1 SBO 2 SBO 3 SBO 4 SBO 5 SBO 6 SBO 7 *++ Code to use above table (R1 has CRU bit to set) SLA R1,1 ;make it an index into SBOTBL X @SBOTBL(R1) ;execute appropriate SBO instruction R1 should probably be checked that it is within range of the table. A similar setup would be needed for clearing the bits. Again, a bit wasteful of space, but a possibly useful alternative. [Note: I originally had the table index in R0, but, as @Jeff White and @JasonACT indicated, R0 cannot be used for indexed addressing.] ...lee Edited February 10 by Lee Stewart correction 4 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted February 9 Share Posted February 9 Another way, which works even with code in ROM, is to store the opcode for SBO 0 or SBZ 0 in a register. When you know which bit to set, load that offset into the low byte of the register. Then eXecute the register. 6 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted February 9 Share Posted February 9 6 hours ago, apersson850 said: Another way, which works even with code in ROM, is to store the opcode for SBO 0 or SBZ 0 in a register. When you know which bit to set, load that offset into the low byte of the register. Then eXecute the register. I think I need to steal that idea. Thanks. 1 Quote Link to comment Share on other sites More sharing options...
Stuart Posted February 9 Share Posted February 9 21 hours ago, Vorticon said: How would one do that? My use case was somewhat simpler than what my learned colleagues have come up. If you don't know the CRU bit number at assembly time, but you end up with it at runtime in R1 (for example), then (R12 has already been set to the CRU base address somewhere earlier) AI R1,>1D00 'Add opcode for SBO 0 instruction to bit number in R1. MOV R1,@INSTR 'Save as an opcode. ... INSTR DATA >0000 'Gets overwritten with the SBO opcode for the required bit number. ... Using the X instruction is an excellent idea. Although the method above might be better if you need to set an instruction that gets executed sometime later, or in another module or routine perhaps. Lots of ways to skin this cat. 3 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted February 9 Share Posted February 9 Sure. The distinguishing feature of the method to eXecute the SBO/SBZ with the instruction in a register is that even code running from ROM must have their workspace in RAM. Thus it works regardless of the memory type. 2 Quote Link to comment Share on other sites More sharing options...
Jeff White Posted February 10 Share Posted February 10 20 hours ago, Lee Stewart said: Maybe nothing more than a way to manage changing the CRU bit from ROM or an alternate way to organize the code. If all relevant code is in RAM, the following would be shorter and quicker for SBO (and similar for SBZ): *++ Set specified CRU bit (1). R0 has bit to set in MSB MOVB R0,@SBOBIT+1 ;set up SBO instruction for appropriate CRU bit SBOBIT SBO 0 ;execute SBO for bit in R0 MSB A good way to use the X instruction is on a table of instructions of constant length, which SBO and SBZ instructions are. This method is probably not useful for setting and clearing CRU bits because it would be larger than desirable, but, if most of the CRU bits between 0 and 7 needed attention, then the following might be useful for setting the bits: *++ Table of 1-word SBO instructions for successive CRU bits SBOTBL SBO 0 SBO 1 SBO 2 SBO 3 SBO 4 SBO 5 SBO 6 SBO 7 *++ Code to use above table (R0 has CRU bit to set) SLA R0,1 ;make it an index into SBOTBL X @SBOTBL(R0) ;execute appropriate SBO instruction R0 should probably be checked that it is within range of the table. A similar setup would be needed for clearing the bits. Again, a bit wasteful of space, but a possibly useful alternative. ...lee Unless you EQUate R0 to something other than 0, that will not work as intended. In fact, I would think a robust assembler would only work if R0 was a value from 1 to 15. 1 Quote Link to comment Share on other sites More sharing options...
HOME AUTOMATION Posted February 10 Share Posted February 10 (edited) I think you may have missed it as well... INDEXING ...only works with REGISTERS. EDIT: ...nevermind. Edited February 10 by HOME AUTOMATION Quote Link to comment Share on other sites More sharing options...
JasonACT Posted February 10 Share Posted February 10 E/A manual page 59: "Workspace Register 0 may not be specified as an index register." 4 1 Quote Link to comment Share on other sites More sharing options...
+dhe Posted February 10 Share Posted February 10 xdt99 proves helpful. * 02/10/2023 IDT 'TST' DEF X REF VSBW,VMBW,VWTR,KSCAN * Hard Coded Address in Console STATUS EQU >837C GPL STATUS BYTE MOV @STATUS(R0),R9 END d:\classic99_vm\molesworth\mydisks>d:\ti\xdt99\xdt99-3.6.0\xdt99-3.6.0\xas99.py -R .\dsk2\asmtst.asm -o .\dsk3\asmtst.obj -L .\dsk4\asmtst.lst : xas99, version 3.6.0 > asmtst.asm <2> 0009 - MOV @STATUS(R0),R9 ***** Error: Cannot index with register 0 1 Error found. 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted February 10 Share Posted February 10 That's because indexed and symbolic modes are the same. Register number being zero says no index. 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted February 11 Share Posted February 11 Yeah...The reason R0 cannot be used for indexing is that there are 5 addressing modes, but only room in the T fields (see below) of the instruction word for 4 (002 012 102 112), so the operand fields were coopted by the TMS9900 designers to provide the extra information to indicate the extra mode for T=102. For T=102 and a corresponding operand of 0, the addressing mode is symbolic. And for T=102 and a corresponding non-zero operand, the addressing mode is indexed, with the non-zero operand indicating the index register, which, obviously cannot be R0 because of the above-mentioned design decision. Layout of TMS9900 instruction word: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │OP-CODE │B │ Td │Destination│ Ts │ Source │ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ ...lee 5 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted February 11 Share Posted February 11 Does inactivating the RS232 card with a sbz 0 wipe out the card registers and buffers (rate, interval etc...)? I have a requirement in the pcode system to activate/inactivate the card repeatedly, and it would be nice not to have to set it up every time... Quote Link to comment Share on other sites More sharing options...
+mizapf Posted February 11 Share Posted February 11 Bit 0 goes to the ROM enable pin, so it should only map the ROM in and out, nothing else. 1 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.