Part 8 of 11 -- Simple Assembly for Atari BASIC - Convert Integer to Bit String
Convert Integer To Bit String
==============================================================
Part 1 - Introduction
http://atariage.com/forums/blog/576/entry-13175-part-1-of-11-simple-assembly-for-atari-basic/
Part 2 - Learn 82.7% of Assembly Language in About Three Pages
http://atariage.com/forums/blog/576/entry-13176-part-2-of-11-simple-assembly-for-atari-basic/
Part 3 - The World Inside a USR() Routine
http://atariage.com/forums/blog/576/entry-13177-part-3-of-11-simple-assembly-for-atari-basic/
Part 4 - Implement DPEEK()
http://atariage.com/forums/blog/576/entry-13178-part-4-of-11-simple-assembly-for-atari-basic/
Part 5 - Implement DPOKE
http://atariage.com/forums/blog/576/entry-13180-part-5-of-11-simple-assembly-for-atari-basic/
Part 6 - Various Bit Manipulations
http://atariage.com/forums/blog/576/entry-13181-part-6-of-11-simple-assembly-for-atari-basic/
Part 7 - Convert Integer to Hex String
http://atariage.com/forums/blog/576/entry-13182-part-7-of-11-simple-assembly-for-atari-basic/
Part 8 - Convert Integer to Bit String
http://atariage.com/forums/blog/576/entry-13183-part-8-of-11-simple-assembly-for-atari-basic/
Part 9 - Memory Copy
http://atariage.com/forums/blog/576/entry-13184-part-9-of-11-simple-assembly-for-atari-basic/
Part 10 - Binary File I/O Part 1 (XIO is Broken)
http://atariage.com/forums/blog/576/entry-13185-part-10-of-11-simple-assembly-for-atari-basic/
Part 11 - Binary File I/O Part 2 (XIO is Broken)
http://atariage.com/forums/blog/576/entry-13186-part-11-simple-assembly-for-atari-basic-the-end/
==============================================================
This machine language routine converts a 16-bit integer into a string of values representing 0 and 1 bits. This is useful for visualizing bits in a byte, word, or address for diagnostic purposes. This is practical on the Atari for displaying character set or player/missile graphics data in a human-readable way. This routine has a different number of arguments from the INT2HEX string conversion routine and so is presented on its own.
This routine has similar problems to solve as the INT2HEX routine. It must deal with the low byte stored in memory before the high byte, because it must output the bit values in order of highest bits first and lowest bits last. (e.g 258 or hex $0102 should be output as “0000000100000010” though it is stored as $02 $01).
Converting a byte to a string of bits is fairly easy in 6502. In general terms: test the high bit and output a “0” or a “1” as needed, then shift the bits of the byte and repeat until 8 bits have been extracted. The routine below includes a touch of customization – the USR() routine may also specify the characters (ASCII/ATASCII) used to represent “0” and “1”.
INT2BITS in Mac/65 Assembler Code
0100 ; INT2BITS 0105 ; 0110 ; Convert 16-bit integer into 0115 ; string of bits. 0120 ; 0125 ; INT2BITS USR 2 arguments: 0130 ; Value == Integer to convert. 0135 ; StrAdr == Address of string 0140 ; which must be able 0145 ; to hold 16 characters 0150 ; Zero == Character used for 0155 ; clear bit. 0160 ; One == Character used for 0165 ; set bit. 0170 ; 0175 ; USR return value 0 means no 0180 ; conversion. Non-Zero means 0185 ; STRADR contains data. 0190 ; 0195 ; Use the FR0/FR1 FP register. 0200 ; The return value for BASIC 0205 ; goes in FR0. 0210 ; No FP is used so all of FR0 0215 ; (and more FP registers) can 0220 ; be considered available. 0225 ; 0230 ZRET = $D4 ; FR0 $D4/$D5 Return value 0235 ZARGS = $D5 ; $D6-1 for arg Pulldown loop 0240 ZONE = $D6 ; FR0 $D6/$D7 char for "1" 0245 ZZERO = $D8 ; FR0 $D8/$D9 char for "0" 0250 ZSTR = $DA ; FR0 $DA/$DB StrAdr 0255 ZVAL = $DC ; FR0 $DC/$DD Integer value 0260 ; 0265 .OPT OBJ 0270 ; 0275 ; Arbitrary. This is relocatable. 0280 ; 0285 *= $9300 0290 ; 0295 INIT 0300 LDA #$00 ; Make sure return 0305 STA ZRET ; value is cleared 0310 STA ZRET+1 ; by default. 0315 PLA ; Get argument count 0320 BEQ EXIT ; Shortcut for no args 0325 ASL A ; Now number of bytes 0330 TAY 0335 CMP #$08 ; Integer Value1, StrAdr, Zero, One 0340 BEQ PULLDOW N0345 ; 0350 ; Bad args. Clean up for exit. 0355 ; 0360 DISPOSE ; any number of args 0365 PLA 0370 DEY 0375 BNE DISPOSE 0380 RTS ; Abandon ship 0385 ; 0390 ; This code works the same 0395 ; for 1, 4, 8 ... arguments. 0400 ; 0405 PULLDOWN 0410 PLA 0415 STA ZARGS,Y 0420 DEY 0425 BNE PULLDOWN 0430 ; 0435 ; Arg validation. 0440 ; StrAdr may not be null. 0445 ; Zero and One may not 0450 ; be equal. 0455 ; 0460 LDA ZSTR 0465 ORA ZSTR+1 0470 BEQ EXIT ; zstr is null 0475 LDA ZZERO 0480 CMP ZONE 0485 BEQ EXIT ; zero == one 0490 ; 0495 ; Break Integer Value into 0500 ; bytes and test bits from 0505 ; high to low... 0510 ; 0515 LDX #$01 ; X index bytes. 0520 ; Y is already 0 0525 ; Y index string. 0530 ; 0535 WALK_BITS 0540 CLC 0545 ASL ZVAL,X ; Shift out bit 0550 LDA ZZERO ; Assume Zero 0555 BCC COPY2STR ; Copy if so 0560 LDA ZONE ; Actually One 0565 COPY2STR 0570 STA (ZSTR),Y 0575 INY ; Next string position 0580 CPY #$08 ; End of high byte? 0585 BEQ NEXT_BYTE ; Yes. Dec index. 0590 CPY #$10 ; End of low byte? 0595 BNE WALK_BITS ; No, loop again. 0600 NEXT_BYTE 0605 DEX ; 1, 0 will continue 0610 BPL WALK_BITS ; -1 ends loop 0615 END_LOOP 0620 ; 0625 INC ZRET ; Successful return 0630 EXIT 0635 RTS 0640 ; 0645 .END
The variable validation has a trivial addition to make sure the character values for “0” and “1” are not the same:
0475 LDA ZZERO 0480 CMP ZONE 0485 BEQ EXIT ; zero == one
Unlike the hex conversion there is just one part to the bit conversion:
0515 LDX #$01 ; X index bytes. 0520 ; Y is already 0 0525 ; Y index string. 0530 ; 0535 WALK_BITS 0540 CLC 0545 ASL ZVAL,X ; Shift out bit 0550 LDA ZZERO ; Assume Zero 0555 BCC COPY2STR ; Copy if so 0560 LDA ZONE ; Actually One 0565 COPY2STR 0570 STA (ZSTR),Y 0575 INY ; Next string position 0580 CPY #$08 ; End of high byte? 0585 BEQ NEXT_BYTE ; Yes. Dec index. 0590 CPY #$10 ; End of low byte? 0595 BNE WALK_BITS ; No, loop again. 0600 NEXT_BYTE 0605 DEX ; 1, 0 will continue 0610 BPL WALK_BITS ; -1 ends loop 0615 END_LOOP
There are two loops happening here. One loop, indexed by X, counts in reverse, 1 to 0, from the high byte to the low byte of the integer. Within that loop is the activity to output all the bits in the byte which is done as part of the loop indexed by Y to count from character position 0 to 15. When the Y loop reaches values 8 and 16 it signals that all the bits in the byte have been output, so then it is time to continue the outer loop to get the next byte. The Y index is thus incremented 8 times for each decrement (one byte) of the X loop.
As with the integer to hexadecimal conversion this utility receives the address of the output string, not its control information, so it can only fill in the bytes in the string and can't change the size as BASIC understands it. A BASIC program using the results of the conversion must insure that it populates the length of the string prior to calling the conversion utility:
10 DIM A$(16) 20 A$=" ":REM 16 SPACES
Now that we have routines to convert values into hex strings and bit representation, the test program for BITS can be revisited to provide improved diagnostic information.
Testing BITS Again (with INT2HEX and INT2BITS)
Below is the Atari BASIC TESTBITS.BAS program upgraded with the new conversion utilities to produce much more sensible output illustrating the changes in the bits:
100 REM TESTBIT2.BAS 105 REM TEST BIT OPERATIONS UTILITY 2 110 GRAPHICS 0:POKE 710,0:POKE 82,0 115 DIM B(3,1),N$(21),HX$(5),BIT$(17) 120 N$="OR ANDEORLSRLSLRORROL" 125 HX$=" ":BIT$=" " 130 AZERO=48:AONE=49:REM ATASCII 0 1 135 REM ENUMERATE BIT OPERATIONS 140 RESTORE 150 145 READ BOR,BAND,BEOR,BLSR,BLSL,BROR,BROL 150 DATA 1,2,3,4,5,6,7 155 GOSUB 10000:REM BITS UTILITY 160 RESTORE 190:REM BIT PATTERNS 165 FOR X=0 TO 1 170 FOR Y=0 TO 3 175 READ D:B(Y,X)=D 180 NEXT Y 185 NEXT X 190 DATA 0,257,0,257,0,0,258,258 195 REM 200 REM TEST OR, AND, EOR 205 REM 210 FOR OPER=BOR TO BEOR 215 FOR Y=0 TO 3 220 ? " "; 225 VALUE=B(Y,0):GOSUB 405 230 ? N$(OPER*3-2,OPER*3); 235 VALUE=B(Y,1):GOSUB 405 240 ? "=== ===== ===================" 245 VALUE=USR(BITS,OPER,B(Y,0),B(Y,1)) 250 ? " ";:GOSUB 405 255 ? 260 NEXT Y 265 NEXT OPER 270 REM 275 REM TEST SHIFT AND ROTATE 280 REM 285 V=129:REM $81 290 FOR OPER=BLSR TO BROL 295 ? "Testing ";N$(OPER*3-2,OPER*3);" on Value "; 300 VALUE=V:GOSUB 505 305 FOR Y=0 TO 8 310 ? N$(OPER*3-2,OPER*3);" ";Y;" = "; 315 VALUE=USR(BITS,OPER,V,Y) 320 GOSUB 505 325 NEXT Y 330 ? 335 NEXT OPER 340 END 400 REM 401 REM OUTPUT INTEGER CONVERTED TO 402 REM USEFUL FORMAT: 403 REM $HEX = BITS BITS BITS BITS 404 REM 405 RH=USR(INT2HEX,VALUE,ADR(HX$)) 406 RB=USR(BIT2STR,VALUE,ADR(BIT$),AZERO,AONE) 407 ? " $";HX$;" = ";BIT$(1,4);" ";BIT$(5,;" ";BIT$(9,12);" ";BIT$(13,16) 408 RETURN 500 REM 501 REM OUTPUT BYTE VALUE CONVERTED TO 502 REM USEFUL FORMAT: 503 REM $HEX = BITS BITS 504 REM 505 RH=USR(INT2HEX,VALUE,ADR(HX$)) 506 RB=USR(BIT2STR,VALUE,ADR(BIT$),AZERO,AONE) 507 ? "$";HX$(3,4);" = ";BIT$(9,12);" ";BIT$(13,16) 508 RETURN 9997 REM 9998 REM SETUP ML UTILITIES 9999 REM 10000 DIM BT$(162),B2S$(67),I2H$(72) 10001 BITS=ADR(BT$) 10002 RESTORE 27000:? "Loading BITS" 10003 FOR I=0 TO 161 10004 READ D:POKE BITS+I,D 10005 NEXT I:? 10006 BIT2STR=ADR(B2S$) 10007 RESTORE 25000:? "Loading BIT2STR" 10008 FOR I=0 TO 66 10009 READ D:POKE BIT2STR+I,D 10010 NEXT I:? 10011 INT2HEX=ADR(I2H$) 10012 RESTORE 26000:? "Loading INT2HEX" 10013 FOR I=0 TO 71 10014 READ D:POKE INT2HEX+I,D 10015 NEXT I:? 10016 RETURN 24996 REM H1:INT2BITS.OBJ 24997 REM SIZE = 67 24998 REM START = 37632 24999 REM END = 37698 25000 DATA 169,0,133,212,133,213,104,240 25001 DATA 57,10,168,201,8,240,5,104 25002 DATA 136,208,252,96,104,153,213,0 25003 DATA 136,208,249,165,218,5,219,240 25004 DATA 33,165,216,197,214,240,27,162 25005 DATA 1,24,22,220,165,216,144,2 25006 DATA 165,214,145,218,200,192,8,240 25007 DATA 4,192,16,208,236,202,16,233 25008 DATA 230,212,96 25996 REM H1:INT2HEX.OBJ 25997 REM SIZE = 72 25998 REM START = 37888 25999 REM END = 37959 26000 DATA 169,0,133,212,133,213,104,240 26001 DATA 62,10,168,201,4,240,5,104 26002 DATA 136,208,252,96,104,153,213,0 26003 DATA 136,208,249,5,215,240,40,216 26004 DATA 162,1,181,216,74,74,74,74 26005 DATA 145,214,181,216,41,15,200,145 26006 DATA 214,200,202,16,237,136,177,214 26007 DATA 201,10,144,2,105,6,105,48 26008 DATA 145,214,136,16,241,230,212,96 26996 REM H1:BITS.OBJ 26997 REM SIZE = 162 26998 REM START = 38144 26999 REM END = 38305 27000 DATA 169,0,133,212,133,213,104,240 27001 DATA 43,10,168,201,6,240,5,104 27002 DATA 136,208,252,96,104,153,213,0 27003 DATA 136,208,249,164,218,240,21,136 27004 DATA 240,19,136,240,29,136,240,39 27005 DATA 136,240,49,136,240,61,136, 27006 DATA 73,136,240,90,96,165,216,5 27007 DATA 214,133,212,165,217,5,215,133 27008 DATA 213,96,165,216,37,214,133,212 27009 DATA 165,217,37,215,133,213,96,165 27010 DATA 216,69,214,133,212,165,217,69 27011 DATA 215,133,213,96,165,216,133,212 27012 DATA 166,214,240,208,74,202,208,252 27013 DATA 133,212,96,165,216,133,212,166 27014 DATA 214,240,193,10,202,208,252,133 27015 DATA 212,96,165,216,133,212,166,214 27016 DATA 240,178,24,106,144,2,9,128 27017 DATA 202,208,247,133,212,96,165,216 27018 DATA 133,212,166,214,240,158,24,42 27019 DATA 144,2,9,1,202,208,247,133 27020 DATA 212,96
Here is the kinder, gentler TESTBIT2 output with the values and bits illustrated:
The output is considerably easier to understand. So neat, so organized, so obvious and informative!
Below are the source files and examples of how to load the machine language routine into BASIC included in the disk image and archive:
INT2BITS File List:
INT2BITS.M65 Saved Mac/65 source
INT2BITS.L65 Mac/65 source listing
INT2BITS.T65 Mac/65 source listed to H6: (linux)
INT2BITS.ASM Mac/65 assembly listing
INT2BITS.TSM Mac/65 assembly listing to H6: (linux)
INT2BITS.OBJ Mac/65 assembled machine language program (with load segments)
INT2BITS.BIN Assembled machine language program without load segments
INT2BITS.LIS LISTed DATA statements for INT2BITS.BIN routine.
INT2BITS.TLS LISTed DATA statements for INT2BITS.BIN routine to H6: (linux)
MAKEI2B.BAS BASIC program to create the INT2BITS.BIN file. This also contains the INT2BITS routine in DATA statements.
MAKEI2B.LIS LISTed version of MAKEI2B.BAS
MAKEI2B.TLS LISTed version of MAKEI2B.BAS to H6: (linux)
TESTI2B.BAS BASIC program that tests the INT2BITS USR() routines.
TESTI2B.LIS LISTed version of TESTI2B.BAS.
TESTI2B.TLS LISTed version of TESTI2B.BAS to H6: (linux)
ZIP archive of files:
Convert_Disk.zip
Tar archive of files (remove the .zip after download)
Convert_Disk.tgz.zip
The Lord will fulfill his purpose for me; your steadfast love, O Lord, endures forever. Do not forsake the work of your hands.
Psalm 138:8
0 Comments
Recommended Comments
There are no comments to display.