;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; CS/ECE 252 - Introduction to Computer Engineering ; CONNECT FOUR ; Prof. Mark D. Hill and Prof. Gurindar Sohi ; TAs: Preeti Agarwal, Mona Jalal, Rebecca Lam, Pradip Vallathol ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .ORIG x3000 MAIN JSR INITBOARD JSR DISPLAYINITBOARD MLOOP ; Ask player for input LEA R0, MSGST PUTS LD R0, CURPLYR LD R6, CONV ADD R0, R0, R6 OUT LEA R0, MSGED PUTS GETC OUT ADD R1, R0, #0 LEA R0, ENDL PUTS ; Check Input valid JSR CHECKINPUTVALID ADD R3, R1, #1 BRz MLOOP ADD R3, R1, #2 BRz END ; Check Column valid JSR CHECKCOLUMNVALID ADD R2, R2, #0 BRn MLOOP ; Update board state ST R1, CURCOL ST R2, CURROW LD R3, CURPLYR JSR UPDATEBOARDSTATE ; Display board LD R3, CURCLR JSR DISPLAYBOARD ; HALT if end of game ; Loop again, if not LD R1, CURCOL LD R2, CURROW LD R3, CURPLYR JSR CHECKEND ADD R1, R1, #0 BRn END ST R1, CURPLYR ST R2, CURCLR BR MLOOP END HALT CURCOL .FILL 0 CURROW .FILL 0 CURPLYR .FILL x01 CURCLR .FILL x7C00 MSGST .STRINGZ "Player " MSGED .STRINGZ " Enter Column: " ENDL .STRINGZ "\n" CONV .FILL x30 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: CHECKINPUTVALID ; INPUT : R1 - Column as ASCII ; OUTPUT : R1 - Column as INT if digit, otherwise -1 ; HELP : Checks if the input char in R1 is a digit ; If digit, convert to INT and store in R1 ; If 'x', set R1 to -2 ; Else, set R1 to -1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CHECKINPUTVALID ; AND R1, R1, #0 ; EMPTY IMPL LD R5, NEG0 ADD R5, R1, R5 BRn ERRC LD R6, NEG9 ADD R6, R1, R6 BRp CHKX ADD R1, R5, #0 BR ENDCHECKINPUTVALID CHKX LD R5, NEGx ADD R5, R1, R5 BRnp ERRC AND R1, R1, #0 ADD R1, R1, #-2 BR ENDCHECKINPUTVALID ERRC AND R1, R1, #0 ADD R1, R1, #-1 ENDCHECKINPUTVALID RET ; DATA NEG0 .FILL 0xFFD0 NEG9 .FILL 0xFFC7 NEGx .FILL 0xFF88 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: CHECKCOLUMNVALID ; INPUT : R1 - Column of the board ; OUTPUT : R2 - Row of the board ; HELP : DO NOT CHANGE THE VALUE OF R1 ; Checks if the input column of the board (R1) ; is valid and not full ; If not full, set R2 to the lowest free Row ; If full or not valid, set R2 to -1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CHECKCOLUMNVALID ; AND R2, R2, #0 ; EMPTY IMPL ADD R5, R1, #0 BRn CLIV ADD R5, R1, #-6 BRp CLIV AND R2, R2, #0 LEA R5, BOARD ADD R5, R5, R1 CCLOOP LDR R4, R5, #0 BRz ENDCHECKCOLUMNVALID ADD R5, R5, #7 ADD R2, R2, #1 ADD R4, R2, #-6 BRz CLIV BR CCLOOP CLIV AND R2, R2, #0 ADD R2, R2, #-1 ENDCHECKCOLUMNVALID RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: INITBOARD ; INPUT : NONE ; OUTPUT : NONE ; HELP : Initializes the state of the board on the start ; of the game ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; INITBOARD AND R4, R4, #0 LEA R5, BOARD LD R6, BSIZE IBLOOP STR R4, R5, #0 ADD R5, R5, #1 ADD R6, R6, #-1 BRp IBLOOP ENDINITBOARD RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: UPDATEBOARDSTATE ; INPUT : R1, R2 - Column, Row of the board to update ; R3 - Current player ; OUTPUT : NONE ; HELP : Updates the state of the board for the current ; player, for the input Column, Row ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; UPDATEBOARDSTATE LEA R5, BOARD ADD R5, R5, R1 ADD R4, R2, 0 UBSLOOP BRz UPSTATE ADD R5, R5, #7 ADD R4, R4, #-1 BR UBSLOOP UPSTATE STR R3, R5, #0 ENDUPDATEBOARDSTATE RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: GETBOARDADDR ; INPUT : R1, R2 - Column, Row of the board to get data from ; OUTPUT : R5 - Board address of the location ; HELP : Gets the address of the board for the given input ; column, row ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GETBOARDADDR ST R4, TMP_R4 LEA R5, BOARD ADD R5, R5, R1 ADD R4, R2, 0 GBSLOOP BRz ENDGETBOARDADDR ADD R5, R5, #7 ADD R4, R4, #-1 BR GBSLOOP ENDGETBOARDADDR LD R4, TMP_R4 RET BSIZE .FILL 42 BOARD .BLKW 42 TMP_R0 .FILL 0 TMP_R1 .FILL 0 TMP_R2 .FILL 0 TMP_R3 .FILL 0 TMP_R4 .FILL 0 TMP_R5 .FILL 0 TMP_R6 .FILL 0 TMP_R7 .FILL 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: CHECKEND ; INPUT : R1,R2 - Most recently played column, row ; R3 - Current player ; OUTPUT : R1 - Next player or -1 if END ; R2 - Next player color or 0 if END ; HELP : Checks the current state of the board to check ; if the current player has won or the board is full ; If win, print message, set R1 to -1 ; Else set R1 to next player ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CHECKEND ; Save relevant registers that will be modified ST R1, TMP_R1 ST R2, TMP_R2 ST R3, TMP_R3 ST R7, TMP_R7 ; Check for win condition CHECKWIN AND R4, R4, #0 ; The counter LD R1, TMP_R1 ; Col LD R2, TMP_R2 ; Row LD R3, TMP_R3 ; Player ; Check the column for four in a row CHECKCOL JSR GETBOARDADDR LDR R6, R5, #0 ; If R3 == R6, R4++. Otherwise reset R4 NOT R6, R6 ADD R6, R6, 1 ADD R6, R3, R6 BRz COLINC AND R4, R4, #0 BRnzp SKIPCOL COLINC ADD R4, R4, #1 ADD R6, R4, #-4 ; Check if we have 4 BRzp WIN SKIPCOL ADD R2, R2, #-1 ; Next row BRzp CHECKCOL ; Check the row for four in a row ; Check board[row][col-3] to [row][6] AND R4, R4, #0 LD R1, TMP_R1 ; Col LD R2, TMP_R2 ; Row LD R3, TMP_R3 ; Get starting address, row, col-3 ADD R1, R1, #-3 BRn MINCOL AND R1, R1, #0 MINCOL JSR GETBOARDADDR CHECKROW LDR R6, R5, #0 ; R6=BOARD[r2][r1] NOT R6, R6 ADD R6, R6, #1 ADD R6, R3, R6 ; R3 == R6? if so, increment R4 BRz ROWINC AND R4, R4, #0 BRnzp SKIPROW ROWINC ADD R4, R4, #1 ADD R6, R4, #-4 BRzp WIN SKIPROW ADD R5, R5, #1 ADD R1, R1, #1 ADD R6, R1, #-6 ; Bound our column to max=6 BRnz CHECKROW ; Check diagonals AND R4, R4, #0 LD R1, TMP_R1 LD R2, TMP_R2 LD R3, TMP_R3 CHECKLDIAG ; \ ; Using R1, R2, check from R1 = col-3 to col+3, R2 = row+3 to row-3 ADD R1, R1, #-3 ADD R2, R2, #3 ; Set starting coordinates LBOUNDLOOP ; Check bounds. If R1 < 0 || R2 > 5, R1++, R2-- ADD R6, R1, 0 BRn LINC ADD R6, R2, #-5 BRnz LDIAGLOOP ; Both conditions have been met, break out LINC ADD R1, R1, #1 ADD R2, R2, #-1 BRnzp LBOUNDLOOP LDIAGLOOP JSR GETBOARDADDR ; Get address LDR R6, R5, #0 NOT R6, R6 ADD R6, R6, #1 ADD R6, R3, R6 BRz LDIAGINC AND R4, R4, #0 BRnzp SKIPLDIAG LDIAGINC ADD R4, R4, #1 ADD R6, R4, #-4 BRzp WIN SKIPLDIAG ADD R1, R1, #1 ; If R1 > 6, break out ADD R6, R1, #-6 BRp CHECKRDIAG ADD R2, R2, #-1 ; If R2 < 0, break out BRzp LDIAGLOOP CHECKRDIAG ; / AND R4, R3, #0 LD R1, TMP_R1 LD R2, TMP_R2 LD R3, TMP_R3 ; Using R1, R2, check from R1 = col-3 to col+3, R2 = row-3 to row+3 ADD R1, R1, #-3 ADD R2, R2, #-3 ; Set starting coordinates RBOUNDLOOP ; Check bounds. If R1 < 0 || R2 < 5, R1++, R2-- ADD R6, R1, 0 BRn RINC ADD R6, R2, 0 BRzp RDIAGLOOP ; Both conditions have been met, break out RINC ADD R1, R1, #1 ADD R2, R2, #1 BRnzp RBOUNDLOOP RDIAGLOOP JSR GETBOARDADDR LDR R6, R5, #0 NOT R6, R6 ADD R6, R6, #1 ADD R6, R3, R6 BRz RDIAGINC AND R4, R4, #0 BRnzp SKIPRDIAG RDIAGINC ADD R4, R4, #1 ADD R6, R4, #-4 BRzp WIN SKIPRDIAG ADD R1, R1, #1 ; If R1 > 6, break out ADD R6, R1, #-6 BRp CHECKFULL ADD R2, R2, #1 ; If R2 > 5, break out ADD R6, R2, #-5 BRnz RDIAGLOOP CHECKFULL ; Check top row for fullness AND R1, R1, 0 ; Col = 6 to 0 , Row = 5 AND R2, R2, 0 ADD R2, R2, 5 JSR GETBOARDADDR ADD R1, R1, 6 CHECKFULLLOOP ADD R6, R5, R1 LDR R6, R6, 0 BRz SWITCHPLAYER ; If empty, break out ADD R1, R1, -1 BRp CHECKFULLLOOP LEA R0, TIEMSG ; Full board, display tie msg PUTS BRnzp GAMEEND ; Always alternate player SWITCHPLAYER LD R2, PLYR1ID NOT R2, R2 ADD R2, R2, #1 ADD R2, R3, R2 BRz SET2 LD R1, PLYR1ID LD R2, PLYR1CL BR ENDCHECKEND SET2 LD R1, PLYR2ID LD R2, PLYR2CL BRnzp ENDCHECKEND WIN LEA R0, WINMSG PUTS LD R1, CONV ADD R0, R3, R1 OUT GAMEEND AND R2, R2, 0 AND R1, R1, 0 ADD R1, R1, -1 ENDCHECKEND LD R7, TMP_R7 ; Restore registers RET PLYR1ID .FILL 0x01 PLYR1CL .FILL 0x7C00 PLYR2ID .FILL 0x02 PLYR2CL .FILL 0x001F WINMSG .STRINGZ "The winner is Player " TIEMSG .STRINGZ "Tie game\n" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: DISPLAYINITBOARD ; INPUT : NONE ; OUTPUT : NONE ; HELP : Displays the initial board for the game ; Implemented - Donot Change ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISPLAYINITBOARD ST R7, SAVE_R7_1 LD R4, VIDEO LD R5, BLACK LD R3, VIDEO_INC CLEAR_BOARD STR R5,R4,0x0 ADD R4, R4, 0x1 ADD R3, R3, #-1 BRnp CLEAR_BOARD DRAW_ROW_INIT AND R0, R0, 0x0 LD R1, X_START LD R2, Y_START LD R5, COLOR DRAW_ROW_LOOP JSR CALCULATE_ADDR ; R4 gets the address STR R5, R4, 0x0 ADD R1, R1, 0x1 JSR CHECK_ROWBOUND ADD R3, R3, 0x0 BRn DRAW_COL_INIT BRnzp DRAW_ROW_LOOP DRAW_COL_INIT AND R0, R0, 0x0 LD R1, X_START LD R2, Y_START LD R5, COLOR DRAW_COL_LOOP JSR CALCULATE_ADDR STR R5, R4, 0x0 ADD R2, R2, 0x1 ST R7, SAVE_R7 JSR CHECK_COLBOUND LD R7, SAVE_R7 ADD R3, R3, 0x0 BRn ENDDISPLAYINITBOARD BRnzp DRAW_COL_LOOP ENDDISPLAYINITBOARD LD R7, SAVE_R7_1 RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: CALCULATE_ADDR ; INPUT : R1: Row, R2: Column ; OUTPUT : R4, modifies R3 ; HELP : Used in initial display; ; Calculates the memory address:xC000+row*x0080+col ; - Donot Change ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CALCULATE_ADDR ;save inputs and outputs ST R1, SAVE_R1 ST R2, SAVE_R2 ST R3, SAVE_R3 LD R3, VIDEO LD R4, ROW_WIDTH MUL R4, R4, R2 ADD R3, R3, R4 ADD R4, R3, R1 LD R1, SAVE_R1 LD R2, SAVE_R2 LD R3, SAVE_R3 RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: CHECK_ROWBOUND ; INPUT : R1 ; OUTPUT : R0,R3,R2 ; HELP : Used in initial Display; Calculates if row is ; within bound, icrements to next row if it is not. ; - Donot Change ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CHECK_ROWBOUND LD R3, X_MAX ADD R3, R3, R1 BRn CHECK_ROWBOUND_OVER LD R3, ROW_COUNT ADD R3, R0, R3 BRnz INCREMENT_ROWCOUNT AND R3, R3, 0x0 NOT R3, R3 RET INCREMENT_ROWCOUNT ADD R0, R0, 0x1 LD R3, BLOCK_HEIGHT ADD R2, R2, R3 AND R1, R1, 0x0 CHECK_ROWBOUND_OVER AND R3, R3, 0x0 RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: CHECK_ROWBOUND ; INPUT : R2 ; OUTPUT : R0,R3,R1 ; HELP : Used in initial Display; Calculates if column is ; within bound, icrements to next column if it is not. ; - Donot Change ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CHECK_COLBOUND LD R3, Y_MAX ADD R3, R3, R2 BRn CHECK_COLBOUND_OVER LD R3, COL_COUNT ADD R3, R0, R3 BRnz INCREMENT_COLCOUNT AND R3, R3, 0x0 NOT R3, R3 RET INCREMENT_COLCOUNT ADD R0, R0, 0x1 LD R3, BLOCK_WIDTH ADD R1, R1, R3 AND R2, R2, 0x0 CHECK_COLBOUND_OVER AND R3, R3, 0x0 RET VIDEO .FILL 0xC000 VIDEO_INC .FILL 0x3DFF COLOR .FILL 0x7FFF BLACK .FILL 0x0000 Y_START: .FILL 0 X_START: .FILL 0 X_MAX: .FILL 0xFF80 Y_MAX .FILL 0xFF84 ROW_COUNT .FILL 0xFFFA COL_COUNT .FILL 0xFFFA ROW_WIDTH .FILL 0x0080 BLOCK_HEIGHT .FILL 0x0014 BLOCK_WIDTH .FILL 0x0012 NEG_BLOCK_WIDTH .FILL 0xFFFE NEG_BLOCK_HEIGHT .FILL 0xFFEC NEG_ROW_WIDTH .FILL 0xFF80 MINUS_ONE .FILL 0xFFFF ROW_OFFSET .BLKW 1 BLOCK_START .BLKW 1 ;locations for saving and restoring register values SAVE_R0_1 .BLKW 1 SAVE_R1_1 .BLKW 1 SAVE_R2_1 .BLKW 1 SAVE_R3_1 .BLKW 1 SAVE_R4_1 .BLKW 1 SAVE_R5_1 .BLKW 1 SAVE_R6_1 .BLKW 1 SAVE_R7_1 .BLKW 1 SAVE_R0 .BLKW 1 SAVE_R1 .BLKW 1 SAVE_R2 .BLKW 1 SAVE_R3 .BLKW 1 SAVE_R4 .BLKW 1 SAVE_R5 .BLKW 1 SAVE_R6 .BLKW 1 SAVE_R7 .BLKW 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: DISPLAYBOARD ; INPUT : R1, R2 - Column, Row of the board to update ; R3 - Current color ; OUTPUT : NONE ; HELP : Updates the display board, for the current ; player, for the input Column, Row ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISPLAYBOARD ST R0, SAVE_R0_1 ST R1, SAVE_R1_1 ST R2, SAVE_R2_1 ST R3, SAVE_R3_1 ST R4, SAVE_R4_1 ST R5, SAVE_R5_1 ST R7, SAVE_R7_1 LD R5, MINUS_ONE CHANGE_ROW_MAPPING AND R4, R4, 0x0 ADD R4, R4, 0x5 NOT R0, R2 ADD R0, R0, 0x1 ADD R2, R4, R0 LD R4, BLOCK_HEIGHT MUL R0, R2, R4 ADD R0, R0, 0x1 LD R4, ROW_WIDTH MUL R4, R4, R0 ST R4, ROW_OFFSET LD R4, BLOCK_WIDTH MUL R4, R1, R4 ADD R2, R4, 0x01 LD R1, ROW_OFFSET ST R7, SAVE_R7 JSR CALCULATE_ADDR_2 LD R7, SAVE_R7 ;Label: DRAW_BLOCK: INPUTS: R1 : Row , R2: column ; Outputs : R4: Memory address ;modifies, R4 DRAW_BLOCK LD R0, BLOCK_HEIGHT ADD R0, R0, #-1 DRAW_BLOCK_ROW_INIT ST R4, BLOCK_START LD R2, BLOCK_WIDTH ADD R2, R2, #-1 DRAW_BLOCK_ROW STR R3, R4, #0 ADD R4, R4, 0x1 ADD R2, R2, R5 BRp DRAW_BLOCK_ROW DRAW_BLOCK_COL LD R4, BLOCK_START LD R1, ROW_WIDTH ADD R4, R4, R1 ADD R0, R0, R5 BRp DRAW_BLOCK_ROW_INIT ENDDISPLAYBOARD LD R0, SAVE_R0_1 LD R1, SAVE_R1_1 LD R2, SAVE_R2_1 LD R3, SAVE_R3_1 LD R4, SAVE_R4_1 LD R5, SAVE_R5_1 LD R7, SAVE_R7_1 RET LD R0, SAVE_R0_1 LD R1, SAVE_R1_1 LD R2, SAVE_R2_1 LD R3, SAVE_R3_1 LD R4, SAVE_R4_1 LD R5, SAVE_R5_1 LD R6, SAVE_R6_1 LD R7, SAVE_R7_1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; FUNCTION: CALCULATE_ADDR_2 ; INPUT : R1,R2 ; OUTPUT : R4, modifies R3 ; HELP : Used in initial display; Calculates the memory address : xC000 + row*x0080 + col ; - Donot Change ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CALCULATE_ADDR_2 ;save inputs and outputs ST R1, SAVE_R1 ST R2, SAVE_R2 LD R4, VIDEO ADD R4, R4, R1 ADD R4, R4, R2 LD R1, SAVE_R1 LD R2, SAVE_R2 RET .END