;; Emacs Mode Selection Info: -*-mode: ASM; coding: iso-latin-1-dos;-*- * ;; ******************************************************************************************** ;; File Name: Four_1.asm ;; Auther: John L. Weinrich ;; Date: 01/31/03 ;; Useage 4004 TIC-TAC-TOE Game ;; Description: ;; ;; This is the main routine for the 4004 TIC-TAC-TOE Game. ;; ;; Assumptions: ;; This assembly code and all the included files assume the following: ;; ;; RAM Memory: 2048 X 4 (8 RAM banks, 4 RAMs/bank, 4 registers/RAM, 16 Char/Reg) ;; 256 status characters. ;; 2 I/O Port ;; RAM1: SPEAKER PITCH/write ;; RAM2: SPEAKER LEVEL/write ;; ;; ROM Memory: 4096 X 8 (16 ROMs @ 256 locations ;; 11 I/O Ports (3 - R/W, 4- Read, 4 - Write) ;; ROM0: MISC/read ;; ROM0: MISC/write ;; ROM3: DISPLAY HIGH IN/read ;; ROM3: DISPLAY HIGH OUT/write ;; ROM4: DISPLAY LOW IN/read ;; ROM4: DISPLAY LOW OUT/write ;; ROM5: KEYBOARD HIGH INPUT/read ;; ROM6: KEYBOARD LOW INPUT/read ;; ROM7: MISC2/write ;; ROM8: PAGE/write ;; ROM9: RANDOM NUMBER GENERATOR/read ;; ROM10: FPGA VERSION/read ;; ;; See "4004 FPGA Design" and "4004 Software Design " documents for more detail information. ;; ;; Registers used: ;; Memory used: ;; Entrance parameters: ;; Exit parameters: ;; Labels used: ;; ******************************************************************************************** ;; ******************************************************************************************** ;; Here are the assembler directives ;; What CPU to assemble for and where in memory to start ;; Also there is the all the include files. include "four_ALL.equ" ; Get all equates include "bitfuncs.inc" ; Include bit functions so that fin can be ; loaded from a label (upper 4 bits of address ; are loped off) include "four_01.equ" ; Get Page #1 equates cpu 4004 ; Tell assembler that the processor is a 4004 org CODE_LOCATION ; Set code start location in memory ;; ******************************************************************************************** ;; This is the begining of the test routine ;; ******************************************************************************************** HardStart nop ; Wants a nop here, don't know why! ;; Run and display Built In Test on RAM jun BITP2 ; Call BIT on page #2 BITP2Rtn nop ;; ******************************************************************************************** ;; This is the begining of the big loop ;; ExecLoop jun GetPlayersP3 ; Get player names, page #3 GetPlayersP3Rtn nop GameStart jms DisplayModeCMND ; Put the display into command mode jms ClearDisplay ; Clear the display jms WaitForDisplay ; Wait for display to become ready for data or commands jms OffCurDisplay ; Turn off display cursor jms WaitForDisplay ; Wait for display to become ready for data or commands jms CurBlinkOffDis ; Turn off display cursor blink jms WaitForDisplay ; Wait for display to become ready for data or commands jms DisplayModeData ; Set the display to data mode ;; Display game board jms DisGB1 ; Setup Display board line #1 jms DisGB2 ; Setup Display board line #2 jms DisGB3 ; Setup Display board line #3 ;; Display game board numbering jms DisGBN1 ; Display game board numbering line #1 jms DisGBN2 ; Display game board numbering line #2 jms DisGBN3 ; Display game board numbering line #3 ;; Display gameboard message jms DisGBMSG1 ; Display game board message #1 jms DisGBMSG2 ; Display game board message #2 jms DisTurn ; Display game board your turn message ;; Zero out player turn counter in RAM fim SRC_P,TURN_COUNT_RAM ; Select player turn counter RAM location src SRC_P ; Tell RAM of selection ldm 000H ; Set to 0 turns wrm ; Write player turn counter to RAM ;; Get random number and determine which player plays first (and gets the "X") fim SRC_P,RAND_NUM_GEN_PORT ; Select random number port src SRC_P ; Send out port selection clb ; Make sure accumulator is clear rdr ; Read the random number generator from FPGA ral ; Move MSB to carr/link bit jcn C,Player1First ; Use carry/link bit to determine who starts ;; Setup if player #2 is first Player2First fim SRC_P,PLAYER_TURN_RAM ; Select player turn charactor src SRC_P ; Tell RAM of selection ldm PLAYER_2_TURN ; Set to player #1 wrm ; Set Player turn charactor from RAM ;; Set player start RAM fim SRC_P,PLAYER_START_RAM ; Select player start charactor src SRC_P ; Tell RAM of selection ldm PLAYER_2_START ; Set to player #2 wrm ; Set Player Start charactor in RAM ;; Set player #1 with O mark fim SRC_P,PLAYER_1_MARK_RAM ; Select RAM position charactor src SRC_P ; Send out RAM charactor selection ldm PLAYER_O_CHAR ; Set player #1 mark as O wrm ; Write init data to storage location ;; Set player #2 with X mark fim SRC_P,PLAYER_2_MARK_RAM ; Select RAM position charactor src SRC_P ; Send out RAM charactor selection ldm PLAYER_X_CHAR ; Set player #2 mark as X wrm ; Write init data to storage location jun NextPlayer ; Start game play loop ;; Setup if playrer #1 is first Player1First fim SRC_P,PLAYER_TURN_RAM ; Select player turn charactor src SRC_P ; Tell RAM of selection ldm PLAYER_1_TURN ; Set to player #1 wrm ; Set Player turn charactor from RAM ;; Set player start RAM fim SRC_P,PLAYER_START_RAM ; Select player start charactor src SRC_P ; Tell RAM of selection ldm PLAYER_1_START ; Set to player #1 wrm ; Set Player Start charactor in RAM ;; Set player #1 with X mark fim SRC_P,PLAYER_1_MARK_RAM ; Select RAM position charactor src SRC_P ; Send out RAM charactor selection ldm PLAYER_X_CHAR ; Set player #1 mark as X wrm ; Write init data to storage location ;; Set player #2 with O mark fim SRC_P,PLAYER_2_MARK_RAM ; Select RAM position charactor src SRC_P ; Send out RAM charactor selection ldm PLAYER_O_CHAR ; Set player #2 mark as O wrm ; Write init data to storage location ;; This is the play game loop NextPlayer fim UTILITY_1_P,L4C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms ClearName ; Display player name fim SRC_P,PLAYER_TURN_RAM ; Select player turn charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get Player turn charactor from RAM jcn Z,Player2Turn ; Player #1 or #2? ;; Player #1 turn next Player1Turn fim UTILITY_1_P,L4C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms Player1Name ; Display player #1 name fim SRC_P,PLAYER_1_MARK_RAM ; Select player #1 mark charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get Player #1 mark charactor from RAM fim SRC_P,PLAYER_MARK_RAM ; Select player mark charactor src SRC_P ; Tell RAM of selection wrm ; Put player #1 mark charactor in RAM fim SRC_P,PLAYER_TURN_RAM ; Select player turn charactor src SRC_P ; Tell RAM of selection ldm PLAYER_2_TURN ; Set player #2 turn next wrm ; """" jun Turn ; """" ;; Player #2 turn next Player2Turn fim UTILITY_1_P,L4C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms Player2Name ; Display player #2 name fim SRC_P,PLAYER_2_MARK_RAM ; Select player #2 mark charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get Player #2 mark charactor from RAM fim SRC_P,PLAYER_MARK_RAM ; Select player mark charactor src SRC_P ; Tell RAM of selection wrm ; Put player #2 mark charactor in RAM fim SRC_P,PLAYER_TURN_RAM ; Select player turn charactor src SRC_P ; Tell RAM of selection ldm PLAYER_1_TURN ; Set player #2 turn next wrm ; """" ;; Check if player vs 4004 ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,GAME_MODE_RAM ; Select mode charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get mode fim SCRATCH_1_P,MODE2 ; Select Mode #2 sub SCRATCH_1_L ; Check for mode #2 jcn Z,Turn ; Not Mode #2 ;; Player vs 4004 ;; Call routine to do 4004 move jun Get4004PosP6 ; Go to page #6 and get 4004 position Get4004PosP6Rtn jun GetPosP4Rtn ;; Go to page #4 and get player position Turn jun GetPosP4 ; Get position from player ;; Got to page #4 and display board positions GetPosP4Rtn jun DisBrdPosP4 ; Get RAM positions and display ;; Check to see if either player has won DisBrdPosP4Rtn jun CheckWinP4 ; Check for win or draw ;; Now check game status (win, draw, or play) CheckWinP4Rtn ldm RAM_BANK_0 ; Move RAM bank pointer to ACC dcl ; Select RAM bank fim SRC_P,GAME_STATUS_RAM ; Select RAM game status charactor src SRC_P ; Send out RAM charactor selection clb ; Make sure accumulator is clear rdm ; Read status charactor jcn Z,NoDrawWin ; Check for draw or win ;; There is a draw or win, clear out board message area fim UTILITY_1_P,L1C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms ClearBoard ; Display player name fim UTILITY_1_P,L2C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms ClearBoard ; Display player name fim UTILITY_1_P,L3C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms ClearBoard ; Display player name ;; Now check for draw, X win, or O win ldm RAM_BANK_0 ; Move RAM bank pointer to ACC dcl ; Select RAM bank fim SRC_P,GAME_STATUS_RAM ; Select RAM game status charactor src SRC_P ; Send out RAM charactor selection clb ; Make sure accumulator is clear ldm GS_XWIN ; Get X win constant sbm ; Test if X win jcn NZ,TestOWin ; X win jun XHasWon ; Goto X has won routine TestOWin clb ; Make sure accumulator is clear ldm GS_OWIN ; Get O win constant sbm ; Test for O win jcn NZ,TestDraw ; O win jun OHasWon ; Goto O has won routine TestDraw clb ; Make sure accumulator is clear ldm GS_DRAW ; Get draw constant sbm ; Test for draw jcn NZ,NoDrawWin ; Draw jun Draw ; Goto draw routine ;; Neither a draw or win... ;; Increment player turn counter and determine if game is done based on the 9 turns total ;; This is only necessary for testing, game never gets to 9 plays, always a win or draw first NoDrawWin fim SRC_P,TURN_COUNT_RAM ; Select player turn counter RAM location src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is zeroed rdm ; Get turn count from RAM iac ; Increment counter wrm ; Save the counter to RAM clb ; Make sure accumulator is clear ldm MAX_TURNS ; Get the max count sbm ; Compare player counter in RAM jcn Z,MaxTurns ; If max count, start new game jun NextPlayer ; Have not met maximum number of turns, next turn MaxTurns jun MoreGame org CODE_LOCATION + 0100h ;; Determine which player is X ;; Display X player name ;; Display win message XHasWon fim SRC_P,PLAYER_1_MARK_RAM ; Select RAM position charactor src SRC_P ; Send out RAM charactor selection clb ; Make sure accumulator is clear ldm PLAYER_X_CHAR ; Get X charactor sbm ; Test if X jcn NZ,XNotPlayer_1 ; Player #1 not X fim UTILITY_1_P,L1C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms Player1Name ; Display player #1 name jms DisWon1 ; Display won message jun MoreGame ; Continue XNotPlayer_1 fim SRC_P,PLAYER_2_MARK_RAM ; Select RAM position charactor src SRC_P ; Send out RAM charactor selection clb ; Make sure accumulator is clear ldm PLAYER_X_CHAR ; Get X charactor sbm ; Test if X jcn NZ,XNotPlayer_2 ; Player #2 not X fim UTILITY_1_P,L1C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms Player2Name ; Display player #1 name jms DisWon1 ; Display win message XNotPlayer_2 jun MoreGame ; Continue ;; Determine which player is O ;; Display O player name ;; Display win message OHasWon fim SRC_P,PLAYER_1_MARK_RAM ; Select RAM position charactor src SRC_P ; Send out RAM charactor selection clb ; Make sure accumulator is clear ldm PLAYER_O_CHAR ; Get O charactor sbm ; Test if O jcn NZ,ONotPlayer_1 ; Player #1 not O fim UTILITY_1_P,L1C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms Player1Name ; Display player #1 name jms DisWon1 ; Display win message jun MoreGame ; Continue ONotPlayer_1 fim SRC_P,PLAYER_2_MARK_RAM ; Select RAM position charactor src SRC_P ; Send out RAM charactor selection clb ; Make sure accumulator is clear ldm PLAYER_O_CHAR ; Get O charactor sbm ; Test if O jcn NZ,ONotPlayer_2 ; Player #2 not O fim UTILITY_1_P,L1C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms Player2Name ; Display player #1 name jms DisWon1 ; Display win message ONotPlayer_2 jun MoreGame ; Continue org CODE_LOCATION + 0200h ; ORG cause' jcn jump too large ;; Display draw message Draw jms Draw1 ; Display draw message jms Draw2 ; Display draw message jms Draw3 ; Display draw message ;; Wait for prompt MoreGame fim UTILITY_1_P,L4C1 ; Set the display to line 4 & column 1 jms DisSetLineCol ; Call the routine to set the display cursor jms DisplayModeData ; Set display to data mode jms ClearName ; Display player name jms DisKeyPress ; Prompt user to press any key to continue jms InitKYBD ; clear out any key presses jms GetChar ; Wait for keypress jms Level5 ; Set level to "5" jms Pitch1116HZ ; Set pitch to "happy" jms Beep ; Tell user that key was pressed ;; Another game? jms DisplayModeCMND ; Put the display into command mode jms ClearDisplay ; Clear the display jms WaitForDisplay ; Wait for display to become ready for data or commands jms OffCurDisplay ; Turn off display cursor jms WaitForDisplay ; Wait for display to become ready for data or commands jms CurBlinkOffDis ; Turn off display cursor blink jms WaitForDisplay ; Wait for display to become ready for data or commands jms DisplayModeData ; Set the display to data mode jms DisAnother ; Display another message jms DisYN ; Display yes not prompt KeyNotValid jms InitKYBD ; clear out any key presses jms GetChar ; Get charactor from keyboard ;; Get selection ;; Get upper nibble from keyboard and check for "N" CheckN ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,KYB_STATE_H_RAM ; Select high keyboard state charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get keyboard high state charactor from RAM fim SCRATCH_1_P,'N' ; Get the charactor "N" sub SCRATCH_1_H ; Check that the upper nibble is a "N" jcn Z,GetLowNibN ; Equal, now get lower nibble jun Checkn ; Not equal ;; Get lower nibble from keyboard and check for "N" GetLowNibN ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,KYB_STATE_L_RAM ; Select low keyboard state charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get keyboard low state charactor from RAM fim SCRATCH_1_P,'N' ; Get the charactor "N" sub SCRATCH_1_L ; Check that the lower nibble is a "N" jcn Z,NSelected ; Equal Checkn ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,KYB_STATE_H_RAM ; Select high keyboard state charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get keyboard high state charactor from RAM fim SCRATCH_1_P,'n' ; Get the charactor "N" sub SCRATCH_1_H ; Check that the upper nibble is a "N" jcn Z,GetLowNibn ; Equal, now get lower nibble jun CheckY ; Not equal ;; Get lower nibble from keyboard and check for "N" GetLowNibn ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,KYB_STATE_L_RAM ; Select low keyboard state charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get keyboard low state charactor from RAM fim SCRATCH_1_P,'n' ; Get the charactor "N" sub SCRATCH_1_L ; Check that the lower nibble is a "N" jcn Z,NSelected ; Equal ;; Get upper nibble from keyboard and check for "Y" CheckY ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,KYB_STATE_H_RAM ; Select high keyboard state charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get keyboard high state charactor from RAM fim SCRATCH_1_P,'Y' ; Get the charactor "Y" sub SCRATCH_1_H ; Check that the upper nibble is a "Y" jcn Z,GetLowNibY ; Equal, now get lower nibble jun Checky ; Not equal ;; Get lower nibble from keyboard and check for "Y" GetLowNibY ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,KYB_STATE_L_RAM ; Select low keyboard state charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get keyboard low state charactor from RAM fim SCRATCH_1_P,'Y' ; Get the charactor "Y" sub SCRATCH_1_L ; Check that the lower nibble is a "Y" jcn Z,YSelected ; Equal Checky ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,KYB_STATE_H_RAM ; Select high keyboard state charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get keyboard high state charactor from RAM fim SCRATCH_1_P,'y' ; Get the charactor "Y" sub SCRATCH_1_H ; Check that the upper nibble is a "Y" jcn Z,GetLowNiby ; Equal, now get lower nibble jun Neither ; Not equal ;; Get lower nibble from keyboard and check for "Y" GetLowNiby ldm RAM_BANK_0 ; Select RAM bank 0 dcl ; Send out RAM bank selection fim SRC_P,KYB_STATE_L_RAM ; Select low keyboard state charactor src SRC_P ; Tell RAM of selection clb ; Make sure accumulator is clear rdm ; Get keyboard low state charactor from RAM fim SCRATCH_1_P,'y' ; Get the charactor "Y" sub SCRATCH_1_L ; Check that the lower nibble is a "Y" jcn Z,YSelected ; Equal Neither jms Level15 ; Set level to "15" jms Pitch406HZ ; Set pitch to "sad" jms Beep ; Tell user that key was pressed jun KeyNotValid ; Loop till valid key is pressed YSelected jms InitGB ; Initialize game board in RAM jms InitStat ; Initialize game status in RAM jun GameStart ; Continur with another game jms Level5 ; Set level to "5" jms Pitch1116HZ ; Set pitch to "happy" jms Beep ; Tell user that key was pressed NSelected jms InitGB ; Initialize game board in RAM jms InitStat ; Initialize game status in RAM jms Level5 ; Set level to "5" jms Pitch1116HZ ; Set pitch to "happy" jms Beep ; Tell user that key was pressed jun ExecLoop ; Start new game, mode, and player(s)