	.CR	SCMP
	.TF SNAKE_V1.HEX,INT
;   .TF SNAKE_V1.BIN,bin
	.LF	SNAKE_V1.LST
	
; *****************************************************************************
; MK14 Snake v1 8th Dec 2023
; Developed by Ian Reynolds for the SBASM 8060 assembler
;
; Requires continuous memory from $0200 to $07FF and base RAM at $0F00
; Program operates in character mode
;
; $200-$3FF VDU RAM
; $400-$4FF Snake body segment array
; $500-$7FE Program
; $7FF PiView control byte
; $F00-$F0F SCIOS Variables
; $F10-$F27 Game Variables
; $F28-$FF7 Game subroutines
; $FF8-$FFF SCIOS variables (inc. fast loader)
;
; Keys: 1 to turn left
;       3 to turn right
;       GO to start game 
;
; The snake can have 126 segments max. If you achieve that then you win!!
;
; Visit the UK Vintage Radio Forums, Vintage Computers, for updates
;
; https://www.vintage-radio.net/     My username is Realtime
; *****************************************************************************

;--------------------------------------------------------------------
;Game Constants
DISP_CH		.EQ $0200      ; Start of VDU frame store for characters
SNAKE_ARRAY .EQ $0400      ; 256 bytes allows for 127 snake elements
PROG		.EQ $0500      ; Start of program memory
VAR			.EQ $0F10      ; Variables storage area ($18 bytes)
PIVIEW_MODE .EQ $07FF      ; PiView VDU mode control address
INS8154		.EQ $0800      ; MK14 I/O chip base address
LED_DISP    .EQ $0D00      ; MK14 LED display and keypad

CELL_EMPTY  .EQ $FF        ; unoccupied cell in the snake array
CHAR_SPACE	.EQ $20		   ; ' '
CHAR_BODY   .EQ $0F        ; 'O'
CHAR_HEAD_R .EQ $3C        ; '<' (cannot be $00)
CHAR_HEAD_L .EQ $3E        ; '>' (cannot be $00)
CHAR_HEAD_U .EQ $16        ; 'V' (cannot be $00)
CHAR_HEAD_D .EQ $1E        ; '^' (cannot be $00)
CHAR_APPLE  .EQ $2A        ; '*' (cannot be $00)
PORT_B		.EQ $21		   ; INS8154 Port B Output register write address
MESSAGE     .EQ $02E0      ; Address at which to display end of game message
MESSAGE2    .EQ $0380      ; Address at which the "PRESS GO" mesaage is displayed
SEGMENTS    .EQ $7D        ; Max number of snake segments allowed
GAME_DELAY  .EQ $30        ; Sets the loop speed

; Game Variables
COUNT1      .EQ $00	       ; When not zero Game has ended		
P3H_TMP     .EQ $01        ; Temporary store for P3
P3L_TMP     .EQ $02        ; Temporary store for P3
X_COORD     .EQ $03        ; x position of snake segment
Y_COORD     .EQ $04        ; y position of snake segment
SNAKE_LEN   .EQ $05        ; Current length of the snake
CHAR_HEAD   .EQ $06        ; Head character to be displayed 
KEY_LATCH   .EQ $07        ; 00= no key pressed (used for key debounce)
APPLE       .EQ $08        ; Non zero indicates an apple is on screen
GAME_OVER	.EQ $09	       ; When zero Game has ended	
DIR         .EQ $0A        ; Direction vector
HEAD        .EQ $0B        ; Indicates if Head character is being output
P3H_WIPE    .EQ $0C        ; Last position of tail end to be wiped out when snake moves
P3L_WIPE    .EQ $0D        ; 
SEED        .EQ $0E        ; Pseudo random number gen for Apple position
X_BYTE      .EQ $0F        ; Local copy of snake segment X data
Y_BYTE      .EQ $10        ; Local copy of snake segment Y data
SCORE_H     .EQ $11        ; BCD counter high byte
SCORE_L     .EQ $12        ; BCD counter low byte
YOU_WIN     .EQ $13        ; 00 indicates you have exceeded the max number of body segments and have won the game

