	.CR	SCMP
	.TF MoonLander_v1.HEX,INT
;	.TF MoonLander_v1.BIN,bin
	.LF	MoonLander_v1.LST
	
; *****************************************************************************
; MK14 MoonLander
; Rev 1.0 7th Dec 2023
; Developed by Ian Reynolds for the SBASM 8060 assembler
; Uses the core Moon Lander game from the SoC MK14 manual
; Graphics version based on an idea by SiriusHardware, Vintage Radio UK forums
; Thanks to SiriusHardware for the moonscape graphic
;
; Requires continuous memory from 0x0200 to 0x07FF and base RAM at 0x0B00 and 0x0F00
; For correct operation the VDU TOPPAGE signal needs to be connected to PS1, to use 2 pages of video RAM, and
; connected to VDU Graph_nChar input to generate a top page of characters and lower page of graphics (or visa-versa)
; The LED display still functions as per the original game
;
; Keys: 1 to 7 set the thrust 
;		0 kill motor
;       Any system key to restart the game at any point
;
; Comparison of original LED display to new VDU display. Note the information for the
; increased fidelity is already in the original game - it just needed displaying
;=====================================================================================!
;! Feature    ! LED Display                      ! VDU Display                        !
;!------------------------------------------------------------------------------------!
;! Altitude   ! 3 digits. 0-999. 999=touch down  ! 4 digits. 0-9999. 0000=touch down  !
;! Velocity   ! 2 digits. Unsigned (absolute)    ! 3 digits. Signed. -ve = Ascent     !
;! Thrust     ! Not displayed                    ! 1 digit. 0-7                       !
;! Fuel       ! 1 digit. 0-5. F=empty            ! 2 digits. 0-88. 0=EMPTY            !
;!------------------------------------------------------------------------------------!
;      
; Additional features
; -------------------
; Random starting altitude from 600 - 977
; On touchdown a graphic indicates how good a landing you had:
;    Velocity >=30 = Crash landing; 
;    Velocity >=10 and <30 = Hard landing
;    Velocity <10 = Perfect landing
; Moonscape graphic displayed during game
;
; Visit the UK Vintage Radio Forums, Vintage Computers, for updates
;
; https://www.vintage-radio.net/     My username is Realtime
; *****************************************************************************

;Game Constants
DISP_CH		.EQ 0x0200		; Start of VDU frame store for characters
DISP_GR		.EQ 0x0300		; Start of VDU frame store for graphics
DISP_LAND   .EQ DISP_GR+0x0A ; Position for displaying landing graphic
PROG		.EQ 0x0400		; Start of program memory
VAR			.EQ 0x07F0		; Variables storage area, separate from the MoonLander core variables at 0x0F05
PIVIEW_MODE .EQ 0x07FF      ; PiView VDU mode control address
INS8154		.EQ 0x0800		; MK14 I/O chip base address
MOONSCAPE   .EQ 0x0B00      ; Location of moonscape graphic
ML_VAR      .EQ 0xF05       ; Local variable storage for core moon lander routine

Char_Space	.EQ 0x20		; ' '
Port_B		.EQ 0x21		; INS8154 Port B Output register write address

; Game Variables			; This list order needs to be maintained as it is cleared as a block during game initialisation
GAME_OVER	.EQ 0x00		; When not zero Game has ended		
LAND_TYPE   .EQ 0x01        ; Holds the Crash, Hard, Soft landing result
COUNT1		.EQ 0x02		; General purpose loop counter
P1H			.EQ 0x03		; Temporary store for P1 High
P1L			.EQ 0x04		; Temporary store for P1 Low
P2H			.EQ 0x05		; Temporary store for P2 High
P2L			.EQ 0x06		; Temporary store for P2 Low
P3H			.EQ 0x07		; Temporary store for P3 High
P3L			.EQ 0x08		; Temporary store for P3 Low
FUEL_MSN	.EQ 0x09		; Conversion of binary fuel level to BCD
FUEL_LSN	.EQ 0x0A		; Conversion of binary fuel level to BCD
ROD_ABS_H	.EQ 0x0B		; Rate Of Descent (Velocity) absolute calculation upper byte
ROD_ABS_L	.EQ 0x0C		; Rate Of Descent (Velocity) absolute calculation lower byte
RAND        .EQ 0x0D        ; Pseudo random number generated by incrementing each cycle of moon lander


	.OR	PROG

