Problem 6

Programming in LC-3 Assembly Language

Objective

In this final problem you will design and program a small calculator program in the LC-3 language. You will be demonstrating a beginning competence in assembly programming. You will learn how to use subroutines and input/output capabilities in a simple program.

Description

The LC-3 tiny 4-function calculator will perform addition, subtraction, multiplication, and division using two operands entered by a user. All of the math will be single precision (i.e. contained within a 16-bit register size) and we will artificially limit the magnitude of the inputs so as not to allow overflow conditions (to keep it simple).

The program will consist of a main portion that will initialize the computer registers and enter a loop in which it prints a menu of options for the user, calculate or exit. If the user selects calculate the user will enter two operands and then select which operation (+, -, *, or /) to perform. The operands will be integers and the division will produce an integer result and remainder. The results will be displayed on the console with a message and when the user presses the ENTER key, the menu will be displayed again. See the console screens below.

Requirements

The program will use subroutines to get user menu selections, operands, and operation selections. It will use TRAP commands given in Table A.2 on page 543 (trap vectors and alternate mnemonics are listed with the functions performed.)

The program will do as follows:

1.  Initialize registers for data and for handling loops, etc. then enter a loop that terminates when the user selects exit.
2.  Print the message: "LC-3 Tiny Calculator" followed by a return-line feed.
3.  Print the one line menu message and prompt: "1) Calculate  2) Quit: _" (the underscore represents the cursor).
4.  Get the user input.
5.  If the user entered a '2' branch to the exit label (HALT), otherwise goto 6.
6.  Prompt the user for the first operand: "Enter a two-digit decimal number: __" followed by a return-line feed.
7.  Get the user's operand input, convert it to an integer value for storage in a register or memory.
8.  Prompt the user for the second operand: "Enter a two-digit decimal number: __" followed by a return-line feed.
9.  Get the user's operand input, convert it to an integer value for storage in a register or memory.
10. Prompt the user for the operation choice: "Enter the number of the operation, 1) ADD, 2) SUB, 3) MUL, 4) DIV: _".
11. Get the user's selection (an ascii character '1', '2', '3', or '4'.)
12. Convert the user's selection to an integer and use this to determine which subroutine to call.
13. Branch to the appropriate subroutine and execute the calculation. Note that in the case of division the remainder is to be reported on the screen so the main loop will need to know that it should print out the result and the remainder.
14. Store the result(s) in registers and return to the calling main loop.
15. Print out the result(s): "Result: ___" or "Result: ___ Remainder: ___" followed by a carriage return-line feed.
16. Return to the main menu at #3 above.
17. On exit, print a farewell message (of your choice but keep it clean).

Design

Design the algorithms using flow charting. You may use the Wikipedia article: https://en.wikipedia.org/wiki/Flowchart for reference to how to use the shapes. But emulate the style as shown in Fig. 5.16, page 139. Draw each subroutine as its own independent chart. See below for the subroutines required.

Determine in advance which registers to use for various purposes. Remember R7 is reserved for the return address so do not use it for any other purpose. If you need to nest subroutine calls I will show you how to do this by saving the value in R7 to a temporary memory location. You may need to nest calls more than one level deep. Select registers for passing parameters if needed (e.g R1 and R2) and for return values (e.g. R0, but remember R0 is also used by some of the TRAP commands so be careful). Select the registers to be used for holding data in each of the process boxes in your flowchart and show them in the charts.

You may use any convenient charting tool (e.g. PowerPoint or some other charting tool). Or you may draw them by hand and scan them, however, make sure the diagrams are neat and clear with readable lettering. Make sure you can export the charts to a .png file for import into a Word document. See below for the required documentation of charts and screen shots.

Programming

The program should be named "tinyCalc.asm". Make sure everyone's names are in the header comments.

The program should have the following subroutines (each with its own chart):

  1. GETSEL: gets a single number character from the prompt, converts the char to int and returns the value in the return register (e.g. in R0). Used by the main menu and by the operation selection in the main loop.
  2. GETOP: gets a two character numeric operand input from the prompt. Calls the CONVCHAR subroutine below (twice) to convert the two char string to its numeric integer value returned in the return value register
  3. ADD: adds the two operands passed to it in registers. Returns the answer in the return register.
  4. SUB: subtracts the second operand from the first, returning the answer in the return register.
  5. MUL: multiplies the two operands returning the result in the return register. Note that with only two digit (decimal) operands the largest return value will be 9801.
  6. DIV: divides the first operand by the second. The integer result should be returned in the return register and the remainder returned in a second register.
  7. CONVCHAR: converts a single digit character into its integer value.
  8. Other as needed to increase modularity!