;--------------------------------------------------------------------
; Splash Screen during programme load
    .OR DISP_CH
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  
	.DB $20,$20,$20,$20,$20,$20,$2C,$2D,$2E,$20,$20,$20,$20,$20,$20,$20          ;                 
    .DB $20,$20,$20,$20,$2C,$2D,$20,$20,$20,$2D,$2E,$20,$20,$20,$20,$20          ;     ,-----.       
    .DB $20,$20,$20,$2C,$20,$20,$20,$20,$20,$20,$20,$2E,$20,$20,$20,$20          ;    ,       .      
    .DB $20,$20,$2F,$20,$1E,$20,$20,$20,$20,$20,$1E,$20,$1C,$20,$20,$20          ;   / ^     ^ \       
    .DB $20,$2C,$2D,$28,$30,$29,$2D,$20,$2D,$28,$30,$29,$2D,$2E,$20,$20          ;  ,-(0)- -(0)-.    
    .DB $20,$21,$20,$20,$21,$20,$20,$20,$20,$20,$21,$20,$20,$21,$20,$20          ;  !  !     !  !    
    .DB $20,$1C,$1F,$20,$20,$20,$20,$20,$20,$20,$20,$20,$1F,$2F,$20,$20          ;  \_         _/    
    .DB $20,$20,$21,$20,$20,$20,$20,$20,$20,$20,$20,$20,$21,$20,$20,$20          ;   !         !  
    .DB $20,$20,$1C,$20,$20,$20,$0F,$20,$0F,$20,$20,$20,$2F,$20,$20,$20          ;   \   O O   /     
    .DB $20,$20,$20,$1C,$1F,$1F,$20,$20,$20,$1F,$1F,$2F,$20,$20,$20,$20          ;    \__   __/
	.DB $20,$20,$20,$20,$21,$20,$20,$20,$20,$20,$21,$20,$20,$20,$20,$20   	     ;     !     !
    .DB $20,$20,$20,$20,$1C,$20,$1C,$20,$2F,$20,$2F,$20,$20,$20,$20,$20          ;     \ \ / /       
    .DB $20,$20,$20,$20,$20,$1C,$20,$21,$20,$2F,$20,$20,$20,$20,$20,$20          ;      \ ! / 
	.DB $20,$20,$20,$20,$20,$20,$20,$21,$20,$20,$20,$20,$20,$20,$20,$20          ;       V!V
	.DB $20,$20,$20,$20,$20,$20,$16,$20,$16,$20,$20,$20,$20,$20,$20,$20          ;            
    .DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;            
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;       
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;       
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;       
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;       
	.DB $20,$0D,$0B,$31,$34,$20,$13,$0E,$01,$0B,$05,$20,$16,$31,$20,$20          ;  MK14 SNAKE V1   
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;   
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ; 
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  
	.DB $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20          ;  

; Game entry point
	.OR	PROG
ENTRY:
; Set up INS8154 
; The following is for Realtime's 'Realview' MK14 VDU, using Port B for the control byte
; Other VDU's may require a different set up byte

	LDI	INS8154/256			; Base address of I/O device
	XPAH P3
	LDI	INS8154\256
	XPAL P3
	; LDI	$08
	; ST PORT_B+2(P3)	 		; Port B output definition register - bit3 (VDUOFF) as output, all others as inputs
	; LDI $FF				; Set VDU control bits - Enable VDU only. All other controls are via RealView DIP switches
	; ST Port_B(P3)			; Set port B outputs (Port B is always in basic I/O mode)
;
;	Port B bit 7 = PS3 - set to '0'	  \
;	Port B bit 6 = PS1 - set to '1'		\  Sets the video RAM address to $0200
;	Port B bit 5 = PS2 - set to '1'		/  However, note that PS1 must not be physically connected
;	Port B bit 4 = PS4 - set to '0'	  /	   to the VDU card as this line is controlled by the TOPPAGE signal
;	Port B bit 3 = VDUOFF               - set to '0' for VDU on
;	Port B bit 2 = Graphics/nCharacters - set to '1' to allow TOPPAGE to control the mixed graphic/character display
;	Port B bit 1 = REVPAGES             - set to '0' for $200 at top of the screen ($300 at bottom)
;	Port B bit 0 = INVERT               - set to '0' for white video on black background