; 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
ENTRY:
	LDI	INS8154/256			; Base address of I/O device
	XPAH P3
	LDI	INS8154\256
	XPAL P3
	LDI	0x08
	ST PORT_B+2(P3)	 		; Port B output definition register - bit3 (VDUOFF) as output, all others as inputs
	LDI 0xFF				; 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 0x0200
;	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 0x200 at top of the screen (0x300 at bottom)
;	Port B bit 0 = INVERT               - set to '0' for white video on black background

; Set PiView mode: 0E = text at top, graphics at bottom of display
	LDI	PIVIEW_MODE/256			; Base address of I/O device
	XPAH P3
	LDI	PIVIEW_MODE\256
	XPAL P3
	LDI	0x0F                    ; Set graphics at bottom half of screen, characters at top
	ST (P3)
	
;================================================
; Initialise the display
; Copy splash screen to the graphics page
; Fill the character page with space character
;================================================	
;Clear screen
SC1:
	LDI	DISP_GR/256
	XPAH P1
	LDI	DISP_GR\256  
	XPAL P1					; P1 now contains start address of graphics display
	LDI	DISP_CH/256
	XPAH P3
	LDI	DISP_CH\256  
	XPAL P3					; P3 now contains start address of character display
	LDI MOONSCAPE/256
	XPAH P2
	LDI MOONSCAPE\256
	XPAL P2                 ; P2 points to graphic initialisation data
SC2:
	LDI Char_Space
	ST @1(P3)				; Clear character location
    LD @1(P2)               ; get splash screen byte
    ST @1(P1)	            ; store in graphics area
	XPAH P3
	XRI	DISP_CH/256+1 	    ; XOR to determine if page clear completed
	JZ	SC3				    ; If zero then then finished clear screen 
	XRI	DISP_CH/256+1 	    ; Restore P1_H
	XPAH P3
	JMP	SC2	
SC3:
	LDI VAR/256
	XPAH	P2
	LDI	VAR\256
	XPAL	P2
	
	LDI 0x00
	ST GAME_OVER(P2)   ; 00 is game not over. non-zero is game over
	
; Output Title and status display text
	LDI Title_text/256		; Get start address of Title text block
	XPAH P3
	LDI Title_text\256
	XPAL P3
	LDI DISP_CH/256
	XPAH P1
	LDI DISP_CH\256+0x10
	XPAL P1
	LDI 0x05
	ST COUNT1(P2)           ; number of lines of text to output
SC4:
	LD @1(P3)				; get character from text string
	XRI 0x55				; 0x55 is EOL
	JZ SC5
	XRI 0x55				; restore character value
	ST @1(P1)				; copy it to screen
	JMP SC4
SC5:
	DLD COUNT1(P2)
	JZ Start				; end if count1 is zero
	XPAL P1
	ANI 0xF0
	CCL
	ADI 0x30
	XPAL P1					; move P1 pointer to start of next line on screen
	JMP SC4
	
;-----------
; the following block is taken from the Moonlanding main program to free up some space in page 0F00
;-----------

Start:	
	LDI VAR/256
	XPAH P2
	LDI	VAR\256
	XPAL P2
	LDI /Init
	XPAH 1
	LDI #Init
	XPAL 1
	;new section to generate random start altitude
	LD RAND(P2)         ; get latest 'random' number
    ANI 0x03
	CCL
    ADI 0x06
	ST 0(P1)            ; Result can be 6, 7, 8, 9 => high byte of altitude constant
	LD RAND(P2)
	ANI 0x77
	ST 1(P1)            ; result can be up to 77 => low byte of altitude constant
	
	LDI /Ret
	XPAH 2
	LDI #Ret
	XPAL 2
	LDI 12
	ST Count(2)
Set:                   ; copy game defaults to ML_VAR area
	LD +11(1)
	ST @-1(1)
	DLD Count(2)
	JNZ Set

; jump to main program
	JS P3,Again
	
