AY-3-8910 - can't write odd values to its registers? - Page 1
Forum section: electronics / projects

author: nockieboy
author_rank: Super Contributor
timestamp: February 26, 2019, 05:54:25 pm
content: Hi everyone,This is a pernicious problem that has me stumped - I've built an 8-bit sound card from my homebrew computer based on the AY-3-8910 PSG. Problem is, it's not working, at least it's not making music like it should do.I'm using a reference design for the LM386 amplifier stage and am not overly concerned about that at the moment - my problem lies with the PSG chip itself. For some unfathomable reason, I'm unable to write any odd values (bit 0 set) to any of the registers.I can read values from the registers, I can write even values to the registers and read them back just fine, but if I try to write an odd value to any of the registers, the chip just seems to ignore the write and returns its previous value when I next read it.I've checked the data bus to the chip and it seems to be fine. I'm getting values of FFh returned from the IO ports, which is correct as nothing is connected to them and they have internal pull-up resistors according to the documentation, so I'm happy that the data bus is okay and D0 is functioning in some capacity, unless I'm missing something.I've even swapped the chip out for a duplicate - same problem.Does anybody, anywhere, have a clue what might be going on or how I might go about finding the problem? Or have I missed something obvious in the datasheet where it says it only takes even values, and the sound distortion is being caused by a problem elsewhere downstream of the PSG?

author: radiolistener
author_rank: Super Contributor
timestamp: February 26, 2019, 06:32:19 pm
content: Quote from: nockieboy on February 26, 2019, 05:54:25 pmthis behavior has strong indication that there is something wrong with data line D0, check it's connection.Probably you just connected it to a different pin. Or mixed it with other signal

author: floobydust
author_rank: Super Contributor
timestamp: February 26, 2019, 06:33:20 pm
content: I would look at write bus timing including BC1 and BC2. It's a slow chip, write timing tDW is 500ns-10us (8910,8912) plus databus setup time and hold time. It's an NMOS IC and might have weak drive if your databus load is high.Otherwise, I can't see a reason for the LSB to not stick unless you are hitting the wrong registers."General Instruments did take orders for customized MSB bits (factory set to other than '0000'). The chips made with customize-set MSB register bits allow the same processor to control more than one AY chip on the same bus (e.g. Mockingboard sound card for Apple or TurboSound for ZX Spectrum). There are many new-old-stock (NOS) chips on the secondary market with MSB bits factory set to a non-'0000' value. The non-0000 value can cause significant developmental troubles for designers and repair technicians. Software must be written to identify the correct value of the MSB bits on any given chip. Also, software must be changed or hardware added to allow these factory set MSB chips to be used in place of the default '0000' chips."

author: nockieboy
author_rank: Super Contributor
timestamp: February 26, 2019, 08:04:57 pm
content: Quote from: radiolistener on February 26, 2019, 06:32:19 pmYes, this was the first thing I thought of as well - I've checked the entire data bus to the PSG and there's nothing wrong with it that I can detect. I'm seeing highs and lows on D0 via my oscilloscope as well.

author: radiolistener
author_rank: Super Contributor
timestamp: February 26, 2019, 08:12:33 pm
content: then may be there is short circuit of line D0 with some control line?Try to disconnect D0 from computer and connect it to the ground and Vcc, and check how it works in such mode.If there is some short circuit between D0 and control line, it will not work with D0 connected to the ground.Then you can find the location of short circuit.

author: nockieboy
author_rank: Super Contributor
timestamp: February 26, 2019, 08:15:57 pm
content: Quote from: floobydust on February 26, 2019, 06:33:20 pmHmm.. possibly. Thing is, this setup worked fine on the breadboard prototype - now I've got it on a proper PCB, the problem is showing itself. I guess this doesn't exclude timing issues, though. FWIW, the CPU is running at 4 MHz, but the clock for the PSG is halved to 2 MHz via a 7474 FF. I can quarter the clock speed down to 1 MHz by swapping a jumper, but that makes no difference to the problem it seems.Quote from: floobydust on February 26, 2019, 06:33:20 pmThese two chips worked just fine on the breadboard prototype, so there's no hardware masking going on. I'm testing the registers directly in my monitor program (the commands should be self-explanatory, although they're not assembler mnemonics, they're more akin to BASIC commands):Code:OUT &08,02 // Latch Register 2ReadyIN &08 // Read latched register (2)VALUE: 00 // Contains 00hReadyOUT &09,08 // Write 08h to latched register (2)ReadyIN &08 // Read latched register (2)VALUE: 08 // Contains 08h (write was successful)ReadyOUT &09,09 // Write 09h to latched register (2)ReadyIN &08 // Read latched register (2)VALUE: 08 // Still contains 08h....ReadyOUT &09,04 // Write 04h to latched register (2)ReadyIN &08 // Read latched register (2)VALUE: 04 // Contains 04hI can show you identical output for the other registers as well - none of them will accept odd values. :/

