moulinaie Posted February 3, 2012 Share Posted February 3, 2012 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. Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted February 3, 2012 Share Posted February 3, 2012 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 Quote Link to comment Share on other sites More sharing options...
Stuart Posted February 3, 2012 Share Posted February 3, 2012 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. Quote Link to comment Share on other sites More sharing options...
Tursi Posted February 3, 2012 Share Posted February 3, 2012 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. Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted February 4, 2012 Share Posted February 4, 2012 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. Quote Link to comment Share on other sites More sharing options...
moulinaie Posted February 4, 2012 Author Share Posted February 4, 2012 (edited) 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 February 4, 2012 by moulinaie Quote Link to comment Share on other sites More sharing options...
Tursi Posted February 4, 2012 Share Posted February 4, 2012 (edited) 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 February 4, 2012 by Tursi Quote Link to comment Share on other sites More sharing options...
moulinaie Posted February 4, 2012 Author Share Posted February 4, 2012 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. Quote Link to comment Share on other sites More sharing options...
Tursi Posted February 4, 2012 Share Posted February 4, 2012 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! Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted February 4, 2012 Share Posted February 4, 2012 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? Quote Link to comment Share on other sites More sharing options...
+acadiel Posted February 4, 2012 Share Posted February 4, 2012 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... :-) Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted February 4, 2012 Share Posted February 4, 2012 . . . 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 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.