; Set PiView mode: $00 = Character mode
	LDI $00
	ST -1(P3)                  ; Store at $07FF
  	LDI VAR/256
	XPAH P2
	LDI VAR\256
	XPAL P2                   ; P2 is the games variables pointer
	LDI $00
	ST GAME_OVER(P2)          ; Force game over so that keyboad scan looks only for the GO key	 
	JS P3,KBD                 ; wait for the GO key to be pressed to start the game
	 
GAME_START:
	JS P3,CLS                  ; Clear screen and initialise the snake array

;--------------------------------------------------------------------
; Initialise Variables

	LDI $05
	ST GAME_OVER(P2)        ; $00 is game over
	ST SNAKE_LEN(P2)        ; Number of segments in snake's body
	ST YOU_WIN(P2)          ; Any non-zero value means you haven't won yet
	
	LDI CHAR_HEAD_R
	ST CHAR_HEAD(P2)        ; Initial head direction is right
	LDI $00
	ST KEY_LATCH(P2)        ; Indicate no key pressed yet
    ST APPLE(P2)            ; No apple on screen
	LD SEED(P2)             ; ensure random number seed is non-zero
	JNZ START
	ILD SEED(P2)

;=============================================================================
; Main loop
; Interpret array to generate display
; Before head byte is output look ahead to see if there is an obstacle
START:	

GEN_DISP:
    LDI $00
	ST HEAD(P2)             ; 0 indicates current position is the head
	LDI	SNAKE_ARRAY/256
	XPAH P1
	LDI	SNAKE_ARRAY\256 
	XPAL P1					; P1 now contains start address of snake array
	LD SNAKE_LEN(P2)
	ST COUNT1(P2)
GEN:
    LD (P1)                 ; Get X byte of array entry
    ST X_BYTE(P2)
	LD 1(P1)
	ST Y_BYTE(P2)
	ANI $1F                 ; Mask off Y co-ordinate
	ST Y_COORD(P2)
    LD X_BYTE(P2)
	ANI $0F                 ; Mask off X co-ordinate
	ST X_COORD(P2)
	CCL
	LD Y_COORD(P2)
	RRL
	RRL
	RRL
	RRL
	RRL
	XAE                     ; E=16*Y_COORD
	RRL                     ; rotate carry bit into bit 7
	JP G1                   ; if +ve then location is in upper display page
    LDI DISP_CH/256+1       ; if -ve then location is in lower display page
    JMP G2
G1:
    LDI DISP_CH/256	
G2:
    XPAH P3
	CCL
	LDE                    ; retreive offset
	ADD X_COORD(P2)        ; add X co-ordinate
	XPAL P3                ; P3 now points to correct position in display RAM
	                       ; Check if next move is into a free cell
	LD HEAD(P2)            ; if HEAD is 00 then check if obstacle before updating and outputing CHAR_HEAD
	JNZ G3
	                       ; Head clash check
	LD (P3)                ; get character at display position
	XRI CHAR_SPACE         ; is it an empty space
	JZ HEAD_OUT            ; If yes then display head as normal
    LD (P3)                ; cell is occupied so
	XRI CHAR_APPLE         ; is it an Apple?
	JZ CONT                ; if yes then increment snake length. If not then it's game over
G_END:
	JS P3,GAME_END
	JMP KBD_STEP
CONT:
	LD SNAKE_LEN(P2)
	XRI SEGMENTS           ; Max number of snake segments allowed
	JNZ INC_SNAKE_LEN
	ST YOU_WIN(P2)         ; 00 indicates you win by reaching 126 segments long
	JMP G_END

GEN_STEP:
    JMP GEN                ; This is a stepping stone
