| ECE291 |
Computer Engineering II |
Lockwood, Spring 1999 |
Machine Problem 3: RPN Calculator GUI
| Assigned |
Thursday 3/4/99 |
| Due Date |
Thursday 3/25/99 |
|
| Purpose |
Keyboard and Mouse Interrupts,
Text-Mode Graphics |
| Points |
50 |
Introduction
End users like a Graphical User Interface (GUI)
because it provides them with
a simple, easy-to-use, point-and-click interface.
Programmers, however,
typically prefer designing command line interfaces (CLI's) because
their interface can be simpler and can more easily be used both
from the keyboard and as a part scripting environment.
In the end, though, GUI's are included as a part of
all modern software because they are often more intuitive
to use than CLI's and reduce the learning curve
for the end-user of the application.
In MP2 you implemented a stack-based RPN calculator with a
simple CLI. In MP3, you will start with the same three procedures from MP2
(ProcessInput,
Calculate, and FormatOutput) and implement a GUI around
them. The new interface will accept both the keyboard commands from
MP3 as well as commands created by pressing "buttons" on the graphical
display.
Problem Description
For this machine problem, you will implement a graphical user interface
for the RPN Calculator of MP2.
A screen dump of the running program is shown below:
Using the GUI, the calulation of 6+27 can be computed by:
- Clicking on the [6] button
- Clicking on the [ENTER] button
- Clicking on the [2] button
- Clicking on the [7] button
- Clicking on the [ENTER] button
- Clicking on the [+]
The best way to understand how the MP works is to
run it,.
Hit [Q] then [ENTER] to quit.
Major Features
Full-Screen Text-mode Video
The graphics for the GUI will be implemented using 40x25
text-mode video. For maximum speed, your code will write directly to
video memory (beginning at address B8000h).
Each character block on the screen represents
an ASCII character and its corresponding attributes. The attributes
include the foreground color, background color, and whether the character
blinks or not. Text-mode video is discussed in lecture 12.
The 40x25 mode operates exactly like the 80x25 mode, except that there
are only half as many characters in each row.
Since specifying the graphics yourself would be tedious,
a 'skin' has been written as a single byte-array (calcskin)
that contains an ASCII "image" of the calculator. This
skin is stored in a separate data file called calcskin.dat.
Feel free to change the variable textattr, in order
to vary the color scheme of your calculator.
The color shown in the screendump has blue text on a white background.
Interrupt Service Routines
In MP2, we used LIB291's kbdine to read data from
the keyboard. Calling this function causes your computer
to poll the default keyboard handler until
a key is read into the DOS keyboard buffer.
But what if you wanted to do something else
while waiting for a keyboard input. Suppose, for example,
you also wanted to read from a mouse at the same time
you were waiting for input from the keyboard.
You could not do this with blocking I/O.
The use of customized interrupt service routines (interrupt handlers)
allows the program to handle asynchronous I/O.
With asynchronous
I/O, the program is able to do other things while waiting for data from
one particular input. In this MP you are required to watch for inputs
from both the keyboard and the mouse at the same time. By writing
a routine for each, triggered only by external device interrupts, this
will be possible.
The subject of ISRs is discussed in lectures 13
through 16. Read the lecture notes and Chapter 9 in the lab manual
for more information.
Implementation
Variables
From MP2 :
-
DispMode - Specifies which base to input and display values in. {2, 10.
16}
-
InputBuffer - Contains one line of user input in ASCII. Can be either
a new operand, an operation, or a mode change.
-
BufLength - Actual length of InputBuffer
-
OutputBuffer - Contains the formatted result in ASCII.
New for MP3 :
-
oldKbdV - Far pointer to the default keyboard interrupt handler
-
inputValid - Status about input from the keyboard and mouse.
- 0 - InputBuffer is not ready
- +1 - InputBuffer is ready for processing
- -1 - Escape key was pressed. Exit immediately.
- bottomOfStack - The stack pointer's value at the beginning. Used
to determine number of operands on the stack.
- calcskin - byte array of graphical framework in file calcskin.dat.
Procedures
For this program, you will write ten procedures and add one feature.
You may use the library
versions of the three MP2 procedures.
-
MP3Main
This is the main routine for this program and you should implement it first.
Before you start, read through the entire writeup and
make sure you understand the other functions that you
will need to call.
Program Body
- Your main program must initially:
- Install the mouse and keyboard interrupt handlers.
- Draw the graphics of the current screen.
- Record the initial stack pointer offset,
so that your display can show the number of items on the stack..
- Main loop
- It should wait for the user to enter a complete string to InputBuffer
- Exit the program if 'Q' or 'q' is pressed.
- Processed the InputBuffer string, like MP2.
- Calculate results, like MP2
- Format the results, like MP2
- Display the results in the gray window.
- Final steps
- When the program is ready to
exit, both the mouse and keyboard should be restored to their original
form and any remaining operands on the stack should be flushed.
Example Operation
- You enter "80FF" into the program using the mouse or the keyboard and
then enter it by either pressing ENTER or
clicking on the "ENTER" button.
The placement of the keys into the buffer occurs in the Interrupt
Service Routine. The processing of the loop occurs in main.
Note
- It is important that you NOT accept mouse or keyboard
input while you main program is processing the InputBuffer String.
The time between when your program starts and finishes
the processing of InputBuffer is a critical section.
In order to avoid corruption of InputBuffer, the
input (keyboard and mouse) event handlers should not be allowed to write
to InputBuffer during this time.
This can be done by disabling and
then re-enabling external interrupts.
Use the STI and CLI assembly instructions as discussed in lecture 15.
Disable interrupts after completing input to InputBuffer and re-enable
interrupts after you are done using InputBuffer.
- DrawScreen
-
Inputs: calcskin
-
Outputs: Writes graphics video memory (segment 0B800h).
- Purpose: Draw the "skin" of the calculator to the screen.
Read the byte array calcskin and write it to video memory using
the attribute byte textattr. Also fill in the results window
with gray background.
- WaitForInput
- Input:
- inputValid: Variable to indicate when buffer is ready.
-
Outputs:
- InputBuffer is ready
- Carry flag is set if the program should exit immediately.
- Description: Initially clears the content of InputBuffer
and sets BufLength to zero.
It then waits for inputValid to be set
by the routine that processes input.
Note that the writing of InputBuffer
will be done asynchronously by the keyboard and mouse interrupt handlers.
- DisplayResult
- Input: OutputBuffer
- Output: Writes new results to display window on screen with:
- Result value displayed right-justified on the second line.
- A 'b', 'd', or 'h' appended to the result depending upon the value of DispMode.
- The number of operands remaining on the stack display on the left side
of the first line.
- Notes: Watch how window changes in program given.
- KbdInstall
- Input: None
- Output: oldKbdV variable
- Purpose:
- Installs Interrupt 9's (IRQ1's) vector to the address of KbdHandler.
- Saves far pointer to default keyboard handler in oldKbdV
- Notes:
- Code this routine at the same time you code KbdUninstall
- KbdUninstall
- Input: oldKbdV variable
- Output: None
- Purpose: Restore keyboard Interrupt vector to the original value.
- KdbHandler
- Input: None
- Output:
- InputBuffer updated
- inputValid
- 0 if input not finished (carriage return not seen)
- +1 if input finished
- -1 if escape key pressed
- Results window updated.
The unfinished input operand should be displayed
left-justified on the second line.
- Purpose:
This routine is the Interrupt Service Routine called when your
keyboard hardware reads in the scan code from the keyboard.
By reading the scancode from the keyboard's hardware register
(see lab notes, chapter 9), your program can determine
which key was pressed.
Your routine should then translate this scan code into
a corresponding ASCII code.
You do not need to translate all keys, but rather just the
characters that we expect as input ('+', '~', 'A', '5', '%', etc.). Add
the character to InputBuffer and display the current contents left-justified
on the second line of the results window. Make sure to handle the
backspace key, so that we can edit our entry. Set inputValid to +1
when a carriage return is seen.
- Notes:
Remember that this handler is called on every key press and key release.
Bit 7 of the scan code is set if this event is a key release and is unset
if this event is a key press. The handler must accept all valid keystrokes
and ignore the others. Also note that you need to keep track of whether
one of the shift keys is down or not. Do not worry about events on
the numeric keypad if you do not wish to.
- MouseInstall
-
Input: None
-
Output: None
- Purpose: Instruct the mouse driver to call
your Mousehandler routine for specified clicks.
- Implementation: Three calls to Int 33h routines must be made.
- Reset the mouse driver. (Described in chapter 9 of the lab manual)
- Show the mouse cursor. (Described in chapter 9 of the lab manual)
- Set MouseHandler to be the user event handler for left-mouse-button (LMB)
clicks.
-
Input:
-
AX = 000Ch
-
CX = Event mask
Bit 0: mouse movement
Bit 1: LMB activated
Bit 2: LMB released
Bit 3: RMB activated
Bit 4: RMB released
Bit 5: MMB activated
Bit 6: MMB released
Bits 7-15: Unused
-
ES = Segment address of handler
-
DX = Offset address of handler
-
Output: None
- MouseUninstall
-
Input: None
-
Output: None
- Purpose: Restore the mouse driver to it's original state
- Implementation: First hide the mouse
cursor, then reset the driver.
- MouseHandler
- Description: This routine will be called by the
mouse driver. It should process clicks on the screen
and put characters into InputBuffer.
- Input:
-
AX = event mask (same format as described in MouseInstall above)
-
BX = mouse button status
Bit 0: LMB activated
Bit 1: RMB activated
Bit 2: MMB activated
Bits 3-15: Unused
-
CX = horizontal mouse position
This is given in pixels. In 40x25 one character space is 16 pixels
wide.
-
DX = vertical mouse position
In 40x25 one character space is 8 pixels tall.
-
SI = length of last horizontal mouse movement
The values in SI and DI are signed and refer to mickeys (1/200 inch).
They communicate relative movement and so are signed integers.
-
DI = length of last vertical mouse movement
-
DS = data segment of the mouse driver
-
Output:
-
InputBuffer updated
-
inputValid
-
0 if input not finished (carriage return not seen)
-
+1 if input finished
-
Results window updated. The unfinished input operand should be displayed
left-justified on the second line.
- Notes:
Event handlers as set up in MouseInstall are called by the mouse driver
through a FAR call and therefore must be terminated with a RETF instruction.
Register contents must be preserved. This procedure is similar to
KbdHandler in that it translates raw input into values for the InputBuffer.
But instead of reading scan codes, it must check in which region of the
display the mouse click occurred. Note that the upper left corner
is position (0, 0). If an operation is specified while an operand
is being entered, then the operand is dropped and the operation is performed.
If a value for an operand is clicked on, then it is added to
InputBuffer. The buffer is ready when the "ENTER" button is clicked
on. If some operation or mode button is clicked on,
then we should fill in the buffer and notify the main program immediately.
- OFF Button
- The current calculator lacks an OFF button.
Modify the
program skin and mouse mappings to include a button
which quits the program when clicked.
Program Assignment
You will begin this machine problem with a fully functional program. The
skeleton file is given below. We have provided the library routines for
each of the ten procedures above. You should complete MP3Main first, because
the library version (LibMP3Main) will only call other library procedures.
You will score points by replacing the library procedures with your own
code. Your score will be proportional to the percentage of the code that
you write yourself. The breakdown in points is given below: Your routine
MUST perform all functions of the subroutine to obtain credit.
-
MP3Main - 5 points
-
DrawScreen - 5 points
-
WaitForInput - 5 points
-
DisplayResult - 5 points
-
KbdInstall and KbdUninstall - 5 points
-
KbdHandler - 7 points
-
MouseInstall and MouseUninstall - 5 points
-
MouseHandler - 7 points
-
Off Button - 6 points
Preliminary Procedure
-
Copy the given MP3 files from the network drive to your home directory
with the following command:
xcopy /s V:\ece291\mp3 W:\mp3
Alternatively, from home you can download the same files as mp3.zip.
-
As with previous MP's, run NMake to build an executable program
using the given ECE291 library functions.
-
As with previous MP's, use a text editor to modify the program. As given,
the program uses LIBMP3 routines to implement all functionality. To receive
full credit for the assignment, you will need to implement each of the
subroutines described above with your own code.
-
As with previous MP's, use CodeView (CV) to debug and test your
program. Because you only receive credit for procedures that function completely
as specified, it is best to debug each routine individually. This
means use all library routines, except for the one you are testing.
-
By modifying a few comments, you can mix and match usage of your own code
and Library routines. You may notice that the LIBMP3 routines contain extraneous
and difficult-to-read code. They are not meant to be easily unassembled!
Final Steps
-
Download and print the MP3 grading sheet from the web site.
-
Verify that your program meets all requirements for handin.
-
Demonstrate MP3.EXE to a TA or to the instructor. Your program must work
with all given input. Once approved, you are ready to turn in your program.
-
Be prepared to answer questions about any aspect of the operation of your
program. The TAs will not accept an MP if you cannot fully explain the
operation of your code.
-
Print MP3.ASM using GreenPrint32 and give it to to the same TA which approved
your demonstration. Be sure that your name is the printout.
-
Electrically submit your programs to the TA's handin floppy:
A:\HANDIN MyWindowsLogin
Guidelines / Hints
-
As a rule, always preserve register values across procedure calls.
This is especially important for interrupt handlers. You can do this
using the LIB291 routines RSAVE and RREST, or more efficiently by pushing
and popping only the registers that your routine modifies.
-
Helper functions will come in handy.
-
You may wish to reuse some version of ProcessKey from MP2.
-
You cannot write strings to video memory using the LIB291 routines dspout
or dspmsg, so write your own version.
-
You will want to convert X and Y screen coordinates to a linear offset,
so write a function to do this.
-
Debugging interrupt handlers is difficult. Do not expect to insert
a breakpoint in one of the handlers in CV and have CV stop at that point.
You should use CV to debug all other routines but special methods are in
order for the handlers. For the keyboard handler, start with toy
code, like getting the main program to write a '#' to the screen each time
any key is pressed. This is especially helpful when dealing with
the shift keys. Try similar things for the mouse, like printing out
what text coordinates the mouse is at when the button is clicked.
-
The race condition mentioned in the description of MP3Main can be covered
rather well by creating a critical section around one routine call in MP3Main.
Which one?
MP3.ASM
TITLE ECE291:MP3-Calculator GUI - Your Name - Date
COMMENT % A GUI for MP2's RPN Calculator
ECE291: Machine Problem 3
Prof. John W. Lockwood
Guest Author: Josh Scheid
University of Illinois
Dept. of Electrical & Computer Engineering
Spring 1999
Ver. 1.1
%
;====== Constants =========================================================
;ASCII values for common characters
BEEP EQU 7
CR EQU 13
LF EQU 10
ESCKEY EQU 27
BSKEY EQU 8
SEMI EQU 59
SPACE EQU 32
;====== Externals =========================================================
; -- LIB291 Routines (Free) ---
extrn dspmsg:near, dspout:near, kbdin:near
extrn rsave:near, rrest:near, binasc:near
; -- LIBMP3 Routines (Your code will replace calls to these functions) ---
extrn LibKbdInstall:near
extrn LibKbdUninstall:near
extrn LibKbdHandler:near
extrn LibMouseInstall:near
extrn LibMouseUninstall:near
extrn LibMouseHandler:near
extrn LibDrawScreen:near
extrn LibWaitForInput:near
extrn LibDisplayResult:near
extrn LibMP3Main:near
extrn MP3XIT:near ; Exit program with a call to this procedure
; Routines from LIBMP2
extrn LibProcessInput:near
extrn LibCalculate:near
extrn LibFormatOutput:near
;====== Stack ========================================================
stkseg segment stack ; *** STACK SEGMENT ***
db 64 dup ('STACK ') ; 64*8 = 512 Bytes of Stack
stkseg ends
;====== Begin Code/Data ==============================================
cseg segment public 'CODE' ; *** CODE SEGMENT ***
assume cs:cseg, ds:cseg, ss:stkseg, es:nothing
;====== Variables ====================================================
inputValid db 0 ; 0: InputBuffer is not ready
; 1: InputBuffer is ready
;-1: Esc key pressed
oldKbdV dd ? ;far pointer to default keyboard
; interrupt function
DispMode dw 10 ; Operate in decimal mode by default
bottomOfStack dw 0 ; Offset of stack at beginning of program
; Used to calculate current number of
; operands on the stack
operandsStr db 'Operands: ','$'
OutputBuffer db 16 dup(?),'$' ; Contains formatted output
; (Should be terminated with '$')
MAXBUFLENGTH EQU 24
InputBuffer db MAXBUFLENGTH dup(?),'$' ; Contains one line of user input
BufLength dw ? ; Actual length of InputBuffer
include calcskin.dat ; 2000 byte character array to define a
; 40x25 screen
PUBLIC DispMode, InputBuffer, BufLength, OutputBuffer ; Needed by LIBMP2/3
PUBLIC inputValid, oldKbdV, bottomOfStack, operandsStr ; Needed by LIBMP3
PUBLIC calcskin ; Needed by LIBMP3
;====== Procedures ========================================================
KbdInstall PROC NEAR
; Your code here
KbdInstall ENDP
;------------------------------------------------------------------------
KbdUninstall PROC NEAR
; Your code here
KbdUninstall ENDP
;------------------------------------------------------------------------
KbdHandler PROC NEAR
; Your code here
KbdHandler ENDP
;------------------------------------------------------------------------
MouseInstall PROC NEAR
; Your code here
MouseInstall ENDP
;------------------------------------------------------------------------
MouseUninstall PROC NEAR
; Your code here
MouseUninstall ENDP
;------------------------------------------------------------------------
MouseHandler PROC NEAR
; Your code here
MouseHandler ENDP
;------------------------------------------------------------------------
DrawScreen PROC NEAR
; Your code here
DrawScreen ENDP
;------------------------------------------------------------------------
WaitForInput PROC NEAR
; Your code here
WaitForInput ENDP
;------------------------------------------------------------------------
DisplayResult PROC NEAR
; Your code here
DisplayResult ENDP
;------------------------------------------------------------------------
MP3Main PROC NEAR
; Your code here
MP3Main ENDP
;====== Main Procedure ====================================================
MAIN PROC FAR
MOV AX, CSEG ; Use common code and data segment
MOV DS, AX
MOV AX, 0B800h ; Use extra segment to access video screen
MOV ES, AX
MOV AX, 0000h ; Put display into 40x25 text mode
INT 10h
MOV AH, 01h ; hide text cursor
MOV CX, 2000h
INT 10h
CALL LibMP3Main ; Replace this call with a call to
; your MP3Main routine.
; Add nothing else to MAIN
; Start your coding by writing main with all LIB routines
;
; ---------------- Pseudo-code for main ---------------
;
; Install Mouse and Keyboard handlers
; Draw initial screen
; Record initial stack pointer
;
; Loop {
; Wait for user to finish entering string from keyboard or mouse
; ..
; Process the input text
; Calculate Result
; Format the Output
; Display the result
; }
;
; Un-install Mouse and Keyboard handlers
CALL MP3XIT ; Exit to DOS
MAIN ENDP
CSEG ENDS
END MAIN