;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;SECTION NUMBER: ; ;GROUP MEMBER NAMES: ;1. ;2. ;3. ;4. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Subroutines (rest of program) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; GET_CHAR (Inputs): ; none ; GET_CHAR (Outputs): ; R0- contains 0 if no input is received, else contains ASCII value of character received ; TRAP x21 or OUT (Inputs): ; R0- ASCII value of char to be displayed ; TRAP x22 or PUTS (Inputs): ; R0- address of start of null-terminated string ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Subroutines (rest of program) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; DRAW_CHAR routine (Inputs): ; R0- x-cordinate ; R1- y-cordinate ; R2- starting address of bitmap ; CALC_BITMAP_ADDRESS (Inputs): ; R0- starting address of bitmaps ; R1- character for which bitmap address needs to be found ; CALC_BITMAP_ADDRESS (Output): ; R0- bitmap address of character given as input in R1 ; DRAW_STRING (Inputs): ; None in registers ; Memory locations - LOCAL_X, LOCAL_Y, STRING, CURR_COLOR ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Register Usage ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Main program: ; R0- ; R1- ; R2- ; R3- ; R4- ; R5- ; R6- ; R7 - only store local values; You should be very careful when tampering with R7; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Memory Locations used for tasks in Homework 8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; KBSR: address for memory-mapped KBSR register ; KBDR: address for memory-mapped KBDR register ; COLOR_LIST: contains the list of colors ; CURR_COLOR: tracks the current color of string ; CURR_COLOR_INDEX: index of current color in COLOR_LIST array, provided for ease of change in color ; MAX_STRING_LEN: holds the maximum number of characters allowed in a string ; PROMPT_FOR_STRING: message to be printed when prompting for string (at start or when z or Z is pressed) ; INPUT_ERR_MSG: message to be printed when wrong command is received ; STRING_ERR_MSG: message to be printed when invalid character is entered in string ; MAX_LEN_ERR_MSG: message to be printed when maximum length is reached for string to be displayed ; COLOR_MSG: message to be printed when changing color ; NEG_*: negative ascii values for various characters (enter, w, W, a, A, z, Z, space) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Memory Locations being used for rest of program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; BITMAP_START: Holds the address from where the bitmap of A-Z starts (Look into hw8_bitmap.asm) ; WRAP_COUNTER: Number of times string we have to wrap before stopping ; STRING_INDEX: This is used to track how many characters we have displayed already ; STRING: reserved space for string of (MAX_STRING_LEN + 1) characters; contains the string being currently displayed ; BITMAP_INCR: Holds the number of entries in bitmap for each char ; X_MAX: holds maximum X-coordinate; used for wraping ; GLOBAL_X: Tracks GLOBAL X coordinate i.e. x-coordinate of first char in string ; LOCAL_X: Tracks LOCAL X coordinate i.e. x-coordinate of start of a character in string (used by DRAW_CHAR routine) ; LOCAl_Y: Tracks LOCAL Y coordinate i.e. y-coordinate of start of a character in string ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Hints to get you started: ; look for TODOs corresponding to each task in the code and you need to fill in instructions as per the comment ; Test after adding few lines of code and see if it behaves the you want it to ; You should be using lc3os_mod.asm as your OS ; You must load bitmap and string file as file before running the program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; program start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .ORIG x3000 ; Start program at x3000 START: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; clear frame buffer on start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; JSR INIT_FRAME_BUFFER_SR ; Initial start point -- set GLOBAL_X to X_START LD R2, X_START ST R2, GLOBAL_X ; initialize WRAP_COUNTER to 10 i.e. wrap 10 times and stop AND R5, R5, #0 ADD R5, R5, #10 ST R5, WRAP_COUNTER ; read first value from array COLOR_LIST and store it at CURR_COLOR ; store the index of current color i.e 0 in CURR_COLOR_INDEX LD R4, COLOR_LIST ST R4, CURR_COLOR AND R4, R4, #0 ST R4, CURR_COLOR_INDEX ; clear display area JSR INIT_FRAME_BUFFER_SR ; TODO (task 2c): Prompt for string before proceeding ; TODO (task 2c): Essentially branch to Z_PRESSED since it'd prompt for a string until a valid is entered BRnzp Z_PRESSED SCROLL_LOOP: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; clear the display area ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; clear display area JSR INIT_FRAME_BUFFER_SR ; TODO (task 2a): Check for input using GET_CHAR subroutine written in task 1 ; TODO (task 2a): If no input received (or R0 equals 0) then branch to NO_KEY_PRESSED ; TODO (task 2a): Echo the character received using OUT or TRAP x21 ; TODO (task 2a): Check if 'w' or 'W' was received, then branch to W_PRESSED ; TODO (task 2a): Check if 'z' or 'Z' is pressed, then branch to Z_PRESSED ; TODO (task 2a): Else print input error message (INPUT_ERR_MSG) using PUTS (or TRAP x22) and branch to NO_KEY_PRESSED ; poll for input AND R0, R0, #0 JSR GET_CHAR ; if zero, no input received. skip all i/o actions ADD R0, R0, #0 BRz NO_KEY_PRESSED ; non-zero char - print out the char TRAP x21 ; OUT ;check if w is pressed; if yes, then move to W_PRESSED LD R4, NEG_LOWER_W ADD R4, R4, R0 BRz W_PRESSED LD R4, NEG_UPPER_W ADD R4, R4, R0 BRz W_PRESSED ; non-zero char - check if x is pressed; if yes, then move to X_PRESSED ;LD R4, NEG_LOWER_X ;ADD R4, R4, R0 ;BRz X_PRESSED ;LD R4, NEG_UPPER_X ;ADD R4, R4, R0 ;BRz X_PRESSED ; non-zero char - check if y is pressed; if yes, then move to Y_PRESSED ;LD R4, NEG_LOWER_Y ;ADD R4, R4, R0 ;BRz Y_PRESSED ;LD R4, NEG_UPPER_Y ;ADD R4, R4, R0 ;BRz Y_PRESSED ; non-zero char - check if z is pressed; if yes, then move to Z_PRESSED LD R4, NEG_LOWER_Z ADD R4, R4, R0 BRz Z_PRESSED LD R4, NEG_UPPER_Z ADD R4, R4, R0 BRz Z_PRESSED ; print err msg using PUTS trap LEA R0, INPUT_ERR_MSG TRAP 0x22 ; PUTS ; No recognizable input - print error message "wrong input" and continue with loop BRnzp NO_KEY_PRESSED W_PRESSED: ; TODO (task 2b): Perform necessary operation when 'w' or 'W' is received ; TODO (task 2b): Read next color from COLOR_LIST using CURR_COLOR_INDEX (it tracks the index of current color in array COLOR_LIST) ; TODO (task 2b): If next color is zero, then reset to first color in list (i.e. value at location labelled by COLOR_LIST) ; TODO (task 2b): Update CURR_COLOR and CURR_COLOR_INDEX ; TODO (task 2b): Display info message (COLOR_MSG) using PUTS and Branch to NO_KEY_PRESSED when done ; AIM: change color of string ; load curr_color_addr, update it and store back LD R4, CURR_COLOR_INDEX ADD R4, R4, #1 ST R4, CURR_COLOR_INDEX ; Load color value stored at CURR_COLOR_INDEX LEA R6, COLOR_LIST LD R4, CURR_COLOR_INDEX ADD R6, R4, R6 LDR R4, R6, #0 ; If zero then reset to start of array, else set CURR_COLOR and continue ST R4, CURR_COLOR BRnp SKIP_COLOR_RESET ; Need to reset the color back to start of array ; Reset CURR_COLOR_INDEX i.e. set to 0 ADD R4, R4, #0 ST R4, CURR_COLOR_INDEX ; Reset CURR_COLOR i.e. to first value in COLOR_LIST LD R6, COLOR_LIST ST R6, CURR_COLOR SKIP_COLOR_RESET: LEA R0, COLOR_MSG TRAP x22 BR NO_KEY_PRESSED ;X_PRESSED: ; AIM: decrement Y_START by 1 and wrap if at the top ; load value from Y_START and decrement by 1 ; LD R4, Y_START ; ADD R4, R4, #-1 ; check if we need to reset Y to bottom (Y_START_MAX) ; if positive then no need to reset, else reset to Y_START_MAX ; BRzp SKIP_Y_DECR_RESET ; LD R5, Y_START_MAX ; ADD R4, R5, #0 ;SKIP_Y_DECR_RESET: ; store updated value at Y_START ; ST R4, Y_START ; BR NO_KEY_PRESSED ;Y_PRESSED: ; AIM: increment Y_START by 1 and wrap if at the bottom ; load value from Y_START and increment by 1 ; LD R4, Y_START ; ADD R4, R4, #1 ; check if we need to reset Y to 0 ; subtract MAX_Y from current Y ; LD R5, NEG_Y_START_MAX ; ADD R5, R5, R4 ;if result is negative, then we don't need to reset else we have to reset Y to 0 ; BRn SKIP_Y_INCR_RESET ; AND R4, R4, #0 ;SKIP_Y_INCR_RESET: ; store updated value at Y_START ; ST R4, Y_START ; BR NO_KEY_PRESSED Z_PRESSED: ; TODO (task 2c): Perform necessary operation when Z is received - take input string and store at memory reserved at STRING ; TODO (task 2c): Prompt for string; echo PROMPT_FOR_STRING message to console ; TODO (task 2c): receive one character input using GET_CHAR routine; remember GET_CHAR routine is non-blocking ; TODO (task 2c): echo the character received to console using OUT ; TODO (task 2c): check for invalid characters; Valid chars - enter, space, a-z, A-Z ; TODO (task 2c): if invalid char, display string error message (STRING_ERR_MSG) and prompt for string again (i.e. goto step 1) ; TODO (task 2c): else check for length of string before storing the char in memory and display warning message (MAX_LEN_WARN_MSG) if the maximum length is reached and store null to terminate the string ; TODO (task 2c): keep storing character till enter is received; do not store enter but terminate the string with null character ; TODO (task 2c): echo the string to console that will be displayed and branch to NO_KEY_PRESSED when done ; Prompt for string LEA R0, PROMPT_FOR_STRING TRAP 0x22 ; input another string till "\n" or enter or ascii 10 ; store at address STRING LEA R4, STRING ; clear R6 - track string length in R6 AND R6, R6, #0 POLL: AND R0, R0, #0 ; poll till we get a char JSR GET_CHAR ADD R0, R0, #0 BRz POLL ; echo char TRAP x21 ; char entered - check for enter LD R5, NEG_ENTER ADD R5,R5,R0 ; if zero, then we are done, we don't store enter BRz CHAR_LOOP_DONE ; else check for space LD R5, NEG_ASCII_SPACE ADD R5,R5,R0 ; if zero, then store char, BRz STORE_CHAR ; else check if it is less than A LD R5, NEG_UPPER_A ADD R5,R5,R0 ; if negative (< A), then error BRn ERROR ; if zero or positive (i.e >= A), check with Z LD R5, NEG_UPPER_Z ADD R5,R5,R0 ; if negative (<=Z), valid char BRnz STORE_CHAR ; if positive (i.e > Z), then check for a LD R5, NEG_LOWER_A ADD R5,R5,R0 ; if negative (< a), then error BRn ERROR ; if zero or positive (i.e >= a), check with z LD R5, NEG_LOWER_Z ADD R5,R5,R0 ; if positive (>z) error BRp ERROR ; if negative ( - LD R6, NEG_ASCII_START ADD R1, R1, R6 ; if A, then we are done, R0 already contains bitmap address for 'A' BRz SKIP_INCR ; next loop essentially multiplies offset in R1 with 49 by adding 49 multiple times to reach the bitmap of character we need ; i.e. when offset goes down to 0 LD R6, BITMAP_INCR STRING_INCR_LOOP: ; Add number of entries in bitmap of each char i.e. 49 ADD R0, R0, R6 ; decrement char offset ADD R1, R1, #-1 ; repeat if still positive BRp STRING_INCR_LOOP SKIP_INCR: ; Register Restoring LD R1,DB_R1 LD R2,DB_R2 LD R3,DB_R3 LD R4,DB_R4 LD R5,DB_R5 LD R6,DB_R6 LD R7,DB_R7 RET DRAW_CHAR: ;Inputs: ;R0 - X-coordinate where character needs to be displayed ;R1 - Y-coordinate where character needs to be displayed ;R2 - Color ;R3 - Bitmap address of the character being displayed ;Outputs: None ;All registers are saved and restore ; Register Saving ST R0,DB_R0 ST R1,DB_R1 ST R2,DB_R2 ST R3,DB_R3 ST R4,DB_R4 ST R5,DB_R5 ST R6,DB_R6 ST R7,DB_R7 ; initialize row loop count LD R6, BITMAP_WIDTH ROW_LOOP: ; initialize column loop count LD R4, BITMAP_WIDTH COLUMN_LOOP: ; read bitmap value LDR R5, R3, #0 ; skip displaying the block if 0 BRz SKIP_TRAP TRAP x40 SKIP_TRAP: ; increment x by 1 ADD R0, R0, #1 ; increment R2 to read next bitmap value ADD R3, R3, #1 ; decrease column_loop count ADD R4, R4, #-1 ; branch if column loop counter is still positive BRp COLUMN_LOOP ; increment Y by 1 ADD R1, R1, #1 ; decrement X by BITMAP_WIDTH LD R5, NEG_BITMAP_WIDTH ADD R0, R0, R5 ; decrement row loop counter by 1 ADD R6, R6, #-1 ; branch to row loop if positive BRp ROW_LOOP ; Register Restoring LD R0,DB_R0 LD R1,DB_R1 LD R2,DB_R2 LD R3,DB_R3 LD R4,DB_R4 LD R5,DB_R5 LD R6,DB_R6 LD R7,DB_R7 RET ; Memory locations for register saving DB_R0: .FILL 0x0 DB_R1: .FILL 0x0 DB_R2: .FILL 0x0 DB_R3: .FILL 0x0 DB_R4: .FILL 0x0 DB_R5: .FILL 0x0 DB_R6: .FILL 0x0 DB_R7: .FILL 0x0 DB_R7_2: .FILL 0x0 INIT_FRAME_BUFFER_SR ST R5,DB_R5 ST R1,DB_R1 ST R4,DB_R4 ST R6,DB_R6 ST R7,DB_R7 ST R2,DB_R2 ST R0,DB_R0 ST R3,DB_R3 LD R5,VIDEO ; R5 is the pointer to the where the pixels will be written to the display LD R6,BLACK ; Black pixel value LD R3,TOT_SIZE ; The size of the entire frame buffer (We are going to write the value of BLACK in the entire frame buffer) INIT_FRAME_LOOP: STR R6,R5,#0 ; In this loop, we are storing the pixel in the appropriate location, then incrementing R5 ;I repeat this same operation 8 times, that way we can speed up the overall loop (8 writes/18 instructions instead of 1 write/4 instructions) STR R6,R5,#1 STR R6,R5,#2 STR R6,R5,#3 STR R6,R5,#4 STR R6,R5,#5 STR R6,R5,#6 STR R6,R5,#7 ADD R5,R5,#8 ADD R3,R3,#-8 ; Checking to see if the entire frame buffer has been written into BRp INIT_FRAME_LOOP ;subtracting 8 because this operation is done 8 times. LD R5,DB_R5 LD R1,DB_R1 LD R4,DB_R4 LD R6,DB_R6 LD R7,DB_R7 LD R2,DB_R2 LD R0,DB_R0 LD R3,DB_R3 RET CLR_DISPLAY_AREA: ST R5,DB_R5 ST R1,DB_R1 ST R4,DB_R4 ST R6,DB_R6 ST R7,DB_R7 ST R2,DB_R2 ST R0,DB_R0 ST R3,DB_R3 LD R6,BLACK ; Black pixel value LD R3,DISPSIZE ; The size of the entire frame buffer (We are going to write the value of BLACK in the entire frame buffer) LD R5, VIDEO ; R5 is the pointer to the where the pixels will be written to the display LD R0, Y_START ; LD R1, FOUR_ROW_WIDTH ; Loop for updating R5 to coordinate (0, Y_START) SET_Y_OFFSET: ADD R5, R5, R1 ADD R0, R0, #-1 BRp SET_Y_OFFSET ; This loop is similar to init_frame_loop but clears only rows 6-13 CLR_DISPLAY_LOOP: STR R6,R5,#0 ;I repeat this same operation 8 times, that way we can speed up the overall loop (8 writes/18 instructions instead of 1 write/4 instructions) STR R6,R5,#1 STR R6,R5,#2 STR R6,R5,#3 STR R6,R5,#4 STR R6,R5,#5 STR R6,R5,#6 STR R6,R5,#7 ADD R5,R5,#8 ADD R3,R3,#-8 ; Checking to see if the entire frame buffer has been written into BRp CLR_DISPLAY_LOOP ;subtracting 8 because this operation is done 8 times. LD R5,DB_R5 LD R1,DB_R1 LD R4,DB_R4 LD R6,DB_R6 LD R7,DB_R7 LD R2,DB_R2 LD R0,DB_R0 LD R3,DB_R3 RET .END