SIMON
Program for PIC16F628 micro

P1   P2   P3   P4  P5

The following sets up the ports and the equates for the notes for the tunes:



;****************************************************************
;* MEMORY GAME - Simon    			*
;****************************************************************

;Port A definitions
PORTA_CONFIG1	equ	0xFD	;1111 1110
			0	;not used
BUZZER		equ	1	;buzzer output
			2	;not used
			3	;not used
			4	;not used

;Port B definitions
PORTB_CONFIG1	equ	0x0F	;bit7: out,out,out,out,in,in,in,in :bit0
KEY_RED		equ	0	;red key input   - bit0
KEY_GREEN	equ	1	;green key input  - bit1
KEY_YELLOW	equ	2	;yellow key input - bit2
KEY_ORANGE	equ	3	;orange key input - bit3
LED_RED		equ	4	;red led output   - bit4
LED_GREEN	equ	5	;green led output - bit5
LED_YELLOW	equ	6	;yellow led output- bit6
LED_ORANGE	equ	7	;orange led output- bit7

RAM_START	equ	0x20	;start of global variable ram
LINE_OFFSET	equ	0x3A	;start of step memory in ram area

RECORD_STEPS	equ	0x00	;eeprom address for step record

				;Data for song notes

				;Value = 10's of microseconds
				;octave 1
NOTE_G0		equ	D'255'	;196 Hz
NOTE_A0		equ	D'227'	;220 Hz
NOTE_B0		equ	D'202'	;247 Hz

;octave 2
NOTE_C1		equ	D'191'	;262 Hz
NOTE_D1		equ	D'170'	;294 Hz
NOTE_E1		equ	D'152'	;330 Hz
NOTE_F1		equ	D'143'	;349 Hz
NOTE_G1		equ	D'128'	;392 Hz
NOTE_A1		equ	D'114'	;440 Hz
NOTE_B1		equ	D'101'	;494 Hz

;octave 3
NOTE_C2		equ	D'95'	;524 Hz
NOTE_D2		equ	D'85'	;588 Hz
NOTE_E2		equ	D'76'	;660 Hz
NOTE_F2		equ	D'72'	;698 Hz
NOTE_G2		equ	D'64'	;784 Hz
NOTE_A2		equ	D'57'	;880 Hz
NOTE_B2		equ	D'51'	;988 Hz

;octave 4
NOTE_C3		equ	D'48'	;1048 Hz
NOTE_D3		equ	D'43'	;1176 Hz
NOTE_E3		equ	D'38'	;1320 Hz
NOTE_F3		equ	D'36'	;1396 Hz
NOTE_G3		equ	D'32'	;1568 Hz
NOTE_A3		equ	D'28'	;1760 Hz
NOTE_B3		equ	D'25'	;1976 Hz

				;length of notes
;"tempo"(nomalized) length is set in SoundPlay function by timerb
LENGTH_SEMIBREVE	equ	0x20	;tempo	
LENGTH_MINIM		equ	0x10	;tempo/2	
LENGTH_CROTCHET		equ	0x08	;tempo/4	
LENGTH_QUAVER		equ	0x04	;tempo/8	
LENGTH_SEMIQUAVER	equ	0x02	;tempo/16
LENGTH_DEMISEMIQUAVER	equ	0x01	;tempo/32	


SONG_HEY_JUDE_LEN	equ	D'68'	;total No of notes + lengths
SONG_OSUSANA_LEN	equ	D'108'  
SONG_DEATHMARCH_LEN	equ	D'22'

KEY_RED_SOUND		equ	NOTE_C2	
KEY_GREEN_SOUND	equ	NOTE_E2
KEY_YELLOW_SOUND	equ	NOTE_G2
KEY_ORANGE_SOUND	equ	NOTE_B2
       

Program for PIC16F628 micro (Simon.asm)
The following contains all the comments for the Simon program:

Note: __Config 3F18h covers the following:

_CP_off & _LVP_off & _PWRTE_off & Boden_off & _WDT_off & _IntRC_osc_I/O

where:
CP = code protection
LVP = low-voltage programming
PWRTE = power-up timer
Boden = Brown-out detector
WDT = watchdog timer
IntRC_osc_I/O = internal RC for 4MHz - all pins for in-out

You can simply write: __Config 3F18h
or:

__Config _CP_off & _LVP_off & _PWRTE_off & Boden_off & _WDT_off & _IntRC_osc_I/O

or select the boxes in IC Prog at the time of burning the chip.
In all cases the chip will get burnt with the correct configuration value and when it is copied, the copy will automatically have the correct configuration value.
 