;--------------------------------------------------------------------
; Increment snake length and place new entry in array
;
INC_SNAKE_LEN:
	LDI $00
	ST APPLE(P2)           ; Indicate no apple on screen
	; increase snake length
	LD SNAKE_LEN(P2)
	CCL
	ADD SNAKE_LEN(P2)      ; Point to next free array position (=2xSNAKE_LEN)
	XPAL P1
	LDI SNAKE_ARRAY/256
	XPAH P1
	LD -2(P1)              ; Duplicate last entry in next position
	ST (P1)
	LD -1(P1)
	ST 1(P1)
	ANI $C0                ; update new entry position based on direction bits
	ST DIR(P2)
	JNZ DIR_LEFT_T
DIR_RIGHT:          ; dir bits = 00
    DLD (P1)
	ANI $0F          ; if X <0 the roll back to zero
	ST (P1)
	JMP DIR_END
DIR_LEFT_T:
    XRI $80
	JNZ DIR_UP_T
DIR_LEFT:           ; dir bits = 10
    ILD (P1)
	ANI $0F
	ST (P1)
	JMP DIR_END
DIR_UP_T:
    XRI $C0
	JNZ DIR_DOWN
DIR_UP:             ; dir bits = 01
    ILD 1(P1)
	ANI $1F
	OR DIR(P2)
	ST 1(P1)
    JMP DIR_END
DIR_DOWN:           ; dir bits must be 11
    DLD 1(P1)
	ANI $1F
	OR DIR(P2)
	ST 1(P1)
DIR_END: 
    ILD SNAKE_LEN(P2)
	LDI SNAKE_ARRAY/256
	XPAH P1
	LDI SNAKE_ARRAY\256
	XPAL P1
	JMP HEAD_OUT
	
;**************************************************
DISP_END_STEP:         ;                          *
    JMP DISP_END       ; this is a stepping stone *
KBD_STEP:              ;                          *
	JMP KBD            ; this is a stepping stone *
;**************************************************

HEAD_OUT:	
	LD CHAR_HEAD(P2)
	ST HEAD(P2)            ; set head flag to non-zero
	JMP G4
G3:
	LDI CHAR_BODY          ; else output body character
G4: 
    ST (P3)                ; store snake character on screen
	
	LD @2(P1)              ; move P1 onto next entry in the snake array
	DLD COUNT1(P2)
    JNZ GEN_STEP           ; Jump to display generation loop via stepping stone
DISP_END:
    ; P3 holds the screen address of the last snake segment. Copy this 
    LD P3H_WIPE(P2)
    XPAH P3
    ST P3H_WIPE(P2)
    LD P3L_WIPE(P2)
    XPAL P3
    ST P3L_WIPE(P2)	      ; P3_WIPE now holds the last screen write
	                      ; P3 holds the previous last position
	LDI CHAR_SPACE
	ST (P3)               ; Remove old snake tail from screen

; *****************************************************************************
; Move Snake in the array
    LD SNAKE_LEN(P2)
	ST COUNT1(P2)
	CCL
	ADD SNAKE_LEN(P2)
	XPAL P1               ; Point P1 to end of snake array +1
	LD @-1(P1)            ; P1 now pointing to end of array
	DLD COUNT1(P2)        ; want to process 1 less than length (ignore head)

AGAIN:
    ; Copy direction array(n-1) to direction array(n)
	LD -2(P1)             ; copy next position direction to current position
	ANI $C0               ; Mask off direction bits
	ST DIR(P2)
	XAE
	LD (P1)
	ANI $1F               ; Mask off Y co-ordinate
	ORE                   ; combine with new direction
	ST (P1)
    LD @-2(P1)            ; Move P1 to next ENTRY
    DLD COUNT1(P2)
    JNZ AGAIN             ; Note: The head direction doesn't get changed

;================================================
; scan keyboard for 1,3, GO
; Change snake head direction when 1 or 3 is pressed
; On entry to this routine P1 is pointing to Array+1
;================================================
KBD:
	LD @-$01(P1)          ; P1 now points to beginning of array
	LDI LED_DISP/256
	XPAH P3   
	LDI LED_DISP\256
	XPAL P3               ; P3 points to MK14 display/keyboard
    LDI $00
	ST (P3)               ; Set all display segments to off	
	LD GAME_OVER(P2)      ; If Game over flag is zero then only test GO key
	JZ TEST_GO
