Jump to content
IGNORED

Assembly on the 99/4A


matthew180

Recommended Posts

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.

  • Like 4
Link to comment
Share on other sites

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.

  • Haha 4
Link to comment
Share on other sites

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

 

  • Like 2
Link to comment
Share on other sites

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

  • Like 3
Link to comment
Share on other sites

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.

  • Like 3
Link to comment
Share on other sites

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. 

 

  • Like 2
Link to comment
Share on other sites

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

 

  • Like 1
Link to comment
Share on other sites

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

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

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 by Lee Stewart
correction
  • Like 4
Link to comment
Share on other sites

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.

  • Like 1
Link to comment
Share on other sites

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

 

  • Like 3
Link to comment
Share on other sites

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.

  • Thanks 1
Link to comment
Share on other sites

 

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.

 

  • Like 1
Link to comment
Share on other sites

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

  • Like 5
Link to comment
Share on other sites

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

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