;****************************************************************
;* Memory Game - SIMON   			*
;****************************************************************

	list p=16f628, 	;microcontroller 

	include "p16F628.inc" ;registers for F628
	include "simon628.inc" ;Simon definitions for F628

__Config 3F18h

;****************************************************************
;global variables 
;Files for PIC16F628 start at 0x20 
;****************************************************************
timera		equ	0x2c	;general purpose timer
timerb		equ	0x2d	;general purpose timer
timerc		equ	0x2e	;general purpose timer
timerd		equ	0x2f	;general purpose timer
note_select	equ	0x30	;selection of note
note_tone		equ	0x31	;frequency of note
note_length	equ	0x32	;length of note
note_tempo	equ	0x33	;tempo of song
random		equ	0x34	;random number
key		equ	0x35	;key last pressed
column_w		equ	0x36	;write pointer in sequence table X
line_w		equ	0x37	;write pointer in sequence table Y
column_r		equ	0x38	;read pointer in sequence table X
line_r		equ	0x39	;read pointer in sequence table Y
steps0104		equ	0x3a	;step memory
steps0508		equ	0x3b	;step memory
steps0912		equ	0x3c	;step memory
steps1316		equ	0x3d	;step memory
steps1720		equ	0x3e	;step memory
steps2124		equ	0x3f	;step memory
steps2528		equ	0x40	;step memory
steps2932		equ	0x41	;step memory
steps3336		equ	0x42	;step memory
steps3740		equ	0x43	;step memory
steps4144		equ	0x44	;step memory
steps4548		equ	0x45	;step memory
steps4952		equ	0x46	;step memory
steptemp		equ	0x47	;temporary step memory
stepsgood		equ	0x48	;number of successful steps by player

;****************************************************************
;reset vector
;****************************************************************
reset:	org	0x00		;reset vector address	
	goto	Begin		;start program execution
	

Begin:	org 	0x06		;start of program
	goto	start
;****************************************************************
; Data tables for Songs
;****************************************************************
SongHeyJude:	
	addwf	pcl,f		;jump forward according to W value 
	retlw	NOTE_G1		;Hey
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E1		;jude
	retlw	LENGTH_MINIM	
	retlw	NOTE_E1		;don't
	retlw	LENGTH_QUAVER
	retlw	NOTE_G1		;make
	retlw	LENGTH_QUAVER
	retlw	NOTE_A1		;it
	retlw	LENGTH_QUAVER
	retlw	NOTE_D1		;bad,
	retlw	LENGTH_MINIM
	retlw	NOTE_D1		;take
	retlw	LENGTH_QUAVER
	retlw	NOTE_E1		;a
	retlw	LENGTH_QUAVER
	retlw	NOTE_F1		;sad
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C2		;song
	retlw	LENGTH_MINIM
	retlw	NOTE_C2		;and
	retlw	LENGTH_QUAVER
	retlw	NOTE_B1		;make
	retlw	LENGTH_QUAVER
	retlw	NOTE_G1		;it
	retlw	LENGTH_QUAVER
	retlw	NOTE_A1		;bet-
	retlw	LENGTH_QUAVER
	retlw	NOTE_G1		;ter.
	retlw	LENGTH_MINIM
	retlw	NOTE_G1		;Re-
	retlw	LENGTH_QUAVER
	retlw	NOTE_A1		;mem-
	retlw	LENGTH_QUAVER
	retlw	NOTE_A1		;ber
	retlw	LENGTH_CROTCHET
	retlw	NOTE_A1		;to
	retlw	LENGTH_QUAVER
	retlw	NOTE_D2		;let
	retlw	LENGTH_SEMIQUAVER
	retlw	NOTE_C2		;her
	retlw	LENGTH_CROTCHET
	retlw	NOTE_B1		;in
	retlw	LENGTH_QUAVER
	retlw	NOTE_C2		;to
	retlw	LENGTH_QUAVER
	retlw	NOTE_A1		;your
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G1		;heart,
	retlw	LENGTH_MINIM
	retlw	NOTE_C1		;then
	retlw	LENGTH_QUAVER
	retlw	NOTE_D1		;you
	retlw	LENGTH_QUAVER
	retlw	NOTE_E1		;can
	retlw	LENGTH_QUAVER
	retlw	NOTE_A1		;start
	retlw	LENGTH_MINIM
	retlw	NOTE_G1		;to
	retlw	LENGTH_QUAVER
	retlw	NOTE_F1		;make
	retlw	LENGTH_QUAVER
	retlw	NOTE_E1		;it
	retlw	LENGTH_QUAVER
	retlw	NOTE_C1		;bet-
	retlw	LENGTH_QUAVER
	retlw	NOTE_C1		;ter.
	retlw	LENGTH_MINIM

