Okay, I have been able to test the routine, and in fact it did work
first time it executed... It didn't assemble first time because I
had left out a local symbol, but with that corrected it built on the
second try.
In designing the algorithm I used, I noted that converting to Roman
is the same as converting a binary value to decimal (finding the
digit 0-9 for a given power-of-ten) but with the added step of
converting that digit to the appropriate characters for the given
power-of-ten.
The routine has a table of values which are used for successively
subtracting a power of ten from the value until it has a digit 0-9 and a
remainder (which is handled by decreasing powers of ten on successive
passes through the loop). It also maintains a pointer to the current
roman numeral corresponding with the current power-of-ten.
The conversion for 0-3 is easy, it simply outputs the requisite number
of the current roman numeral. For 4, it outputs the current numeral
followed by the numeral one higher. For 5-8, it starts by printing
the numeral one higher followed by 0-3 of the current numeral. For
9, it outputs the current numeral followed by the numeral two higher.
At the end of each loop, the power-of-ten pointer is incremented to
the next entry, but the pointer to the roman numeral is also incremented
by two. This way, the 'current numeral' pointer is always pointing to
'M', 'C', 'X', or 'I'. Since no number in the range which
can be
converted required numerals above 'M', I only have to worry about C,
X and I. The numeral one higher than each is, respectively, D, L and V.
The numeral two higher than each is, respectively, M, C and X.
That's it...
I didn't get info on cycles, but I did for number of instructions, which
I included in the comments for the routine.
One last thing - since there are quite a few members in the family
of pdp-11 CPUs, the code is written to run correctly on any one of
them. There are no restrictions, so using the T-11 (as I think
Allison mentioned) would be possible.
Megan Gentry
Former RT-11 Developer
+--------------------------------+-------------------------------------+
| Megan Gentry, EMT/B, PP-ASEL | Internet (work): gentry(a)zk3.dec.com |
| Unix Support Engineering Group | (home): mbg(a)world.std.com |
| Compaq Computer Corporation | |
| 110 Spitbrook Rd. ZK03-2/T43 | URL:
http://world.std.com/~mbg/ |
| Nashua, NH 03062 | "pdp-11 programmer - some assembler |
| (603) 884 1055 | required." - mbg |
+--------------------------------+-------------------------------------+
- - - - -
.SBTTL CVBTAR - Convert Binary to Ascii Roman Numerals
;+
;
; Copyright (c) 1999 by Megan Gentry
;
; CVBTAR
; Converts a binary value to string of ascii characters which
; represent the 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
; 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
;
; 60 words (120 bytes) of code
; 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
;
; Value Instructions executed
; 0 5
; 4000 7
; 1 78
; 3999 185
; 3888 220
;
;-
.PSECT .CODE.
.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 -> 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 current 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 one higher numeral
SUB #5.,R0 ; followed by one to three current
60$: ADD #5.,R0 ;Return value to range zero to three
BEQ 80$ ;It was zero, nothing to do...
70$: MOVB @R3,(R1)+ ;Store a numeral
DEC R0 ;More to do?
BGT 70$ ;Yep...
; Tail of the loop
80$: ADD #2,R3 ;Bump the numeral pointer by *2*
MOV (SP)+,R0 ;Pop the remainder (already popped
; the 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
; Conversion data
.PSECT .DATA.
; Binary to decimal conversion table
BTDTAB: .WORD 1000.
.WORD 100.
.WORD 10.
.WORD 1.
.WORD 0 ; ** Table Fence **
.PSECT .TEXT.
; Roman Numerals (1st, 3rd... entries match entries in BTDTAB)
ROMCHR: .ASCII /MDCLXVI/
.EVEN
.END