
; SX-based video system for Z80 Project
; By Phil Ruston 27-8-2005
; V 0.09

; Changes...
; shifted display window left 8 pixels
; added a clear_cf to RLs in "data line" and "output pixels" - adjusted timing to suit
; fixed bug where right edge x_HWS timing compensator was not using cached HWS value

; Status:

;---------------------------------------------------------------------------------------------
;Chip Config......

DEVICE		SX28AC,TURBO,BANKS8,OSCHS2,SYNC,OPTIONX,IFBD
		
		;chip model, 1 instruction per clock, standard memory size
		;High Speed (external) oscillator, Synchronize inputs internally
		;Use standard 8 level stack, disable internal oscillator resistor
		;See docs for other settings

;----------------------------------------------------------------------------------------------

RESET		initialize	;address to jump to on reset / power up

;----------------------------------------------------------------------------------------------
IRC_CAL		IRC_SLOW	;not necessary - just stops a SASM warning
;----------------------------------------------------------------------------------------------
FREQ		32_000_000	;not necessary - for SXsim debugging only
;----------------------------------------------------------------------------------------------

;Some useful macros

SKIPIFZERO	macro
		SB status.2
		endm
SKIPNOTZERO	macro
		SNB status.2
		endm
SKIPONCARRY	macro
		SB status.0
		endm
SKIPNOCARRY	macro
		SNB status.0
		endm

CLEAR_CF	macro
		CLRB status.0
		endm

SET_CF		macro
		SETB status.0
		endm

FOUR_NOPS	macro
		NOP
		NOP
		NOP
		NOP
		endm

LINE_DATA_BYTE	macro
		mov w,#step_0_unc	
		mov RB,w
		mov w,#step_1_unc
		mov RB,w
		mov w,#step_2_unc
		mov RB,w
		mov w,#step_3_unc
		mov RB,w
		mov w,#step_4_unc
		mov RB,w
		mov w,#step_5_unc
		mov RB,w
		mov w,#step_6_unc
		mov RB,w
		mov w,#step_7_unc
		mov RB,w
		mov w,#step_8_unc
		mov RB,w
		mov w,#step_9_unc
		mov RB,w
		mov w,#step_a_unc
		mov RB,w
		mov w,#step_b_unc
		mov RB,w
		mov w,#step_c_unc
		mov RB,w
		mov w,#step_d_unc
		mov RB,w
		mov w,#step_e_unc
		mov RB,w
		mov w,#step_f_unc
		mov RB,w
		endm

;---------------------------------------------------------------------------------------------

; Project variables

counter1		EQU $08		;first global SRAM address 
counter2		EQU $09
loops			EQU $0A
temp			EQU $0B
temp2			EQU $0C
original_y_HWS		EQU $0D
y_HWS_bits		EQU $0E
x_HWS_cache		EQU $0F

; ----- PORT RA PINS --------		;all inputs
use_wide_border		equ 3
xy_hw_scroll_bit2	equ 2
xy_hw_scroll_bit1	equ 1
xy_hw_scroll_bit0	equ 0
;----------------------------

; ----- PORT RB PINS --------		;all outputs
parallel_load		equ 7
shift_clock		equ 6
step_reset		equ 5
x_mask			equ 4
y_mask			equ 3
data_fetch		equ 2
vram_address_a14	equ 1
vram_address_a13	equ 0
;----------------------------

;------- PORT RC PINS -------		;all outputs
HWS_input_select	equ 7
vert_retrace		equ 6
inhibit_video		equ 5
sync_line		equ 4
video_busy		equ 3
vram_address_a7		equ 2
vram_address_a6		equ 1
vram_address_a5		equ 0
;-----------------------------


step_0_cov	equ %00100000
step_1_cov	equ %10000000
step_2_cov	equ %11000000
step_3_cov	equ %10000000
step_4_cov	equ %11000001
step_5_cov	equ %10000001
step_6_cov	equ %11000001
step_7_cov	equ %10000001
step_8_cov	equ %11000010
step_9_cov	equ %10000010
step_a_cov	equ %11000010
step_b_cov	equ %10000010
step_c_cov	equ %11000011
step_d_cov	equ %10000011
step_e_cov	equ %11000011
step_f_cov	equ %10000011