Running the Program

Run your program and after each test (putting in operands, etc.) capture a screen shot. You can upload the screenshot into a Paint drawing and export it as a .png file for later incorporation into a Word document (below). Number the graphic files test1.png, test2.png, etc. for each test. Test each of the four functions twice with different operands. Note that since the program is in a loop, you can actually get several tests into one screenshot. Just make sure they are sequentially numbered and incorporate them in the .docx file accordingly.

Extra Credit

It may have occurred to you that I have passed over negative operands! As specified above, you only need to enter two digit positive numbers. To make things a little more interesting, you can earn extra credit (10%) if you modify the operand input routines to accept positive (just two characters) or negative two digit values (three character strings). If you do this you will need to run another set of tests and get screenshots to show the program handling negative numbers correctly. Be sure to note in a header comment that you have implemented this feature.

Sample Code for Getting Data

;  get_data.asm - a data entry subroutine example
;
; George Mobus
;
;
; The program demonstrates the use of subroutines, including a two-deep nesting of one subroutine
; calling another subroutine.
;
		.orig		x3000
;
		JSR		GETDATA
		ST		R1,FIRST
		AND		R5,R5,#0
		JSR		GETDATA
		ST		R1,SECOND
STOP		HALT
FIRST		.BLKW		1
SECOND		.BLKW		1

;
; Subroutine to get a two digit number
;
GETDATA		ST		R7,GDREG7		; save return address
		ST		R6,GDREG6		; registers to be used need saving
		ST		R5,GDREG5
		ST		R2,GDREG2
;
		AND		R1,R1,#0
		AND		R2,R2,#0
		LEA		R0,PROMPT
		LD		R6,THIRTY
		PUTS	
		GETC
		OUT
		ADD		R1,R0,#0	; move R0 to R1
		ADD		R1,R1,R6	; subtract x30 from R1 to get digit
		LD		R2,TEN
		JSR		MULT		; multiply R1 by 10
		GETC
		OUT
		ADD		R0,R0,R6	; subtract x30 from next character
		ADD		R1,R0,R1	; add two registers to get decimal value
		LD		R0,CR		; output a carriage return
		OUT		
		LD		R0,LF
		OUT
		LD		R2,GDREG2
		LD		R5,GDREG5		; restore register values
		LD		R6,GDREG6
		LD		R7,GDREG7
		RET				; value returned in R1
GDREG7		.BLKW		1		; use to keep subroutine return address
GDREG6 		.BLKW		1		; save registers modified in this subroutine
GDREG5		.BLKW		1
GDREG2		.BLKW		1
;
TEN		.FILL		#10
THIRTY		.FILL		xFFD0		; -48 or neg x30
PROMPT		.STRINGZ	"Enter a two digit number: "
CR		.FILL		#13		; carriage return
LF		.FILL		#10		; line feed
;
;
; Subroutine to multiply R5 * R1
;
MULT		ST		R7,MUREG7		; save return address
		ST		R3,MUREG3		; registers to be used need saving
		ST		R5,MUREG5
		AND		R3,R3,#0	; R3 will be the result
AGAIN		ADD		R3,R3,R1
		ADD		R5,R5,#-1
		BRp		AGAIN
		AND		R1,R1,#0	; falls through when R5 == 0 or -1
		ADD		R1,R3,#0
		LD		R5,MUREG5
		LD		R3,MUREG3
		LD		R7,MUREG7	;restore return address
		RET				;answer in R1
MUREG7		.BLKW		1
MUREG3		.BLKW		1
MUREG5		.BLKW		1
		.END

Turn-in

Prepare a Word document for turning in. It should have all team member names at the top. You will use this to copy/paste the .png files, charts and test run screenshots for submission. Name the file screen.docx.

Zip up the tinyCalc.asm text file, and screen.docx file and submit that zip file as usual. Please name the zip file problem5.zip.