No, you need to generate wait states.
You could build it and try out with a Z80 clock speed of 4MHz - if that works you can go back to 8MHz and see what happens.
Wait states? Something new to learn about there!
Okay, so you're suggesting before I get too wrapped up in timings I should confirm it all works at 4MHz then try it at 8 as there's a chance it could still work and either way would save me a lot of hassle by not jumping the gun? I really need to change my methodology as I'm in too much of a rush to get it working all the time!
The only consideration I can think of is that the serial comms speed will need to be halved if I do that, otherwise it should be pretty straightforward, I'm hoping?
Will let you know how it goes!
This stretches the active length of the I/O cycle with an 8MHz CPU clock to about 550ns - which should be fine for the AY-3-8912.
If you don't want to slow all I/O cycles use a select signal generated from \$\small\overline{IORQ}\$ and relevant address lines rather than just \$\small\overline{IORQ}\$ as input to the 1st flip-flop.
CPSGOUT:
POP HL ; Get command line pointer
CALL GETBYTE ; Get 1-byte value from command line into E
LD HL,AYPWRITE ; Display the port write text
CALL MPRINT
LD A,E ; Load value into A
CALL PHEX ; Display it as a hexadecimal
LD A,'H' ; ...with an 'H' on the end
CALL TXA
; Set IOA to OUTPUT
LD A,07H ; Select address R7 (ENABLE register)
OUT (AY_LATCH),A ; Latch address R7
LD A,40H ;
OUT (AY_WRITE),A ; Set R7 to 40H (IOA set to output - bit 6 HIGH)
; Set value in IOA
LD A,0FH ; Load A with Register 16 (IO Port A)
OUT (AY_LATCH),A ; Latch Register 16 in PSG
LD A,E ; Load A with value from GETBYTE
OUT (AY_WRITE),A ; Write value to PSG
JP COMMAND ; Return to Direct Mode CLI
CPSGIN:
POP HL ; Dump command line pointer
LD HL,AYPREAD ; Display read text
CALL MPRINT
; Set IOA to INPUT
LD A,07H ; Select address R7 (ENABLE register)
OUT (AY_LATCH),A ; Latch address R7
LD A,0
OUT (AY_WRITE),A ; Set R7 to 0 (IOA set to input - bit 6 LOW)
; Read IOA
LD A,0FH ; Load A with Register 16
OUT (AY_LATCH),A ; Latch Register 16 in PSG
IN A,(AY_READ) ; Read register R15
CALL PHEX
LD A,'H'
CALL TXA
JP COMMAND ; Return to Direct Mode CLI
CPSGOUT:
POP HL ; Get command line pointer
CALL GETBYTE ; Get 1-byte value from command line
LD HL,AYPWRITE ; Display the port write text
CALL MPRINT
LD A,E ; Load value into A
CALL PHEX ; Display it...
LD A,'h' ; ...with an 'H' on the end
CALL TXA
; Set IOA to OUTPUT
LD A,$07 ; Select address R7 (select ENABLE register)
OUT (AY_LATCH),A ; Latch address R7
LD A,40H ;
OUT (AY_WRITE),A ; Set R7 to 40H (IOA set to output)
; Set value in IOA
LD A,0EH ; Load A with Register 16
OUT (AY_LATCH),A ; Latch Register 16 in PSG
LD A,E ; Load A with value
OUT (AY_WRITE),A ; Write value to PSG
JP COMMAND ; Return to Direct Mode CLI
CPSGIN:
POP HL ; Dump command line pointer
LD HL,AYPREAD ; Display read text
CALL MPRINT
; Set IOA to INPUT
LD A,$07 ; Select address R7 (select ENABLE register)
OUT (AY_LATCH),A ; Latch address R7
LD A,0
OUT (AY_WRITE),A ; Set R7 to 0 (IOA set to input)
; Read IOA
LD A,0EH ; Load A with Register 16
OUT (AY_LATCH),A ; Latch Register 16 in PSG
IN A,(AY_READ) ; Read register R15
CALL PHEX
LD A,'h'
CALL TXA
JP COMMAND ; Return to Direct Mode CLI
Can you post the exact arrangement for driving BDIR, BC1, BC2 and A8/9 if applicable?
BDIR | BC2 | BC1 | |
0 | 0 | 0 | Inactive |
0 | 0 | 1 | Latch address |
0 | 1 | 0 | Inactive |
0 | 1 | 1 | Read |
1 | 0 | 0 | Latch address |
1 | 0 | 1 | Inactive |
1 | 1 | 0 | Write |
1 | 1 | 1 | Latch address |
BDIR | BC2 | BC1 | |
0 | 0 | 0 | Inactive |
0 | 0 | 1 | Latch address |
1 | 0 | 0 | Latch address |
1 | 0 | 1 | Inactive |
Question though regarding the proposed solution - given my existing setup, would it be sufficient to take the inverted input to BC2 and connect that to A8, and instead pull BC2 high by connecting to Vcc?
That way, A8 will be held low all the time the PSG isn't being accessed (and, if I've read the manual right, should effectively disable the PSG). When the CPU wants to latch, read or write the PSG's registers, A8 will go high and the PSG will be available (as BC2 is permanently held high), leaving A0 and A1 to select the correct function through the BC1 and BDIR pins...?
That way I can save adding any extra logic chips and just swap a couple of wires...
EDIT: Hmm... no, that appears not to be working either.
I was going to say give it a go
The way I read the datasheet it wasn't completely clear that having A8 low deactivated the chip, rather than just the data bus buffers.
Edit: Though I suppose it should given the intended CPU interfacing. However to be certain I'd make sure that BDIR/BC1/BC2 are forced inactive when you don't want to talk to the chip.
LD A,$07 ; Select address R7 (select ENABLE register)
OUT (AY_LATCH),A ; Latch address R7
LD A,0
OUT (AY_WRITE),A ; Set R7 to 0 (IOA set to input)
; Read IOA
OUT (AY_LATCH),0DH ; Latch Register 14 in PSG
IN A,(AY_READ) ; Read register R14
Okay, this is how I've interpreted your solution, grumpydoc - I hope it's correct. Ironically, if I'm reading your solution properly, it means I can drop the inverter and replace it with the NOR gate, so the chip count remains the same.
Is this what you're suggesting? So long as ~Y1 and ~IORQ remain high, BC1 and BDIR will be low. But when the PSG is being accessed, ~Y1 and ~IORQ will go low, allowing either (or both) A0 and A1 to pass a high through to the PSG to read/write/latch as appropriate - am I right?
A low to high of WR is the Z80 normal transition. Here you have IORQ going high as a PSG write transition and end of PSG read. Again timing matters and needs to be checked
IORQ by it's self is not enough as IORQ goes low at other times then just IO read & write.
Ah, yes - I was forgetting something myself. IORQ is active with M1 to indicate an interrupt acknowledge so, yes, you are right as it stands there can still be problems. I get so used to running IORQ and M1 into the enable pins on I/O decode that I didn't think about this - Grant's design does not do so and you need to make sure that the select is not active if M1 is low.
Using A0 to drive the bus direction is unusual, certainly, and I would choose to use WR as I have said a couple of times but it would actually work - as long as one address is always used for read and one for write.
Ah, yes - I was forgetting something myself. IORQ is active with M1 to indicate an interrupt acknowledge so, yes, you are right as it stands there can still be problems. I get so used to running IORQ and M1 into the enable pins on I/O decode that I didn't think about this - Grant's design does not do so and you need to make sure that the select is not active if M1 is low.
I was wondering if something else was going on, but don't know enough about the system to have spotted it. One question I have about Grant's I/O decode design though - and it's been bugging me since I moved from the v1 (non-CP/M) SBC to the v2 one - and that's why doesn't he have IORQ and M1 going to the enable pins on the '138?
Anyhow - the SIO/2 is interrupt driven on the Rx side, so that's likely causing problems with the interrupt causing chaos with the PSG. So, another gate is required for the PSG select signal (currently ~Y1 and ~IORQ) to ensure the PSG is not active when M1 is low?
Using A0 to drive the bus direction is unusual, certainly, and I would choose to use WR as I have said a couple of times but it would actually work - as long as one address is always used for read and one for write.
I only went with using A0 and A1 as it was the first solution that sprang to mind with needing to be able to read, write AND latch using only 2 lines. If there's benefits to using ~WR instead of A1 (presumably) then let me know and I'll change the design - it's only a few equates I need to change in the assembly.
There is a lot about Grant's design I do not care for.
.... the common practice is to have two 138's used. One would have RD as final signal to enable 138 outputs, while other uses WR...
The above is built to expand while working with the Z80.
There are good reasons to have separate WR & RD signals like Z80 uses compared to one signal like some CPU's use. One problem is when is the combined RD/WR valid. With separate signals valid & signal are one.
Like I said
use IORQ & RD for IO Read
use IORQ & WR for IO Write.
and you will not need to worry about other times IORQ goes active with a good design.
When you do not do this then you have to worry more about things like PSG read driving data bus while the Z80 starts driving the data bus for next bus step..
Need to look real close if your logic can create a glitch.
For example PSG can go from idle to write mode with no actual write then read mode for a Z80 read.
It is BAD For example to have PSG go from idle to read mode then write mode for a Z80 write. You have Z80 & PSG both driving bus for a time.
Best to us RD to enable PSG to put data on Data bus.
Best to use WR to write data into PSG with the actual write happening on rise of WR
Edited to add Problem above
Okay guys, I have to admit to half of the conversation so far completely going over my head.
So I just need to redesign the interface, using ~WR and A0 for BDIR and BC1 respectively, and gate those two signals with ~IORQ and ~M1 somehow to ensure that BDIR and BC1 are held LOW, no matter what ~WR and A0 are doing, if ~M1 is LOW or ~IORQ is HIGH?
I should not leave out the Write to PSG time of 1950 ns.
I think what I would suggest is the following
Connect \$\small\overline{M1}\$ to the active high enable of the 138, OR together A6 and A7 and connect the resulting signal to one of the active low inputs to the 138, and connect \$\small\overline{IORQ}\$ to the other.
That will give you a set of clean I/O select lines to use and will not change the decoded address ranges.
Then gate A0 and \$\small\overline{WR}\$ to BC1 and BDIR as suggested, with BC2 and A8 tied high, A9 tied low.
That should give you clean signals to drive the sound chip - note that with BC1 and BDIR both low the AY-3-8912 buffers are high impedance so you don't need to use A8/A9 as additional chip selects.