author: radiolistener
author_rank: Super Contributor
timestamp: February 26, 2019, 08:20:27 pm
content: if it works fine with even register address, I don't think that there is an issue with clock frequency.It looks like D0 line affects some other control line and it leads to such effect. So, there is most likely short circuuit of D0 with some other signal.

author: nockieboy
author_rank: Super Contributor
timestamp: February 26, 2019, 08:21:06 pm
content: Quote from: radiolistener on February 26, 2019, 08:12:33 pmI will test this further tomorrow when I break out the logic analyser and really go to town on the data bus and monitor an IO transaction, but I'm fairly happy there's no issue with D0 as I'm getting odd values back from the IO ports:Code:OUT &08,0EReadyIN &08VALUE: FFReadyIn the extract above, I'm selecting register OEh (IO Port A) which is returning a value of FFh. This is expected behaviour as Port A isn't connected to anything, so the internal pull-ups will give it a value of FFh. If there was an issue with the D0 line, I'd expect this to return F0h?

author: radiolistener
author_rank: Super Contributor
timestamp: February 26, 2019, 08:29:28 pm
content: Quote from: nockieboy on February 26, 2019, 08:21:06 pm0xFE to be exact, but D0 may have short circuit with some input control line. In such case it will not affect D0, but vice versa D0 value will affect some control line and it may prevent read/write operation for example.For example D0 may have short circuit wiht ~RESET line. In such case zero value on D0 will leads to reset AY8910.Another possible short circuit lines: BDIR, BC1, BC2 or something otherIf you have logic analyzer, you can connect it to control lines and check what happens exactly

author: nockieboy
author_rank: Super Contributor
timestamp: February 26, 2019, 08:59:08 pm
content: Quote from: radiolistener on February 26, 2019, 08:29:28 pmYes, my mistake.Quote from: radiolistener on February 26, 2019, 08:29:28 pmAh yes, good point. I'll take a look tomorrow and see what I can find - thanks for the direction!

author: nockieboy
author_rank: Super Contributor
timestamp: February 27, 2019, 01:01:27 pm
content: Okay.Here's the result and my analysis of the logic testing:Code:XORAOUT(AY_LATCH),A; Clear register 0psgrl_test:1LDA,$10; Value = $102OUT(AY_WRITE),A; Write $10 to register 03INA,(AY_READ); Port = RSEL/RD4LDA,$11; Value = $115OUT(AY_WRITE),A; Write $11 to register 06INA,(AY_READ); Port = RSEL/RD7JPpsgrl_test; LoopThe above logic analyser trace was produced using the above code (line numbered for ease of reference).I have an 8-channel logic analyser, so I have restricted the data bus analysis to the lower 5 bits and the values used in the test accordingly, so I can record BC1, BDIR and ~WR (direct from the Z80) as well.The first LOW in WR is line 2 of the code. BDIR goes HIGH, BC1 remains LOW for a WRITE operation to the PSG. The value on the data bus is 0x10, as loaded into the accumulator in line 1.Line 3 executes a READ operation on the PSG, signified by the LOW on BDIR and HIGH on BC1. The value read on the data bus is 0x10, which is correct.The next LOW on WR is line 5 of the code. A WRITE operation SHOULD be executed here, but it is not – BDIR remains LOW. The data bus correctly contains the value 0x11.So it's obviously performing a write to receive the first value of 0x10, and returning that value on a read, but when I try to write an odd value BDIR doesn't go high to signal a write to the PSG's register.I can't see how DQ0 (D0) would interfere with BDIR. The BDIR line from the 7402 (where WR is NOR'd with the chip select) doesn't go anywhere near DQ0 on the PCB!Here's a gratuitous snapshot of the relevant (I hope!) part of the schematic:EDIT: Something else I just noticed - there's no corresponding RD transaction after the attempt to write the odd value, either!