step_0_unc	equ %00110000
step_1_unc	equ %10010000
step_2_unc	equ %11010000
step_3_unc	equ %10010000
step_4_unc	equ %11010001
step_5_unc	equ %10010001
step_6_unc	equ %11010001
step_7_unc	equ %10010001
step_8_unc	equ %11010010
step_9_unc	equ %10010010
step_a_unc	equ %11010010
step_b_unc	equ %10010010
step_c_unc	equ %11010011
step_d_unc	equ %10010011
step_e_unc	equ %11010011
step_f_unc	equ %10010011

final_step1	equ %10100111		;data_fetch off, x_mask: on, reset 4017 step to 0
final_step2	equ %10000111		;as above but reset 4017 step low again

;---------------------------------------------------------------------------------------------

		org $000

interrupt	NOP
		RETI			;interrupt routine here if required
		
;---------------------------------------------------------------------------------------------
; SX hardware setup

initialize	MOV W,#$0f		;Set all PORT A pins to inputs 
		MOV !RA,W
		MOV W,#$00		;Set all PORT B pins to outputs 
		MOV !RB,W
		MOV W,#$00		;Set all PORT C pins to outputs 
		MOV !RC,W
		
		MOV W,#%00000000	;Set PORT A defaults
		MOV RA,W			
		MOV W,#%10101100	;Set PORT B defaults
		MOV RB,W
		MOV W,#%00111000	;Set PORT C defaults
		MOV RC,W
		
		MOV M,#$0d		;Mode $0D = adjust voltage levels
		MOV W,#$00		;Set all ports to use CMOS levels
		MOV !RA,W
		MOV !RB,W
		MOV !RC,W

;-----------------------------------------------------------------------------------------------
; video system setup
		
		mov w,#$ff		;init vars
		mov original_y_HWS,w
		clr y_HWS_bits

		page $00
		jmp main_loop

;---------------------------------------------------------------------------------------------------
; Subroutines
;---------------------------------------------------------------------------------------------------


delay		mov counter2,w		;1	total delay = (w*4) + 8 cycles
delay_loop	decsz counter2		;1	(1 "load w", 3 for "call", 1 for "store loop count" 
		jmp delay_loop		;3	3 for "ret")
		nop			;1
		nop			;1
		ret			;3

;---------------------------------------------------------------------------------------------------

wait_n_us_1	mov counter1,w		;1	waits w microseconds LESS ONE CYCLE including "call",
		dec counter1		;1	"setup w" and "ret" ** minimum value = 2 **
countloop1	mov w,#5		;
		call delay		;28
		decsz counter1		;1
		jmp countloop1		;3
		mov w,#4		;
		call delay		;24
		ret			;3

;--------------------------------------------------------------------------------------------------

short_sync	clrb RC.sync_line	;1 cycle
		mov w,#2		;
		call wait_n_us_1	;
		setb RC.sync_line	;2 us
		mov w,#29		;
		call wait_n_us_1	;
		nop			;29 us		
		nop			;1 cycle
		mov w,#3		;
		call delay		;20 cycles
		ret			;3 cycles

;--------------------------------------------------------------------------------------------------

long_sync	clrb RC.sync_line	;1 cycle
		mov w,#30		;
		call wait_n_us_1	;
		setb RC.sync_line	;30 us
		mov w,#11		;
		call delay		;52 cycles
		nop			;1 cycle
		ret			;3 cycles

;---------------------------------------------------------------------------------------------------

blank_line	clrb RC.sync_line	;1 cycle
		mov w,#4		;
		call wait_n_us_1	;         sync pulse
		setb RC.sync_line	;4 us
		mov w,#8		;
		call wait_n_us_1	;         back porch
		clrb RC.inhibit_video	;8 us	
		setb RB.y_mask		;1
		mov w,#51		;
		call wait_n_us_1	;
		nop			;51 us
		
		mov w,RC		;1	zero pixel line address bits 0-2
		and w,#%11111000	;1	prevents row advance glitch when
		or w, #%00100000	;1	bit 2 goes 1->0 on y-hws change
		mov RC,w		;1 4 cycles	

		mov w,#2		;
		call delay		;16 cycles
		ret			;3 cycles    63 us + 28 cycles (inc originating call)

;--------------------------------------------------------------------------------------------------

