;---------------------------------------
;
; PSG test v1.0
;
;
; by drx [www.hacking-cult.org]
;
;---------------------------------------


Vectors:	dc.l $FFFE00,	Entrypoint,	Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l HBlank,	Error,		VBlank,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
		dc.l Error,	Error,		Error,	Error
Header:		dc.b 'SEGA MEGA DRIVE ' ; Console name
		dc.b '(C) DRX 2004.NOV' ; Copyright/Date
DomesticName:	dc.b 'PSG test by drx - www.hacking-cult.org          ' ; Domestic Name
		dc.b 'PSG test by drx - www.hacking-cult.org          ' ; International Name
		dc.b 'GM 00000000-00'   ; Version
Checksum:	dc.w $1337
					; Checksum
		dc.b 'J               ' ; I/O Support
RomStartLoc:	dc.l 0			; ROM Start
RomEndLoc:	dc.l RomEnd
					; ROM End
RamStartLoc:	dc.l $FF0000		; RAM Start
RamEndLoc:	dc.l $FFFFFF		; RAM End

		dc.b $20,$20,$20,$20	; 'RA',$F8,$20 if SRAM = on
		
SramStart:	dc.l $20202020		; $200000 if SRAM = on
SramEnd:	dc.l $20202020		; $20xxxx if SRAM = on
		
		dc.b '                                              ' ; Notes
		dc.b '      '
		dc.b 'JUE             ' ; Country

;---------------------
; Code start
;---------------------
		
Entrypoint:

		tst.l	($A10008).l		;Test Port A control
		bne	PortA_Ok

		tst.w	($A1000C).l		;Test Port C control

PortA_Ok:
		bne	SkipSetup

		move.b	($A10001).l,d0		;version
		andi.b	#$F,d0
		beq	SkipSecurity		;if the smd/gen model is 1, skip the security
		move.l	#'SEGA',($A14000).l

SkipSecurity:   

		move.w	($C00004).l,d0		;test if VDP works

		moveq	#0,d0
		movea.l	d0,a6
		move	a6,usp			;set usp to $0
		
;---------------------
; Setup VDP registers
;---------------------
		lea	(VDPSetupArray),a0
		move.w	#(VDPSetupArrayEnd-VDPSetupArray)/2,d1	;$18 VDP registers
		
VDPSetupLoop:
		move.w	(a0)+,($C00004).l
		dbf	d1,VDPSetupLoop
		
		
		move.l	#$40000080,($C00004).l
		move.w	#0,($C00000).l		;clean the screen
	
	
;---------------------
; Init the Z80
;---------------------	

		move.w	#$100,($A11100).l	;Stop the Z80
		move.w	#$100,($A11200).l	;Reset the Z80
		
Waitforz80:
		btst	#0,($A11100).l
		bne	Waitforz80		;Wait for z80 to halt
		
		lea	(Z80Init),a0
		lea	($A00000).l,a1
		move.w	#Z80InitEnd-Z80Init,d1
		
InitZ80:
		move.b	(a0)+,(a1)+
		dbf	d1,InitZ80
		
		move.w	#0,($A11200).l
		move.w	#0,($A11100).l		;Start the Z80
		move.w	#$100,($A11200).l
		
	
;---------------------
; Reset the RAM
;---------------------	

		lea	($FFFF0000).l,a0
		move.w	#$3fff,d1
		
ClearRAM:
		move.l	#0,(a0)+
		dbf	d1,ClearRAM
		
		
;---------------------
; VDP again
;---------------------			
		
		move.w	#$8174,($C00004).l
		move.w	#$8F02,($C00004).l
		
		
;---------------------
; Clear the CRAM
;---------------------	

		move.l	#$C0000000,($C00004).l	;Set VDP ctrl to CRAM write
		move.w	#$3f,d1
		
ClearCRAM:
		move.w	#0,($C00000).l
		dbf	d1,ClearCRAM
		
			
;---------------------
; Clear the VDP stuff
;---------------------		

		move.l	#$40000010,($C00004).l
		move.w	#$13,d1
		
ClearStuff:
		move.l	#0,($C00000).l
		dbf	d1,ClearStuff
		

;---------------------
; Init the PSG
;---------------------	

		move.b	#$9F,($C00011).l
		move.b	#$BF,($C00011).l
		move.b	#$DF,($C00011).l
		move.b	#$FF,($C00011).l
		
		
		move.w	#0,($A11200).l
		
		
;---------------------
; Load the z80 driver
;---------------------

		move.w	#$100,($A11100).l	;Stop the Z80
		move.w	#$100,($A11200).l	;Reset the Z80
		
Waitforz80a:
		btst	#0,($A11100).l
		bne	Waitforz80a		;Wait for z80 to halt
		
		lea	(Z80Driver),a0
		lea	($A00000).l,a1
		move.W	#Z80DriverEnd-Z80Driver,d1
		
LoadZ80Driver:
		move.b	(a0)+,(a1)+
		dbf	d1,LoadZ80Driver
		
		move.w	#0,($A11100).l		;Start the Z80
	
;---------------------
; Clear the registers
; and set the SR
;---------------------	

		movem.l	($FF0000).l,d0-a6	
		lea	($FFFE00).l,a7
		move	#$2700,sr

SkipSetup:	

	
;-----------------------
; Here starts your code
;-----------------------
Main:

		move.b	#10,d0
		move.b	#0,d1
		jsr	SetVol
		
		move.b	#10,d0
		move.b	#1,d1
		jsr	SetVol
				
		move.b	#10,d0
		move.b	#2,d1
		jsr	SetVol
		
		move.w	#$3ff,d7
