Noob question: Tri-state logic chaos and system startup
Noob question: Tri-state logic chaos and system startup
Hello! I'm Aaron -- First post! Woo-hoo!
I'm not a credentialed EE, just an enthusiastic electronics hobbyist who's worked with microcontrollers for a while and has finally resolved to take on 6502 project. I've got what I believe to be a good (if somewhat weird) design worked out, but my question is far more general and perhaps eye-rollingly noobish. Here goes:
So, my memory system comprises an assortment of buffer and register ICs with tri-state outputs and output-enable (OE) pins. The OE signals to each IC are, according to the address decoding logic, mutually exclusive. That is, only one OE should be asserted at any time. OE is further predicated on Phi2, the period of which is a massive ~560ns in this design, so there's no way that the outputs of one IC could still be driven when another IC takes over. I see no potential for bus conflicts during actual system operation.
...but what about at system startup? It seems likely that, for some tens of ns--perhaps longer--after power is applied, the OE signals of multiple ICs may be effectively asserted because the controlling logic isn't "awake" yet and hasn't had time to de-assert them (and de-asserting takes some time, too). So multiple ICs may be putting conflicting garbage onto the data bus. Is this just...ok? Too brief of an event to be damaging? I'm guessing so. I noticed that the TI datasheets for "AC" series logic mention putting pull-up resistors on the OE pins to ensure high-Z at startup (even that makes me scratch my head a bit), but I'm using "HC" series logic and there's no such warning in the datasheets for those parts. Further, I don't see pull-ups used for this sort of thing in any example schematics, or indeed in schematics of commercially-sold 6502-based equipment. *shrug*
I suppose it's possibly silly to worry about something that only happens for tens of ns and only during system startup, but...these are the sorts of things that irritate me and make me realize that I'm missing some obvious rule-of-thumb or something.
...Thanks for reading!
I'm not a credentialed EE, just an enthusiastic electronics hobbyist who's worked with microcontrollers for a while and has finally resolved to take on 6502 project. I've got what I believe to be a good (if somewhat weird) design worked out, but my question is far more general and perhaps eye-rollingly noobish. Here goes:
So, my memory system comprises an assortment of buffer and register ICs with tri-state outputs and output-enable (OE) pins. The OE signals to each IC are, according to the address decoding logic, mutually exclusive. That is, only one OE should be asserted at any time. OE is further predicated on Phi2, the period of which is a massive ~560ns in this design, so there's no way that the outputs of one IC could still be driven when another IC takes over. I see no potential for bus conflicts during actual system operation.
...but what about at system startup? It seems likely that, for some tens of ns--perhaps longer--after power is applied, the OE signals of multiple ICs may be effectively asserted because the controlling logic isn't "awake" yet and hasn't had time to de-assert them (and de-asserting takes some time, too). So multiple ICs may be putting conflicting garbage onto the data bus. Is this just...ok? Too brief of an event to be damaging? I'm guessing so. I noticed that the TI datasheets for "AC" series logic mention putting pull-up resistors on the OE pins to ensure high-Z at startup (even that makes me scratch my head a bit), but I'm using "HC" series logic and there's no such warning in the datasheets for those parts. Further, I don't see pull-ups used for this sort of thing in any example schematics, or indeed in schematics of commercially-sold 6502-based equipment. *shrug*
I suppose it's possibly silly to worry about something that only happens for tens of ns and only during system startup, but...these are the sorts of things that irritate me and make me realize that I'm missing some obvious rule-of-thumb or something.
...Thanks for reading!
- BigDumbDinosaur
- Posts: 9426
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: Noob question: Tri-state logic chaos and system startup
Aaron wrote:
Hello! I'm Aaron -- First post! Woo-hoo!
Quote:
...but what about at system startup? It seems likely that, for some tens of ns--perhaps longer--after power is applied, the OE signals of multiple ICs may be effectively asserted because the controlling logic isn't "awake" yet and hasn't had time to de-assert them (and de-asserting takes some time, too).
x86? We ain't got no x86. We don't NEED no stinking x86!
Re: Noob question: Tri-state logic chaos and system startup
Indeed, welcome!
Broadly, I'd say yes, the conflict, if any, is going to be too short to be problematic - if you're using logic gates. If you'd built your glue logic out of an FPGA, then it will take some fractions of a second to load its configuration, so that might be a different case. (But note that FPGA pins are all inputs at reset time, and therefore external resistors could set appropriate values.) Similarly if you built the glue logic with a Propeller or a PIC or other microcontroller, startup might take some little time.
But note that other things also take time: the time for the power rail to ramp up, and the time for a crystal oscillator to start oscillating. I would guess tens of milliseconds for both.
Broadly, I'd say yes, the conflict, if any, is going to be too short to be problematic - if you're using logic gates. If you'd built your glue logic out of an FPGA, then it will take some fractions of a second to load its configuration, so that might be a different case. (But note that FPGA pins are all inputs at reset time, and therefore external resistors could set appropriate values.) Similarly if you built the glue logic with a Propeller or a PIC or other microcontroller, startup might take some little time.
But note that other things also take time: the time for the power rail to ramp up, and the time for a crystal oscillator to start oscillating. I would guess tens of milliseconds for both.
- BigDumbDinosaur
- Posts: 9426
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
Re: Noob question: Tri-state logic chaos and system startup
BigEd wrote:
Broadly, I'd say yes, the conflict, if any, is going to be too short to be problematic - if you're using logic gates. If you'd built your glue logic out of an FPGA, then it will take some fractions of a second to load its configuration, so that might be a different case. (But note that FPGA pins are all inputs at reset time, and therefore external resistors could set appropriate values.) Similarly if you built the glue logic with a Propeller or a PIC or other microcontroller, startup might take some little time.
Quote:
But note that other things also take time: the time for the power rail to ramp up, and the time for a crystal oscillator to start oscillating. I would guess tens of milliseconds for both.
POC V1.1 used discrete logic and never caused any undefined behavior while reset was low.
x86? We ain't got no x86. We don't NEED no stinking x86!
Re: Noob question: Tri-state logic chaos and system startup
Thank you both for the kind welcome and the quick replies!
Yes! Schematic below. (My reply is delayed because I hadn't drawn one yet. It was just handwritten notes and thoughts.) I suppose "startup" was ambiguous. I should have said "power on." I wasn't referring to the reset time, but rather to the time between when power is first applied to the circuit and the time the logic gates find valid states.
...although I suppose the same concern (if real) would apply during operation as well--for example, if as some posts advise, one chooses not to pay attention to Phi2 for read-only devices. But if you have multiple ROMs in your system and a decoder (e.g. 74HC138) supplying the output-enables, might not a transition between two addresses lead to momentary "conflicts" on the bus if the transition causes one device to be selected and another to be deselected? I suppose this is a scenario that would suggest pull-ups on the OE pins (to hasten their disabling)? I see that being done in some circuits, though mainly for the 65xx peripheral ICs (Here's an example where this is done for the 6551 and others.) This isn't a situation that applies to my own circuit, I don't think, as it's easy enough for me to pay attention to Phi2, and my whole external memory system is read-only besides. (More on that down below.)
That's sort of what I thought, and I don't see people designing to avoid it. It feels like one of those "just don't worry about it" situations, but I couldn't help asking. No programmable logic in this circuit, no. Just 74HCxxx.
Here's the requested schematic: Doubtless this looks pretty strange, so here's the overdue explanation: The CPU in use is actually a Ricoh RP2A03G, the customized 6502 found in the Nintendo Entertainment System. The goal of this circuit is to give an MCU (Arduino) easy control of the internal audio functions of the 2A03, which are mapped internally at addresses $40xx. The MCU will (hopefully) just clock the data it wants to write into the BYTE4 flip-flop (IC5), clock the address offset xx into the BYTE6 flip-flop (IC6), and then assert NMI. The 2A03 should then perform the desired write.
The diode matrix implements the following code:
$0000: JMP $0000
$0003: LDA #$xx ; operand xx is supplied by the BYTE4 flip-flop
$0005: STA $40xx ; operand xx is supplied by the BYTE6 flip-flop
$0008: RTI
$000A: $03 ; this is the low byte of the NMI vector. A0-A3 are the only addr lines used, so this is also address $FFFA
Bytes not supplied by the matrix or by the flip-flops read as zeros. This includes the reset and IRQ/BRK vectors.
The stack is read-only, and will reside in the same physical location in memory as the interrupt vector table, most of which is zero. The result of this is that, when an NMI is taken, the stack pushes will go nowhere, but on RTI, PC will be restored by popping zeros from the vector table, returning execution to $0000--which is what's desired.
Phew!
Anyway. That's the idea!
BigDumbDinosaur wrote:
Well, assuming your microprocessor (MPU) reset circuit works properly, all of the MPU's outputs would be deasserted at reset and hence your glue logic should not be asserting any /OE or /WE inputs on your memory and I/O hardware. Can you post a (monochrome) schematic so we can help you analyze this? Glue logic behavior during reset is usually predictable, but having multiple sets of eyes looking at your circuit never hurts.
...although I suppose the same concern (if real) would apply during operation as well--for example, if as some posts advise, one chooses not to pay attention to Phi2 for read-only devices. But if you have multiple ROMs in your system and a decoder (e.g. 74HC138) supplying the output-enables, might not a transition between two addresses lead to momentary "conflicts" on the bus if the transition causes one device to be selected and another to be deselected? I suppose this is a scenario that would suggest pull-ups on the OE pins (to hasten their disabling)? I see that being done in some circuits, though mainly for the 65xx peripheral ICs (Here's an example where this is done for the 6551 and others.) This isn't a situation that applies to my own circuit, I don't think, as it's easy enough for me to pay attention to Phi2, and my whole external memory system is read-only besides. (More on that down below.)
BigEd wrote:
Broadly, I'd say yes, the conflict, if any, is going to be too short to be problematic - if you're using logic gates. If you'd built your glue logic out of an FPGA, then it will take some fractions of a second to load its configuration, so that might be a different case. (But note that FPGA pins are all inputs at reset time, and therefore external resistors could set appropriate values.) Similarly if you built the glue logic with a Propeller or a PIC or other microcontroller, startup might take some little time.
Here's the requested schematic: Doubtless this looks pretty strange, so here's the overdue explanation: The CPU in use is actually a Ricoh RP2A03G, the customized 6502 found in the Nintendo Entertainment System. The goal of this circuit is to give an MCU (Arduino) easy control of the internal audio functions of the 2A03, which are mapped internally at addresses $40xx. The MCU will (hopefully) just clock the data it wants to write into the BYTE4 flip-flop (IC5), clock the address offset xx into the BYTE6 flip-flop (IC6), and then assert NMI. The 2A03 should then perform the desired write.
The diode matrix implements the following code:
$0000: JMP $0000
$0003: LDA #$xx ; operand xx is supplied by the BYTE4 flip-flop
$0005: STA $40xx ; operand xx is supplied by the BYTE6 flip-flop
$0008: RTI
$000A: $03 ; this is the low byte of the NMI vector. A0-A3 are the only addr lines used, so this is also address $FFFA
Bytes not supplied by the matrix or by the flip-flops read as zeros. This includes the reset and IRQ/BRK vectors.
The stack is read-only, and will reside in the same physical location in memory as the interrupt vector table, most of which is zero. The result of this is that, when an NMI is taken, the stack pushes will go nowhere, but on RTI, PC will be restored by popping zeros from the vector table, returning execution to $0000--which is what's desired.
Phew!
Anyway. That's the idea!
Last edited by Aaron on Sat Mar 17, 2018 2:27 pm, edited 1 time in total.
Re: Noob question: Tri-state logic chaos and system startup
Now that's an interesting idea and an interesting circuit! I'm a big fan of diode ROMs, perhaps partly because they are rarely seen. (I think it would be good for you to repost that in the hardware thread with a suitable title - you might not catch your audience in this thread!)
Re: Noob question: Tri-state logic chaos and system startup
BigEd wrote:
Now that's an interesting idea and an interesting circuit! I'm a big fan of diode ROMs, perhaps partly because they are rarely seen. (I think it would be good for you to repost that in the hardware thread with a suitable title - you might not catch your audience in this thread!)
This will not be the first 2A03/Arduino project. There are two others, one of which is a simple variation on the other. These use the Arduino as the memory, with the Arduino madly watching the address and control lines. This seems like an interesting approach too, but the hardware is surprisingly similar in complexity to what I've done here, and the code is definitely more fragile. I'll be sticking to my own approach for now.
More as the project develops!
(The next project I hope to embark on will be a general-purpose MCU based on the Ricoh 5A22, the Nintendo-customized 65C816. That'll be a much more involved circuit, methinks!)
Re: Noob question: Tri-state logic chaos and system startup
Works-in-progress are fine posts too, here - which is a good thing, as some projects are never finished.
(Feel free to Introduce Yourself too.)
(Feel free to Introduce Yourself too.)
Re: Noob question: Tri-state logic chaos and system startup
Aaron, anyone who notices opportunities to do something bizarre -- and worries about missing such opportunities! -- is good folks as far as I'm concerned.
Welcome! I think I like your inline operands even better than your diode matrix!
But you've made a minor booboo, I think. You said, on RTI, PC will be restored by popping zeros from the vector table, returning execution to $0000. But it seems to me you want a BRK, not an RTI. BRK reads vector table as desired. RTI uses the (uninitialized) stack pointer S to read something probably not desired!
BTW on this forum you'll find if you look carefully there's a monospaced font available for code. Like this:
cheers,
Jeff
But you've made a minor booboo, I think. You said, on RTI, PC will be restored by popping zeros from the vector table, returning execution to $0000. But it seems to me you want a BRK, not an RTI. BRK reads vector table as desired. RTI uses the (uninitialized) stack pointer S to read something probably not desired!
BTW on this forum you'll find if you look carefully there's a monospaced font available for code. Like this:
Code: Select all
$0000: JMP $0000
$0003: LDA #$xx ; operand xx is supplied by the BYTE4 flip-flop
$0005: STA $40xx ; operand xx is supplied by the BYTE6 flip-flop
$0008: RTI
$000A: $03 ; this is the low byte of the NMI vector. A0-A3 are the only addr lines used, so this is also address $FFFAJeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
Re: Noob question: Tri-state logic chaos and system startup
Dr Jefyll wrote:
Aaron, anyone who notices opportunities to do something bizarre -- and worries about missing such opportunities! -- is good folks as far as I'm concerned.
Welcome! I think I like your inline operands even better than your diode matrix!
But you've made a minor booboo, I think. You said, on RTI, PC will be restored by popping zeros from the vector table, returning execution to $0000. But it seems to me you want a BRK, not an RTI. BRK reads vector table as desired. RTI uses the (uninitialized) stack pointer S to read something probably not desired!
BTW on this forum you'll find if you look carefully there's a monospaced font available for code. Like this:
cheers,
Jeff
But you've made a minor booboo, I think. You said, on RTI, PC will be restored by popping zeros from the vector table, returning execution to $0000. But it seems to me you want a BRK, not an RTI. BRK reads vector table as desired. RTI uses the (uninitialized) stack pointer S to read something probably not desired!
BTW on this forum you'll find if you look carefully there's a monospaced font available for code. Like this:
Code: Select all
$0000: JMP $0000
$0003: LDA #$xx ; operand xx is supplied by the BYTE4 flip-flop
$0005: STA $40xx ; operand xx is supplied by the BYTE6 flip-flop
$0008: RTI
$000A: $03 ; this is the low byte of the NMI vector. A0-A3 are the only addr lines used, so this is also address $FFFAJeff
In any case, your BRK suggestion is fantastic and seems like a clear winner. Let me reason it out: So, it doesn't matter to BRK that I'm already in the NMI handler, and BRK is endlessly reentrant (yes?), so I can use BRK to (effectively) jump to $0000. (And for a savings of one diode over RTI.) BRK will push the return address and status onto the stack (wherever that is), and as I'm BRK-ing like mad and never RTI-ing, the stack will eventually just wrap around (which doesn't matter in this circuit). If that works, I wonder: Might I also replace JMP $0000 with BRK? That would save me four more diodes (three for the JMP opcode, and one more because my NMI vector would go from $03 to $01). Presumably, if that worked, it would have a negative (but probably inconsequential) impact on my NMI handling latency.
Let me cogitate over this some more, because I certainly wouldn't mind cutting my diode count by a full third.
Sorry 'bout the code font thing. I ought to have noticed the Code button, but was half asleep as I composed the post.
Re: Noob question: Tri-state logic chaos and system startup
Quote:
I wonder: Might I also replace JMP $0000 with BRK?
First, here's your original memory map (as I understand it) except I've replaced the RTI at xxx8 with BRK as discussed.
Code: Select all
xxx0: 4C jmp abs opcode
xxx1: 00
xxx2: 00
xxx3: A9 lda# opcode
xxx4: ** (port)
xxx5: 8D sta abs opcode
xxx6: ** (port)
xxx7: 40
xxx8: 00 brk opcode (was: rti)
xxx9: 00 (not used)
xxxA: 03 lo-byte of NMI vector
xxxB: 00 hi-byte of NMI vector
xxxC: 00 lo-byte of RST vector
xxxD: 00 hi-byte of RST vector
xxxE: 00 lo-byte of IRQ/BRK vector
xxxF: 00 hi-byte of IRQ/BRK vector
; Plan A: the pattern as shown repeats every 16 bytes throughout all 64K
; Plan B: (discussed below) a similar pattern repeats every 16 bytes throughout lowest 32KMore subtly, and WRT using BRK as a replacement for the JMP 0000 at xxx0: some 65xx chips are vulnerable "interrupt highjacking," which is the gray-area behavior you get when a hardware interrupt is roughly coincident with a software interrupt (ie, BRK). Which vector will the CPU fetch? I don't know these details offhand. But I'm inclined to say it doesn't matter, as long as none of our NMI's actually get lost. To be on the safe side we could just keep the JMP 0000 at xxx0.
-- Jeff
Last edited by Dr Jefyll on Sun Mar 18, 2018 5:38 am, edited 1 time in total.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
Re: Noob question: Tri-state logic chaos and system startup
Hi Jeff -- Ah! You beat me to it. I was considering the now extremely underutilized second '138 and how to get rid of it. To make sure I understand the hijacking concern (which, according to the nesdev forums, is a valid concern on the 2A03): The BRK in the NMI ISR would be considered safe because it could be avoided by simply ensuring that the MCU provided sufficient delay between NMIs to prevent them from ever landing on it. Obviously, with BRK in place of JMP $0000, no (reasonable) timing tricks would guarantee safety. Yes? I think I'm keeping up.
Great suggestions, Jeff. I really appreciate it!
Re: Noob question: Tri-state logic chaos and system startup
Fun, eh?
Btw you can save 3 diodes if you use register Y instead of A. The LDA# opcode is $A9; the equivalent for Y is $A0. Likewise the STA abs opcode is $8D; for Y it's $8C.
There's one other idea, but I don't think we'll need it. To gain an extra byte, move the ISR lower so it begins at 0002 instead of 0003. ie; the NMI vector would point to 0002. Yes, the byte at 0002 is the hi-byte of the operand of the JMP instruction... but the hi-byte is kinda-sorta a don't care; we can mess with it. It's gratifyingly tricky. The byte at 0002 would do double duty -- both as an operand and as an opcode!
There's one other idea, but I don't think we'll need it. To gain an extra byte, move the ISR lower so it begins at 0002 instead of 0003. ie; the NMI vector would point to 0002. Yes, the byte at 0002 is the hi-byte of the operand of the JMP instruction... but the hi-byte is kinda-sorta a don't care; we can mess with it. It's gratifyingly tricky. The byte at 0002 would do double duty -- both as an operand and as an opcode!
Last edited by Dr Jefyll on Sun Mar 18, 2018 6:33 am, edited 1 time in total.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html
Re: Noob question: Tri-state logic chaos and system startup
I hadn't taken the diode pruning too seriously in the beginning, but it's a fun exercise, yes. And while certainly not needed, the $0002 NMI vector is yet another diode saved as well, so...*shrug*... why not? 
Re: Noob question: Tri-state logic chaos and system startup
I edited that last post; it now describes the operand hi-byte as a "kinda-sorta" don't care. But if we use Y then the opcode/operand will be $A0 -- and the main loop will run at $A000, always repeating a JMP $A000. That's alright but only if, in my schematic, you feed A14 (eg) to the NAND and decoder, not A15.
If it were imperative to gain another byte then the double-duty operand/opcode would be worth it. But merely to save a diode... I dunno. Sorry for the sleepy, half-baked posts. Off to bed now!
If it were imperative to gain another byte then the double-duty operand/opcode would be worth it. But merely to save a diode... I dunno. Sorry for the sleepy, half-baked posts. Off to bed now!
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
https://laughtonelectronics.com/Arcana/ ... mmary.html