;================================================
; Lines of Text for writing to display. EOL is 0x55
;================================================
Title_text:	.DB 0x20,0xD,0xF,0xF,0xE,0x20,0xC,0x1,0xE,0x4,0x5,0x12,0x20,0x16,0x31,0x20,0x55	;  MOON LANDER V1
			.DB 0x1,0xC,0x14,0x9,0x14,0x15,0x4,0x5,0x20,0x3D,0x55							; ALTITUDE = 
			.DB 0x16,0x5,0xC,0xF,0x3,0x9,0x14,0x19,0x20,0x3D,0x20,0x55						; VELOCITY = 
			.DB 0x14,0x8,0x12,0x15,0x13,0x14,0x20,0x20,0x20,0x3D,0x55						; THRUST   = 
			.DB 0x6,0x15,0x5,0xC,0x20,0x20,0x20,0x20,0x20,0x3D,0x55							; FUEL     = 
; Crash:   	.DB 0x3,0x12,0x1,0x13,0x8,0x20,0xC,0x1,0xE,0x4,0x9,0xE,0x7,0x55                 ; CRASH LANDING   
; Hard:		.DB 0x8,0x1,0x12,0x4,0x20,0xC,0x1,0xE,0x4,0x9,0xE,0x7,0x55                      ; HARD LANDING    
; Soft:     .DB 0x10,0x5,0x12,0x6,0x5,0x3,0x14,0x20,0xC,0x1,0xE,0x4,0x9,0xE,0x7,0x55        ; PERFECT LANDING 

;=====================================================
; VDU output subroutine
;
;Altitude      ML_VAR+3 = 0xF08
;Velocity      ML_VAR+6 = 0xF0B ; refered to as Rate of Descent in VDU driver
;Acceleration  ML_VAR+9 = 0xF0E
;Thrust        ML_VAR+11= 0xF10
;Fuel Left     ML_VAR+13= 0xF12
;
;========================================================
VDU:
	LDI VAR/256			; Local variables pointer
	XPAH P3				; P3 can be used as it's re-initialised on exit from this subroutine
	LDI VAR\256
	XPAL P3

    LD GAME_OVER(P3)
	JZ PILOT_DISPLAY
; Game over so use p3 for a long jump to return from the VDU handler	
	JS P3,VDU_RET
	
PILOT_DISPLAY:
    ILD RAND(P3)        ; Increment 'random' number every cycle
	
	XPAH P1				; Temporary store for P1
	ST P1H(P3)
	XPAL P1
	ST P1L(P3)

	XPAH P2				; Temporary store for P2
	ST P2H(P3)
	XPAL P2
	ST P2L(P3)

	LDI ML_VAR/256		; Point to the Moon Lander variables 
	XPAH P1
	LDI ML_VAR\256
	XPAL P1
	
	LDI DISP_CH/256		; Point to the character display area
	XPAH P2
	LDI DISP_CH+0x5B\256
	XPAL P2
	CCL
ALTITUDE:	
	LDI 0x00
	ST LAND_TYPE(P3)    
	LD 3(P1)			; Altitude variable at ML_VAR+3 - 4 Nibbles, always positive until touchdown
    JP DISP_ALT         ; If negative then display zeros
    LDI 0x30            ; display all zeros for altitude
    ST @1(P2)
    ST @1(P2)
    ST @1(P2)
	ST @0x2D(P2)
	LD 0(P2)            ; Get ROD MSN from screen location. If '-' then good landing, else if non zero then definately a crash
	XRI 0x2D            ; is it '-'?
	JNZ LAND1
	LDI 0x03            ; = Soft landing
	ST LAND_TYPE(P3)    ; Temp store landing result
	JMP LAND_END
LAND1:
	LD 0(P2)            ; Get ROD MSN from screen location. If '-' then good landing, else if non zero then definately a crash
	XRI 0x30            ; is it '0'?
	JZ LAND1b
	LDI 0x01            ; = crash landing
	ST LAND_TYPE(P3)    ; Temp store landing result
	JMP LAND_END	
LAND1b:
	LD 1(P2)            ; Get ROD middle digit from screen location. If >2 then crash
	CCL
	ADI 0x01            ; add 1 to result. 
	ANI 0x0C            ; If bits 2 or 3 are set result is >3 (i.e. digit >2)    
	JZ LAND2
	LDI 0x01            ; = Crash landing
	ST LAND_TYPE(P3)    ; Temp store landing result	
	JMP LAND_END	
