;; This source is part of the AY-3-8912 PSG additional notes document
;; and shows:
;;
;; when the port is set to output and the output latch is read, the data
;; that is returned is modified by the input data, and the modification is a logical AND.
;;
;; This code is designed for port A only. 
;;
;; - On the Amstrad CPC, port A is connected to the keyboard.
;; - On the Amstrad CPC, port B is not connected and always has a input of 0x0ff.
;;   (this is confirmed in example 3)
;;
;; This example is for the Amstrad CPC and also shows how
;; to read/write data from the PSG.
;;
;; This example can be assembled using Maxam or compatible assembler.
;;
;; assemble, then jump to &8000 to begin
;;
;; (c) Kevin Thacker 2001,2002
;;
;; This source is released under the GNU Public License v2.

;; this is the index of the PSG port register to test
;; (14 for PSG port A, 15 for PSG port B)

;; comment this line to test port A
;; uncomment this line to test port B
.psg_port_register		equ		15

;; comment this line to test port B
;; uncomment this line to test port A
;;.psg_port_register		equ		14



;; comment this line to test port A
;; uncomment this line to test port B
.psg_port_mixer_enable	equ		%10000000

;; comment this line to test port B
;; uncomment this line to test port A
;;.psg_port_mixer_enable	equ		%01000000

org &8000

;; firmware function to display ASCII character on the screen at the current
;; text cursor location
.txt_output		equ &bb5a

;; disable interrupts
;; (do not let CPC firmware effect this test)
di

;;-------------------------------------------------------------------------------
;; set port A to output
ld c,7								;; PSG mixer register
ld a,%11111111						;; port A output, port B output
									;; disable noise for channels A,B and C
									;; disable tone for channels A,B and C
call write_reg

;;-------------------------------------------------------------------------------
;; write &ff into output latch of port. From example 1 we have proved that this 
;; will store data into the output latch.
ld c,psg_port_register
ld a,&ff
call write_reg

;;-------------------------------------------------------------------------------
;; set port to input
ld c,7								;; PSG mixer register
ld a,%00111111						;; port A input, port B output
									;; disable noise for channels A,B and C
									;; disable tone for channels A,B and C
call write_reg

;;-------------------------------------------------------------------------------
;; write 10 into output latch of port. If the data is written to the output latch,
;; then it will change from &ff (the value written above) to 10 (the new value).
ld c,psg_port_register
ld a,10
call write_reg

;;-------------------------------------------------------------------------------
;; set port to output
ld c,7
ld a,%00111111
or psg_port_mixer_enable
call write_reg

;;-------------------------------------------------------------------------------
;; now read the output latch
ld c,psg_port_register
call read_reg

;; enable interrupts
ei

;; display contents of register A as hex
call print_hex_number
ret




;;-------------------------------------------------------------------------------
;; display a number as hex 
;;
;; Entry Conditions:
;;
;; A = number (0-255)
;;
.print_hex_number
push af

;; transfer upper nibble into lower nibble
rrca
rrca
rrca
rrca
;; display nibble
call print_digit
pop af
;; display lower nibble

;; print a hex digit on the screen
.print_digit
;; mask off lower bits 3..0
and &f
;; convert number (0-15) to ASCII character "0","1"..."9","A"..."F"
add a,"0"
cp "0"+10
jr c,pd2
add a,"A"-"0"-10
.pd2
;; display ASCII char on screen
jp txt_output



;;------------------------------------------------
;; Read from a AY-3-8912 register
;;
;; Entry conditions:
;;
;; C = register number
;; PPI port A is assumed to be set to output.
;; PSG operation is assumed to be "inactive"
;;
;; Exit conditions:
;;
;; A = register data
;; BC corrupt
;;
;; This function is compatible with the CPC+.

.read_reg

;; step 1 - select register

;; write register index to PPI port A
ld b,&f4
out (c),c

;; set PSG operation -  "select register"
ld bc,&f6c0
out (c),c

;; set PSG operation -  "inactive"
ld bc,&f600
out (c),c

;; PPI port A set to input, PPI port B set to input,
;; PPI port C (lower) set to output, PPI port C (upper) set to output
ld bc,&f700+%10010010
out (c),c

;; set PSG operation -  "read register data"
ld bc,&f640
out (c),c

;; step 2 - read data from register

;; read PSG register data from PPI port A
ld b,&f4
in a,(c)

;; PPI port A set to output, PPI port B set to input,
;; PPI port C (lower) set to output, PPI port C (upper) set to output
ld bc,&f700+%10000010
out (c),c

;; set PSG operation -  "inactive"
ld bc,&f600
out (c),c
ret

;;------------------------------------------------
;; Write to a AY-3-8912 register
;;
;; Entry conditions:
;;
;; C = register number
;; A = data 
;; PPI port A is assumed to be set to output.
;; PSG operation is assumed to be "inactive"
;;
;; Exit conditions:
;;
;; BC corrupt
;;
;; This function is compatible with the CPC+.

.write_reg

;; step 1 - select register

;; write register index to PPI port A
ld b,&f4
out (c),c

;; set PSG operation -  "select register"
ld bc,&f6c0
out (c),c

;; set PSG operation -  "inactive"
ld bc,&f600
out (c),c

;; step 2 - write data to register 

;; write data to PPI port A
ld b,&f4
out (c),a

;; set PSG operation -  "write data to register"
ld bc,&f680
out (c),c

;; set PSG operation -  "inactive"
ld bc,&f600
out (c),c
ret