SongOSusana:
	addwf	pcl,f		;jump forward according to W value
	retlw	NOTE_C2
	retlw	LENGTH_MINIM
	retlw	NOTE_D2
	retlw	LENGTH_QUAVER
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_A2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C2
	retlw	LENGTH_MINIM
	retlw	NOTE_D2
	retlw	LENGTH_QUAVER
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_D2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_D2
	retlw	LENGTH_MINIM
	retlw	NOTE_C2
	retlw	LENGTH_MINIM
	retlw	NOTE_D2
	retlw	LENGTH_QUAVER
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_A2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C2
	retlw	LENGTH_MINIM
	retlw	NOTE_D2
	retlw	LENGTH_MINIM
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_D2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C2
	retlw	LENGTH_MINIM
	retlw	NOTE_F2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_F2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_A2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_A2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_A2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_D2
	retlw	LENGTH_MINIM
	retlw	NOTE_C2
	retlw	LENGTH_MINIM
	retlw	NOTE_D2
	retlw	LENGTH_QUAVER
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_A2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_G2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C2
	retlw	LENGTH_MINIM
	retlw	NOTE_D2
	retlw	LENGTH_QUAVER
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_D2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_D2
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C2
	retlw	LENGTH_SEMIBREVE

SongDeathMarch:
	addwf	pcl,f	;jump forward according to W value
	retlw	NOTE_C1
	retlw	LENGTH_MINIM
	retlw	NOTE_C1
	retlw	LENGTH_QUAVER
	retlw	NOTE_C1
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C1
	retlw	LENGTH_QUAVER
	retlw	NOTE_C1
	retlw	LENGTH_CROTCHET
	retlw	NOTE_E1
	retlw	LENGTH_QUAVER
	retlw	NOTE_D1
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C1
	retlw	LENGTH_QUAVER
	retlw	NOTE_C1
	retlw	LENGTH_CROTCHET
	retlw	NOTE_B0
	retlw	LENGTH_CROTCHET
	retlw	NOTE_C1
	retlw	LENGTH_MINIM

;****************************************************************
;Name : Start
;Description : set-up ports A and B
;****************************************************************
Start: 	MOVLW 07 	;to disable the comparators
	MOVWF 0x1F 	;file 1F is the CMCON file 
	bsf status,rp0 	;select bank1 register



	movlw PORTA_CONFIG1 	;porta configuration
	movwf 0x05 
	movlw PORTB_CONFIG1 	;portb configuration	
	movwf 0x06
	movlw 0x81 		;Fosc/4;No prescaler
	movwf 0x81 		;Timer configuration in option register
	bcf status,rp0 		;select bank0 registers



NewGame:
	clrf	porta		;turn off status leds
	clrf	portb		;turn off all leds	
	movlw	RAM_START	;clear global variables
	movwf	fsr
S1:	clrf	indf
	incf	fsr,f
	btfss	fsr,6
	goto	S1	
	movf	line_w,w		;initialise step memory base
	addlw	LINE_OFFSET	;put 3Ah into file 37h at beginning
	movwf	line_w
	call	ClearRecord	;clear record steps?
	call	Introduction	;introductory song & calibration

;****************************************************************
;Name		: Mainloop
;Description	: 
;****************************************************************
Mainloop:
	call	MakeStep		;create a new step & add it to sequence
	call	ShowSequence	;show sequence on LEDs
	call	GetUserSequence	;player's sequence (result returned in W)
				;W=1 - correct, W=0 - wrong
	xorlw	1		;is player's sequence correct?	
	btfss	status,z		;yes - ignore next instruction
	goto	SequenceBad	;no - it's wrong!	
	incf	stepsgood,f	;another successful step by player
	call	Delay150
	call	Delay150
	call	Delay150
	movf	line_w,w		;max sequence reached (52 steps)?
	xorlw	D'52'
	btfss	status,z
	goto	Mainloop		;no - do another step
	movf	column_w,w
	xorlw	D'3'
	btfss	status,z
	goto	Mainloop		;no - do another step
	goto	SequenceRecord	;yes - max sequence correct! 
					

;****************************************************************
;Name		: ClearRecord
;Description	: allows the player to clear the current step
;		: record. Player must press one of the keys
;		: at power-on for EEPROM to be set to zero
;****************************************************************
ClearRecord:
	movf	portb,w		;test for a key press
	andlw	0x0f		;mask keys
	xorlw	0x00		;are any keys being pressed?
	btfsc	status,z		;yes - skip next instruction
	return			;no - return!	
	movlw	RECORD_STEPS	;clear step record in EEPROM
	movwf	eeadr
	clrf	eedata
	bsf	status,rp0		;select bank1
	bsf	eecon1,wren	;enable write
	movlw	0x55		;unlock codes
	movwf	eecon2
	movlw	0xaa
	movwf	eecon2
	bsf	eecon1,wr		;write begins
	bcf	eecon1,wren	;disable further writes
