MCALL  .MODULE
MODULE CVBTAR,RELEASE=V01,VERSION=04,COMMENT=<CVBTAR/MBGLIB>,IDENT=NO,LIB=YES

;                        Copyright (c) 1999, 2000
;                              Megan Gentry
;                       Framingham, Massachusetts
;                          All Rights Reserved
;                  Commercial Distribution Prohibited
;
; This software may be  freely copied  and used in its entirety for any
; purpose  so long as the above copyright notice and these comments are
; preserved  in  the  source  form  of  this  software, and  the binary
; copyright is preserved in any image built from it.
;
; 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  would welcome  any reports  of problems,
; comments  or suggestions  regarding the software.   Please send email
; to <[email protected]>.
      .SBTTL  Abstract and Edit History

;+
;
; The code in this module was developed in response to a challenge
; posted in a message on the Classic Computer Collector's Mailing
; List in 1999.
;
; Edit History:
;
; (01) 1999 Megan Gentry
;       Original coding and entry
;
; (02) 06-FEB-2000 Megan Gentry
;       Addition of standard copyright, abstract and edit history
;
; (03) 10-Feb-2000 Megan Gentry
;       Added EIS conditional and Source ID string
;
; (04) 11-Feb-2000 Megan Gentry
;       Corrected Release information
;
; Futures:
;       o The code should be modified to use the standard calling
;         sequence
;
;-
      .SBTTL  Miscellaneous Definitions

       .IIF NDF FT.EIS FT.EIS = 0      ;By default, don't use EIS
      .SBTTL  Revision and Copyright string for Images

       .PSECT  .COPY.  RO,D

       .NLCSI  TYPE=I
       .ASCII  /Copyright (c) 1999, 2000 Megan Gentry/<15><12>
      .SBTTL  CVBTAR  - Convert Binary to Ascii Roman Numerals

;+
;
; CVBTAR
;       Converts a binary value to a string of ascii characters which
;       represent the binary value in Roman Numerals.
;
; Call:
;       R0 = Binary value to convert
;       R1 -> Storage space for resulting string (nul-terminated)
;
; Returns:
;       R0 = zero
;       R1 -> Byte beyond end of nul-terminated string
;               (should be at least 16 bytes long)
;       other registers are unaffected as they are saved and restored
;
; Notes:
;       o Valid range for input is 1 to 3999.
;       o Roman numerals are:
;               M  1000
;               D   500
;               C   100
;               L    50
;               X    10
;               V     5
;               I     1
;
; 62 words (132 bytes) of code (non-EIS)
; 5 words (10 bytes) of data
; 7 bytes of text
; 3 words (6 bytes) of stack used
;
; Code ROMable:         yes
; Data ROMable:         yes
; Code Reentrant:       yes
; Data Reentrant:       yes
; Undefined opcodes:    no
; Undefined behaviour:  no
;
;-

       .GLOBL  CVBTAR

       .PSECT  SYS$I,I

       .ENABL  LSB

CVBTAR::

; Range check the input

       TST     R0                      ;Is it valid?
       BLE     100$                    ;Nope...
       CMP     R0,#3999.               ;Maybe, check upper limit...
       BGT     100$                    ;Nope...

; Save registers and do some setup

       MOV     R2,-(SP)                ;Save R2
       MOV     R3,-(SP)                ; and R3 while they are used

       MOV     #BTDTAB,R2              ;R2 -> Binary to decimal conversion table
       MOV     #ROMCHR,R3              ;R3 -> Roman numeral character list
       BR      20$                     ;Just starting conversion...

; Head of the loop

10$:    TST     @R2                     ;End of the conversion table?
       BEQ     90$                     ;Yep, conversion should be complete
20$:    MOV     R0,-(SP)                ;Save current binary on stack

       CLR     R0                      ;Reset R0 for conversion
30$:    INC     R0                      ;Bump count for this digit
       SUB     @R2,@SP                 ;Reduce by this factor of 10
       BHIS    30$                     ;Continue if still positive...

       ADD     (R2)+,@SP               ;We went too far, add it back
                                       ; (and bump conversion table pointer)
                                       ;  remainder is still on stack
       DEC     R0                      ;Reduce the count
       BEQ     80$                     ;If zero, no characters to output

; Here we convert the decimal digit to Roman Numerals

       CMP     R0,#9.                  ;Is it a nine?
       BNE     40$                     ;Nope...
       MOVB    @R3,(R1)+               ;Yes, it converts to current numeral
       MOVB    -2(R3),(R1)+            ; followed by the numeral two higher
       BR      80$

40$:    CMP     R0,#4.                  ;Is it a four?
       BNE     50$                     ;Nope...
       MOVB    @R3,(R1)+               ;Yes, it converts to current numeral
       MOVB    -1(R3),(R1)+            ; followed by the numeral one higher
       BR      80$

50$:    SUB     #5.,R0                  ;Is value five or greater?
       BLT     60$                     ;Nope, in range zero to three...
       MOVB    -1(R3),(R1)+            ;Yes, prefix with next higher numeral
       SUB     #5.,R0                  ; followed by one to three current
60$:    ADD     #5.,R0                  ;Reduce value to range zero to three
       BEQ     80$                     ;It was zero, nothing to do...
70$:    MOVB    @R3,(R1)+               ;Store a numeral

       .IF EQ FT.EIS
       DEC     R0                      ;More to do?
       BGT     70$                     ;Yep...
       .IFF ;EQ FT.EIS
       SOB     R0,70$
       .ENDC ;EQ FT.EIS

; Tail of the loop

80$:    ADD     #2,R3                   ;Bump the numeral pointer by *2*
       MOV     (SP)+,R0                ;Pop the remainder (we've already
                                       ; popped power of ten pointer)
       BNE     10$                     ;More conversion to do if non-zero

; Clean-up

90$:    MOV     (SP)+,R3                ;Restore previously saved R3
       MOV     (SP)+,R2                ; and R2
       BR      110$

; Out-of-range string

100$:   MOVB    #'*,(R1)+               ;Out-of-range conversion string

; String termination and return

110$:   CLRB    (R1)+                   ;String is to be nul-terminated
       RETURN

       .DSABL  LSB
      .SBTTL  Pure Data and Text areas

; Conversion data

       .PSECT  SYS$D,D

; Binary to decimal conversion table

BTDTAB: .WORD   1000.
       .WORD    100.
       .WORD     10.
       .WORD      1.
       .WORD   0       ; ** Table Fence **

; Roman Numerals (1st, 3rd... entries match entries in BTDTAB)

ROMCHR: .ASCII  /MDCLXVI/
       .EVEN

       .END