; > Radix50 ; ; Filing systems such as that used by RT11 and RSX11 use Radix50 to store the ; file names. This is up to nine characters squashed into six bytes by using ; only letters, digits, and a few punctuation characters to use only 40 valid ; characters. 40 is octal 50, so this scheme is called Radix50. ; ; Each two-byte word holds char1*40*40+char2*40+char3 resulting in a values ; 0 to 63999 (40*40*40-1). The first character in a string is encoded in the ; highest value in the word. ; ; Standard Radix50 characters are: " abcdefghijklmnopqrstuvwxyz$%*0123456789" ; Filenames are normally terminated by a space, so these routines reject a ; space character. ; Convert ASCII filename to Radix50 name block ; ============================================ ; In: R1=>filename ; R2=>output buffer, word aligned ; Out: R2=>output buffer ; R1=>character after filename ; R0= character after filename ; CS=filename valid ; CC=filename invalid ; ; Filename is of the form "DK0:ABCDEF.GHI" where the device and the extension ; are optional. The device defaults to the default "DK:", the extension ; defaults to spaces. ; ; Radix50 name block is of the form: ; buff+0 device, defaults to "DK:" ; buff+2 filename1,2,3 ; buff+4 filename4,5,6 ; buff+6 extension1,2,3 ; R50GetFilename: cmpb (r1)+,#ASC" " beq R50GetFilename ; Skip leading spaces dec r1 ; R1=>first nonspace character mov r3,-(sp) ; Save R3 jsr pc,R50GetThree ; Get up to 3 characters for device cmpb r0,#ASC":" ; Device specifier ends with colon beq R50GetName2 ; Yes, continue by scanning filename ; ; Not a device prefix, we've scanned three chars of filename mov -2(r2),(r2)+ ; Copy to start of filename mov #(ASC"D"-64)*40*40+(ASC"K"-64)*40,-4(r2) ; Set device name to 'DK:' br R50GetName3 ; Scan second half of filename ; ; Device name has been scanned, now scan filename R50GetName2: inc r1 ; Step past colon jsr pc,R50GetThree ; Get up to 3 characters of filename cmp r0,#ASC"." beq R50GetName4 ; Dot, scan extension R50GetName3: jsr pc,R50GetThree ; Get up to 3 more characters of filename cmpb r0,#ASC"." ; Extension seperator? beq R50GetName5 ; Yes, step past dot clr (r2)+ ; No extension, set it to spaces br R50GetName7 ; R50GetName4: clr (r2)+ ; Set second half of filename to spaces R50GetName5: inc r1 ; Step past dot R50GetName6: jsr pc,R50GetThree ; Get up to 3 characters of extension R50GetName7: mov (sp)+,r3 ; Restore R3 sub #8,r2 ; Point R2 back to start of output buffer cmpb #ASC" ",r0 ; Are we at end of name? rts pc ; CC=Ok, CS=Bad name ; Scan up to three characters and convert to Radix50 ; -------------------------------------------------- ; In: R1=>character string ; R2=>output buffer ; Out: R0= next input character ; R1=>next input character ; R2=>next output buffer byte ; R3=corrupted ; R50GetThree: clr (r2) ; Set current word to three spaces mov #3,r3 ; Prepare to scan three characters R50GetThreeLp: movb (r1)+,r0 ; Get character jsr pc,R50Char ; Test it for valid R50 character bcs R50GetThreeEnd ; Invalid character, pad to end jsr pc,R50Times40 ; Multiply by 40 and add dec r3 bne R50GetThreeLp ; Loop for up to three characters inc r1 br R50GetThreeDone ; All three done R50GetThreeEnd: jsr pc,R50Times40Zero ; Multiply by 40 to pad with spaces dec r3 bne R50GetThreeEnd ; All three done R50GetThreeDone: movb -(r1),r0 ; Get terminating character tst (r2)+ ; Step to next output word rts pc R50Times40Zero: clr r0 R50Times40: mov r0,-(sp) ; Save this index mov (r2),r0 asl r0 ; *2 asl r0 ; *4 add (r2),r0 ; +1 -> *5 asl r0 ; *10 asl r0 ; *20 asl r0 ; *40 add (sp)+,r0 ; num=num*40+this mov r0,(r2) ; Store in output buffer rts pc ; Check for Valid R50 character ; ----------------------------- ; In: R0=character ; Out: CC=valid character R0=R50 index ; CS=invalid character R0=character or uppercase ; Valid characters are " abcdefghijklmnopqrstuvwxyz$%*0123456789" ; But filenames are terminated by space, so ' ' rejected. ; '%' is wildcard one character ; '*' is wildcard many characters ; R50Char: cmpb r0,#ASC"$" ; Simpler to make these special cases beq R50Char27 ; Convert '$' -> 27 cmpb r0,#ASC"%" beq R50Char28 ; Convert '%' -> 28 cmpb r0,#ASC"*" beq R50Char29 ; Convert '*' -> 29 jsr pc,R50ChkChar ; Check if 0-9,A-Z,a-z bcs R50CharOk ; Exit with CS, R0=preserved or upper case cmp r0,#ASC"@" bcc R50Alpha ; Branch to reduce letters to 1-26 add #&4E,r0 ; Adjust digits to reduce to 30-39 R50Alpha: sub #ASC"@",r0 ; A-Z -> 1-26, 0-9 -> 30-39 rts pc ; CC=Ok character, R0=Radix50 offset R50Char29: mov #38,r0 ; Prepare to convert to 29 R50Char28: R50Char27: sub #9,r0 ; Convert to 27,28,29 R50CharOk: rts pc ; Check for alphanumeric character ; -------------------------------- ; CC=Ok, CS=Not ok ; R50ChkChar: cmpb r0,#ASC"0" bcs R50ChkCharOk ; <'0' - exit with CS cmpb #ASC"9",r0 bcc R50ChkCharOk ; '0'-'9' - exit with CC cmpb r0,#ASC"A" bcs R50ChkCharOk ; <'A' - exit with CS bic #&FFA0,r0 ; Force to upper case cmpb #ASC"Z",r0 ; 'A'-'Z' - exit with CC R50ChkCharOk: rts pc ; Convert Radix50 name block to ASCII string ; ========================================== ; Adapted from disassembly of DIR.SAV in RT11 distribution ; In: R1=>filename buffer ; R2=>name block, word aligned ; Out: R0=corrupted ; R1=>zero terminator ; R2=>after name block ; R50PutFilename: mov r3,-(sp) ; Save registers mov r4,-(sp) jsr pc,R50Word ; Convert word to three chars tst -2(R2) beq R50PutName2 ; No device name, skip colon movb #ASC":",(r1)+ ; Colon after device name br R50PutName2 ; ; Enter here for no device name R50PutName: mov r3,-(sp) ; Save registers mov r4,-(sp) R50PutName2: jsr pc,R50Word ; First three chars jsr pc,R50Word ; Second three chars movb #ASC".",(r1)+ ; Dot before extension jsr pc,R50Word ; Three extension chars clrb (r1) ; Zero terminator mov (sp)+,r4 ; Restore mov (sp)+,r3 rts pc R50Word: mov (r2)+,r0 ; Fetch word from filename block cmp r0,#64000 bcc R50WordDone ; Out of range, no output adr R50Fourties,r3 ; R3=>power of 40 R50WordLp1: mov #-1,r4 ; Increment to zero R50Word3: inc r4 ; Standard looping divide code sub (r3),r0 bcc R50Word3 ; Divide by power-of-40 add (r3),r0 ; Add last divider back tst r4 beq R50WordSpc ; 0 -> add &20 -> space cmp r4,#29 beq R50WordChar29 ; 29 -> add &0D -> * bcc R50WordDigit ; >29 -> add &12 -> digit cmp r4,#27 bcc R50WordChar27 ; 27/28 -> add &09 -> $,% add #&20,r4 ; Add &40 R50WordSpc: add #&0E,r4 ; Add &20 R50WordDigit: add #&05,r4 ; Add &12 R50WordChar29: add #&04,r4 ; Add &0D R50WordChar27: add #&09,r4 ; Add &09 movb r4,(r1)+ ; Store character tst -(r3) ; Run out of powers? bne R50WordLp1 ; Keep going mov #3,r3 ; Three characters R50WordLp2: cmpb -1(r1),#ASC" " ; Step back if any spaces bne R50WordDone dec r1 ; Step back to drop space dec r3 bne R50WordLp2 R50WordDone: rts pc equw 0,1,40 ; Powers of 40 R50Fourties: equw 40*40