The purpose of this final programming assignment is to test the limits of your LC3 skill by giving you a challenging implementation problem straight out of the textbook.
High Level Description
There is a server somewhere, called the Busyness Server. This server tracks whether 16 different machines connected to it are busy (0)β or β free (1)βΒ Β Β Β Β :β this information is stored in a single LC-3 word (aka a βbit-vectorβ).
You will write a menu-driven system that allows the user to query this bit-vector as to the availability of the 16 machines, in various combinations.
Β
Before You Start Coding
This assignment is based on a variation ofΒ βQuestion 9.9β (p. 242 of the textbook) β which will require that you first work through the following:
- Example 2.11 (p. 37)
- Question 2.36 (p. 46)
- Question 5.6 (p. 146)
(βNote:β I have lightly edited the wording of the following excerpts from the text for increased clarity)
Example 2.11
Suppose we have eight machines that we want to monitor with respect to their availability. We can keep track of them with an 8-bit BUSYNESS vector, where a bit is 1 if the unit is free and 0 if the unit is busy. The bits are labeled 0 through 7, from right (lsb) to left (msb).
The BUSYNESS bit vector 11000010 corresponds to the situation where only units 7, 6, and 1 are free, and therefore available for work assignment.
Suppose work is assigned to unit 7. We update our BUSYNESS bit vector by performing the logical AND, where our two operands are the current bit vector 11000010 and the bit mask 01111111. The purpose of the bit mask is to clear β(set to 0)β bit 7 of the BUSYNESS bit vector, without affecting the remaining 7 bits. The result is the bit vector 01000010, which replaces the previous BUSYNESS.
Recall that we encountered the concept of bit mask in Example 2.7. Recall that a bit mask enables one to interact with some bits of a binary pattern while ignoring the rest. In this case, the bit mask βclearsβ bit 7 and βleaves unchangedβ (ignores) bits 6 through 0.
Suppose unit 5 finishes its task and becomes idle. We can update the BUSYNESS bit vector by performing the logical OR of it with the bit mask 00100000. The result is 01100010, which again replaces the previous BUSYNESS.
Β
Β
Question 2.36β β(see Homework 2)
Refer to Example 2.11 (above) for the following questions.
- What mask value and what operation would one use to set machine 2 from freeβ β (1) to βbusy
(0)?Β Β Β Β Β Β β(Without changing the state of the other machines, obviously!)
- What mask value and what operation would one use to set machines 2 and 6 to βfreeβ (1)? (Again, without changing the state of the other machines)β.
Note: This can be done with a single βboolean operationβ, but it cannot be implemented in LC-3 assembly language with a βsingle instructionβ!
- What mask value and what operation would one use to set βallβ machines to busyβ β (0)?
- What mask value and what operation would one use to set allβ β machines to βfreeβ (1)?
- Develop a procedure to βinterrogateβ the status of machine 2 by isolating it as the βsign bitβ (i.e. the msb).
For example, if the BUSYNESS pattern is 0101 1100, then the output of this procedure is 10000000. If the BUSYNESS pattern is 0111 0011, then the output is 0110 0000. In general, if the BUSYNESS pattern is:
Β
the output is
| b2 | b1 | b0 | Β 0 | Β 0 | Β 0 | Β 0 | Β 0 |
Hint: What happens when you ADD a bit pattern to itself?
Question 5.6
Recall the machine busy example from Section 2.7.1. Assuming the BUSYNESS bit vector is stored in R2, we can use the LC3 instruction AND R3, R2, #1 to determine whether machine 0 is busy or not. If the result of this instruction is 0, then machine 0 is busy.
- Write an LC3 instruction that determines whether machine 2 is busy.
- Write an LC3 instruction that determines whether βbothβ machines 2 and 3 are busy.
- Write an LC3 instruction that indicates whether none of the machines are busy.
- Can you write a single LC3 instruction that determines whether machine 6 is busy? Is there a problem here?
Β
The variation of βQuestion 9.9β that you will implement in this assignment:
(remember β 0 = busy; 1 = free)
- Check if βallβ machines are busy; return 1 if all are busy, 0 otherwise (i.e. if any are free).
- Check if βallβ machines are free; return 1 if all are free, 0 otherwise (i.e. if any are busy).
- Check βhow manyβ machines are busy; return the number of busy machines.
- Check βhow manyβ machines are free; return the number of free machines.
- Check the βstatusβ of a specific machine whose number is passed as an argument in R1; return 1 if that machine is free, 0 if it is busy.
- Return the βnumberβ of the first (lowest numbered, or rightmost) machine that is free β i.e. a number between 0 and 15.Β Β Β βIf no machine is free, return -1β β(= xFFFF)
e.g. if the busyness vector is 0101 0100, then the first available machine is #2
(Remember β βthe lsb is always considered bit #0β) Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β
Your Tasks
The assignment can be broken down into the following tasks:
Β
- Your main code block should call a MENU subroutine, which prints out a fancy looking menu with numerical options, allows the user to input a choice, and returns in R1β the userβs selectionβ {1, 2, 3, 4, 5, 6, 7} If the user inputs a non-existent option, output an error message and re-print the menu; repeat until a valid entry is obtained.
Here is the menu that you will be using for the assignment:
(it is given to you in the starter code as a single long string located at memoryΒ address βx6000)
Β
***********************
* The Busyness Server *
***********************
- Check to see whether all machines are busy
- Check to see whether all machines are free
- Report the number of busy machines
- Report the number of free machines
- Report the status of machine n
- Report the number of the first available machine
- Quit
Β
- Write the following corresponding subroutines:
- MENU
- ALL_MACHINES_BUSY
- ALL_MACHINES_FREE
- NUM_BUSY_MACHINES
- NUM_FREE_MACHINES
- MACHINE_STATUS
- FIRST_FREE
Β
plus the two helper subroutines:
GET_MACHINE_NUM
PRINT_NUM
Β
=========================================================================
Β
Β
Subroutine Headers
The following headers have been provided to you in the template.
NOTE:β R1 is always used to return a numeric or character value; R2 to return a flag value
;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: MENU
; Inputs: None
; Postcondition: The subroutine has printed out a menu with numerical options, allowed the ;Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β user to select an option, and returned the selected option.
; Return Value (R1): The option selected:Β #1, #2, #3, #4, #5, #6 or #7
; Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β no other return value is valid.
;ββββββββββββββββββββββββββββββββββββββ ;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: ALL_MACHINES_BUSY (#1)
; Inputs: None
; Postcondition: The subroutine has returned a value indicating whether all machines are busy
; Return value (R2): 1 if all machines are busy, 0 otherwise
;ββββββββββββββββββββββββββββββββββββββ
;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: ALL_MACHINES_FREE (#2)
; Inputs: None
; Postcondition: The subroutine has returned a value indicating whether all machines are free
; Return value (R2): 1 if all machines are free, 0 otherwise
;ββββββββββββββββββββββββββββββββββββββ
;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: NUM_BUSY_MACHINES (#3)
; Inputs: None
; Postcondition: The subroutine has returned the number of busy machines.
; Return Value (R1): The number of machines that are busy (0)
;ββββββββββββββββββββββββββββββββββββββ
;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: NUM_FREE_MACHINES (#4)
; Inputs: None
; Postcondition: The subroutine has returned the number of free machines
; Return Value (R1): The number of machines that are free (1)
;ββββββββββββββββββββββββββββββββββββββ
;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: MACHINE_STATUS (#5)
; Input (R1): Which machine to check
; Postcondition: The subroutine has returned a value indicating whether the machine indicated
;Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β by (R1) is busy or not.
; Return Value (R2): 0 if machine (R1) is busy, 1 if it is free
;ββββββββββββββββββββββββββββββββββββββ
;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: FIRST_FREE (#6)
; Inputs: None
; Postcondition: The subroutine has returned a value in R1
;Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β indicating the lowest numbered free machine
; Return Value (R1): the number of the free machine
;ββββββββββββββββββββββββββββββββββββββ
Β
Β
Β
Β
Β
Helper subroutines (i.e. not included in menu)
Both subroutines are required for Option 5 (MACHINE_STATUS);
PRINT_NUM is required also for Options 3, 4 and 6
Β
;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: GET_MACHINE_NUM
; Inputs: None
; Postcondition: The number entered by the user at the keyboard has been converted into binary,
;Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β and stored in R1. The number has been validated to be in the range {0,15}
; Return Value (R1): The binary equivalent of the numeric keyboard entry
; NOTE: You can use your code from assignment 4 for this subroutine, changing the prompt,
;Β Β Β Β Β Β and with the addition of validation to restrict acceptable values to the range {0,15}
;ββββββββββββββββββββββββββββββββββββββ
Your assignment 4 code is kind of overkill for this purpose, as it acceptsΒ & converts to binary all possible numbers in range {-32768, +32767}, while we only want {0, 15}
However, the code is already written & tested, so it is simpler to just package it as a subroutine and modify it a bit for the new purpose:
Required changes to your assn 4 code:
- The binary value must be returned in R1β , rather than the register specified for assn 4β
- The prompt and error messages in assn 4 were provided as remoteβ β data, requiring the use of pointers to access them. You must substitute these with the new prompt & error messages, which are provided in the starter code as localβ β
So in assn 4 you would probably have set up the string output like this:
LD R0, msg_pointer ; msg_pointer stores remote address of message stringΒ In this subroutine version make sure you change that to:
LEA R0, msg_label ; msg_label is start of local message string
If you have trouble understanding this advice, go back & redo labs 2 & 3!!)
- Treat an initial β-ββ β sign as an invalid input, exactly as you would a non-numeric input
NOTEβ: This is different from the behavior depicted in sample screen 9 below, which shows user entry β-14β: this spec requires that the β-β sign βimmediatelyβ trigger the error handler.
- After successfully converting the user input number, you must test that it is <= 15 (you already know that it is >=0, because you rejected negative inputs). If the the number is >15, it is invalid, so start over.
Β
;ββββββββββββββββββββββββββββββββββββββ
; Subroutine: PRINT_NUM
; Inputs: R1, guaranteed to be in range {0,15}
; Postcondition: The subroutine has output the number in R1 as a decimal ascii string
; Return Value : R1 (unchanged from input)
;ββββββββββββββββββββββββββββββββββββββ
- Do NOTβ output a newline after the number output, as it may be part of a larger message.β
- if n < 10, it is a single digit, and can be output as ascii by just adding x30
- if n >= 10, it is a 2-digit number: the first digit is β1β, and the second digit is (n-10)
Expected/ Sample output Output
- The caption for each sample screen lists the corresponding menu selection & value of the test busyness vector
- Note the placing of newlines in the output!
Β
Examples
Β
Β
- Wrong Input for menu, BUSYNESS = x0000 Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β 2. Option 1, BUSYNESS = x0000
Β
- Option 1, BUSYNESS = xABCD 4. Option 2, BUSYNESS = xFFFF
Β
5.(Option 2, BUSYNESS = xABCD Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β 6. Option 3, BUSYNESS = xABCD
Β
- Option 4, BUSYNESS = xABCD 8. Option 5, BUSYNESS = x0000 with correct input
Β
- Option 5, BUSYNESS = x0000 with incorrect input 10. Option 5, BUSYNESS = x0000 with incorrect
example #1 Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β input example #2
Β
- Option 6, BUSYNESS = x0000 12. Option 6, BUSYNESS = xABCD
Β
Notes:
- As always, you must echo βallβ inputs (no βghost writingβ).
- When an invalid input is detected: Output the error message and re-prompt the user for input
- all outputs must be newline terminated
(except the number in machine status, which is internal to a larger message)
Β
Your code will obviously be tested with a range of different busyness vectors:Β Make sure you do likewise!
Β
Β
Uhβ¦help?
No individual component of this assignment is really difficult β but it has a lot of βmoving partsβ that all have to work together properly, so it can be βveryβ challenging, and take a βlongβ time to complete! So weβll give you some hintsΒ π
Β
Really, Really Important
β 1 means free; 0 means busy
- Store the BUSYNESS vector at the memory address β given to you in the template.
β The grader will test different values using this address
- Several of your subroutines require input validation: make sure that there is no way to exit such a subroutine except by providing valid input β in other words, if the user messes up, the subroutine must start over, with all prompts β(see e.g. the three Option 5 samples above)
Β
Hint 01
All the subroutine headers have been provided in the starter code, along with all prompts and error messages. Use the headers as a guide to the construction of your subroutines.
In particular, detailed guides for the two helper functions are provided with their headers above. DO NOT ALTER ANY STRINGS OR ADDRESSES PROVIDED IN YOUR STARTER CODE!
Β
Hint 02
NEVERβ backup (store/reload) the register used to return a value!
In all subroutines, R1 is used to return a numeric or character value; R2 is used to return a flag value AWAYSβ backup R0 and R7 if your subroutine invokes any Traps; plus all registers used as temporary storage in the course of the subroutine.
Β
Hint 03
Remember the algorithm you created to print out a number in binary: you examined each individual bit of a 16-bit register by βshiftingβ each bit into the msb in turn.
You will be using this same technique in several of your subroutines in this assignment.
Β
Hint 04 β sub A (MENU)
This subroutine gets a βsingle character from the user. You do βΒ Β Β Β Β Β Β Β Β βNOTβ have to press enter for the character to be accepted. The moment the user enters a character, it will be echoed, and the subroutine will try to validate the input {β1β, β7β}; if valid, the option value will be returned in R1; if not, an error message should be output and the prompt repeated (i.e. start over).
Should you return the menu option as an ascii numeric digit, or as the corresponding number? Either can be made to work, but which do you think is easier to test after return to main?
Β
After responding to any menu selection other than #7, the menu must be re-presented, in an infinite loop β(see pseudo-code at end)β.
The only way to exit the loop is by selecting menu option 7 (βGoodbyeβ).
Β
Hint 05 β subs B & C (ALL BUSY/ALL FREE?)
If a machine is free, then it is NOT busy. If a machine is busy, then it is NOT free β i.e. you can use the exact same code structure for these two subroutines.
In both cases, return flag R2 = 1 for βaffirmativeβ (all machines βareβ busy/free respectively).
Β
Hint 06 β subs D & E (HOW MANY BUSY/FREE?)
These two subroutines form a pair like subs B & C above β you can use the same logic for both.
Β
Hint 07 β sub F (MACHINE STATUS)
The first step is to obtain user input by invoking the helper subroutine GET_MACHINE_NUM
This will return a validatedβΒ Β Β Β Β Β β number from 0 to 15 in R1, to be passed directly to subroutine F. The same number is also passed, still in R1, to the other helper subroutine PRINT_NUM when printing the full status report.
The only acceptable return values from GET_MACHINE_NUM are in the range {0,β β 15}.β
Examples of valid input: Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Examples of invalid input:
(sub returns with value in R1) Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β (error message, repeat prompt)
- 12 -12
- 0 16
- 0003 +2g
- +4 g
See also the guide provided with the helper subroutine headers above.
Β
Machine numbers for subroutine F:
The FIRST machine is machine 0 (β the lsb, or rightmost bit)β; the LAST machine is machine 15 (β the msb, or leftmost digit) Machine IDs:
Β
Subroutine F can assume that the value in R1 has been properly validated {0, 15} If machine (R1) is busy, return flag R2 = 0; if it is free, return R2 = 1
Β
Hint 08 β sub G (FIRST_FREE)Β
As for sub F: the βlowest numberedβ machine is the rightmost bit, aka the lsb, aka bit 0
Β
Β Β
Hint 09
To implement your menu-driven system, construct an infinite loopβ that works like this:β
NOTEβ: βPrint (R1)β means invoke βPRINT_NUM(R1)
If you needed to print the contents of a different register, you would have to βR1 <= Rxβ first.
| Β
while( true ) { |
Β |
| Β R1 = menu() | ; call MENU subroutine |
Β
if (R1 == 1)
R2 = all_machines_busy()Β Β Β Β Β ; call ALL_MACHINES_BUSY subroutineΒ Β Β Β if (R2 == 1)
Print βAll machines are busy\nβΒ Β Β Β else
Print βNot all machines are busy\nβ
Β
else if (choice == 2)
[similar]
Β
else if (choice == 3)
R1 = num_busy_machines()Β Β Β Β Β Β Β ; call NUM_BUSY_MACHINES subroutine
Print βThere are β, (R1), β machines busy\nβ
Β
else if (choice == 4)
[similar]
Β
else if (choice == 5)
R1 = get_machine_number() Β Β Β ; validated user entry from #0 to #15Β Β Β Β R2 = machine_status(R1)Β Β Β ; call MACHINE_STATUS and pass in R1Β Β Β Β if (R2 == 1)
Print βMachine β, (R1), β is free\nβΒ Β Β Β else
Print βMachine β, (R1), β is busy\nβ
Β
else if (choice == 6)
R1 = first_machine_free() Β Β Β Β Β ; call FIRST_FREE subroutine
if (R1 == -1 ) Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β ; #-1 == xFFFF
Print βNo machines are freeβ
else
Print βThe first available machine is number β, (R1), β\nβ
; donβt forget to terminate this o/p with a nl!
; all other messages have their terminal nl built in.
Β
else if (choice == 7)
Print βGoodbye!\nβ
HALT
}