LAND2:
	LD 1(P2)            ; Get ROD middle digit from screen location. If >0 then hard landing
	CCL
	ADI 0x01            ; add 1 to result. 
	ANI 0x0E            ; If bits 2,3 or 4 are set then digit is >0    
	JZ LAND3
	LDI 0x02            ; = Hard landing
	ST LAND_TYPE(P3)    ; Temp store landing result
	JMP LAND_END	
LAND3:
 	LDI 0x03            ; Digit must be 0 so is a soft landing
	ST LAND_TYPE(P3)    ; Temp store landing result
LAND_END:	   	
	JMP ROD
DISP_ALT:
	SR					; Shift high nibble right	
	SR
	SR
	SR
	CCL
	ADI 0x30			; Convert to numeric character
	ST @1(P2)			; Write middle nibble to screen
    LD 0x03(P1)
	ANI 0x0F			; Mask off lower nibble
	CCL
	ADI 0x30			; Convert to numeric character
	ST @1(P2)			; Write MS nibble to screen
	LD 0x04(P1)			; Split byte into 2 nibbles
	SR					; Shift high nibble right	
	SR
	SR
	SR
	CCL
	ADI 0x30			; Convert to numeric character
	ST @1(P2)			; Write middle nibble to screen
	LD 0x04(P1)
	ANI 0x0F			; mask off lower nibble
	CCL
	ADI 0x30			; Convert to numeric character
	ST @0x2D(P2)		; Write LS nibble to screen
; Rate Of Descent
ROD:                    ; Rate of Descent 6(P1)=MSB, 7(P1)=LSB
	LD 0x07(P1)			; Rate of Descent, signed BCD number - 3 nibbles displayed
	JNZ NZERO_ROD		; Check if RoD is zero
	LD 0x06(P1)
	JZ ZERO_ROD
NZERO_ROD				; If not zero check if number is negative (bit 7 set)
	LD 0x06(P1)
	JP POS_ROD			; If positive jump to Positive RoD display routine
ZERO_ROD:				; Else convert to a positive number and sign
	LD 0x07(P1)			; Convert -ve BCD to positive BCD by 
	XRI 0xFF			; complementing, 
	SCL                 ;
	CAI 0x65			; subtracting 0x65 and adding zero (requird to complete the calulation)
	CCL
	DAI 0x00			; adding zero (requird to properly complete the calulation)
	ST ROD_ABS_L(P3)
    LD 0x06(P1)
	XRI 0xFF
	CAI 0x65
	CCL
	DAI 0x00
	ST ROD_ABS_H(P3)
	ANI 0x0F
	CCL
	ADI 0x30
	ST @1(P2)		    ; display RoD_H lower nibble
    LD ROD_ABS_L(P3)
	SR
	SR
	SR
	SR
	CCL
	ADI 0x30
	ST @1(P2)			; display RoD_L upper nibble
	LD ROD_ABS_L(P3)
	ANI 0x0F
	CCL
	ADI 0x30
	ST @0x2E(P2)		; display RoD_L lower nibble
	JMP THRUST	
POS_ROD					; descent is a positive number
	LDI 0x2D			; minus sign output as descent is now ascent (-descent!)
	ST @1(P2)
	LD 0x07(P1)
	SR
	SR
	SR
	SR
	CCL
	ADI 0x30
	ST @1(P2)			; display RoD upper nibble
	LD 0x07(P1)
	ANI 0x0F
	CCL
	ADI 0x30
	ST @0x2E(P2)		; display RoD lower nibble
THRUST:
	LD 0x0C(P1)			; Thrust - single nibble always positive
	ANI 0x0F
	CCL
	ADI 0x30
	ST @0x30(P2)		; display Thrust lower nibble	
FUEL_LEVEL:
	LDI 0x00
	ST FUEL_MSN(P3)
	LD 0x0D(P1)			;Fuel is binary not BCD so needs converting to 2 BCD digits
	JP DIV1             ; If Fuel=-1 then display EMPTY
	LDI 0x05            ; E
	ST @1(P2)
	LDI 0x0D            ; M
	ST @1(P2)
	LDI 0x10            ; P
	ST @1(P2)
	LDI 0x14            ; T
	ST @1(P2)
	LDI 0x19            ; Y
	ST @1(P2)
    JMP GAME_END	