author: nick_d
author_rank: Regular Contributor
timestamp: February 27, 2019, 01:32:12 pm
content: You mentioned swapping out the sound chip -- did you try swapping out the Z80? An internal short between BDIR and D0 or similar could be causing this.cheers, Nick

author: nockieboy
author_rank: Super Contributor
timestamp: February 27, 2019, 02:17:19 pm
content: Quote from: nick_d on February 27, 2019, 01:32:12 pmSorry Nick, I don't understand? You think the Z80 may be at fault? I'm 99.9999% sure it's not the Z80. Everything else (including running CP/M) works fine.An internal short in the PSG may be the issue, I suppose, but I've tried it with two PSG chips - I would have thought it highly unlikely they'd both have the same problem, especially as the first one was working just fine in the breadboard prototype.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 27, 2019, 02:31:38 pm
content: Quote from: nockieboy on February 27, 2019, 01:01:27 pmHave you taken a look at the /(P=Q) signal from U4.1 when this happens?

author: radiolistener
author_rank: Super Contributor
timestamp: February 27, 2019, 03:14:29 pm
content: there is definitely something wrong with SN74F521, probably some input lines are incorrect.Unfortunately it's not clean what you put on the input of SN74F521.Try to check if D0 is connected to the input lines of SN74F521.

author: NivagSwerdna
author_rank: Super Contributor
timestamp: February 27, 2019, 03:49:32 pm
content: FWIW Here's a snippet of an old time Z80 and Sound Generator. Nothing special required but maybe it will trigger some thoughts

author: nockieboy
author_rank: Super Contributor
timestamp: February 27, 2019, 04:18:10 pm
content: Quote from: radiolistener on February 27, 2019, 03:14:29 pmThe IN_B_x inputs to the 521 are from a DIP switch block, with the lines pulled high through pull-ups or grounded if the switch is closed. They're all grounded except IN_B_2 to correspond to the 0x08-09 IO address space.Quote from: radiolistener on February 27, 2019, 03:14:29 pmThe 521 (and the address lines) are on one side of the PCB, the data lines are on the other - D0 doesn't go anywhere near the 521 or even the 7402 that generates the BDIR and BC1 signals.