FreqLoop:
		move.w	d7,d0
		move.b	#0,d1
		jsr	SetFreq
		
		move.w	#$3ff,d0
		sub.w	d7,d0
		move.b	#1,d1
		jsr	SetFreq
		
		move.w	d7,d0
		and.w	#$10,d0
		lsl.w	#4,d0
		move.b	#2,d1
		jsr	SetFreq
		
		move.b	#1,d0
		jsr	Sleep
		
		dbf	d7,FreqLoop
		

		jsr	ResetPSG

Loop:
		bra	Loop
		rts
		
ResetPSG:


		move.b	#$9F,($C00011).l
		move.b	#$BF,($C00011).l
		move.b	#$DF,($C00011).l
		move.b	#$FF,($C00011).l
		
		rts
				
;---------------------
; Set frequency
;
; d0 - frequency (0-$3ff)
; d1 - channel (0, 1, 2)
;---------------------		
SetFreq:

		move.b	d0,d2
		and.b	#$F,d2
		add.b	#$80,d2
		and.b	#$3,d1
		lsl.b	#$5,d1
		or.b	d1,d2
		move.b	d2,($C00011).l	;$80+channel<<5+(freq&$f)
		lsr.w	#$4,d0
		move.b	d0,($C00011).l	;freq>>4
		rts
		
;---------------------
; Set volume
;
; d0 - volume (0-$f)
; d1 - channel (0, 1, 2, 3)
;---------------------			
SetVol:
		and.b	#$F,d0
		and.b	#$3,d1
		moveq	#0,d2
		move.b	#$F,d2
		sub.b	d0,d2
		add.b	#$90,d2
		lsl.b	#$5,d1
		or.b	d1,d2
		move.b	d2,($C00011).l	;$90+channel<<5+($f-vol)
		rts
		

;---------------------
; Sleep
;
; d0 - sleep time (ms)
;---------------------

Sleep:
		move.l	#4193,d1
	
ms:
		sub.l	#1,d1
		bne	ms
		
		sub.l	#1,d0
		bne	Sleep
		
		rts


;---------------------
; Error exceptions
;---------------------

Error:
		rte
		
;---------------------
; Horizontal Blank
;---------------------
HBlank:

		rte
				
;---------------------
; Vertical Blank
;---------------------
VBlank:


		rte

;---------------------
; VDP registers array
;---------------------

VDPSetupArray:
		dc.w	$8004	;9-bit palette = 1 (otherwise would be 3-bit), HBlank = 0
		dc.w	$8134	;Genesis display = 1, DMA = 1, VBlank = 1, display = 0
		dc.w	$8230	;Scroll A - $C000
		dc.w	$8338	;Window   - $E000
		dc.w	$8407	;Scroll B - $E000
		dc.w	$857c	;Sprites  - $F800
		dc.w	$8600	;Unused
		dc.w	$8700	;Backdrop color - $00
		dc.w	$8800	;Unused
		dc.w	$8900	;Unused
		dc.w	$8A10	;H Interrupt register
		dc.w	$8B00	;Full screen scroll, no external interrupts
		dc.w	$8C81	;40 cells display
		dc.w	$8D3F	;H Scroll - $FC00
		dc.w	$8E00	;Unused
		dc.w	$8F02	;VDP auto increment
		dc.w	$9001	;64 cells scroll
		dc.w	$9100	;Window H position
		dc.w	$9200	;Window V position
		dc.w	$93FF	;DMA stuff (off)
		dc.w	$94FF	;DMA stuff (off)
		dc.w	$9500	;DMA stuff (off)
		dc.w	$9600	;DMA stuff (off)
		dc.w	$9780	;DMA stuff (off)
VDPSetupArrayEnd:


;---------------------
; Z80 init code
;---------------------

Z80Init:
	dc.w	$af01, $d91f, $1127, $0021, $2600, $f977 
	dc.w    $edb0, $dde1, $fde1, $ed47, $ed4f, $d1e1                                   
	dc.w    $f108, $d9c1, $d1e1, $f1f9, $f3ed, $5636
	dc.w	$e9e9 
Z80InitEnd:

;---------------------
; Music driver (z80)
;---------------------		

Z80Driver:
		dc.b	$c3,$46,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
		dc.b	$00,$00,$00,$00,$00,$f3,$ed,$56,$31,$00,$20,$3a,$39,$00,$b7,$ca,$4c,$00,$21,$3a,$00,$11,$40,$00,$01,$06,$00,$ed,$b0,$3e,$00,$32,$39,$00,$3e,$b4,$32,$02,$40,$3e,$c0,$32,$03,$40,$3e,$2b,$32,$00,$40,$3e,$80,$32,$01,$40,$3a,$43,$00,$4f,$3a,$44,$00,$47,$3e,$06,$3d
		dc.b	$c2,$81,$00,$21,$00,$60,$3a,$41,$00,$07,$77,$3a,$42,$00,$77,$0f,$77,$0f,$77,$0f,$77,$0f,$77,$0f,$77,$0f,$77,$0f,$77,$3a,$40,$00,$6f,$3a,$41,$00,$f6,$80,$67,$3e,$2a,$32,$00,$40,$7e,$32,$01,$40,$21,$40,$00,$7e,$c6,$01,$77,$23,$7e,$ce,$00,$77,$23,$7e,$ce,$00,$77
		dc.b	$3a,$39,$00,$b7,$c2,$4c,$00,$0b,$78,$b1,$c2,$7f,$00,$3a,$45,$00,$b7,$ca,$4c,$00,$3d,$3a,$45,$00,$06,$ff,$0e,$ff,$c3,$7f,$00
Z80DriverEnd:


RomEnd: