When dealing with bits in Color BASIC, we have AND, OR and NOT. Unfortunately, we can really only use these on values 15-bits or less. For example, here is a table represent various 8-bit values in the range of 0-255:
Dec Hex Binary ----- ---- -------- 0 00 00000000 1 01 00000001 2 02 00000010 4 04 00000100 8 08 00001000 16 10 00010000 32 20 00100000 64 40 01000000 128 80 10000000 255 FF 11111111
We have no problem using 8-bit values with standard Color BASIC. Here is my routine that will print out the bits of any 8-bit value:
0 REM 8BITS.BAS 10 DIM BT(7):FOR BT=0 TO 7:BT(BT)=2^BT:NEXT 20 INPUT "VALUE ";Z 30 GOSUB 500:GOTO 20 500 REM SHOW Z AS BINARY 510 FOR BT=7 TO 0 STEP-1 520 IF Z AND BT(BT) THEN PRINT "1"; ELSE PRINT "0"; 530 NEXT 540 PRINT Z:RETURN
Here is a program using that routine that will print out a similar table:
0 REM 8BITTABL.BAS 10 DIM BT(7):FOR BT=0 TO 7:BT(BT)=INT(2^BT):NEXT 20 PRINT "DEC HEX BINARY" 30 PRINT "----- ---- --------" 40 FOR I=0 TO 7:Z=INT(2^I) 50 GOSUB 100 60 NEXT 70 Z=255:GOSUB 100 80 END 100 REM PRINT TABLE ENTRY 110 PRINT USING"##### ";Z; 120 IF Z<&H10 THEN PRINT "0"; 130 PRINT HEX$(Z);" "; 140 GOSUB 500 150 RETURN 500 REM SHOW Z AS BINARY 510 FOR BT=7 TO 0 STEP-1 520 IF Z AND BT(BT) THEN PRINT "1"; ELSE PRINT "0"; 530 NEXT 540 PRINT:RETURN
When I started experimenting with bits like this, I tried to modify my routine to work with 16-bit values. It did not work:
0 REM 8BITTABL.BAS - DOES NOT WORK! 10 DIM BT(15):FOR BT=0 TO 15:BT(BT)=INT(2^BT):NEXT 20 PRINT "DEC HEX BINARY" 30 PRINT "----- ---- ----------------" 40 FOR I=0 TO 15:Z=INT(2^I) 50 GOSUB 100 60 NEXT 70 Z=255:GOSUB 100 80 END 100 REM PRINT TABLE ENTRY 110 PRINT USING"##### ";Z; 120 IF Z<&H10 THEN PRINT "0"; 121 IF Z<&H100 THEN PRINT "0"; 122 IF Z<&H1000 THEN PRINT "0"; 130 PRINT HEX$(Z);" "; 140 GOSUB 500 150 RETURN 500 REM SHOW Z AS BINARY 510 FOR BT=15 TO 0 STEP-1 520 IF Z AND BT(BT) THEN PRINT "1"; ELSE PRINT "0"; 530 NEXT 540 PRINT:RETURN
A bit of investigation revealed that AND could not operate on values greater than 32767 (&H3FFF in hex):
I did not understand why, but I expected it has something to do with integer values being treated as signed values, as if this was an INT16 (−32768 to +32767 range) rather than a UIN16 (0-65535 range).
rflberg to the rescue
I had recently posted a series of YouTube videos discussing bits in Color BASIC. My most recent one showed a program I wrote that demonstrated AND, OR and NOT operations:
The program I demonstrated looked like this:
0 REM ANDOR.BAS 10 DIM BT(7):FOR BT=0 TO 7:BT(BT)=INT(2^BT):NEXT 20 INPUT "VALUE ";V 30 PRINT "(A/O/N)"; 40 A$=INKEY$:IF A$="" THEN 40 50 IF A$="A" THEN M=0:PRINT "AND";:GOTO 90 60 IF A$="O" THEN M=1:PRINT "OR ";:GOTO 90 70 IF A$="N" THEN M=2:PRINT "NOT":GOTO 100 80 SOUND 1,1:GOTO 40 90 INPUT O 100 PRINT:PRINT " ";:Z=V:GOSUB 500 110 IF M=0 THEN PRINT "AND ";:Z=O:GOSUB 500:Z=V AND O:PRINT " ";:GOSUB 500 120 IF M=1 THEN PRINT "OR ";:Z=O:GOSUB 500:Z=V OR O:PRINT " ";:GOSUB 500 130 IF M=2 THEN PRINT "NOT ";:Z=NOT V:GOSUB 500 140 PRINT:GOTO 20 500 REM SHOW Z AS BINARY 510 FOR BT=7 TO 0 STEP-1 520 IF Z AND BT(BT) THEN PRINT "1"; ELSE PRINT "0"; 530 NEXT 540 PRINT:RETURN
In the video I explain how it works, somewhat, but you will notice it works only on 8-bit values. Because I did not know a way to make it work.
However, in the comments, use rflberg left a few comments:
IF you want to see the full bits change the program to this:
10 DIM BT(15):FOR BT=0 TO 15:BT(BT)=2^BT:NEXT
rflberg (via YouTube)
501 IF Z<0 THEN PRINT”1″; ELSE PRINT”0″;
510 FOR BT=14 TO 0 STEP -1
I was intrigued. The modifications did not work for me, but a few additional comments help me understand the intent:
-1 is actually 1111111111111111 and 255 is 0000000011111111. It computes numbers -32768 to 32767. Negative numbers the most significant bit is a 1 and positive numbers is a 0.
rflberg (via YouTube)
…
-32768 is 1000000000000000 and 32767 is 0111111111111111
I experimented with this for awhile last night, and now I think I understand it. AND, NOT and OR allow you to pass in 0 to 32677 just fine. But, you can also pass in -32768 to -1 as well! It seems to be using the high bit (bit 15) to indicate a negative value. The explanation was to simply use negative values to make AND, NOT and OR see that bit.
The code modification would work if I passed in 0-32767 for the normal 15-bit range then -32768 to 1 to represent the high-bit range. I should be able to modify my routine to do this automatically.
I could use standard bit values for bits 0 to 14 (my BT array values of 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, and 16384, just like in the earlier table), and then have a special case for bit 15 — a value of -32768 — which I would have in the array as BT(15)=-32768.
Then, in the print bit routine I could check to see if the value was greater than 32767, and turn it in to a negative number by subtracting 65536. (i.e., 32767 would be fine, but 32768 would turn in to -32768).
Since I print out the integer value after the bit display, I decided to make a temporary (altered) variable Z2, and retain the user’s intended Z value. This means I could pass in 32768 and it would print 32768, but would be really using -32768.
I ended up with a minor modification to my program, giving me this routine that will display the bits of any 16-bit value (0-65535):
0 REM 16BITS.BAS 1 REM WORKS THANKS TO rflberg 10 DIM BT(15):FOR BT=0 TO 14:BT(BT)=INT(2^BT):NEXT:BT(15)=-32768 20 INPUT "VALUE ";Z 30 GOSUB 500:GOTO 20 500 REM SHOW Z AS BINARY 505 IF Z>32767 THEN Z2=Z-65536 ELSE Z2=Z 510 FOR BT=15 TO 0 STEP-1 520 IF Z2 AND BT(BT) THEN PRINT "1"; ELSE PRINT "0"; 530 NEXT 540 PRINT Z;Z2:RETURN
Using this updated routine, I modified my table printing program to handle 16-bits:
0 REM 8BITTABL.BAS 1 REM WORKS THANKS TO rflberg 10 DIM BT(15):FOR BT=0 TO 14:BT(BT)=INT(2^BT):NEXT:BT(15)=-32768 20 PRINT "DEC HEX BINARY" 30 PRINT "----- ---- ----------------" 40 FOR I=0 TO 15:Z=INT(2^I) 50 GOSUB 100 60 NEXT 70 Z=65535:GOSUB 100 80 END 100 REM PRINT TABLE ENTRY 110 PRINT USING"##### ";Z; 120 IF Z<&H10 THEN PRINT "0"; 121 IF Z<&H100 THEN PRINT "0"; 122 IF Z<&H1000 THEN PRINT "0"; 130 PRINT HEX$(Z);" "; 140 GOSUB 500 150 RETURN 500 REM SHOW Z AS BINARY 505 IF Z>32767 THEN Z2=Z-65536 ELSE Z2=Z 510 FOR BT=15 TO 0 STEP-1 520 IF Z2 AND BT(BT) THEN PRINT "1"; ELSE PRINT "0"; 530 NEXT 540 PRINT:RETURN
Tada! Thanks for those great YouTube comments, I now have a workaround to doing bit detection on all 16 bits. Thank you very much, rflberg!
Great work!
This the stuff Microsoft BASIC programmer should possibly know already ;) As an BASIC V2 coder on a Commodore 64 this problem arises, as soon you try to handle integer variable type (which is missing in CoCo’s Color BASIC).
In my CRC16 implementation (just to prove it could be done with BASIC) I usually use a helper function to do the conversion stuff:
7 IM=-32768:IP=32767:IA=65536
8 REM INTEGER CORRECTION (16-BIT SIGNED)
9 DEF FN IC(X)=X+(X>IP)*IA
If you have a 16 bit value from 0 to 65535 just use
P=FN IC(P)
to bring it into integer range (which is compatible with AND, OR, NOT).
For further calculation I stay in the integer domain, but for other operations the the built-in ones, say “shift left” this has to be handled differently (C is shifted to the left)
2110 IF CIP THEN C=C-IA
2130 GOTO 2400
2290 REM shift left a negative value
2300 C=C+C:IF C<IM THEN C=C+IA
2400 :
You did a CRC in BASIC? I’d like to see that. I was working on Base-64 encoding and still haven’t finished that series.
I put it on Github … https://github.com/JeeeK/crc
Pingback: CRC16 routine for 8-bit platforms – J.E.E.K's Blog