author: nockieboy
author_rank: Super Contributor
timestamp: February 27, 2019, 04:20:26 pm
content: Quote from: SiliconWizard on February 27, 2019, 02:31:38 pmNooo.... sounds like a good idea, though. Will make some alterations to the test setup (will have to use D0-D3 and the extra line to record /(P=Q)) and let you know.UPDATE:Well, that doesn't make much sense but it gives me a couple more leads to check. Thanks for the pointer, SiliconWizard - it turns out that /(P=Q) isn't going low for the write of the odd value. It's not going low for the read afterwards either, which makes no sense to me, but I'll turn my attention to the 521 and its wiring now.As you can see above, /(P=Q) (let's call it PSG_SELECT) goes LOW with the two even-value operations - the WR and RD. But when I try to write an odd value, PSG_SELECT doesn't change at all...

author: radiolistener
author_rank: Super Contributor
timestamp: February 27, 2019, 04:30:36 pm
content: Quote from: nockieboy on February 27, 2019, 04:18:10 pmare you sure, there is no mistake? Check connections between sn74f521 pins and Z80 A1-A8 pins with multimeter.What is connected to ~OE line of sn74f521?Does it take into account ~IORQ line from Z80?

author: nockieboy
author_rank: Super Contributor
timestamp: February 27, 2019, 04:35:06 pm
content: Quote from: radiolistener on February 27, 2019, 04:30:36 pmHere's the full schematic for the PSG:The PCB is auto-routed, so unless I've bridged two lines somewhere with some horrendously inept soldering, I'm not expecting to find any problems with the lines, though I might have to start looking at them in more detail if I exclude all other possibilities.

author: radiolistener
author_rank: Super Contributor
timestamp: February 27, 2019, 04:39:21 pm
content: all looks good. May be there is some mistake with connection between PSG board and Z80

author: nockieboy
author_rank: Super Contributor
timestamp: February 27, 2019, 05:38:05 pm
content: Above is the latest trace. This time I'm looking at AQ0, WR and P=Q (PSG_SELECT) to confirm correct generation of BC1 and BDIR signals to the PSG. All looks to be fine.Next I'm going to see if I can hook up the 521 and see what the IN_B_x lines are doing - they should be constant throughout - then check the AQ address lines for the other half of the comparator input.UPDATE:So it seems AQ8 is pulsing high twice, corresponding to the WR and RD with the odd value. This could be a coincidence that these HIGHs on AQ8 are corresponding to the IN/OUT with odd values, but in any case will prevent /(P=Q) going low. I will disconnect AQ8 from the 521 and pull that pin LOW. Not sure why I connected it in the first place, tbh, there was no requirement for it - just a free pin.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 27, 2019, 06:12:55 pm
content: I take it that AQ8 is A8 from the Z80's address bus?IIRC, the Z80 only uses the lower 8 address bits for IN/OUT requests, so the upper 8 address bits may hold any value - I don't think this is specified. So don't use them for decoding IO accesses.

author: mikerj
author_rank: Super Contributor
timestamp: February 27, 2019, 06:29:07 pm
content: FWIW this is documented in the Z80 manual:OUT (n),AThe operandnis placed on the bottom half (A0 through A7) of the address bus to selectthe I/O device at one of 256 possible ports. The contents of the Accumulator (Register A)also appear on the top half (A8 through A15) of the address bus at this time. Then the bytecontained in the Accumulator is placed on the data bus and written to the selected peripheraldevice.OUT (C),rThe contents of Register C are placed on the bottom half (A0 through A7) of the addressbus to select the I/O device at one of 256 possible ports. The contents of Register B areplaced on the top half (A8 through A15) of the address bus at this time. Then the byte containedin registerris placed on the data bus and written to the selected peripheral device.Registerridentifies any of the CPU registers shown in the following table, which alsoshows the corresponding three-bitrfield for each that appears in the assembled objectcode.I'm almost certain some of the old Z80 machines used the value placed on the upper bits to simplify decoding.

author: radiolistener
author_rank: Super Contributor
timestamp: February 27, 2019, 06:33:21 pm
content: Quote from: SiliconWizard on February 27, 2019, 06:12:55 pmthats not true, Z80 uses all 16 address lines for IN/OUT operations.For non-prefixed IN/OUT operations, the high byte address is taken from register A.So, this code:Code:LD A,#AAOUT (#55),Ais equals to OUT (#AA55),#55For #ED prefixed IN/OUT operations, 16-bit address is taken from register BC.For example, ZX Spectum used address lines A14 and A15 for AY8910 port decoding.So it seems, that the issue happens just because topic starter uses address line A8 for port decoding and didn't set port address properly in the codeThere are 3 ways to fix it:1) set all 16 bits of the port address in the code properly. There is need to load high address byte into A.But since unprefixed OUT instructions uses A to store output value, and at the same time it uses A to store high byte of port address, you will not be able to use this instruction to write odd or even values (it will depends on jumper for 74f521 decoder)2) use #ed prefixed instruction to access port, and load all 16 bits of port address into BC3) just disconnect A8 from 74f521 and pull that pin to the ground or VCC (jumper also should be set properly)

author: nockieboy
author_rank: Super Contributor
timestamp: February 27, 2019, 06:36:50 pm
content: All sorted now.Yes, it was because of AQ8 - which is just A8 from the Z80 through a buffer.I'd misunderstood (or more likely forgotten) the operation of OUT (C),A - so it was the contents of the A register on A8-A15 that was throwing the address decode out for the PSG. It's working fine now that I've disconnected AQ8 from the 521 and grounded that pin.Thanks for your help and advice everyone - it's much appreciated.I'll probably be back later for problems with the analogue stage - still getting rubbish out of the speaker, but I've got some more testing I can do with that end before I worry everyone else with it.

author: nick_d
author_rank: Regular Contributor
timestamp: February 27, 2019, 11:14:44 pm
content: Good that you got it solved. The Z80's handling of A8-A15 for IO cycles is indeed quite weird, something that has been addressed in the Z180 by adding the IN0 and OUT0 instructions, though unfortunately they're longer and slower.To clarify my earlier suggestion I meant that the Z80 chip could have been damaged or faulty with a fault that only affected a subset of IO write cycles. But since you have other IO devices on the bus as you mention, that was unlikely.Anyway the A-Y chips are uber cool, I would LOVE to have a Mockingboard for my souped up Apple IIe some day!cheers, Nick

author: floobydust
author_rank: Super Contributor
timestamp: February 27, 2019, 11:31:21 pm
content: A last note, I think 74F inputs float low as opposed to 'LS and TTL which float high. This would affect your address select dipswitch circuit.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 28, 2019, 02:57:17 pm
content: Quote from: radiolistener on February 27, 2019, 06:33:21 pmI haven't used a Z80 in ages, hence the "IIRC"... and I didn't remember that. That's old memories, but I don't think I have ever used anything but the lower 8 bits for IN/OUT operations.That said, the upper 8 address bits with the OUT (n),A instruction kinda looks like a trick, since it will output the same byte on the data bus than on the upper 8 address bits. Could be put to use I guess, but that's kind of funky nonetheless.I downloaded the Z80 user manual to refresh memory (my own). What's somewhat confusing (and maybe why I, and probably others, have never thought of using the upper 8 address bits) is that, whereas it's indeed stated in the instruction set description, the /IORQ pin function description says ('Overview' section):QuoteSo I'm wondering whether this upper half trick wasn't added as an afterthought or something, and the manual not completely updated. Looks like I just learned a Z80 trick more than 20 years since I last used one.And in the OP's case, since he wasn't taking care of the upper half anyway, there was no reason to use anything but the lower half.Brings back fond memories!

author: radiolistener
author_rank: Super Contributor
timestamp: February 28, 2019, 04:16:51 pm
content: Quote from: SiliconWizard on February 28, 2019, 02:57:17 pmI was used Z80 a long time ago, there are a lot of different documentation about Z80, I don't remember exactly where this feature is described, but this is well known behavior and it works on all Z80 modifications and clones in the same way. This behavior was used in some ZX Spectrum programs for fast access to the port with 16-bit decoding. For example it is extensively used in demos from Code Busters group to access AY8910 which uses A14 and A15 lines for port address decoding.There is also one instruction that works in different way on different Z80 clones.OUT (BC),#00 writes #FF on some Z80 modifications and #00 on original Z80.But this instruction is undocumented.

author: nick_d
author_rank: Regular Contributor
timestamp: February 28, 2019, 09:50:39 pm
content: The IN/OUT (C),reg instruction has always treated the port address as 16 bit, it's really kind of a misnomer since it acts as (BC),reg. Based on the mnemonic which only refers to C, it could have been an unintentional feature but I believe it is a reliable one which works on all Z80. I would have to check whether 8080/8085 have this instruction and if so what they do with A8-A15.It's the IN/OUT (immed),reg which is the funky one as discussed. The behaviour of putting A on the bus seems to be an accident even though many rely on the behaviour as mentioned in the thread.That's why the Z180, which uses a quarter of the 00-FF space for the internal peripherals, uses the (C),reg form unchanged but adds the IN0/OUT0 (immed),reg instructions to do the right thing in 16 bit IO spaces without breaking Z80 compatibility. I never use the original funky versions on the Z180!cheers, Nick

author: radiolistener
author_rank: Super Contributor
timestamp: February 28, 2019, 11:07:17 pm
content: Quote from: nick_d on February 28, 2019, 09:50:39 pmno, this behavior is well known and works on all Z80 clones.Quote from: nick_d on February 28, 2019, 09:50:39 pmhm, I also never used Z180, but one time I tried to use it's code on Z80 and it seems to work ok.So I think they should be byte-compatible. Do you know what is the opcode of IN0/OUT0?Just want to check how it corresponds to Z80 opcode...Found some doc for Z180, it claims that Z180 also uses register A for A15..A8, the same as Z80:https://www.wfms.org/sb180/z180qa.pdfCode:A) 8080 type instructionIN A,(n) OUT (n),AA15-A8 ←AccIt also claims that the new instructions IN0/OUT0 uses zero for A15..A8. These instructions was added for on-chip peripherals.Code:D) Z180 original instructions which force A15-A8 to 0IN0 OUT0 OTIM OTIMR OTDM OTDMR TSTIOA15-A8 ←0Very interesting what is opcode for IN0/OUT0, because all non-prefixed opcodes already used by Z80. So I think Z180 uses some unused prefix for these instructionsUpdated: found it in z180 emulator source codehttps://github.com/lgblgblgb/xep128/blob/master/z80ex/z180ex.c0xED 0x08 : IN0 C,(n)0xED 0x09 : OUT0 (n),CFor Z80 these opcodes works as undocumented NOP