; This is the code to run an 8x8 LED array. It plays a watered down version of the ; classic PC game nibbles. ; ; Written by:Steven Easley ; Email: seasley@robotdungeon.com ; Webpage: www.robotdungeon.com ; ; ; LIST p=16F628 include "P16F628.inc" ERRORLEVEL 0, -302 ;suppress bank selection messages __CONFIG _CP_OFF &_BODEN_OFF &_PWRTE_OFF &_WDT_OFF &_LVP_OFF &_MCLRE_OFF &_INTRC_OSC_NOCLKOUT #DEFINE rt_but PORTA,0 #DEFINE lt_but PORTA,1 #DEFINE latcha PORTA,2 #DEFINE latchb PORTA,3 #DEFINE DIR_UP 0 #DEFINE DIR_LT 1 #DEFINE DIR_RT 2 #DEFINE DIR_DN 3 M_lat_a macro bcf latcha bsf latcha bcf latcha endm M_lat_b macro bcf latchb bsf latchb bcf latchb endm cblock 0x20 row0 row1 row2 row3 row4 row5 row6 row7 row0_1 row1_1 row2_1 row3_1 row4_1 row5_1 row6_1 row7_1 worm_dir worm_length worm_temp worm_x worm_y worm0 worm1 worm2 worm3 worm4 worm5 worm6 worm7 worm8 worm9 worm10 worm11 worm12 worm13 worm14 worm15 ;Delay routinne variables d1 d2 d3 display_counter pb_latch row_pos p_temp ;save register s_temp ;save register w_temp ;save register f_temp buttons col_temp point_marker point level endc org 0x0000 goto init ; Interrupt routine handles TMR2 which generates a 1ms tick ; Interrupt vector ORG 0x0004 INT movwf w_temp ; Save W register swapf STATUS,W ; Swap status to be saved into W movwf s_temp ; Save STATUS register movfw PCLATH movwf p_temp ; Save PCLATH ;movfw FSR ;movwf f_temp btfss PIR1,TMR2IF ; Flag set if TMR2 interrupt goto INTX ; Jump if not timed out ; Timer (TMR2) timeout bcf PIR1,TMR2IF ; Clear the calling flag ;Clear all rows to prevent ghosting movlw b'00000000' movwf PORTB M_lat_a ;Set appopriate row in display ram movfw row_pos sublw 0x00 bz set_row0 movfw row_pos sublw 0x01 bz set_row1 movfw row_pos sublw 0x02 bz set_row2 movfw row_pos sublw 0x03 bz set_row3 movfw row_pos sublw 0x04 bz set_row4 movfw row_pos sublw 0x05 bz set_row5 movfw row_pos sublw 0x06 bz set_row6 movfw row_pos sublw 0x07 bz set_row7 goto INTX set_row0: movfw row0 goto do_row set_row1: movfw row1 goto do_row set_row2: movfw row2 goto do_row set_row3: movfw row3 goto do_row set_row4: movfw row4 goto do_row set_row5: movfw row5 goto do_row set_row6: movfw row6 goto do_row set_row7: movfw row7 do_row: xorlw 0xFF movwf PORTB M_lat_b movf pb_latch, w movwf PORTB M_lat_a bcf STATUS, C rrf pb_latch, f incf row_pos,F movf row_pos, w sublw 0x08 bnz INTX movlw 0x00 movwf row_pos movlw 0x80 movwf pb_latch INTX movfw p_temp movwf PCLATH ; Restore PCLATH swapf s_temp,W movwf STATUS ; Restore STATUS register - restores bank swapf w_temp,F swapf w_temp,W ; Restore W register ;movfw f_temp ;movwf FSR retfie points_level_one: addwf PCL, F retlw 0x11 retlw 0x25 retlw 0x46 retlw 0x31 retlw 0x04 retlw 0x61 retlw 0x14 retlw 0x73 ;retlw 0x33 retlw 0x44 retlw 0x74 retlw 0x21 retlw 0x66 retlw 0x44 retlw 0x33 ;retlw 0x44 retlw 0x41 retlw 0x76 retlw 0x15 retlw 0x34 retlw 0x12 retlw 0x57 retlw 0x76 retlw 0x36 ;retlw 0x60 retlw 0x20 retlw 0x30 retlw 0x21 retlw 0x15 retlw 0x43 retlw 0x70 retlw 0x14 retlw 0xFF ;------------ Draw screen when player wins make_win movlw 0x3C movwf row0_1 movlw 0x42 movwf row1_1 movlw 0x95 movwf row2_1 movlw 0xA1 movwf row3_1 movlw 0xA1 movwf row4_1 movlw 0x95 movwf row5_1 movlw 0x42 movwf row6_1 movlw 0x3C movwf row7_1 return ;------------ Draw screen when player wins make_lose movlw 0xBD movwf row0_1 movlw 0x42 movwf row1_1 movlw 0x81 movwf row2_1 movlw 0x99 movwf row3_1 movlw 0x99 movwf row4_1 movlw 0x81 movwf row5_1 movlw 0x42 movwf row6_1 movlw 0xBD movwf row7_1 return ;------------ Draw L and level number load_level movlw 0x00 movwf row3_1 movlw 0x20 movwf row4_1 movlw 0x20 movwf row5_1 movlw 0x20 movwf row6_1 movlw 0x3F movwf row7_1 movfw level sublw .0 bz level_one movfw level sublw .10 bz level_two movfw level sublw .20 bz level_three movfw level sublw .30 bz level_four movfw level sublw .40 bz level_five goto end_load_level level_one: movlw 0x80 movwf row0_1 movlw 0xFE movwf row1_1 movlw 0x84 movwf row2_1 goto end_load_level level_two: movlw 0x8C movwf row0_1 movlw 0x92 movwf row1_1 movlw 0xE4 movwf row2_1 goto end_load_level level_three: movlw 0x6C movwf row0_1 movlw 0x92 movwf row1_1 movlw 0x44 movwf row2_1 goto end_load_level level_four: movlw 0xFE movwf row0_1 movlw 0x10 movwf row1_1 movlw 0x1E movwf row2_1 goto end_load_level level_five: movlw 0x62 movwf row0_1 movlw 0x92 movwf row1_1 movlw 0x5E movwf row2_1 goto end_load_level end_load_level return ;------------ Load secondary display RAM into primary RAM load_display: bcf INTCON,GIE ; Turn interupts off while messing with primary display ram movf row0_1, w movwf row0 movf row1_1, w movwf row1 movf row2_1, w movwf row2 movf row3_1, w movwf row3 movf row4_1, w movwf row4 movf row5_1, w movwf row5 movf row6_1, w movwf row6 movf row7_1, w movwf row7 bsf INTCON,GIE return ;------------- Here is where the worm is placed on the screen draw_worm: clrf worm_temp next_segment: movlw worm0 addwf worm_temp,w movwf FSR movfw INDF andlw 0x0F movwf worm_x swapf INDF,w andlw 0x0F movwf worm_y ;Selet appropriate column in display ram movlw row0_1 addwf worm_x,w movwf FSR ;movfw INDF ;Set appopriate row in display ram movfw worm_y sublw 0x00 bz set_bit0 movfw worm_y sublw 0x01 bz set_bit1 movfw worm_y sublw 0x02 bz set_bit2 movfw worm_y sublw 0x03 bz set_bit3 movfw worm_y sublw 0x04 bz set_bit4 movfw worm_y sublw 0x05 bz set_bit5 movfw worm_y sublw 0x06 bz set_bit6 movfw worm_y sublw 0x07 bz set_bit7 goto get_worm_tail set_bit0: bsf INDF,0 goto get_worm_tail set_bit1: bsf INDF,1 goto get_worm_tail set_bit2: bsf INDF,2 goto get_worm_tail set_bit3: bsf INDF,3 goto get_worm_tail set_bit4: bsf INDF,4 goto get_worm_tail set_bit5: bsf INDF,5 goto get_worm_tail set_bit6: bsf INDF,6 goto get_worm_tail set_bit7: bsf INDF,7 get_worm_tail: incf worm_temp,f movfw worm_temp subwf worm_length,w bnz next_segment return ;------------- Draw the currnt point marker draw_marker: movfw point_marker andlw 0x0F movwf worm_x swapf point_marker,w andlw 0x0F movwf worm_y ;Selet appropriate column in display ram movlw row0_1 addwf worm_x,w movwf FSR ;Set appopriate row in display ram movfw worm_y sublw 0x00 bz set_bit0_1 movfw worm_y sublw 0x01 bz set_bit1_1 movfw worm_y sublw 0x02 bz set_bit2_1 movfw worm_y sublw 0x03 bz set_bit3_1 movfw worm_y sublw 0x04 bz set_bit4_1 movfw worm_y sublw 0x05 bz set_bit5_1 movfw worm_y sublw 0x06 bz set_bit6_1 movfw worm_y sublw 0x07 bz set_bit7_1 goto draw_point_end set_bit0_1: bsf INDF,0 goto draw_point_end set_bit1_1: bsf INDF,1 goto draw_point_end set_bit2_1: bsf INDF,2 goto draw_point_end set_bit3_1: bsf INDF,3 goto draw_point_end set_bit4_1: bsf INDF,4 goto draw_point_end set_bit5_1: bsf INDF,5 goto draw_point_end set_bit6_1: bsf INDF,6 goto draw_point_end set_bit7_1: bsf INDF,7 draw_point_end return ;------------- Move worm according to current movement direction move_worm ;First shift everything towards tail movfw worm14 movwf worm15 movfw worm13 movwf worm14 movfw worm12 movwf worm13 movfw worm11 movwf worm12 movfw worm10 movwf worm11 movfw worm9 movwf worm10 movfw worm8 movwf worm9 movfw worm7 movwf worm8 movfw worm6 movwf worm7 movfw worm5 movwf worm6 movfw worm4 movwf worm5 movfw worm3 movwf worm4 movfw worm2 movwf worm3 movfw worm1 movwf worm2 movfw worm0 movwf worm1 movwf worm1 ;Load last worm head andlw 0x0F movwf worm_x swapf worm1,w andlw 0x0F movwf worm_y movfw worm_dir sublw DIR_UP bz worm_up movfw worm_dir sublw DIR_LT bz worm_lt movfw worm_dir sublw DIR_RT bz worm_rt movfw worm_dir sublw DIR_DN bz worm_dn goto wrap_up worm_up: decf worm_y, f movfw worm_y sublw 0xFF bnz wrap_up movlw 0x07 movwf worm_y goto wrap_up worm_dn: incf worm_y, f movfw worm_y sublw 0x08 bnz wrap_up clrf worm_y goto wrap_up worm_lt: incf worm_x, f movfw worm_x sublw 0x08 bnz wrap_up clrf worm_x goto wrap_up worm_rt: decf worm_x, f movfw worm_x sublw 0xFF bnz wrap_up movlw 0x07 movwf worm_x wrap_up movfw worm_x movwf worm0 swapf worm_y, w addwf worm0, f return ;------------- Test if the worm has colided with itself test_collision movlw 0x01 movwf col_temp movlw worm1 ;Load location of second worm section movwf FSR col_next movfw INDF subwf worm0, w bz worm_hit incf FSR,f incf col_temp,f movfw col_temp subwf worm_length, w bnz col_next retlw 0x00 worm_hit retlw 0x01 ;------------- Here is where the worm is placed on the screen clear_disp_ram movlw 0x00 movwf row0_1 movwf row1_1 movwf row2_1 movwf row3_1 movwf row4_1 movwf row5_1 movwf row6_1 movwf row7_1 return ;------------- Load next point making sure that it is not part of the worm do_next_point movfw worm_length movwf worm_temp incf point,f movfw point call points_level_one movwf point_marker movfw point_marker sublw 0xFF bnz end_do_next_point clrf point movfw point call points_level_one movwf point_marker ;Check to see if it is in the worm movlw worm0 movwf FSR check_next_part movfw INDF subwf point_marker,w bz do_next_point incf FSR,f decfsz worm_temp,f goto check_next_part end_do_next_point return ;50ms Delay Routine at 4MHz delay_50ms: ;4994 cycles movlw 0xE7 movwf d1 movlw 0x04 movwf d2 delay_50ms_0 decfsz d1, f goto $+2 decfsz d2, f goto delay_50ms_0 return ;2s Delay Routine at 4MHz delay_2s: movlw 0x11 movwf d1 movlw 0x5D movwf d2 movlw 0x05 movwf d3 delay_2s_0 decfsz d1, f goto $+2 decfsz d2, f goto $+2 decfsz d3, f goto delay_2s_0 return ;------------- Init this sucker --------------- init: movlw 0x07 ;Turn comparators off movwf CMCON bsf STATUS, RP0 movlw b'00000011' movwf TRISA movlw b'00000000' ;Set all ports to outputs movwf TRISB bcf STATUS, RP0 ; Set up Timer 2. movlw b'00010110' ; Post scale /4, pre scale /16, TMR2 ON movwf T2CON bsf STATUS, RP0 ; select bank 1 movlw .50 ; Set up comparator movwf PR2 bsf PIE1,TMR2IE ; Enable TMR2 interrupt bcf STATUS, RP0 ;Load the display ram clrf row0 clrf row1 clrf row2 clrf row3 clrf row4 clrf row5 clrf row6 clrf row7 movlw 0x00 movwf row_pos movlw 0x80 movwf pb_latch ; Global interrupt enable bsf INTCON,PEIE ; Enable all peripheral interrupts bsf INTCON,GIE ; Global interrupt enable clrf point movlw .100 movwf display_counter ;Load the splash screen movlw 0x40 movwf row0_1 movlw 0x0D movwf row1_1 movlw 0x40 movwf row2_1 movlw 0x6F movwf row3_1 movlw 0x24 movwf row4_1 movlw 0xE2 movwf row5_1 movlw 0x8F movwf row6_1 movlw 0x80 movwf row7_1 call load_display clrf level wait_game_start: btfss lt_but goto restart goto wait_game_start restart: call load_level call load_display call delay_2s movfw point call points_level_one movwf point_marker movfw point_marker sublw 0xFF bnz restart_worm clrf point movwf point movfw point call points_level_one movwf point_marker restart_worm: clrf worm_dir movlw 0x03 movwf worm_length movlw 0x44 movwf worm0 movlw 0x43 movwf worm1 movlw 0x42 movwf worm2 clrf worm3 clrf worm4 clrf worm5 clrf worm6 clrf worm7 clrf worm8 clrf worm9 clrf worm10 clrf worm11 clrf worm12 clrf worm13 clrf worm14 clrf worm15 clrf buttons ;This is the start of the program main bcf buttons, 0 btfsc lt_but goto test_rt_but btfsc buttons, 1 goto test_rt_but bsf buttons, 0 ;Button pressed goto test_rt_but test_rt_but bcf buttons, 2 btfsc rt_but goto execute_turn btfsc buttons, 3 goto execute_turn bsf buttons, 2 ;Button pressed goto execute_turn execute_turn btfsc lt_but bcf buttons, 1 btfss lt_but bsf buttons, 1 btfsc rt_but bcf buttons, 3 btfss rt_but bsf buttons, 3 btfsc buttons, 0 goto do_lt_turn btfsc buttons, 2 goto do_rt_turn goto main_bottom do_lt_turn movfw worm_dir sublw DIR_UP bnz do_lt_turn_1 movlw DIR_LT movwf worm_dir goto main_bottom do_lt_turn_1 movfw worm_dir sublw DIR_LT bnz do_lt_turn_2 movlw DIR_DN movwf worm_dir goto main_bottom do_lt_turn_2 movfw worm_dir sublw DIR_DN bnz do_lt_turn_3 movlw DIR_RT movwf worm_dir goto main_bottom do_lt_turn_3 movfw worm_dir sublw DIR_RT bnz main_bottom movlw DIR_UP movwf worm_dir goto main_bottom do_rt_turn movfw worm_dir sublw DIR_UP bnz do_rt_turn_1 movlw DIR_RT movwf worm_dir goto main_bottom do_rt_turn_1 movfw worm_dir sublw DIR_RT bnz do_rt_turn_2 movlw DIR_DN movwf worm_dir goto main_bottom do_rt_turn_2 movfw worm_dir sublw DIR_DN bnz do_rt_turn_3 movlw DIR_LT movwf worm_dir goto main_bottom do_rt_turn_3 movfw worm_dir sublw DIR_LT bnz main_bottom movlw DIR_UP movwf worm_dir goto main_bottom main_bottom decfsz display_counter,f goto end_main ;Here is where the game is advanced call move_worm call test_collision sublw 0x01 bz game_over ;Test if we hit the point marker movfw worm0 subwf point_marker,w bnz display_me incf worm_length, f movfw worm_length sublw 0x0F bz next_level ;Need to redraw new point call do_next_point display_me call clear_disp_ram call draw_worm call draw_marker call load_display movfw level sublw .100 movwf display_counter end_main call delay_50ms goto main next_level movfw level addlw .10 movwf level sublw .50 bnz restart you_win call make_win call load_display clrf level movfw level sublw .100 movwf display_counter btfss lt_but goto restart call delay_50ms goto you_win game_over call make_lose call load_display clrf level movfw level sublw .100 movwf display_counter btfss lt_but goto restart call delay_50ms goto game_over end