TEST_NO_KEY:
    LD KEY_LATCH(P2)
	JZ TEST_1
	LD 1(P3)
	XOR 3(P3)
	JNZ NO_KEY            ; if both results are the same then there is no key being pressed
    LDI $00
    ST KEY_LATCH(P2)	  ; Reset the key debounce flag
TEST_1:                   ; Rotate left
    LD 1(P3)              ; read keypad $0D01 (Key 1)
	ORI $0F               ; Mask top 4 bits
	XRI $7F               ; Result will be zero if key pressed
	JNZ TEST_3
                          ; change snake direction left rotate
    LD 1(P1)              ; Get Y byte of head entry
    CCL
	ADI $40               ; changing direction in a left rotation simply needs the direction bits to be incremented 
	JMP END_KEYSCAN
TEST_3:                   ; Rotate right
    LD 3(P3)              ; read keypad $0D03 (Key 3)
	ORI $0F               ; Mask top 4 bits
	XRI $7F               ; Result will be zero if key pressed
    JNZ NO_KEY
                          ; change snake direction right rotate
    LD 1(P1)              ; Get Y byte of head entry               
    CCL
	ADI $C0               ; changing direction in a left rotation simply needs the direction bits to be decremented 
    JMP	END_KEYSCAN
TEST_GO:                  ; New Game
	LD 2(P3)              ; read keypad $0D02 (Key GO)
	ORI $0F               ; Mask top 4 bits
	XRI $DF               ; Result will be zero if key pressed
    JNZ TEST_GO
	JS P3,GAME_START      ; Use JS as a long jump to restart the game
END_KEYSCAN:
    ANI $C0               ; constrain to 2 bits (ignore any carry over)
	XAE                   ; Temp store direction new bits
	LD 1(P1)              ; Get Y byte of head entry
	ANI $1F               ; mask Y co-ordinate
	ORE                   ; Include direction bits
    ST 1(P1)              ; Update head Y byte
	LDI $FF              ; Indicate key has been pressed
	ST KEY_LATCH(P2)
	
;********************************************************************************
; Set head character according to the change of direction
	
	LDE                   ; E already holds the new direction bits
TEST_R:
	JNZ TEST_L
    LDI CHAR_HEAD_R       ; if 00 then new direction is right
	JMP SET_HEAD
TEST_L:
    XRI $80
	JNZ TEST_U
    LDI CHAR_HEAD_L       ; if 80 then new direction is left
    JMP SET_HEAD
TEST_U:
    XRI $C0
	JNZ TEST_D
    LDI CHAR_HEAD_U       ; if 40 then new direction is up
	JMP SET_HEAD
TEST_D:
    LDI CHAR_HEAD_D       ; else direction must be down
SET_HEAD:
    ST CHAR_HEAD(P2)      ; store new head character ready for next display loop
NO_KEY:

;********************************************************************************
; Update co-ordinates of each snake segment according to direction bits
; On entry P1 is pointing to start of array

    LD SNAKE_LEN(P2)
	ST COUNT1(P2)
TEST_DIR:
	LD 1(P1)         ; Get Y Byte
	ANI $C0          ; mask off direction bits
	ST DIR(P2)
	JNZ TEST_LEFT
MOVE_RIGHT:          ; dir bits = 00
    ILD (P1)
	ANI $0F          ; if X >15 the roll back to zero
	ST (P1)
	JMP MOVE_END
TEST_LEFT:
    XRI $80
	JNZ TEST_UP
MOVE_LEFT:           ; dir bits = 10
    DLD (P1)
	ANI $0F
	ST (P1)
	JMP MOVE_END
TEST_UP:
    XRI $C0
	JNZ MOVE_DOWN
MOVE_UP:             ; dir bits = 01
    DLD 1(P1)
	ANI $1F
	OR DIR(P2)
	ST 1(P1)
    JMP MOVE_END
MOVE_DOWN:           ; dir bits must be 11
    ILD 1(P1)
	ANI $1F
	OR DIR(P2)
	ST 1(P1)