Crec:	btfsc	eecon1,wr		;wait to write complete
	goto	Crec
	bcf	status,rp0		;select bank0	
	movlw	0x02
	movwf	note_tempo
	call	SoundRisingRocket	;cleared record indication
	return

;****************************************************************
;Name		: Introduction
;Description	: plays the introductory "hey jude" song until
;		: one of the keys is pressed.
;Inputs		: none
;****************************************************************
Introduction:
	clrf	note_select	;beginning of "hey jude" song
Intr1:	incf	steptemp,f
	movf	steptemp,w
	andlw	0x03
	movwf	random
	call	Delay150
	call	ShowLed		;show it on leds		
	movlw	0x10
	movwf	note_tempo	;speed of song
	movf	note_select,w	;get next "hey jude" note
	call	SongHeyJude	;returned in W
	movwf	note_tone
	incf	note_select,f
	movf	note_select,w	;get length of note
	call	SongHeyJude
	movwf	note_length	
	call	SoundPlay		;play music
	clrf	portb		;turn all leds off
	incf	note_select,f	;select next note
	movf	note_select,w
	xorlw	SONG_HEY_JUDE_LEN	;end of song?
	btfsc	status,z		;no - skip next instruction
	clrf	note_select	;yes - play it again from beginning
	movf	portb,w		;test for a key press
	andlw	0x0f		;mask keys
	xorlw	0x00		;are any keys being pressed?
	btfsc	status,z		;yes - skip next instruction
	goto	Intr1		;no - keep playing music!
	movlw	0x02
	movwf	note_tempo
	call	SoundRisingRocket	;start new game indication	
	return			;start new game

;****************************************************************
;Name		: SoundPlay
;Description	: plays a tone on the buzzer
;Inputs		: note_tone - frequency of the tone
;		: note_length - length of note
;		: note_tempo - speed of song
;****************************************************************
SoundPlay:
	clrf	timerc		;initialise timer
Sp1:	movf	timerc,w
	xorwf	note_length,w	;end of note?
	btfsc	status,z		;no - skip next instruction
	return			;yes - exit function	
	movf	note_tempo,w
	movwf	timerb				
Sp2:	movf	note_tone,w	;frequency
	bsf	porta,BUZZER	;high time
	call	SoundDelay
	bcf	porta,BUZZER	;low time
	call	SoundDelay
	decfsz	timerb,f
	goto	Sp2
	incf	timerc,f
	goto	Sp1

