Jump to content
IGNORED

CRU bits question...


moulinaie

Recommended Posts

Hi,

 

Can the CRU bits be used as flags in a program?

For example, instead of using a register with values 0 or 1 (16 bits used!!), can I use a CRU bit?

 

Are there some free ones?

Are they efficient (in terms of speed) compared to the use of a register?

 

is:

TB n
JNE adr

faster than:

MOV Rn,Rn
jne adr

 

Guillaume.

Link to comment
Share on other sites

Hi,

 

Can the CRU bits be used as flags in a program?

For example, instead of using a register with values 0 or 1 (16 bits used!!), can I use a CRU bit?

 

Are there some free ones?

Are they efficient (in terms of speed) compared to the use of a register?

 

is:

TB n
JNE adr

faster than:

MOV Rn,Rn
jne adr

 

Guillaume.

 

I don't see why you can't, as long as you are careful which CRU bits you are setting as this could affect hardware. It's actually a good idea :)

Link to comment
Share on other sites

If you're working on the 99/4A, there are two unused pins on the 9901 that you could program as outputs, and I believe that reading these pins will return the last data output. (Need to ensure that you write to the pins before reading from them in order to program them as outputs). There are another couple of pins you could use as flags but as these control the keyboard scanning and tape operation, you could only use them if not using the keyboard/tape, and you'd have to ensure that the console code did not change them when you're not looking.

 

The TMS9995 processor has an internal CRU flag register with 11 bits available for user-defined application. There is no internal CRU memory in the 9900 in the /4A.

 

You could of course use a bitmask with CPU memory to store 16 flags per word, but that would obviously require more instructions, and your example seems to have a-need-for-speed ...

 

Stuart.

Link to comment
Share on other sites

The trick to remember with CRU bits is that they are hardware, not memory. The abiity to read them back is dependent on how the hardware is wired (with the bits in the 9901, I believe you can read them all back). It may not be a good idea to use the spare 9901 bits, though, as a lot of modifications use them. (Now, how many consoles are modded, I don't know).

 

In general, it's a neat idea, but probably not a safe operation. I don't think I'd count on it personally.

 

As for performance, you can look up the 9900 datasheet. CRU is not really very efficient since it needs to perform special operations on the bus and you only get a single bit.

 

TB n

JNE adr

 

faster than:

 

MOV Rn,Rn

jne adr

 

All else being equal, TB takes the same number of cycles as MOV (14) but half the memory accesses (4:2). It's not clear to me whether CRU accesses trigger the wait state generator, I don't think they do. That means if your MOV is in fast RAM (as registers usually are), that TB and MOV Rn,Rn should take the same amount of time.

 

However, SBO and SBZ take 12 cycles to set the bit, while CLR and SETO are only 10. Of course, if you're saving memory, you probably don't want to waste 16 bits on a flag, so that difference may be moot.

 

If you need more than one bit, though, MOV totally wins, since you have to LDCR at a cost of 20+ cycles and then compare anyway.

 

Since there's no notable speed benefit and risk of hardware interference, it's probably not a good idea to store data in CRU bits. But you may be able to find a few safe spots to sneak data away if you're desperate. :)

Link to comment
Share on other sites

Are you using multiple flags? Instead of one flag per byte or word, why not pack multiple bit flags into the same space? Not sure off the top of my head how you would implement bit flags in 9900, but in 6502 we would do something like

 

; Set bit
LDA flag   ; Load flags into accumulator
ORA #$40   ; Set bit %01000000
STA flag   ; Put back

; Test for bit
LDA flag   ; Load flags into accumulator
AND #$40   ; Mask bit %01000000
BNE bitset ; Branch if result not zero **or**
BEQ notset ; Branch if result is zero

; Clear bit
LDA flag   ; Load flags into accumulator
AND #$DF   ; Clear bit %01000000
STA flag   ; Put back

 

This way you put eight flags per byte or 16 per word.

Link to comment
Share on other sites

Thanks to every one for those explanations.

I was thinking of adding flags to the MLC and it seemed that the CRU instructions were shorter in their implementation than using a WORD of memory.

 

For example, if I want to test the flag 3 of a 16 bits field (without modifying it!)

 

1) THE CRU WAY:

TB 3 (one instruction, 2 bytes, with CRU bits)

2) THE STANDARD WAY:

LI R0,>0008
MOV @FLAGS,R1
COC R0,R1	(3 instructions and 10 bytes)

 

The first one is more efficient in terms of memory and of use in a compiler. Even if R12 was not up to date, you'll have to write:

 

LI R12,cru_adr
TB 3   (2 instructions 6 bytes, still less than 10!)

 

But, if there may be conflicts with hardware, I abandon this for the moment!

 

Guillaume.

Edited by moulinaie
Link to comment
Share on other sites

LI R0,>0008
MOV @FLAGS,R1
COC R0,R1

 

Another, possibly simpler way to do this is to use a table of bits, and then you can reference it directly. For instance:

 

