;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;SECTION NUMBER: ; ;GROUP MEMBER NAMES: ;1. ;2. ;3. ;4. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Register Usage ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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 ; Main program: ; R0- ; R1- ; R2- ; R3- ; R4- ; R5- ; R6- ; R7 - only store local values; You should be very careful when tampering with R7; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Hints to get you started: ; look for TODOs in the code and you need to fill in one or two instructions for each TODO for part a ; Test after adding few lines of code and see if it behaves the you want it to ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Memory Locations being used ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; BITMAP_START: Holds the address from where the bitmap of A-Z starts (Look into hw7_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: Holds the address where string is stored (Look into hw7_string.asm) ; 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 ; TODO (task 3): initialize WRAP_COUNTER to 5 i.e. wrap 5 times and stop AND R5, R5, #0 ADD R5, R5, #5 ST R5, WRAP_COUNTER SCROLL_LOOP: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; clear the display area ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; JSR CLR_DISPLAY_AREA ; Update X for first character -- i.e. set LOCAL_X to value contained in GLOBAL_X LD R0, GLOBAL_X ST R0, LOCAL_X ; Update Y for first character -- i.e. set LOCAL_Y to value contained in Y_START LD R1, Y_START ST R1, LOCAL_Y ; Iniitialize string index to 0 AND R4, R4, #0 ST R4, STRING_INDEX ; Put the address of string in R4 LD R4, STRING ; get first char in R1 LDR R1, R4, #0 STRING_LOOP: ; TODO (task 2): Check if it is space, if yes, don't display anything and branch to next char (SKIP_CHAR) LD R6, NEG_ASCII_SPACE ADD R6, R1, R6 BRz SKIP_CHAR ; IF char is not space, keep executing ; TODO (task 2): Setup arguments for CALC_BITMAP_ADDR routine ; Note: R0: bitmap start address, R1: character, output: R0 - starting address of bitmap of char in R1 ;TODO (task 2): put Bitmap start in R0 LD R0, BITMAP_START ; TODO (task 2): call calc_bitmap_addr routine (written in task1) to get the bitmap address of the char ; (similar to what was done in Applied Ex 4) JSR CALC_BITMAP_ADDR ; TODO (task 2): Setup arguments for DRAW_CHAR routine ; Note: R0: x-coordinate, R1: y-coordinate: R2 - starting address of bitmap of char to be displayed ADD R2, R0, #0 LD R0, LOCAL_X LD R1, LOCAL_Y ; TODO (task 2): use DRAW_CHAR routine to draw one char JSR DRAW_CHAR SKIP_CHAR: ; TODO (task 2): Read STRING_INDEX from memory, Update string index and store back in memory LD R4, STRING_INDEX ADD R4, R4, #1 ST R4, STRING_INDEX ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; prepare for next char ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; TODO (task 2): Update X for next char - Add char length and little space ; Read LOCAL_X from memory, update it and store back LD R0, LOCAL_X LD R4, BITMAP_WIDTH ADD R0, R0, R4 LD R4, SPACE_BETWEEN_CHAR ADD R0, R0, R4 ST R0, LOCAL_X ; TODO (task 2): Update Y for next char ; Read LOCAL_Y from memory, update it and store back ; LOCAL_Y doesn't need to change (why?) ; because LOCAL_Y doesn't change for drawing of each char in string LD R1, Y_START ST R1, LOCAL_Y ; TODO (task 2): Get Next Char using STRING_INDEX (number of chars we have already drawn) ; and STRING (address from where the string starts) LD R4, STRING LD R6, STRING_INDEX ADD R4, R4, R6 LDR R1, R4, #0 ; TODO (task 2): check if next char is zero ; if not zero, branch to STRING_LOOP to display that char ; if zero, keep executing further BRnp STRING_LOOP ; update GLOBAL X ; Read GLOBAL_X from memory, update it (decrease by -1) and store back LD R2, GLOBAL_X ADD R2, R2, #-1 ST R2, GLOBAL_X ; TODO (task 3): Check for WRAP condition on global X ; TODO (task 3): If time to wrap, then update global x and wrap counter ; else, branch to SKIP_WRAP_UPDATE ; Wrap condition can be made dependent on current finishing local x (i.e. R0) ; if (local x) equals 1, then wrap or sub -1 and wrap if result is 0 ; local x is stored in R0, ADD R0, R0, #-1 BRp SKIP_WRAP_UPDATE ; TODO (task 3): set global x (GLOBAL_X) to max x-coordinate ; Read GLOBAL_X from memory, update it and store back LD R2, X_MAX ST R2, GLOBAL_X ; TODO (task 3): Load value of WRAP_COUNTER from memory, update the count and store back in memory LD R5, WRAP_COUNTER ADD R5, R5, #-1 ST R5, WRAP_COUNTER SKIP_WRAP_UPDATE: ;;;; wait for some time JSR WAIT JSR WAIT ; Branch to SCROLL_LOOP if WRAP_COUNTER is positive LD R5, WRAP_COUNTER BRp SCROLL_LOOP ; stop HALT WAIT: ST R7, DB_R7 ST R0, DB_R0 LD R0, SPIN_TIME SPIN: ADD R0, R0, #-1 BRp SPIN LD R7, DB_R7 LD R0, DB_R0 RET SPIN_TIME: .FILL 32767 ; start from row - 6 i.e. Y = 6 Y_START: .FILL 6 ; global start for X i.e. X = 1 X_START: .FILL 1 ; max x-coordinate X_MAX: .FILL 31 ; Space between 2 characters - 1 block SPACE_BETWEEN_CHAR: .FILL 1 ; Space taken by each character CHAR_LEN: .FILL 7 ; Tracks GLOBAL X coordinate i.e. x-coordinate of first char in string GLOBAL_X: .FILL 0 ; Tracks LOCAL X coordinate i.e. x-coordinate of start of a character in string (used by DRAW_CHAR routine) LOCAL_X: .FILL 0 ; Tracks LOCAL Y coordinate i.e. y-coordinate of start of a character in string LOCAL_Y: .FILL 0 STRING: .FILL 0x4E00 ; Start Address of Bitmap of A-Z in memory BITMAP_START: .FILL 0x5000 ; Used to index into the string STRING_INDEX: .FILL 0x0000 ; Negative A to get the char offset NEG_ASCII_START: .FILL -65 ; ASCII bitmap start from A ASCII_START: .FILL 65 ; ASCII for space ASCII_SPACE: .FILL 32 ; Negative ASCII for space NEG_ASCII_SPACE: .FILL -32 ; Number of entries in bitmap for one char BITMAP_INCR: .FILL 49 ; Counter for wrapping WRAP_COUNTER: .FILL 0 ;;; assuming 7x7 bitmap available row wise BITMAP_WIDTH: .FILL 7 NEG_BITMAP_WIDTH: .FILL -7 VIDEO: .FILL 0xC000 ; color value for BLUE COLOR: .FILL 0x001F ; color value for BLACK BLACK: .FILL 0x0000 ; color value for WHITE WHITE: .FILL 0xffff DISPSIZE: .FILL 0xE00 TOT_SIZE: .FILL 0x3E00 ROW_WIDTH: .FILL 0x80 FOUR_ROW_WIDTH: .FILL 0x200 ; TODO (task 1): complete the subroutine ; AIM: to calculate the bitmap address for char ; Calculate character offset i.e. - ; Multiply offset by number of entries in bitmap of each char (using repeated addition - no MUL instruction in LC3) ; Add the result of multiplication to bitmap start address to get the address of bitmap for input char CALC_BITMAP_ADDR: ;Inputs: ;R0 - BITMAP_START address ;R1 - CHAR for which bitmap address needed to be found ;Outputs: ;R0 - address of bitmap of character given as input in R1 ;HINT: should save and restore registers but not all (why?) ; Register Saving 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 ; AIM: to calculate the bitmap address for char ; Calculate character offset i.e. - 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 - 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, R2, #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 R2, R2, #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 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