data_line	clrb RC.sync_line	;1 cycle (accounted for at end)		
		mov w,#$4		;			<------SYNC------- 
		call wait_n_us_1	;         		!   4 us total
		setb RC.sync_line	;			<------------------

		call set_up_line	;3 + 204 = 207         	<----BACK PORCH----
		mov w,#10		;			!   8 us total
		call delay		;48 cycles		! 
		clrb RC.inhibit_video	;1			<------------------

		mov w,#7		;			<----LEFT BORDER---
		call wait_n_us_1	;			!    7 us total
		clrb RC.video_busy	;			<------------------
	
		mov w,#5		;			
		call delay		;28 cycles		
		page $200		;1  cycle		<--- DATA FETCH ---
		jmp output_pixels	;3 (+ 1120)		!    36 us total
					;			<------------------

end_data_line	setb RC.video_busy	;1
		mov w,#8		;			<----RIGHT BORDER---
		call wait_n_us_1	;7 us			!    8 us total
		FOUR_NOPS		;4			!
		setb RC.inhibit_video	;1	                ! plus 28 cycles inc
		mov w,#2		;                       ! (originating call)
		call delay		;16 cycles              !
		ret			;3 cycles		<-------------------

;-------------------------------------------------------------------------------------------------

; check to see if y-hws value has changed

set_up_line	clrb RC.HWS_input_select	;1	- switch to vertical hardware scroll bits
		FOUR_NOPS			;4	- allow switch propagation time
		mov w,RA			;1	- read y HWS value
		and w,#7			;1	
		mov temp,w			;1
		xor w,original_y_HWS		;1
		skipifzero			;1(2)
		jmp y_hws_changed		;3(0)
		mov w,RC			;1	- no change: present the mirrored y-hws bits
		and w,#%11111000		;1	- to the VRAM line address
		or w,y_hws_bits			;1
		mov RC,w			;1
		nop				;1	- condition time adjustment
		nop				;1	- condition time adjustment
		jmp yhws_no_change		;3
y_hws_changed	mov w,RC			;1
		and w,#%1111000			;1
		or w,temp			;1
		mov RC,w			;1	- vram address bits 5-7 updated
		mov w,temp			;1
		mov original_y_HWS,w		;1	
		mov y_HWS_bits,w		;1      - 20 cycles

; set up mask positions based on x-hws value

yhws_no_change	setb RC.HWS_input_select	;1	- switch to horizontal hardware scroll bits
		FOUR_NOPS			;4	- allow switch propagation time
		mov w,RA			;1	- create mask uncover and cover positions
		and w,#7			;1	
  		mov temp,w			;1	- (bit 4 in step bytes)
		mov x_HWS_cache,w		;1
		CLEAR_CF			;1
		rl temp				;1
		inc temp			;1 	- 12 cycles
		
		mov w,#$10			;1
		sb RA.use_wide_border		;
		mov temp,w			;2		
		bank $10				
		mov w,temp			
		inc temp
		and w,#$10
		or w,#step_0_cov		
		mov $10,w			
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_1_cov
		mov $11,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_2_cov
		mov $12,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_3_cov
		mov $13,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_4_cov
		mov $14,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_5_cov
		mov $15,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_6_cov
		mov $16,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_7_cov
		mov $17,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_8_cov
		mov $18,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_9_cov
		mov $19,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_a_cov
		mov $1a,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_b_cov
		mov $1b,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_c_cov
		mov $1c,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_d_cov
		mov $1d,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_e_cov
		mov $1e,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_f_cov
		mov $1f,w			; 84 cycles	

		mov w,#$10			;1
		sb RA.use_wide_border		;
		mov temp,w			;2	
		bank $30			
		mov w,temp				
		inc temp
		and w,#$10
		or w,#step_0_cov		
		mov $30,w			
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_1_cov
		mov $31,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_2_cov
		mov $32,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_3_cov
		mov $33,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_4_cov
		mov $34,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_5_cov
		mov $35,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_6_cov
		mov $36,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_7_cov
		mov $37,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_8_cov
		mov $38,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_9_cov
		mov $39,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_a_cov
		mov $3a,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_b_cov
		mov $3b,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_c_cov
		mov $3c,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_d_cov
		mov $3d,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_e_cov
		mov $3e,w
		mov w,temp
		inc temp
		and w,#$10
		or w,#step_f_cov
		mov $3f,w			; 84 cycles,
		bank 0
		ret				; 3 cycles - 204 in all

