;; This source is part of the AY-3-8912 PSG additional notes document
;; and shows that it is possible to change the output latch data
;; when the corresponding port has been set to input.
;;
;; Example 1 showed that it is possible to write any 8-bit data to the output latch
;; and read it back. The test used port B as an example.
;;
;;
;; This example will setup a initial value in the output latch, set the port to input,
;; then attempt to write to the output latch. If the data has changed, then it is possible
;; to change the output latch when the port is set to input.
;; To read the output latch, we must set the port to output mode.

;; The code can be adjusted (as indicated below) to select either port
;; A or port B.
;;
;; Note: This test relies on the following facts:
;; - the input to port B is always &ff.
;; - the input to port A is &ff if NO key is pressed
;;
;; 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


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

;;-------------------------------------------------------------------------------
;; set port to output
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
or psg_port_mixer_enable
									;; set port A or B (depending on setting
									;; of psg_port_mixer_enable) to output
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