DIV1:
	SCL
	CAI 0x0A
	JP DIV10
	CCL
	ADI 0x0A
	ST FUEL_LSN(P3)		; Store the remainder as the LS nibble
	JMP DIV20
DIV10:
	XAE
	ILD FUEL_MSN(P3)	; Count the number of times 10 can be subtracted - Quotient is the MS nibble
	XAE
	JMP DIV1
DIV20:
	LD FUEL_MSN(P3)
	CCL
	ADI 0x30
	ST @1(P2)			; display Fuel upper nibble
	LD FUEL_LSN(P3)
	XRI 0xFF			; if fuel has gone negative, set to zero
	JZ DIV30
	XRI 0xFF
DIV30:
	CCL
	ADI 0x30
	ST @1(P2)			; display Fuel lower nibble

GAME_END:
; output landing graphic if appropriate
    LD LAND_TYPE(P3)
	JZ RESTORE             ; If zero then ship has not landed
	LDI	DISP_LAND/256
	XPAH P2
	LDI	DISP_LAND\256  
	XPAL P2			  	   ; P2 now contains start address of graphics area  
	LDI	EXG/256
	XPAH P1
	LDI	EXG\256  
	XPAL P1
    LD LAND_TYPE(P3)
	XRI 0x01                ; Is it a Crash landing?
	JNZ NOT_CRASH
	JMP LAND_OUT
NOT_CRASH:	
	XRI 0x03                ; is it a Hard landing?
    JNZ NOT_HARD
	LD @0x78(P1)            ; Increment P1 to point to HLG graphic
	JMP LAND_OUT
NOT_HARD:                	; must be a soft landing	
	LD @0x78(P1)            
	LD @0x78(P1)            ; Increment P1 to point to LLG graphic	
LAND_OUT
	LDI 0x1E                ; Set graphics lines counter
	ST COUNT1(P3)
	LDI 0x00
	XAE                     ; Set E to 0x00
LAND_OUT2:
	LD @1(P1)				; get graphic byte
	ST @1(P2)				; copy it to screen
	LDE
	ST -2(P2)               ; Blank byte left of graphic
	LD @1(P1)				; get graphic byte
	ST @1(P2)				; copy it to screen
	LDE
	ST 2(P2)                ; Blank byte right of graphic
	LD @1(P1)				; get graphic byte
	ST @1(P2)				; copy it to screen
	LD @1(P1)				; get graphic byte
	ST @5(P2)				; copy it to screen, increment to next line
	DLD COUNT1(P3)
	JNZ LAND_OUT2
	LDI 0xFF
	ST GAME_OVER(P3)        ; Indicate game over
RESTORE:
; restore all pointers 
	LD P1H(P3)
	XPAH P1
	LD P1L(P3)
	XPAL P1
	LD P2H(P3)
	XPAH P2
	LD P2L(P3)
	XPAL P2
; Return from VDU handler using p3 for a long jump
	JS P3,VDU_RET

;==================================================================	
; Explosion graphic
EXG:
    .DB 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x10, 0x0C, 0x20, 0x08, 0x20, 0x18, 0x70, 0x18, 0x70, 0x30
    .DB 0x18, 0x1C, 0x70, 0x70, 0x1C, 0x3C, 0x71, 0x90, 0x0E, 0x73, 0x9F, 0xE0, 0x07, 0xE2, 0x0F, 0xE0 
    .DB 0x07, 0xE0, 0x0F, 0xE0, 0x02, 0x80, 0x00, 0x70, 0x83, 0x00, 0x00, 0x7C, 0x72, 0x00, 0x00, 0x2E
    .DB 0x1E, 0x1E, 0xBC, 0x7C, 0x1A, 0x12, 0xA4, 0x70, 0x0B, 0x1E, 0xBC, 0x70, 0x0F, 0x98, 0xA0, 0xE2
    .DB 0x07, 0x14, 0xA0, 0x7C, 0x0E, 0x12, 0xA0, 0x70, 0x1E, 0x00, 0x00, 0x28, 0x32, 0x00, 0x00, 0x34
    .DB 0x76, 0x00, 0x00, 0x7C, 0x03, 0x86, 0x03, 0xE0, 0x03, 0xFE, 0x06, 0xC0, 0x07, 0xFB, 0x0E, 0x40
    .DB 0x07, 0xF7, 0x7F, 0xE0, 0x0E, 0x3F, 0x3F, 0xE0, 0x0C, 0x3D, 0xB0, 0x70, 0x1C, 0x18, 0xF0, 0x18
    .DB 0x70, 0x08, 0x70, 0x1C, 0x40, 0x10, 0x20, 0x04