BITFLAGS DATA >0001,>0002,>0004,>0008
DATA >0010,>0020,>0040,>0080
DATA >0100,>0200,>0400,>0800
DATA >1000,>2000,>4000,>8000

 

then anywhere you need them:

 

 COC @BITFLAGS+6,@FLAGS

 

(where the +6 is because you wanted bit 3). It costs you 32 bytes for the table, but you could only store the flags you actually use. The test itself is one instruction, and while it'll be slower than the TB, not by much. (Especially if you can get the table into scratchpad, though I would not do that unless you do a LOT of bit tests). Still costs 6 bytes, though. You can make it four bytes by keeping FLAGS in a dedicated register, though -- with 15 GP registers that's more possible than on some machines. :)

Edited by Tursi
Link to comment
Share on other sites

LI R0,>0008
MOV @FLAGS,R1
COC R0,R1

 

Another, possibly simpler way to do this is to use a table of bits, and then you can reference it directly. For instance:

 

BITFLAGS DATA >0001,>0002,>0004,>0008
DATA >0010,>0020,>0040,>0080
DATA >0100,>0200,>0400,>0800
DATA >1000,>2000,>4000,>8000

 

then anywhere you need them:

 

 COC @BITFLAGS+6,@FLAGS

 

(where the +6 is because you wanted bit 3). It costs you 32 bytes for the table, but you could only store the flags you actually use. The test itself is one instruction, and while it'll be slower than the TB, not by much. (Especially if you can get the table into scratchpad, though I would not do that unless you do a LOT of bit tests). Still costs 6 bytes, though. You can make it four bytes by keeping FLAGS in a dedicated register, though -- with 15 GP registers that's more possible than on some machines. :)

 

Hi,

 

Yes, I though of that, but the table is large!

Another thing: COC must have a register for the second operand,

so:

 

mov @FLAGS,r0
COC @BITFLAGS+6,r0

and that's 8 bytes + the table.!

 

Guillaume.

Link to comment
Share on other sites

Ah, so it does need a workspace register... that's too bad.

 

Nevertheless, that 8 bytes plus the table for ONE usage (where you wouldn't use a table if that was all you were doing.) Still, 8 bytes is still less than 10, and if your program used 16 bitflag operations, it evens out. More than that and it wins. It depends what the program does.

 

Also, your examples assume there is a single 16-bit @FLAGS variable... keep it in a register instead. Then you don't need to do the move and it works with COC. Does your compiler need all 16 registers?

 

Alternately, rather than having dedicated flags, just let the user have bitwise operations on their own variables. :)

 

All just suggestions, anyway. Looks like you've done great things with this!

Link to comment
Share on other sites

LI R0,>0008
MOV @FLAGS,R1
COC R0,R1

 

Another, possibly simpler way to do this is to use a table of bits, and then you can reference it directly. For instance:

 

BITFLAGS DATA >0001,>0002,>0004,>0008
DATA >0010,>0020,>0040,>0080
DATA >0100,>0200,>0400,>0800
DATA >1000,>2000,>4000,>8000

 

then anywhere you need them:

 

 COC @BITFLAGS+6,@FLAGS

 

(where the +6 is because you wanted bit 3). It costs you 32 bytes for the table, but you could only store the flags you actually use. The test itself is one instruction, and while it'll be slower than the TB, not by much. (Especially if you can get the table into scratchpad, though I would not do that unless you do a LOT of bit tests). Still costs 6 bytes, though. You can make it four bytes by keeping FLAGS in a dedicated register, though -- with 15 GP registers that's more possible than on some machines. :)

 

If you are using an assembler, can you do something like this (again, what I did in 6502):

; binary used for visual reference
bit1on=%00000001
bit2on=%00000010
bit3on=%00000100
bit4on=%00001000
bit5on=%00010000
bit6on=%00100000
bit7on=%01000000
bit8on=%10000000

bit1off=%11111110
bit2off=%11111101
bit3off=%11111011
bit4off=%11110111
bit5off=%11101111
bit6off=%11011111
bit7off=%10111111
bit8off=%01111111

 

Then you AND or ORA the appropriate equate in the code I provided earlier. This way the table is in the assembler and does not take up space in the final executable. This would assume that you can compare a register directly against a constant, which ISTR can be done in 9900?

Link to comment
Share on other sites

I think CRU bits 22 and 23 are the cassette motor, correct? Can those be read back in for status? If people aren't using those (I don't know that many that still use cassettes), those might be pretty easy ones to set. Worst case scenario is someone's casette motor will turn on and off if the unit is set to play and the remote plug is plugged into the deck...

 

:-)

Link to comment
Share on other sites

.

.

.

Then you AND or ORA the appropriate equate in the code I provided earlier. This way the table is in the assembler and does not take up space in the final executable. This would assume that you can compare a register directly against a constant, which ISTR can be done in 9900?

 

AND IMMEDIATE for the constant >0C00 (bits 10 and 11 set) with Register 2:

 ANDI	 2,>0C00

 

Same for OR IMMEDIATE:

 ORI	 2,>0C00

 

...lee

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