;****************************************************************
;Name		: SoundDelay
;Description	: a delay used whenever sound
;		: must be produced on the piezo diaphragm. The W register
;		: contains the number of cycles to wait (in 10's
;		: of microseconds.
;Inputs		: W - contains the note to be played
;		: ie. W=191, delay==1,91msec
;****************************************************************
SoundDelay:
	movwf	timera
Sd1:	nop
	nop
	nop	
	nop
	nop
	nop
	nop
	decfsz	timera,f
	goto	Sd1	
	return

;****************************************************************
;Name		: SoundRisingRocket
;Description	: rising rocket sound effect
;Inputs		: note_tempo - speed of rocket
;Outputs	: none
;****************************************************************
SoundRisingRocket:
	clrf	note_tone		;make tone=255 - start 
	comf	note_tone,f	;with lowest frequency
Srr1:	movlw	LENGTH_DEMISEMIQUAVER
	movwf	note_length		
	call	SoundPlay
	decfsz	note_tone,f	;do a "rising" sound
	goto	Srr1
	CALL	Delay150
	CALL	Delay150
	CALL	Delay150
	CALL	Delay150
	CALL	Delay150
	CALL	Delay150
	CALL	Delay150
	CALL	Delay150
	return

;****************************************************************
;Name		: MakeRandom
;Description	: reads the PIC's timer register at various
;		: "random" intervals caused by the player
;Inputs		: pressing one of the keys.
;Outputs		: random number will be 0, 1, 2, 3
;****************************************************************
MakeRandom:
	movf	tmr0,w
	andlw	0x03	;mask all but bit0 and bit1
	movwf	random	;move random number into file 34h
	return

;****************************************************************
;Name		: MakeStep
;Description	: gets a random number and stores it into the
;		: next available position in table.
;****************************************************************
MakeStep:
	call	MakeRandom	;ascertain random number
	movf	line_w,w		;get current line
	movwf	fsr		;pointer to next available memory
	bcf	status,c		;initialise carry
	movf	column_w,w	;get current column
	xorlw	0	
	BTFSC   STATUS,Z
	GOTO	GCol0		;column=0 - don't shift
	xorlw	0x01
	BTFSC   STATUS,Z
	GOTO	GCol1		;column=1 - shift random 2 times
	XORLW   0x03
	BTFSC   STATUS,Z
	GOTO	GCol2		;column=2 - shift random 4 times
	rlf	random,f		;column=3 - shift random 6 times
	rlf	random,f
GCol2:	rlf	random,f
	rlf	random,f
GCol1:	rlf	random,f
	rlf	random,f
GCol0:	movf	indf,w		;get current memory byte of table
	iorwf	random,w		;merge new random number into table
	movwf	indf		;restore in sequence table
	incf	column_w,f	;update column
	btfss	column_w,2	;end of this memory byte in table?
	return			;no - return
	clrf	column_w		;yes - select next memory byte in table
	incf	line_w,f
	return

;****************************************************************
;Name		: ShowSequence
;Description	: displays the step sequence that the player
;		: has to remember and repeat.
;****************************************************************
ShowSequence:
	clrf	column_r		;begin at start of step sequence
	movlw	LINE_OFFSET		
	movwf	line_r			
Ss1:	movf	line_r,w
	movwf	fsr
	movf	indf,w
	movwf	steptemp
	movf	column_r,w	;get current column
	xorlw	0				
	BTFSC   STATUS,Z
	GOTO	SCol0		;column=0 - don't shift
	xorlw	0x01
	BTFSC   STATUS,Z
	GOTO	SCol1		;column=1 - shift random 2 times
	XORLW   0x03
	BTFSC   STATUS,Z
	GOTO	SCol2		;column=2 - shift random 4 times
	rrf	steptemp,f		;column=3 - shift random 6 times
	rrf	steptemp,f
SCol2:	rrf	steptemp,f
	rrf	steptemp,f
SCol1:	rrf	steptemp,f
	rrf	steptemp,f
SCol0:	movf	steptemp,w	;get current memory byte of table
	andlw	0x03		;mask bits 2-7
	movwf	random
	call	ShowStep		;display LED according to stored value
	call	Delay150		;wait a little after player
	call	Delay150		;has pressed a key
	call	Delay150
	incf	column_r,f		;update column
	btfsc	column_r,2	;overflow?
	goto	Colov1		;yes 	
Ss2:	movf	column_r,w	;no
	xorwf	column_w,w	;column pointers the same?
	btfss	status,z			
	goto	Ss1		;no - at least another step to show
	movf	line_r,w		;yes
	xorwf	line_w,w		;reached the end of sequence?
	btfsc	status,z		;no - jump next instruction
	return			;yes - sequence complete!
	goto	Ss1		;at least another step to show
Colov1:	clrf	column_r
	incf	line_r,f
	goto	Ss2	

;****************************************************************
;Name		: ShowStep
;Description	: turns on one of the LEDs and beeps according to
;		: the random number & level of difficulty
;Inputs		: random - random number
;Outputs	: none
;****************************************************************
ShowStep:
	call	ShowLed		;show random number on led
	movwf	note_tone		;ShowLed returns with beep value in W
	movlw	LENGTH_SEMIBREVE
	movwf	note_length
	movlw	0x10		;easy level
	btfss	porta,LEVEL	;get level of difficulty
	movlw	0x01		;hard level	
	movwf	note_tempo	;speed of beep
	call	SoundPlay		;play button beep
	clrf	portb		;turn all leds off	
	return

;****************************************************************
;Name		: ShowLed
;Description	: turns on one of the LEDs according to the random
;		: number & prepares W with tone value
;Inputs		: random - random number
;Outputs	: W - value of tone frequency
;****************************************************************
ShowLed:
	movf	random,w		;get random number
	xorlw	0	
	BTFSC   	STATUS,Z
	goto	ShowRed		;random=0
	xorlw	0x01
	BTFSC   	STATUS,Z
	GOTO	ShowGreen	;random=1
	xorlw	0x03
	BTFSC   	STATUS,Z
	GOTO	ShowYellow	;random=2
	goto	ShowOrange	;random=3

ShowRed:
	bsf	portb,LED_RED	;turn on red led
	retlw	KEY_RED_SOUND	;tone frequency

ShowGreen:
	bsf	portb,LED_GREEN	;turn on green led
	retlw	KEY_GREEN_SOUND	;tone frequency

ShowYellow:
	bsf	portb,LED_YELLOW	;turn on yellow led
	retlw	KEY_YELLOW_SOUND	;tone frequency

ShowOrange:
	bsf	portb,LED_ORANGE	;turn on orange led
	retlw	KEY_ORANGE_SOUND	;tone frequency

;****************************************************************
;Name		: GetUserSequence
;Description	: checks the player's sequence to that required
;Inputs		: none
;Outputs	: W=0 : player has made a mistake
;		: W=1 : player has successfully repeated sequence
;****************************************************************
GetUserSequence:
	clrf	column_r		;begin at start of step sequence
	movlw	LINE_OFFSET		
	movwf	line_r	
Us1:	movf	line_r,w
	movwf	fsr
	movf	indf,w
	movwf	steptemp
	movf	column_r,w	;get current column
	xorlw	0	
	BTFSC   	STATUS,Z			
	GOTO	UCol0		;column=0 - don't shift
	xorlw	0x01
	BTFSC   	STATUS,Z
	GOTO	UCol1		;column=1 - shift random 2 times
	xorlw	0x03
	BTFSC   	STATUS,Z
	GOTO	UCol2		;column=2 - shift random 4 times
UCol3:	rrf	steptemp,f		;column=3 - shift random 6 times
	rrf	steptemp,f
UCol2:	rrf	steptemp,f
	rrf	steptemp,f
UCol1:	rrf	steptemp,f
	rrf	steptemp,f
UCol0:	movf	steptemp,w	;get current memory byte of table
	andlw	0x03		;mask bits 2-7
	movwf	random

	call	Keypad		;get player's input - returned in W
				;W=0 - no key pressed (timeout)
				;W=1 - player has pressed a key
	xorlw	0		;did player press a key?
	btfsc	status,z		;yes - jump next instruction
	retlw	0		;no - exit function 
	movf	key,w		;compare pressed key with step
	xorwf	random,w		;is it the same?		
	btfss	status,z		;yes - jump next instruction
	retlw	0		;no - incorrect, exit function
	incf	column_r,f		;update column
	btfsc	column_r,2	;overflow?
	goto	Colov2		;yes 	
Us2:	movf	column_r,w	;no
	xorwf	column_w,w	;column pointers the same?
	btfss	status,z			
	goto	Us1		;no - at least another step to show
	movf	line_r,w		;yes
	xorwf	line_w,w		;reached the end of sequence?
	btfsc	status,z		;no - jump next instruction
	retlw	1		;yes - sequence complete!
	goto	Us1		;at least another step to show	

Colov2:	clrf	column_r
	incf	line_r,f
	goto	Us2
	
;****************************************************************
;Name		: Keypad
;Description	: scans the keys for a press and lights up the
;		: corresponding LED and beeps.
;Inputs		: none
;Outputs	: W=0 : key timeout - no key has been pressed
;		: W=1 : key has been pressed
;		: key : 0=red,1=green,2=yellow,3=orange
;****************************************************************
Keypad:
	clrf	key		;initialise key
	movlw	0x07		;assume easy level - 5 sec timeout
	btfss	porta,LEVEL	;get level of difficulty
	movlw	0x03		;hard level - 2 sec timeout
	movwf	timerc
Kp2:	movlw	0xff
	movwf	timerb
Kp1:	movlw	0xff
	movwf	timera

Kwait:	btfsc	portb,KEY_RED
	goto	KeyRed
	btfsc	portb,KEY_GREEN
	goto	KeyGreen
	btfsc	portb,KEY_YELLOW
	goto	KeyYellow
	btfsc	portb,KEY_ORANGE
	goto	KeyOrange
	decfsz	timera,f
	goto	Kwait
	decfsz	timerb,f
	goto	Kp1
	decfsz	timerc,f
	goto	Kp2
	retlw	0		;player hasn't pressed key!
	
KeyRed:
	bsf	portb,LED_RED	;turn on red led
	clrf	key		;key=0
	movlw	KEY_RED_SOUND	;tone frequency
	goto	Beep1

KeyGreen:
	bsf	portb,LED_GREEN	;turn on green led
	bsf	key,0		;key=1
	movlw	KEY_GREEN_SOUND	;tone frequency
	goto	Beep1

KeyYellow:
	bsf	portb,LED_YELLOW	;turn on yellow led
	bsf	key,1		;key=2
	movlw	KEY_YELLOW_SOUND	;tone frequency
	goto 	Beep1

KeyOrange:
	bsf	portb,LED_ORANGE	;turn on orange led
	bsf	key,0		;key=3
	bsf	key,1
	movlw	KEY_ORANGE_SOUND	;tone frequency
Beep1:	movwf	note_tone		;save tone
	movlw	LENGTH_SEMIBREVE
	movwf	note_length
	movlw	0x03	
	movwf	note_tempo	;speed of beep
Beep2:	call	SoundPlay		;play button beep
	movf	portb,w		;test for a key press
	andlw	0x0f		;mask keys
	xorlw	0x00		;are any keys being pressed?
	btfss	status,z		;no - skip next instruction
	goto	Beep2		;yes - keep beeping!
	clrf	portb		;turn off all leds
	retlw	1		;return to calling function


;****************************************************************
;Name		: SequenceBad
;Description	: player has made a mistake - show player the
;		: correct sequence. Test to see if a record has
;		: been made.
;****************************************************************
SequenceBad:
	movlw	0x01
	movwf	note_tempo
	call	SoundRisingRocket
	movlw	0x01
	movwf	note_tempo
	call	SoundRisingRocket
	call	ShowSequence	;replay proper sequence again
	movlw	0x01
	movwf	note_tempo
	call	SoundRisingRocket
	movlw	0x01
	movwf	note_tempo
	call	SoundRisingRocket
	call	Delay150
	call	Delay150
	call	Delay150
	movlw	RECORD_STEPS	;get current record from EEPROM
	movwf	eeadr
	bsf	status,rp0		;select bank1
	bsf	eecon1,rd		;read eeprom
	bcf	status,rp0		;select bank0
	movf	eedata,w		;W=record number of steps
	subwf	stepsgood,w	;a record sequence (or same)?
	btfsc	status,c		;no - jump next instruction
	goto	SequenceRecord	;yes - tell player about it!
	clrf	note_select	;beginning of song
	movlw	0x10		;slow
	movwf	note_tempo	;speed of song
Sb1:	call	Delay150
	movf	note_select,w	;get next note
	call	SongDeathMarch	;returned in W
	movwf	note_tone
	incf	note_select,f
	movf	note_select,w	;get length of note
	call	SongDeathMarch
	movwf	note_length
	call	SoundPlay		;play music
	incf	note_select,f	;select next note
	movf	note_select,w
	xorlw	SONG_DEATHMARCH_LEN	;end of song?
	btfss	status,z		;yes - skip next instruction
	goto	Sb1		;no - keep playing
	call	Delay150
	call	Delay150
	call	Delay150
	goto	NewGame		;start new game

;****************************************************************
;Name		: SequenceRecord
;Description	: player has beaten the record, save new step
;		: record in EEPROM and play record tune.
;****************************************************************
SequenceRecord:
	movlw	RECORD_STEPS	;save new step record in EEPROM
	movwf	eeadr
	movf	stepsgood,w
	movwf	eedata
	bsf	status,rp0		;select bank1
	bsf	eecon1,wren	;enable write
	movlw	0x55		;unlock codes
	movwf	eecon2
	movlw	0xaa
	movwf	eecon2
	bsf	eecon1,wr		;write begins
	bcf	eecon1,wren	;disable other writes
Sre1:	btfsc	eecon1,wr		;wait for "write" to complete 
	goto	Sre1
	bcf	status,rp0		;select bank0
	clrf	note_select	;beginning of song
Sr1:	incf	steptemp,f
	movf	steptemp,w
	andlw	0x03
	movwf	random
	call	Delay150
	call	ShowLed		;show it on leds
	movlw	0x5		;fast
	movwf	note_tempo	;speed of song
	movf	note_select,w	;get next note
	call	SongOSusana	;returned in W
	movwf	note_tone
	incf	note_select,f
	movf	note_select,w	;get length of note
	call	SongOSusana
	movwf	note_length
	call	SoundPlay		;play music
	clrf	portb		;turn all leds off
	incf	note_select,f	;select next note
	movf	note_select,w
	xorlw	SONG_OSUSANA_LEN	;end of song?
	btfsc 	status,z 		;no - skip next instruction
	goto 	Sr2 		;yes - end playing 
	movf 	portb,w 		;test for a key press
	andlw 	0x0f 		;mask keys
	xorlw 	0x00 		;are any keys being pressed?
	btfsc 	status,z 		;yes - skip next instruction
	goto 	Sr1 		;no - keep playing music!
	goto 	NewGame 	;start new game
Sr2 	call 	Delay150
	call 	Delay150
	call 	Delay150
	goto 	NewGame 	;start new game

;****************************************************************
;Name		: Delay
;Description	: causes a delay of 150msec with 4MHz crystal!
;****************************************************************
Delay150:	
	movlw	0xc3		;number of wait states
	movwf	timerb	
L4:	movlw	0xff		;number of wait states
	movwf	timera
L5:	decfsz	timera,f
	goto	L5
	decfsz	timerb,f
	goto	L4	
	return				

	END
 

Hex file for Simon PIC16F628:

:020000000628D0
:04000C00D02882076F
:1000100080340834983410349834043480340434F0
:1000200072340434AA341034AA34043498340434B6
:100030008F3408345F3410345F340434653404344E
:100040008034043472340434803410348034043402
:100050007234043472340834723404345534023443
:100060005F340834653404345F3404347234083443
:1000700080341034BF340434AA3404349834043443
:1000800072341034803404348F340434983404349B
:10009000BF340434BF34103482075F341034553415
:1000A00004344C340834403408344034083439348F
:1000B0000834403408344C3408345F341034553438
:1000C00004344C3408344C340834553408345F3428
:1000D0000834553410345F341034553404344C34FF
:1000E0000834403408344034083439340834403457
:1000F00008344C3408345F341034553410344C34E4
:1001000008344C340834553408345F3410344834DF
:10011000083448340834393408343934083439342C
:10012000083440340834403408344C3408345F34E4
:100130000834553410345F341034553404344C349E
:1001400008344034083440340834393408344034F6
:1001500008344C3408345F341034553404344C348F
:1001600008344C34083455340834553408345F347A
:1001700020348207BF341034BF340434BF34083411
:10018000BF340434BF34083498340434AA340834F7
:10019000BF340434BF340834CA340834BF34103494
:1001A00007309F008316FD3085000F3086008130B8
:1001B000810083128601203084008001840A041F9C
:1001C000DD2837083A3EB700F92010215F217C2155
:1001D000C721013A031D2F2AC80A872287228722B6
:1001E0003708343A031DE6283608033A031DE6288B
:1001F000572A06080F39003A0319080000309B00FF
:100200009A0183161C1555309D00AA309D009C1440
:100210001C119C18092983120230B3004B210800DD
:10022000B001C70A47080339B4008722B42110304F
:10023000B30030080720B100B00A30080720B20030
:1002400030218601B00A3008443A0319B00106088B
:100250000F39003A031911290230B3004B2108006D
:10026000AE012E083206031908003308AD0031082C
:100270008514402185104021AD0B3729AE0A312964
:10028000AC000000000000000000000000000000C2
:10029000AC0B41290800B101B1090130B200302195
:1002A000B10B4D2987228722872287228722872226
:1002B00087228722080001080339B40008005B2167
:1002C0003708840003103608003A03197329013AED
:1002D00003197129033A03196F29B40DB40DB40D34
:1002E000B40DB40DB40D000834048000B60A361DF8
:1002F0000800B601B70A0800B8013A30B900390859
:1003000084000008C7003808003A03199329013A0D
:1003100003199129033A03198F29C70CC70CC70C7D
:10032000C70CC70CC70C47080339B400A9218722A2
:1003300087228722B80A3819A62938083606031DED
:100340007F2939083706031908007F29B801B90A3F
:100350009D29B421B1002030B2001030051E0130BB
:10036000B3003021860108003408003A0319BF2980
:10037000013A0319C129033A0319C329C5290616ED
:100380005F3486164C340617403486173334051113
:100390008515B8013A30B900390884000008C70053
:1003A0003808003A0319E029013A0319DE29033A13
:1003B0000319DC29C70CC70CC70CC70CC70CC70C2A
:1003C00047080339B400FA21003A0319003435080C
:1003D0003406031D0034B80A3819F72938083606E0
:1003E000031DCC293908370603190134CC29B8017B
:1003F000B90AEE29B5010730051E0330AE00FF3003
:10040000AD00FF30AC000618122A8618162A06190D
:100410001A2A86191E2AAC0B032AAD0B012AAE0B31
:10042000FF2900340616B5015F30222A86163514DE
:100430004C30222A0617B5144030222A861735146C
:10044000B5143330B1002030B2000330B300302196
:1004500006080F39003A031D272A860101340130AE
:10046000B3004B210130B3004B217C21872287222E
:10047000872200309B0083161C1483121A0848023E
:100480000318572AB0011030B30087223008B92072
:10049000B100B00A3008B920B2003021B00A3008EB
:1004A000163A031D452A872287228722DA28003040
:1004B0009B0048089A0083161C1555309D00AA30F1
:1004C0009D009C141C119C18632A8312B001C70A5A
:1004D00047080339B4008722B4210530B30030083F
:1004E0004C20B100B00A30084C20B2003021860107
:1004F000B00A30086C3A0319832A06080F39003A0B
:100500000319672ADA28872287228722DA28C3304C
:10051000AD00FF30AC00AC0B8B2AAD0B892A080074
:02400E00183F59
:00000001FF