;==================================================================	
; Hard landing graphic
HLG:
    .DB 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x90, 0x00, 0x0E, 0x18, 0xA0, 0x00, 0x14, 0x14, 0xC0
    .DB 0x00, 0x24, 0x13, 0xF0, 0x00, 0xC4, 0x09, 0x80, 0x01, 0x88, 0x08, 0x40, 0x02, 0x08, 0x08, 0x20 
    .DB 0x04, 0x0A, 0x84, 0x10, 0x04, 0x12, 0x84, 0x10, 0x04, 0x12, 0xA4, 0x10, 0x04, 0x12, 0xF4, 0x08
    .DB 0x08, 0x12, 0x24, 0x08, 0x08, 0x12, 0x24, 0x08, 0x08, 0x10, 0x04, 0x08, 0x08, 0x7F, 0xFF, 0x09
    .DB 0x4F, 0x88, 0x08, 0xF8, 0x04, 0x08, 0x08, 0x12, 0x22, 0x0C, 0x18, 0x30, 0x4B, 0x04, 0x10, 0x22
    .DB 0x01, 0x04, 0x10, 0x40, 0x20, 0xFF, 0xFF, 0x88, 0x09, 0x80, 0x00, 0xC2, 0x13, 0x84, 0x14, 0xA2
    .DB 0x24, 0x90, 0x00, 0x92, 0x08, 0xC3, 0xE1, 0x98, 0x69, 0x7E, 0x3F, 0x08, 0x08, 0x01, 0x40, 0x09
    .DB 0x09, 0x04, 0x80, 0x48, 0x3D, 0x20, 0x0A, 0x1E
;==================================================================	
; Lunar Lander graphic
LLG:
    .DB 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x0E, 0x18, 0x00, 0x00, 0x14, 0x14, 0x00
    .DB 0x00, 0x24, 0x13, 0x00, 0x00, 0xC4, 0x09, 0x80, 0x01, 0x88, 0x08, 0x40, 0x02, 0x08, 0x08, 0x20
    .DB 0x04, 0x0A, 0x84, 0x10, 0x04, 0x12, 0x84, 0x10, 0x04, 0x12, 0xA4, 0x10, 0x04, 0x12, 0xF4, 0x08
    .DB 0x08, 0x12, 0x24, 0x08, 0x08, 0x12, 0x24, 0x08, 0x08, 0x10, 0x04, 0x08, 0x08, 0x7F, 0xFF, 0x08
    .DB 0x0F, 0x88, 0x08, 0xF8, 0x04, 0x08, 0x08, 0x10, 0x02, 0x0C, 0x18, 0x30, 0x03, 0x04, 0x10, 0x20
    .DB 0x01, 0x04, 0x10, 0x40, 0x00, 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x00, 0xC0, 0x03, 0x80, 0x00, 0xA0
    .DB 0x04, 0x80, 0x00, 0x90, 0x08, 0xC3, 0xE1, 0x88, 0x08, 0x7E, 0x3F, 0x08, 0x08, 0x01, 0x40, 0x08
    .DB 0x08, 0x00, 0x80, 0x08, 0x3C, 0x00, 0x00, 0x1E
	
;------------------------------------------------------------------------
; 16 bytes reserved for game variables	
    .OR VAR
	.DB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
	
;========================================================
	; Original Moonlander_0f52 here
	;
	; Converted to SBASM by Slothie 2021
;========================================================

	;Constants
Grav	.EQ 5		;Force of gravity
Disp	.EQ 0xD00	;Display address
Crom	.EQ 0x10B	;Segment table
E		.EQ -128	;Extension register as offset

;**Next 2 lines moved to bottom to eliminate fwd reference
;Row	.EQ Ret-0xF03	;Ram Offsets
;Count	.EQ Ret-0xF04
	;
	;Variables
	.OR ML_VAR
	.DU
