; ROMAN80 - VERSION 0.2
;
; ROMAN CONVERSION PROGRAM
;
; DATE: 10-OCT-78
; BY: M PEDDER
;
;
; DEFINITIONS
;
ORG 100H ;ALLOCATE
START: JMP ROMAN
CR: EQU 0DH
LF: EQU 0AH
CONSTA: EQU 1H ;Console status port
CONDAT: EQU 0H ;Console data port
B$KDR: EQU 02H ;Data available mask
STACK: EQU 400H
B$VDR: EQU 01H ;Tx ready mask
;
; MESSAGES
;
STM DB 'COPYRIGHT (C) 1978 M PEDDER',CR,LF
DB '"ROMAN" ACCEPTS DECIMAL NUMBERS IN THE RANGE 1 - 3999'
DB CR,LF
DB 'AND CONVERTS TO ROMAN NUMERALS, CHECKING VALIDITY.'
DB CR,LF,LF
DB 'ENTER DATA FOLLOWING "READY =", ENDING WITH "CR"'
DB CR,LF,'$'
RDM DB CR,LF,'READY = $'
TOOL: DB ' TOO LARGE$'
INV: DB ' INVALID CHARACTER$'
LIST: DB 0,0,'IVXLCDM'
;
; WORKSPACE:
;
DBUF: DS 5 ;DECIMAL BUFFER
RBUF: DS 16 ;ROMAN BUFFER
DCNT: DS 1 ;DECIMAL COUNT
STK: DS 2 ;SP HOLDER
;
; SUPERVISORY:
;
ROMAN: LXI H,0
DAD SP
SHLD STK
LXI SP,STACK ;PREPARE STACK
LXI H,STM ;POINT TO START MESSAGE
CALL PRINS ;AND OUTPUT IT
RDY: CALL RDYM ;PRODUCE READY MESSAGE, AND SET UP
CALL INPUT ;GET DATA
JC RDY ;IF IT IS VALID
CALL ENC ;ENCODE AND OUTPUT IT
JMP RDY
PAGE
;
; READY MESSAGE AND SETTING UP:
;
RDYM: LXI H,RDM ;POINT TO READY MESSAGE
CALL PRINS ;AND OUTPUT IT
LXI B,DBUF ;PREPARE DECIMAL POINTER
LXI H,DCNT ;AND COUNT POINTER
MVI M,00H ;CLEAR COUNTER
RET
;
; GET INPUT FROM CONSOLE INTO DBUF, CHECKING VALIDITY:
;
INPUT: IN CONSTA ;IF CHARACTER
ANI B$KDR ;IS AVAILABLE
JZ INPUT
IN CONDAT ;GET IT
ANI 7FH ;STRIP PARITY
CPI 03H ;IF IT IS EXIT CMD
JZ EXIT ;THEN GO
CPI 0DH ;IF IT IS 'CR'
JNZ ECHO ;THEN
MVI A,20H ;LOAD 'SPACE'
CALL PRINC ;AND OUTPUT IT
CALL PRINC ;TWICE
MVI A,'$' ;MARK END
STAX B ;OF DATA
ORA A ;CLEAR FLAG
RET
;
EXIT: LHLD STK
SPHL
RET
;
ECHO: CALL PRINC ;ECHO CHARACTER
CPI '0' ;IF IT IS ZERO OR MORE
JM INVCH ;AND
CPI ':' ;IF IT IS NINE OR LESS
JP INVCH ;THEN IT IS VALID CHARACTER
INR M ;SO COUNT IT
STAX B ;AND STORE IT
INX B ;ADVANCE POINTER
MOV A,M ;CHECK COUNT
CPI 05H ;IF IT IS LESS THAN FIVE
JM INPUT ;THEN CONTINUE
LXI H,TOOL ;ELSE POINT TO 'TOO LARGE'
JMP MES
;
INVCH: LXI H,INV ;POINT TO 'INVALID CHARACTER'
MES: CALL PRINS ;AND OUTPUT IT
STC ;SET ERROR FLAG
RET
;
;
PAGE
;
; PREPARE TO ENCODE:
;
ENC: LXI B,DBUF ;PREPARE DECIMAL POINTER
LXI D,LIST ;PREPARE LIST POINTER
LXI H,DCNT ;PREPARE COUNT POINTER
MOV A,M ;GET COUNT
CPI 04H ;IF IT IS NOT FOUR
JNZ CONT ;CONTINUE
LDAX B ;ELSE GET FIRST CHARACTER
CPI 34H ;IF IT IS NOT FOUR
JM CONT ;CONTINUE
LXI H,TOOL ;ELSE LOAD 'TOO LARGE'
CALL PRINS ;AND OUTPUT IT
RET
;
CONT: MOV L,M ;GET COUNT
MVI H,00H ;INTO HL
DAD H ;DOUBLE IT
DAD D ;ADD TO LIST
XCHG ;AND RESTORE LIST
LXI H,RBUF ;PREPARE ROMAN POINTER
;
; ENCODE CHARACTER STREAM IN DBUF:
;
ENCA: LDAX B ;GET A CHARACTER
INX B ;UPDATE THE POINTER
CPI '$' ;IF IT IS NOT "END MARKER"
RZ ;THEN
CPI '9' ;IF IT IS NOT A NINE
JZ NINE ;THEN
CPI '5' ;IF IT IS NOT FIVE OR MORE
JP FIVE ;THEN
CPI '4' ;IF IT IS NOT FOUR
JZ FOUR ;THEN
ETA: CPI '0' ;IF IT IS ZERO
JNZ ONE ;THEN
ETB: DCX D ;MODIFY ROMAN POINTER
DCX D ;TWICE
LDA DCNT ;REDUCE COUNT
DCR A ;AND
STA DCNT ;IF IT IS NOT ZERO
JNZ ENCA ;THEN LOOP
MVI A,'$' ;ELSE MARK END
CALL STOR ;AND STORE IT
JMP ROUT ;ENCODE COMPLETED
;
PAGE
;
; ITS A 1=I, 10=X, 100=C, 1000=M OR MORE:
;
ONE: PUSH PSW ;SAVE DATA
LDAX D ;LOAD ROMAN CHARACTER
CALL STOR ;AND STORE IT
POP PSW ;UNSAVE DATA
DCR A ;SUBTRACT ONE
JMP ETA ;AND TRY AGAIN
;
; ITS A 4=IV, 40=XL, 400=CD:
;
FOUR: LDAX D ;LOAD ROMAN CHARACTER I, X OR C
CALL STOR ;AND STORE IT
INX D ;GET NEXT
LDAX D ;ROMAN CHARACTER V, L OR D
CALL STOR ;AND STORE THAT
DCX D ;RESTORE POINTER
JMP ETB ;AND EXIT
;
; ITS A 5=V, 50=L, 500=D OR MORE:
;
FIVE: PUSH PSW ;SAVE DATA
INX D ;PREPARE POINTER
LDAX D ;GET ROMAN CHARACTER V, L OR D
CALL STOR ;AND STORE IT
DCX D ;RESTORE POINTER
POP PSW ;AND DATA
SUI 05H ;SUBTRACT FIVE
JMP ETA ;AND TRY AGAIN
;
; ITS A 9=IX, 90=XC, OR 900=CM:
;
NINE: LDAX D ;GET ROMAN CHARACTER I, X OR C
CALL STOR ;AND STORE IT
INX D ;MOVE
INX D ;POINTER
LDAX D ;GET ROMAN CHARACTER X, C OR M
CALL STOR ;AND STORE THAT
DCX D ;RESTORE
DCX D ;POINTER
JMP ETB ;AND EXIT
;
PAGE
;
; STORE ROMAN CHARACTER IN RBUF FOR OUTPUT:
;
STOR: MOV M,A ;STORE DATA IN BUFFER
INX H ;AND MOVE POINTER
RET
;
; ROMAN OUTPUT TO CONSOLE:
;
ROUT: LXI H,RBUF ;POINT TO ROMAN BUFFER
CALL PRINS ;AND OUTPUT IT
RET
;
; OUTPUT A STRING OF CHARACTERS:
;
PRX: CALL PRINC ;OUTPUT IT
PRINS: MOV A,M ;GET CHARACTER
INX H ;POINT TO NEXT
CPI '$' ;IF IT IS NOT END
JNZ PRX ;THEN GO
RET
;
; OUTPUT A CHARACTER TO CONSOLE:
;
PRINC: PUSH PSW ;SAVE DATA
PRA: IN CONSTA ;IF CHARACTER
ANI B$VDR ;CAN BE TAKEN
JZ PRA
POP PSW ;UNSAVE CHARACTER
OUT CONDAT ;AND OUTPUT IT
RET
;
END