.MCALL .MODULE .MODULE ZRTLIB,RELEASE=X00,VERSION=02,COMMENT=,AUDIT=NO ;+ ; ; Copyright (C) 2000 by Megan Gentry ; Framingham, Massachussetts ; All Rights Reserved ; Commercial Use and Distribution Prohibited ; ; This software was developed for use with the Z-machine emulator by ; Johnny Billquist. In this context, rights are hereby granted by ; the author for the software to be freely copied and used in its ; entirety for any non-commercial purpose so long as the above ; copyright notice and these comments are preserved. ; ; The author has used best efforts in the research, design, development ; and testing of this software. The author makes no warranty of any ; kind, expressed or implied, with regard to this software and its ; suitability for a given application. The author shall not be liable ; in any event for incidental or consequential damages in connection ; with, or arising out of, the use or performance of this software. Use ; of this software constitutes acceptance of these terms. ; ; The author is committed to making a best effort at fixing any errors ; found in the software and welcomes any reports of problems, comments, ; or suggestions regarding the software at . ; ;- .SBTTL Abstract and Edit History ;+ ; ; ZEDMSG ; This routine is the RT-11 replacement for the RSX routine ; which expands a string to be printed using formatting ; characters ala U*x printf(). ; ; History: ; ; (00) 22-Aug-2000 Megan Gentry ; Initial coding ; ; (01) 23-Aug-2000 Megan Gentry ; o Added code to $EDMSG to properly check for the end of the ; format string and to add a final NUL to the end of the ; output string. ; o Added line to specify CODE psect in front of all routines ; o Down-sized some code relating to sign extension ; o Down-sized some code relating to NUL termination ; ; (02) edit reason lost ; ; (03) 30-Apr-2006 Johnny Billquist ; Added $SAVVR ; ;-- .SBTTL $EDMSG - Edit a message string (like printf) ;+ ; ; $EDMSG ; Like printf() in U*x, this routine builds a printable string ; in an output buffer based on an input string which contains ; formatting information. ; ; Input: ; R0 -> Output buffer ; R1 -> Input buffer ; R2 -> List of single-word arguments to be printed ; ; Output: ; R0 -> Byte beyond buffer ; R1 = undefined ; R2 = undefined ; ; Notes: ; Conversion control is based on the following characters: ; ; %D - signed decimal. ; %O - signed octal. ; %M - unsigned decimal. ; %P - unsigned octal. ; %U - unsigned decimal. ; %B - unsigned octal byte. Argument is address of byte. ; %% - Passes a single '%' to the output string ; ;- .PSECT CODE,I,RO .ENABL LSB $EDMSG:: MOV R1,-(SP) ;Save some registers MOV R2,-(SP) ; ... MOV R3,-(SP) ; ... 10$: TSTB @R1 ;At end of formatting string? BEQ 80$ ;Yep... all done CMPB @R1,#'% ;Is this beginning of conversion? BEQ 30$ ;Yep... 20$: MOVB (R1)+,(R0)+ ;Nope, move character to output BNE 10$ ;Haven't reached EOS yet, continue BR 80$ ;We're all done... 30$: INC R1 ;Bump pointer to conversion character CMPB @R1,#'% ;Is it an escape for the '%' char? BEQ 20$ ;Yep... 40$: MOV #$EDCTB,R3 ;R3 -> Conversion table 50$: TSTB @R3 ;End of table? BNE 60$ ;Nope... DEC R1 ;Back up to escape character BR 20$ ;Now treat it as non-special 60$: CMPB @R1,@R3 ;Does it match this special character? BEQ 70$ ;Yes... ADD #4,R3 ;Nope, on to next entry... BR 50$ 70$: CALL @2(R3) ;Do the conversion INC R1 ;Bump pointer past conversion char BR 10$ 80$: CLRB @R0 ;Ensure string is NUL-terminated MOV (SP)+,R3 ;Restore previously saved registers MOV (SP)+,R2 ; ... MOV (SP)+,R1 ; ... RETURN .DSABL LSB .PSECT DATA,D,RW $EDCTB: .WORD 'D, $EDSDE ;Signed decimal .WORD 'O, $EDSOC ;Signed octal .WORD 'M, $EDUDE ;Unsigned decimal .WORD 'P, $EDUOC ;Unsigned octal .WORD 'U, $EDUDE ;Unsigned decimal .WORD 'B, $EDUOB ;Unsigned octal, byte .WORD 0 ; ** Table Fence ** .SBTTL $EDSDE - Signed Decimal .PSECT CODE,I,RO $EDSDE: MOV R1,-(SP) ;Save pointer to format string MOV (R2)+,R1 ;R1 = Number to convert BPL 10$ ;If plus... go do it MOVB #'-,(R0)+ ;If minus, put a '-' to output buffer NEG R1 ; and negate the value 10$: CALL $EDDEC ;Go do the conversion MOV (SP)+,R1 ;Restore pointer to format string RETURN .SBTTL $EDSOC - Signed Octal .PSECT CODE,I,RO $EDSOC: MOV R1,-(SP) ;Save pointer to format string MOV (R2)+,R1 ;R1 = Number to convert BPL 10$ ;If plus... go do it MOVB #'-,(R0)+ ;If minus, put a '-' to output buffer NEG R1 ; and negate the value 10$: CALL $EDOCT ;Go do the conversion MOV (SP)+,R1 ;Restore pointer to format string RETURN .SBTTL $EDUDE - Unsigned Decimal .PSECT CODE,I,RO $EDUDE: MOV R1,-(SP) ;Save pointer to format string MOV (R2)+,R1 ;R1 = Number to convert CALL $EDDEC ;Go do it... MOV (SP)+,R1 ;Restore pointer to format string RETURN .SBTTL $EDUOC - Unsigned Octal .PSECT CODE,I,RO $EDUOC: MOV R1,-(SP) ;Save pointer to format string MOV (R2)+,R1 ;R1 = Number to convert CALL $EDOCT ;Go do it... MOV (SP)+,R1 ;Restore pointer to format string RETURN .SBTTL $EDUOZ - Unsigned Octal, Leading Zeroes .PSECT CODE,I,RO $EDUOZ: MOV R1,-(SP) ;Save pointer to format string MOV R0,-(SP) ;Save current output pointer MOV @R2,R1 ;R1 = Number to convert CALL $EDOCT ;Do the conversion MOV R0,R1 ;Determine length of conversion SUB @SP,R1 ; ... MOV (SP)+,R0 ;Restore pointer to output string NEG R1 ;Determine count of leading zeroes ADD #6,R1 ;R1 = Count of leading zeroes required BEQ 20$ ;If none required... 10$: MOVB #'0,(R0)+ ;Output a leading zero... DEC R1 ;More to do? BGT 10$ ;Yep... 20$: MOV (R2)+,R1 ;R1 = Number to convert CALL $EDOCT ;Do the real conversion MOV (SP)+,R1 ;Restore pointer to format string RETURN .SBTTL $EDUOB - Unsigned Octal, Byte .PSECT CODE,I,RO $EDUOB: MOV R1,-(SP) ;Save pointer to format string MOV (R2)+,R1 ;R1 -> Byte to convert MOVB @R1,R1 ;R1 = Byte to convert BIC #^C<377>,R1 ;Discard any sign extension CALL $EDOCT ;Do the conversion MOV (SP)+,R1 ;Restore pointer to format string RETURN .SBTTL $EDOCT - Binary to Octal conversion .PSECT CODE,I,RO $EDOCT: MOV R1,-(SP) ;Save the current value BIC #^C<7>,@SP ;Isolate an octal digit's worth ADD #'0,@SP ;Make it printable ROR R1 ;Shift right (don't replicate MSB) ASR R1 ; for next ASR R1 ; octal digit BEQ 10$ ;If all done converting... CALL $EDOCT ;More to do... 10$: MOVB (SP)+,(R0)+ ;Store a character RETURN ; ! Recurse ! - unwind stack .SBTTL $EDDEC - Binary to Decimal conversion .PSECT CODE,I,RO $EDDEC: MOV R1,-(SP) ;Make a copy of the number CLR R1 ;Crude divide by 10. 10$: INC R1 ; ... SUB #10.,@SP ; ... BHIS 10$ ; ... ADD #10.+'0,@SP ;Make the digit printable DEC R1 ;Correct the quotient BEQ 20$ ;If all done converting... CALL $EDDEC ;More to do... 20$: MOVB (SP)+,(R0)+ ;Store a character RETURN ; ! Recurse ! - unwind stack .SBTTL $SAVAL - Saves all registers (coroutine) $SAVAL:: MOV R0,-(SP) ;Save all the registers MOV R1,-(SP) ; ... MOV R2,-(SP) ; ... MOV R3,-(SP) ; ... MOV R4,-(SP) ; ... MOV R5,-(SP) ; ... CALL @14(SP) ;Co-routine back to our caller MOV (SP)+,R5 ;*C* Restore the registers MOV (SP)+,R4 ;*C* (preserving C-bit) MOV (SP)+,R3 ;*C* ... MOV (SP)+,R2 ;*C* ... MOV (SP)+,R1 ;*C* ... MOV (SP)+,R0 ;*C* ... DEC (SP)+ ;*C* Don't return to our caller RETURN ;*C* rather to our caller's caller .SBTTL .SAVR1 - Saves R1-R5 (coroutine) .SAVR1:: MOV R4,-(SP) ;Save all the registers MOV R3,-(SP) ; ... MOV R2,-(SP) ; ... MOV R1,-(SP) ; ... MOV R5,-(SP) ; Push return address. MOV 12(SP),R5 ; Get old R5. CALL @(SP)+ ; Co-routine back to caller. MOV (SP)+,R1 ;*C* Restore the registers MOV (SP)+,R2 ;*C* (preserving C-bit) MOV (SP)+,R3 ;*C* ... MOV (SP)+,R4 ;*C* ... MOV (SP)+,R5 ;*C* ... RETURN ;*C* .SBTTL $SAVVR - Saves R0-R2 (coroutine) $SAVVR:: MOV R1,-(SP) ;Save all the registers MOV R0,-(SP) ; ... MOV R2,-(SP) ; Push return address. MOV 6(SP),R2 ; Get old R2. CALL @(SP)+ ; Co-routine back to caller. MOV (SP)+,R0 ;*C* Restore the registers MOV (SP)+,R1 ;*C* (preserving C-bit) MOV (SP)+,R2 ;*C* ... RETURN ;*C* .END