;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------

main_loop:	mov w,#56		;1
		mov loops,w		;1
top_border	call blank_line		;
		decsz loops		;
		jmp top_border		;loop 2048 cycles, last pass = 2046 cycles

;-------------------------------------------------------------------------------------------------
	
		mov w,#192		;1
		mov loops,w		;1
display_area	call data_line		;
		decsz loops		;
		jmp display_area	;loop 2048 cycles, last pass = 2046 cycles

;-------------------------------------------------------------------------------------------------

		mov w,#56		;1
		mov loops,w		;1
bottom_border	call blank_line		;
		decsz loops		;
		jmp bottom_border	;loop 2048 cycles, last pass = 2046 cycles

;-------------------------------------------------------------------------------------------------

		mov w,#6		;1          vertical sync pulses
		mov loops,w		;1
sync_train1	call short_sync		;
		decsz loops		;
		jmp sync_train1		;loop 1024 cycles, last pass = 1022 cycles

		mov w,#5		;1
		mov loops,w		;1
sync_train2	call long_sync		;
		decsz loops		;
		jmp sync_train2		;loop 1024 cycles, last pass = 1022 cycles

		mov w,#4		;1
		mov loops,w		;1
sync_train3	call short_sync		;
		decsz loops		;
		jmp sync_train3		;loop 1024 cycles, last pass = 1022 cycles
		nop			;1
		nop			;1
		
		setb RC.vert_retrace	;1 \  non-subroutine last sync code here to save a cycle for loop JMP 
		nop			;1  > 3 cycles equivalent time to a call
		nop			;1 /
		clrb RC.sync_line	;1 cycle
		mov w,#2		;
		call wait_n_us_1	;
		setb RC.sync_line	;2 us
		mov w,#29		;
		call wait_n_us_1	;
		nop			;29 us		
		mov w,#3		;
		call delay		;20 cycles
		nop			;1 cycle
		nop			;1 cycle
		clrb RC.vert_retrace	;1 cycle	
		JMP main_loop		;3 cycles - so 30 cycles in all, ready for 2 cycles at start of main_loop

;=================================================================================================

		org $200
		
