Machine Problem 2 Solved
22C:18, Spring 1996
Douglas W. Jones
; MP2, by Douglas Jones, 22C:18, Spring 1996.
;
; an M68000 program that repeatedly evaluates expressions written in
; an RPN calculator notation
; constants
LINELN: EQU 80 ; maximum length of an input line
XREF STROUT,STRIN,NEWLINE,STOP
START: ; boilerplate
LEA START,A4 ; boilerplate (so A4 points to code seg)
MAINLP: LEA MSGPRT,A0
MOVE.W #MSGPRL,D0
JSR STROUT ; prompt for input.
LEA LINE,A0
MOVE.W #LINELN,D0
JSR STRIN ; get the line
TST.W D0 ; see how long it is
BLE.S QUIT ; quit if empty
JSR PROCES ; go do computation
BRA.S MAINLP
QUIT: JSR STOP ; boilerplate end of program
PROCES:
; procedure to process 1 line of input
; expects A0 = pointer to line
; D0 = length of line
; uses A1 = calculator SP
; D1 = calculator top element on stack
; does not use
; A4,A5,A6
LEA CALSTK,A1 ; initialize calculator stack
CLR.W D0 ; and put 0 on calc stack top
PROCLP: SUBQ.W #1,D0 ; count one character
BLE.S PROCQT ; quit if less than 1 left
CLR.L D2 ; setup so character will be long
MOVE.B (A0)+,D2 ; get the character
JSR PROCCH ; and process it
BRA.S PROCLP
PROCQT: RTS
; constants needed above
MSGPRT: DC.B 'input: '
MSGPRL: EQU *-MSGPNT
PROCCH:
; procedure to process 1 character of input
; expects D2 = character
; A1 = calculator SP
; D1 = calculator top element of stack
; uses A2 = jump table computation
; D3 = jump table computation
; does not touch
; A0,D0,A4,A5,A6
LEA PROTAB,A2
MOV.L D2,D3
LSL.L #2,D2 ; make longword offset
ADDA.L D2,A2 ; make address of table entry
MOVE.L (A2),A2 ; get table entry
ADDA.L A4,A2 ; relocate relative to code seg!
JMP (A2) ; go there!
PROTAB: ; this table is organized with one entry per ASCII character
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;control
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;control
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;control
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;control
DC.L PRONOP,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ; !"#$%&'
DC.L PROER ,PROER ,PROMUL,PROPLS,PROER ,PROMIN,PROER ,PRODIV ;()*+,-./
DC.L PRODIG,PRODIG,PRODIG,PRODIG,PRODIG,PRODIG,PRODIG,PRODIG ;01234567
DC.L PRODIG,PRODIG,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;89:;<=>?
DC.L PROER ,PROER ,PROODD,PROER ,PROER ,PROENT,PROER ,PROER ;@ABCDEFG
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;HIJKLMNO
DC.L PROPRI,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;PQRSTUVW
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;XYZ[\]^_
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;`abcdefg
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;hijklmno
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;pqrstuvw
DC.L PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ,PROER ;xyz{|}~
; code for the end of the procedure in each case follows. On entry, the
; expects D2 = character
; A1 = calculator SP
; D1 = calculator top element of stack
; cannot touch
; A0,D0
PROER: MOVE.L A0,-(SP) ; save
MOVE.L D0,-(SP)
LEA MSGERT,A0
MOVE.W #MSGERL,D0
JSR STROUT ; error message
JSR NEWLINE
MOVE.L (SP)+,D0 ; restore
MOVE.L (SP)+,A0
RTS
MSGERT: DC.B "Error"
MSGERL: EQU *-MSGERT
; D2 is a digit
PRODIG: MULS.W #10,D1
SUB.W #'0',D2 ; convert D2 to integer
ADD.W D2,D1 ; add to 10 times stack top
RTS
; Plus
PROPLS: ADD.W -(A1),D1 ; add top elements on stack
RTS
; Minus
PROMIN: MOVE.W -(A1),D2 ; pop item under top
SUB.W D1,D2 ; subtract top from item under it
MOVE.W D2,D1 ; put result on top
RTS
; Mul
PROMUL: MULS.W -(A1),D1 ; multiply
RTS
; Divide
PRODIV: MOVE.W -(A1),D2 ; pop item under top
EXT.L D2 ; sign extend
DIVS.W D1,D2 ; divide top into item under it
MOVE.W D2,D1 ; put result on top
RTS
; Enter
PROENT: MOVE.W D1,+(A1) ; push
CLR.W D1 ; and clear
RTS
; Print
PROPRI: MOVE.L A0,-(SP) ; save prior to print
MOVE.L D0,-(SP)
MOVE.W D1,D0 ; put number in place
MOVE.W #10,D1 ; put base in place
JSR PRINTO ; print number
MOVE.L (SP)+,D0 ; restore
MOVE.L (SP)+,A0
MOVE.W -(A1),D1 ; pop stack
RTS
; odd Base print
PROODD: MOVE.L A0,-(SP) ; save prior to print
MOVE.L D0,-(SP)
MOVE.W -(A1),D0 ; put number in place
; note that base is in D1
JSR PRINTO ; print number
MOVE.L (SP)+,D0 ; restore
MOVE.L (SP)+,A0
MOVE.W -(A1),D1 ; pop stack
RTS
; space
PRONOP: RTS
PRINTO:
; procedure to print a number in any odd base
; given D0 = number
; D1 = base
; recursively handles negative and multidigit numbers
TST.W D0
BGE.S PRINNG ; skip if not neg
MOVE.L A0,-(SP) ; save prior to print
MOVE.L D0,-(SP)
LEA MSGNEG,A0
MOVE.W #1,D0
JSR STROUT ; print sign
MOVE.L (SP)+,D0 ; restore
MOVE.L (SP)+,A0
NEG.W D0 ; make number positive
PRINNG: ; print nonnegative number
EXT.L D0 ; setup for divide
DIVS.W D0,D1 ; divide by base
MOVE.L A0,-(SP) ; save everything
MOVE.L D0,-(SP)
SWAP D0
TST.W D0 ; if remainder is zero
BEQ.S PRINDN ; skip ahead
SWAP D0 ; else get quotient ready
JSR PRINTO ; and print other digits
PRINDN: MOVE.L (SP)+,D0 ; restore remainder
SWAP D0 ; get into low half
CMP.W #10,D0 ; test the digit
BGE.S PRINLT ; branch if D3-10 >= 0 or (D3 >= 10)
ADD.B #'0',D0 ; convert to a digit in 0..9
BRA.S PRINPT
PRINLT ADD.B #'A'-10,D3 ; convert to a digit in 'A'..'Z'
PRINPT MOVE.B D0,PRINBF ; put letter in print buffer
LEA PRINBF,A0
MOVE.W #1,D0
JSR STROUT ; output the digit
MOVE.L (SP)+,A0 ; restore saved A0
RTS
MSGNEG: DC.B '-'
DATA ; boilerplate start of data section
CALSTK: DS.W LINELN ; calculator stack (allows lots of E instrs)
LINE: DS.B LINELN ; space for a line of text
PRINBF: DS.B 1
END ; boilerplate end of program