;	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