Save	.BS 1
H1		.BS 1
L1		.BS 1
Alt		.BS 3	;Altitude      ML_VAR+3 = 0xF08
Vel		.BS 3	;Velocity      ML_VAR+6 = 0xF0B ; refered to as Rate of Descent in VDU driver
Accn	.BS 2	;Acceleration  ML_VAR+9 = 0xF0E
Thr		.BS 2	;Thrust        ML_VAR+11= 0xF10
Fuel	.BS 2	;Fuel Left     ML_VAR+13= 0xF12
	.ED
	;
	; Initial values
	.OR 0xF14
Init:
	.DB 0x08, 0x50, 0x00      ; Altitude = 850
	.DB 0x99, 0x80, 0x00      ; Velocity = -20
	.DB 0x99, 0x98            ; Acceleration = -2
	.DB 0x00, 0x02            ; Thrust = 2
	.DB 0x58, 0x00            ; Fuel = 5.8
	
Ret:
	XPPC 2                    ; P2 contains 0F20
Displ:
	ST Save
	LDI /Crom
	XPAH 1
	ST H1                     ; Run out of pointers
	LDI #Crom
	XPAL 1
	ST L1
	LD Save
	CCL
	ANI 0x0F
	XAE
Loop:
	LD E(1)
	ST @+1(3)
	LDI 0		;Delay point
	DLY 1		;Determines speed
	LD Save
	SR
	SR
	SR
	SR
	XAE
	CSA
	SCL
	JP Loop		;Do it twice
	LDI 0
	ST @+1(3)	;Blank between
	LD H1		;Restores P1
	XPAH 1
	LD l1
	XPAL 1
	JMP Ret		;Return
	
	; Main moon landing program - This section moved to expansion RAM to make space in 0xF00 RAM
; Start:	
	; LDI /Init
	; XPAH 1
	; LDI #Init
	; XPAL 1
	; LDI /Ret
	; XPAH 2
	; LDI #Ret
	; XPAL 2
	; LDI 12
	; ST Count(2)
; Set:
	; LD +11(1)
	; ST @-1(1)
	; DLD Count(2)
	; JNZ Set
;Main Loop
Again:
	JS P3,VDU	; Output flight parameters to the VDU
VDU_RET:
	LDI /Disp-1
	XPAH 3
	LDI #Disp-1
	XPAL 3
	LDI 1
	ST Count(2)
	LD @+6(1)	;P1->Vel+2
	JP Twice	;Altitude positive?
	LD @+4(1)	;P1->Thr+1
	JMP Off		;Don't update
Twice:
	LDI 2		;Update velocity and
	ST Row(2)	;Then altitude...
	CCL
Dadd:
	LD @-1(1)
	DAD +2(1)
	ST (1)
	DLD Row(2)
	JNZ Dadd
	LD +2(1)
	JP Pos		;Gone negative?
	LDI 0x99
Pos:
	DAD @-1(1)
	ST (1)
	DLD Count(2)
	JP Twice
	LD @12(1)	;P1->Alt
	ILD Row(2)	;Row = 1
	SCL
Dsub:
	LD @-1(1)	;Fuel	
	CAD -2(1)	;Subtract thrust
	ST (1)
	NOP
	DLD Row(2)
	JP Dsub
	CSA         ;P1->Fuel now
	JP Off		;Fuel run out?
	JMP Accns
Off:
	LDI 0
	ST -1(1)	;Zero thrust
Accns:
	LD -1(1)
	SCL
	DAI 0x99-Grav
	ST -3(1)	;Accn + 1
	LDI 0x99
	DAI 0
	ST -4(1)	;Accn
Dispy:
	LD (1)		;Fuel
	XPPC 2		;Display it OK
	LD -7(1)	;Vel
	JP Posv
	LDI 0x99
	SCL
	CAD -6(1)	;Vel+1
	SCL
	DAI 0
	JMP Sto
Posv:
	LD -6(1)	;Vel+1
Sto:
	XPPC 2		;Display velocity
	LD -9(1)	;Alt+1
	XPPC 2		;Display it
	LD @-1(3)	;Get rid of blank
	LD @-10(1)	;P1->Alt now
	XPPC 2
	LDI 10
	ST Count(2)
Toil:
	LD @-1(3)	; Key pressed?
	JP Press	; Key 0-7?
	XRI 0xDF	; Command key?
	JNZ CONT	; rStart(2)	;Begin again if so