output_pixels	mov w,/x_HWS_cache		;1	- get the x HWS bits that were used to make the line  
		and w,#7			;1
		mov temp,w			;1
		CLEAR_CF			;1
		rl temp				;1
		mov w,<<temp			;1
		jmp pc+w			;3     = n cycles overhead plus (0,4,8,12,16,20,24,28 based on x_hws)
		FOUR_NOPS			;x hws = 7		
		FOUR_NOPS			;x hws = 6
		FOUR_NOPS			;x hws = 5
		FOUR_NOPS			;x hws = 4
		FOUR_NOPS			;x hws = 3
		FOUR_NOPS			;x hws = 2
		FOUR_NOPS			;x hws = 1


		mov w,#step_0_cov		;covered first byte data fetch area
		mov RB,w			;for byte 0 below
		mov w,#step_1_cov
		mov RB,w
		mov w,#step_2_cov
		mov RB,w
		mov w,#step_3_cov
		mov RB,w
		mov w,#step_4_cov
		mov RB,w
		mov w,#step_5_cov
		mov RB,w
		mov w,#step_6_cov
		mov RB,w
		mov w,#step_7_cov
		mov RB,w
		mov w,#step_8_cov
		mov RB,w
		mov w,#step_9_cov
		mov RB,w
		mov w,#step_a_cov
		mov RB,w
		mov w,#step_b_cov
		mov RB,w
		mov w,#step_c_cov
		mov RB,w
		mov w,#step_d_cov
		mov RB,w
		mov w,#step_e_cov
		mov RB,w
		mov w,#step_f_cov
		mov RB,w

		mov w,$10		;variable mask area (data display starts here for no x-hws)
		mov RB,w
		mov w,$11
		mov RB,w
		mov w,$12
		mov RB,w
		mov w,$13
		mov RB,w
		mov w,$14
		mov RB,w
		mov w,$15
		mov RB,w
		mov w,$16
		mov RB,w
		mov w,$17
		mov RB,w
		mov w,$18
		mov RB,w
		mov w,$19
		mov RB,w
		mov w,$1a
		mov RB,w
		mov w,$1b
		mov RB,w
		mov w,$1c
		mov RB,w
		mov w,$1d
		mov RB,w
		mov w,$1e
		mov RB,w
		mov w,$1f
		mov RB,w

		LINE_DATA_BYTE		;byte1
		LINE_DATA_BYTE
		LINE_DATA_BYTE
		LINE_DATA_BYTE

		LINE_DATA_BYTE		;byte 5
		LINE_DATA_BYTE
		LINE_DATA_BYTE
		LINE_DATA_BYTE

		LINE_DATA_BYTE		;byte 9
		LINE_DATA_BYTE
		LINE_DATA_BYTE
		LINE_DATA_BYTE

		LINE_DATA_BYTE		;byte 13
		LINE_DATA_BYTE
		LINE_DATA_BYTE
		LINE_DATA_BYTE

		LINE_DATA_BYTE		;byte 17
		LINE_DATA_BYTE
		LINE_DATA_BYTE
		LINE_DATA_BYTE

		LINE_DATA_BYTE		;byte 21
		LINE_DATA_BYTE
		LINE_DATA_BYTE
		LINE_DATA_BYTE

		LINE_DATA_BYTE		;byte 25
		LINE_DATA_BYTE
		LINE_DATA_BYTE
		LINE_DATA_BYTE

		LINE_DATA_BYTE		;byte 29
		
		mov w,#step_0_unc	;byte 30 
		mov RB,w
		mov w,#step_1_unc
		mov RB,w
		mov w,#step_2_unc
		mov RB,w
		mov w,#step_3_unc
		mov RB,w
		mov w,#step_4_unc
		mov RB,w
		mov w,#step_5_unc
		mov RB,w
		mov w,#step_6_unc
		mov RB,w
		mov w,#step_7_unc
		mov RB,w
		mov w,#step_8_unc
		mov RB,w
		mov w,#step_9_unc
		mov RB,w
		mov w,#step_a_unc
		mov RB,w
		mov w,#step_b_unc
		mov RB,w
		mov w,#step_c_unc
		mov RB,w
		mov w,#step_d_unc
		mov RB,w
		mov w,#step_e_unc
		mov RB,w
		bank $30			
		clrb RB.shift_clock	;step f replacement due to above line	

		mov w,$30		;byte 31 - variable mask area for right edge of line
		mov RB,w
		mov w,$31
		mov RB,w
		mov w,$32
		mov RB,w
		mov w,$33
		mov RB,w
		mov w,$34
		mov RB,w
		mov w,$35
		mov RB,w
		mov w,$36
		mov RB,w
		mov w,$37
		mov RB,w
		mov w,$38
		mov RB,w
		mov w,$39
		mov RB,w
		mov w,$3a
		mov RB,w
		mov w,$3b
		mov RB,w
		mov w,$3c
		mov RB,w
		mov w,$3d
		mov RB,w
		mov w,$3e
		mov RB,w
		mov w,$3f
		mov RB,w
		mov w,#final_step1		;pixel 255 appears upon this instruction (due to lag)
		mov RB,w			
		mov w,#final_step2		;latch colour 0 
		mov RB,w
		mov w,#final_step1		;"pixel 256" (border) appears upoon this instruction
		mov RB,w			;(33 x 32) + 6 = 1062 cycles

		page $600			;1	PAGE $600 -as that's where we are by now
		mov w,/x_HWS_cache		;1	make data fetch take same time no matter 
		and w,#7			;1	what hardware scroll value
		mov temp,w			;1
		inc temp			;1      5 cycles overhead plus 4,8,12,16,20,24,28,32 for x_hws
realign_loop	decsz temp			;1 (2)
		jmp realign_loop		;3 (0)	
		nop				;1
		nop				;1

		MOV w,++y_HWS_bits		;1	advance a pixel line
		AND w,#7			;1
		MOV y_HWS_bits,w		;1
		NOP				;1
		FOUR_NOPS			;4     8 cycles

		page 0				;1      
		jmp end_data_line		;3      4 cycles  (TOTAL 1120 cycles = 35 us)

==================================================================================================================

		END
