PRTBYT takes a byte and sends it to the serial TY as two hex ascii characters
The byte is entered in A, two characters are printed and A is saved.
0914 1E3B ; 0915 1E3B ; PRINT 1 HEX BYTE AS 2 ASCII CHAR'S 0916 1E3B ; 0917 1E3B 85 FC PRTBYT STA TEMP 0918 1E3D 4A LSR A ; SHIFT CHAR RIGHT 4 BITS 0919 1E3E 4A LSR A 0920 1E3F 4A LSR A 0921 1E40 4A LSR A 0922 1E41 20 4C 1E JSR HEXTA ; CONVERT TO HEX AND PRINT 0923 1E44 A5 FC LDA TEMP ; GET OTHER HALF 0924 1E46 20 4C 1E JSR HEXTA ; CONVERT TO HEX AND PRINT 0925 1E49 A5 FC LDA TEMP ; RESTORE BYTE IN A AND RETURN 0926 1E4B 60 RTS 0927 1E4C ; 0928 1E4C 29 0F HEXTA AND #$0F ; MASK HI 4 BITS 0929 1E4E C9 0A CMP #$0A 0930 1E50 18 CLC 0931 1E51 30 02 BMI HEXTA1 0932 1E53 69 07 ADC #$07 ; ALPHA HEX 0933 1E55 69 30 HEXTA1 ADC #$30 ; DEC HEX 0934 1E57 4C A0 1E JMP OUTCH ; PRINT CHAR
What is happening here?
- The byte in A is saved (917)
- the high nibble is shifted to the lower nibble (918-921)
- the nibble is converted to hex (922, calls hexta)
- the byte is restored and the low nibble converted to hex
- A is restored
- hexta masks off low nibble (928)
- convert A..F to ascii (929-932)
- convert hex to ascii and print(933-934)
GETBYT and PACK
1148 1F9D ; 1149 1F9D ; GET 2 HEX CHAR'S AND PACK 1150 1F9D ; INTO INL AND INH 1151 1F9D ; X PRESERVED Y RETURNED = 0 1152 1F9D ; NON-HEX WILL BE LOADED AS NEAREST HEX EQU 1153 1F9D ; 1154 1F9D 20 5A 1E GETBYT JSR GETCH 1155 1FA0 20 AC 1F JSR PACK 1156 1FA3 20 5A 1E JSR GETCH 1157 1FA6 20 AC 1F JSR PACK 1158 1FA9 A5 F8 LDA INL 1159 1FAB 60 RTS 1160 1FAC ; 1161 1FAC ; SHIFT CHAR IN A INTO 1162 1FAC ; INL AND INH 1163 1FAC ; 1164 1FAC C9 30 PACK CMP #$30 ; CHECK FOR HEX 1165 1FAE 30 1B BMI UPDAT2 1166 1FB0 C9 47 CMP #$47 ; NOT HEX EXIT 1167 1FB2 10 17 BPL UPDAT2 1168 1FB4 C9 40 CMP #$40 ; CONVERT TO HEX 1169 1FB6 30 03 BMI UPDATE 1170 1FB8 18 CLC 1171 1FB9 69 09 ADC #$09 1172 1FBB 2A UPDATE ROL A 1173 1FBC 2A ROL A 1174 1FBD 2A ROL A 1175 1FBE 2A ROL A 1176 1FBF A0 04 LDY #$04 ; SHIFT INTO I/O BUFFER 1177 1FC1 2A UPDAT1 ROL A 1178 1FC2 26 F8 ROL INL 1179 1FC4 26 F9 ROL INH 1180 1FC6 88 DEY 1181 1FC7 D0 F8 BNE UPDAT1 1182 1FC9 A9 00 LDA #$00 ; A=0 IF HEX NUM 1183 1FCB 60 UPDAT2 RTS
What is happening here?
GETBYT
The GETBYT routine is used in the TTY part of the KIM-1 monitor to enter two hex characters (0..9 and A..F) and pack it into one byte.
- read the first character (1154)
- pack it into INL lower nibble (1155)
- read the second character (1156)
- pack it into INL, shifting the lower nibble to high and shifting in the second nibble (1157)
- return byte from INL to A
PACK
- check if < '0' and error out with A > 0 (1164-1165)
- check if > ‘F’ and error out with A > 0 (1166-1167)
- if A..F add $09 (1168-1171)
- shift in nibble via INH and INL
- return zero if valid hex but with invalid Z flag
Note that the range between ‘9’ and ‘A’ is not checked, so those are taken as valid hex characters.
The PACK routine accepts ‘:’– ‘?’, $3A .. $3F as valid hex characters A ..F.
KIM 0200 A9 ;; 00BB 00 :: 00AA 00 ???? FFFF 1C
The ASCII encoding is arranged so that adding 9 to ‘A’–’F’ aligns them perfectly with the desired hexadecimal nibble after four left rotates. This avoids a separate subtraction of ‘A’ and addition of 10.
The following demo with PRTBYT and GETBYT illustrates how this could be done in a user program.
0001 0000 ; 0002 0000 ; GETBYTC with error checking 0003 0000 ; illustrates shortcomings in PACK 0004 0000 ; - G and ; and possibly more accepted without error 0005 0000 ; 0006 0000 ; Demo of program: 0007 0000 ; KIM 0008 0000 ; 0000 00 200 0009 0000 ; 0200 A9 G 0010 0000 ; >12=12 0011 0000 ; >33=33 0012 0000 ; >G? 0013 0000 ; >H? 0014 0000 ; >GG=00 0015 0000 ; >;;=BB 0016 0000 ; >AB=AB 0017 0000 ; >CD=CD 0018 0000 ; >EE=EE 0019 0000 ; > 0020 0000 ; 0021 0000 ; KIM-1 defines 0022 0000 ; 0023 0000 PACK = $1FAC ; pack hex character into INL, shift in 0024 0000 PRTBYT = $1E3B ; print byte as 2 hex characters 0025 0000 GETCH = $1E5A ; receive character from TTY serial 0026 0000 OUTCH = $1EA0 ; send character via TTY serial 0027 0000 INL = $F8 0028 0000 INH = $F9 0029 0000 ; 0030 0200 .org $0200 0031 0200 0032 0200 ; demo code 0033 0200 ; 0034 0200 A9 00 LOOP LDA #$00 0035 0202 85 F8 STA INL ; zero hex byte 0036 0204 85 F9 STA INH 0037 0206 20 3E 02 JSR CRLF 0038 0209 A9 3E LDA #'>' ; prompt 0039 020B 20 A0 1E JSR OUTCH 0040 020E 20 28 02 JSR GETBYTC 0041 0211 90 08 BCC OK 0042 0213 A9 3F LDA #'?' ; error 0043 0215 20 A0 1E JSR OUTCH 0044 0218 4C 00 02 JMP LOOP 0045 021B ; 0046 021B 48 OK PHA 0047 021C A9 3D LDA #'=' 0048 021E 20 A0 1E JSR OUTCH 0049 0221 68 PLA 0050 0222 20 3B 1E JSR PRTBYT 0051 0225 4C 00 02 JMP LOOP ; repeat 0052 0228 ; 0053 0228 ; subroutine GETBYTC 0054 0228 ; read 2 hex characters from TTY input 0055 0228 ; pack into one byte 0056 0228 ; Returns: carry clear if hex OK, A == hex byte 0057 0228 ; clobbers X and Y 0058 0228 ; 0059 0228 0060 0228 0061 0228 20 5A 1E GETBYTC JSR GETCH ; read character 0062 022B 20 AC 1F JSR PACK ; pack into INL 0063 022E D0 0C BNE EGETB ; A = 0 if hex number 0064 0230 20 5A 1E JSR GETCH ; read second character 0065 0233 20 AC 1F JSR PACK ; pack into INL 0066 0236 D0 04 BNE EGETB ; A = 0 if hex number 0067 0238 A5 F8 LDA INL 0068 023A 18 CLC 0069 023B 60 RTS 0070 023C 38 EGETB SEC 0071 023D 60 RTS 0072 023E 0073 023E A9 0D CRLF LDA #$0D 0074 0240 20 A0 1E JSR OUTCH 0075 0243 A9 0A LDA #$0A 0076 0245 20 A0 1E JSR OUTCH 0077 0248 60 RTS 0078 0249 0079 0249 .END 0080 0249 0081 0249 tasm: Number of errors = 0