WAIT_KEY:       ; New code to wait for the key to be released
	LD (3)	    ; Key still pressed?
	XRI 0xDF	; Command key?
	JZ WAIT_KEY ; Still pressed so go back
	JS P3,SC1	; Full restart of Game
CONT:
	DLD Count(2)
	JNZ Toil
	JMP rAgain(2)	;Another circuit
Press:
	LD +9(1)	;Thr+1
	JZ Back		;Engines stopped?
	XPAL 3		;Which Row?
	ST +9(1)	;Set thrust
Back:
	JMP rAgain(2)

; These lines moved here to eliminate forward references
; that SBASM complains about.
; Also the SoC listing has the subtraction backwards!
; These values are the offset relative to P1 which points to
; 0xF20, or the Ret label. All variables are stored before this
; memory location at -ve offsets.
Row		.EQ 0xF03-Ret	;Ram Offsets
Count	.EQ 0xF04-Ret
;
; these calcs done to fix the way SBASM does calculations.	
rAgain	.EQ Again-Ret-1
rStart 	.EQ Start-Ret-1

    .OR MOONSCAPE
; Graham's Moonscape
	.DB 0x9F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF9
	.DB 0x2F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF4
	.DB 0x4C,0x00,0x00,0x00,0x00,0x00,0x00,0x32
 	.DB 0x90,0x00,0x40,0x00,0x00,0x80,0x00,0x09
 	.DB 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x07
 	.DB 0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x07
	.DB 0xC0,0x00,0x00,0x04,0x00,0x00,0x00,0x03
	.DB 0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x23
	.DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
	.DB 0xC0,0x08,0x00,0x00,0x00,0x00,0x00,0x03
	.DB 0xC0,0x14,0x00,0x00,0x40,0x00,0x20,0x03
	.DB 0xC0,0x0E,0x00,0x00,0x00,0x08,0x00,0x03
	.DB 0xC0,0x5F,0x00,0x80,0x00,0x1C,0x00,0x03
	.DB 0xC0,0x2F,0x80,0x00,0x00,0x2E,0x00,0x03
	.DB 0xC1,0x1F,0xC0,0x00,0x00,0x1F,0x00,0x03
	.DB 0xC0,0x3F,0xE0,0x00,0x00,0xBF,0x80,0x03
	.DB 0xC4,0x5F,0xF0,0x00,0x00,0x7F,0xC0,0x03
	.DB 0xC0,0x3F,0xF8,0x04,0x02,0xFF,0xE0,0x03
	.DB 0xD0,0x5F,0xFC,0x00,0x01,0xFF,0xF0,0x03
	.DB 0xC0,0xBF,0xFE,0x00,0x0A,0xFF,0xF8,0x03
	.DB 0xC0,0x5F,0xFF,0x00,0x05,0xFF,0xFC,0x03
    .DB 0xC0,0xAF,0xFF,0x80,0x2B,0xFF,0xFE,0x03
    .DB 0xC0,0x5F,0xFF,0xC0,0x15,0xFF,0xFF,0x03
	.DB 0xC0,0x2F,0xFF,0xE0,0xAA,0xFF,0xFF,0x83
    .DB 0xC0,0x17,0xFF,0xF0,0x15,0x7F,0xFF,0xC3
    .DB 0xC0,0x2B,0xFF,0xF8,0x2A,0xFF,0xFF,0xE3
    .DB 0xE0,0x15,0xFF,0xFC,0x15,0x7F,0xFF,0xF7
    .DB 0xE0,0x0A,0xFF,0xFE,0x02,0xBF,0xFF,0xE7
    .DB 0x90,0x01,0x7F,0xFF,0x01,0x5F,0xFF,0x89
    .DB 0x4C,0x00,0x00,0x00,0x00,0x00,0x00,0x32
    .DB 0x2F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF4
    .DB 0x9F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF9

	; empty scape
    ; .DB 0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD
    ; .DB 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA
    ; .DB 0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x05
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03
    ; .DB 0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x05
    ; .DB 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA
    ; .DB 0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD

; ENTRY is the execution address that the Hex loader will use during program load
EXEC_ADR:	
	.OR 0xFFFE
	.DB ENTRY/256
	.DB ENTRY\256
	 