Jump to content

Photo

CRU bits question...


11 replies to this topic

#1 moulinaie OFFLINE  

moulinaie

    Moonsweeper

  • 303 posts
  • Location:France, Burgundy

Posted Fri Feb 3, 2012 3:33 AM

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.

#2 Vorticon OFFLINE  

Vorticon

    Stargunner

  • 1,308 posts
  • Location:Eagan, MN, USA

Posted Fri Feb 3, 2012 6:06 AM

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 :)

#3 Stuart OFFLINE  

Stuart

    Chopper Commander

  • 209 posts
  • Location:Southampton, UK

Posted Fri Feb 3, 2012 6:51 AM

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.

#4 Tursi OFFLINE  

Tursi

    River Patroller

  • 2,698 posts
  • Location:BUR

Posted Fri Feb 3, 2012 3:27 PM

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

#5 OLD CS1 ONLINE  

OLD CS1

    Stargunner

  • 1,666 posts
  • IT Samurai
  • Location:Tallahassee, FL

Posted Fri Feb 3, 2012 11:09 PM

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.

#6 moulinaie OFFLINE  

moulinaie

    Moonsweeper

  • Topic Starter
  • 303 posts
  • Location:France, Burgundy

Posted Sat Feb 4, 2012 2:09 AM

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, Sat Feb 4, 2012 2:11 AM.


#7 Tursi OFFLINE  

Tursi

    River Patroller

  • 2,698 posts
  • Location:BUR

Posted Sat Feb 4, 2012 5:34 AM

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, Sat Feb 4, 2012 5:40 AM.


#8 moulinaie OFFLINE  

moulinaie

    Moonsweeper

  • Topic Starter
  • 303 posts
  • Location:France, Burgundy

Posted Sat Feb 4, 2012 6:24 AM

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.

#9 Tursi OFFLINE  

Tursi

    River Patroller

  • 2,698 posts
  • Location:BUR

Posted Sat Feb 4, 2012 8:35 AM

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!

#10 OLD CS1 ONLINE  

OLD CS1

    Stargunner

  • 1,666 posts
  • IT Samurai
  • Location:Tallahassee, FL

Posted Sat Feb 4, 2012 9:46 AM

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?

#11 acadiel OFFLINE  

acadiel

    Dragonstomper

  • 560 posts
  • Location:USA

Posted Sat Feb 4, 2012 10:42 AM

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

:-)

#12 Lee Stewart ONLINE  

Lee Stewart

    Stargunner

  • 1,615 posts
  • Location:Maryland

Posted Sat Feb 4, 2012 11:50 AM

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




0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users