MOVE_END: 
    LD @2(P1)        ; Move P1 to next ENTRY
    DLD COUNT1(P2)
    JNZ TEST_DIR
    LD SNAKE_LEN(P2)
	ADI $80
	ST COUNT1(P2)
BODY_DLY:            ; Delay is inversely proportional to the number of body segments. 
	LDI $40          ; This avoids the game slowing as the body length increases
	DLY $0
	ILD COUNT1(P2)
	JNZ BODY_DLY
;-------------------------------------------------------------------
; Place an Apple on screen

    LD APPLE(P2)       ; If APPLE is not zero then there's already one on screen
	JNZ PLACED
 
 ;Generate random number for position of the next Apple's position
	LD SEED(P2)
    ANI $01
    XAE
	LD SEED(P2)       ; This small piece of code implements an 8 bit PRNG
	SR
	XAE
	JZ NO_XOR
	LDE
    XRI $B8
	JMP STORE
NO_XOR:
    LDE
STORE:
    ST SEED(P2)
	XPAL P3
	LD SEED(P2)
	ANI $01
	ORI $02
	XPAH P3
TEST_APPLE:             ; Check that position for next Apple is empty. If not increment it until aspace if found
	LD (P3)
	XRI $20
	JZ PLACE_APPLE
	XPAL P3
	CCL
	ADI $01
	XPAL P3
	JMP TEST_APPLE
PLACE_APPLE:
    LDI CHAR_APPLE
    ST (P3)             ; Display Apple on screen
	ST APPLE(P2)        ; Make apple flag non-zero to indicate aplle is on screen
PLACED:

    DLY GAME_DELAY          
	DLY GAME_DELAY

    JS P3,START      ; long jump back to start of main loop
    

;================================================
;Clear screen and initialise snake array - Subroutine
CLS:
	LDI	DISP_CH/256
	ST P3H_WIPE(P2)
	XPAH P1
	LDI	DISP_CH\256  
	ST P3L_WIPE(P2)
	XPAL P1					; P1 now contains start address of character display
CLS2:
	LDI CHAR_SPACE
	ST @1(P1)				; Clear character location
	XPAH P1
	XRI	DISP_CH/256+2 	    ; XOR to determine if page clear completed
	JZ	CLS3				    ; If zero then then finished clear screen  
	XRI	DISP_CH/256+2 	    ; Restore P1_H
	XPAH P1
	JMP	CLS2	
CLS3:
; Place Snake in the array
	LDI	SNAKE_ARRAY/256
	XPAH P1
	; P1L is already $00

	;---------------------------------------------
	; X_BYTE = 7  6  5  4  3  2  1  0
	;          0  0  0  0 X3 X2 X1 X0  
	;
	; X = X co-ordinate on screen, bit 4 reserved for overflow
	; If X=FF then indicates end of snake reached
	;
	; Y_BYTE = 7  6  5  4  3  2  1  0 
	;          D1 D0 0 Y4 Y3 Y2 Y1 Y0
	;
	; D = direction, Y = Y co-ordinate on screen, bit 5 reserved for overflow
	; Direction 0= right, 1 = up, 2 = left, 3 = down
	; 
	;---------------------------------------------

    LDI $06    ; Top of array is always the head, X=6
    ST (P1)
    LDI $05    ; X=5
    ST 2(P1)
    LDI $04    ; X=4
    ST 4(P1)
    LDI $03    ; X=3
    ST 6(P1)
    LDI $02    ; X=2
    ST 8(P1)
	LDI $10    ; Direction=0=Right, Y=$10
	ST 1(P1)
    ST 3(P1)
	ST 5(P1)
	ST 7(P1)
	ST 9(P1)
	
    RET P3

;======================================================
; Subroutine
; Ouput message to screen
; P1 needs to point to the screen location
;======================================================
OUT_MESSAGE
   LD @1(P3)
IS2:
	LD @1(P3)          ; copy it to screen
	JZ END_MESS        ; EOF is $00
	ST @1(P1)
	JMP IS2
END_MESS:
    LD @-1(P3)
	RET P3

;------------------------------------------------------------------------------
; SCIOS Variables $0F00 to $0F0F
; Game variables $0F10 to $0F27	
;------------------------------------------------------------------------------
    .OR $F28
;======================================================
; GAME over subroutine
;======================================================
GAME_END:
	XPAH P3            ; Temporarily store return address held in P3
	ST P3H_TMP(P2)
	XPAL P3
	ST P3L_TMP(P2)
    LDI $00
    ST GAME_OVER(P2)   ; 0 = game over
	JS P3,CLS          ; Clear screen and initialise the snake array
	LDI MESSAGE/256    ; Get address of message display area 
	XPAH P1
	LDI MESSAGE\256
	XPAL P1
	LD YOU_WIN(P2)
	JNZ nU_WIN
	JS P3,OUT_MESSAGE
U_WON:    .DB $1,$D,$1,$1A,$9,$E,$7,$21,$20,$19,$F,$15,$20,$17,$F,$E,$00   ; AMAZING! YOU WON
    LD @$10(P1)        ; increment to next line of display
nU_WIN:
	JS P3,OUT_MESSAGE
SNAKE14:  .DB $20,$D,$B,$31,$34,$20,$13,$E,$1,$B,$5,$20,$16,$31,$00          ;   MK14 SNAKE V1 
    LD @$15(P1)        ; increment to Next line of display
	JS P3,OUT_MESSAGE
OVER:    .DB $07,$01,$0D,$05,$20,$0F,$16,$05,$12,$00                    ; GAME OVER
    LD @$13(P1)        ; increment to next line of display
    JS P3,OUT_MESSAGE
SCORE:	 .DB $20,$13,$E,$1,$B,$5,$20,$13,$9,$1A,$5,$3D,$00                     ; SNAKE SIZE=     
	LD SNAKE_LEN(P2)		;
	ST COUNT1(P2)
	LDI $00
	ST SCORE_H(P2)
	ST SCORE_L(P2)
UPDATE1:
    LD SCORE_L(P2)
    CCL
	DAI $01
    ST SCORE_L(P2)
    RRL              ; rotate carry flag into bit 7
	JP UPDATE2
    LD SCORE_H(P2)
    CCL
	DAI $01
    ST SCORE_H(P2)	
UPDATE2:	
	CCL
	LD SCORE_H(P2)
	ANI $0F				; Mask off lower nibble
	ADI $30				; Convert to number character
	ST @1(P1)			; Display number and increment pointer
	LD SCORE_L(P2)
	ANI $F0				; Mask off upper nibble
	SR					; Shift right 4 times
	SR
	SR
	SR
	ADI $30				; Convert to number character
	ST @1(P1)		
	LD SCORE_L(P2)
	ANI $0F				; Mask off lower nibble
	ADI $30				; Convert to number character
	ST @(P1)			; Display number
	LD @-2(P1)          ; Move P1 pointer back to start of score
	DLY $A0             ; Delay for visual effect only
	DLD COUNT1(P2)
	JNZ UPDATE1
RET_KBD:
    LD @$18(P1)        ; increment to next line of display
    JS P3,OUT_MESSAGE
PRESSGO:   .DB $10,$12,$05,$13,$13,$20,$07,$0F,$00             ;     PRESS GO   
	LD P3H_TMP(P2)    ; Restore P3 return address
	XPAH P3
	LD P3L_TMP(P2)
	XPAL P3 
	RET P3
;
;******************************************************************************	
;	NOTE: THE PROGRAM LOAD MUST NOT GO PAST $FF7 AS THE FAST LOADER VARIABLES WILL BE CORRUPTED
; *****************************************************************************
;   This line is displayed at the end of program load only
    .OR MESSAGE2
	.DB $20,$20,$20,$20,$10,$12,$5,$13,$13,$20,$7,$F,$20,$20,$20,$20             ;     PRESS GO   
		
; ENTRY is the execution address that the Hex loader will use during program load
EXEC_ADR:	
	.OR $FFFE
	.DB ENTRY/256
	.DB ENTRY\256
	
	