Behaviour during reset low
- Alarm Siren
- Posts: 363
- Joined: 25 Oct 2016
Behaviour during reset low
What happens whilst the Reset pin is being held low?
I know what happens when the pin is released after being held low, the chip goes through its normal and well documented reset process, but what does it do before it is released?
I know what happens when the pin is released after being held low, the chip goes through its normal and well documented reset process, but what does it do before it is released?
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
- jac_goudsmit
- Posts: 229
- Joined: 23 Jun 2011
- Location: Rancho Cucamonga, California
- Contact:
Re: Behaviour during reset low
The data bus is held in High-Z mode. That's pretty much the most important thing.
The address bus stays online and doesn't change between clock pulses while RESET is active.
You have to keep RESET active for at least 2 clocks or it doesn't work correctly. I don't know exactly why this is the case, but I suspect that it's necessary because the reset sequence is basically handled like a pretend-interrupt. So it finishes the current instruction to get the instruction decoder to state T0.
You probably already know that after RESET goes inactive (high) again, the 6502 reads one more instruction, then pretends to push the return address and flags onto the stack but holds R/!W high to keep that from happening, and then it loads the address from $FFFC/$FFFD and starts executing at the address that's stored there.
Here's a page I wrote a couple of years ago on my old Propeddle project website that shows the address bus and databus during and after a reset: http://propeddle.com/?p=162 (I've abandoned that project and am now working on a simplified version called L-Star, see http://l-star.org).
===Jac
The address bus stays online and doesn't change between clock pulses while RESET is active.
You have to keep RESET active for at least 2 clocks or it doesn't work correctly. I don't know exactly why this is the case, but I suspect that it's necessary because the reset sequence is basically handled like a pretend-interrupt. So it finishes the current instruction to get the instruction decoder to state T0.
You probably already know that after RESET goes inactive (high) again, the 6502 reads one more instruction, then pretends to push the return address and flags onto the stack but holds R/!W high to keep that from happening, and then it loads the address from $FFFC/$FFFD and starts executing at the address that's stored there.
Here's a page I wrote a couple of years ago on my old Propeddle project website that shows the address bus and databus during and after a reset: http://propeddle.com/?p=162 (I've abandoned that project and am now working on a simplified version called L-Star, see http://l-star.org).
===Jac
Re: Behaviour during reset low
I think I've seen in visual6502 that what happens in the first few cycles of holding reset active will depend on which instruction is being executed. For example here we see JSR producing a stack address but no write occurs. There's no second stack access. The PC gets a bogus value, and reads are made from that bogus address. (Could be interesting if there was a side-effect.)
http://www.visual6502.org/JSSim/expert. ... 8&steps=40
http://www.visual6502.org/JSSim/expert. ... 8&steps=40
- Alarm Siren
- Posts: 363
- Joined: 25 Oct 2016
Re: Behaviour during reset low
The reason I ask is because I'm designing a system where the 6502 CPU is a "slave" to another processor with some shared RAM between the two. To bootstrap the slave, the host can write a small bootstrap program into the shared RAM whilst the slave is being held in reset. Once its done that, it releases the slave which then bootstraps itself using the program & vector left for it by the host. The problem is that the dual-port RAM would perma-block the host if the slave is attempting to "write" to the shared RAM due to some weird consequence of being held in reset. It sounds like this won't be an issue due to R/W being held in the read state.
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Re: Behaviour during reset low
Yes, sounds safe.
- Alarm Siren
- Posts: 363
- Joined: 25 Oct 2016
Re: Behaviour during reset low
On a related note, ~ML is breaking my brain.
Obviously this a multiprocessor system with shared RAM, so I need to use ML to protect the atomicity of RMW instructions (or ban their use on shared RAM); which is easy enough, I just connect ~ML into the ~BUSY signal going to the other CPU, which causes it to wait until ~ML is inactive. The problem is what happens if both Slave and Master happen to assert ~ML at the same time? They'd both be halted and never recover.
I guess I need a circuit or system of some kind whereby ~ML works as described above, EXCEPT if they're both asserted in the same cycle, in which case one is given priority and the relevant CPU allowed to run to completion whilst the other is made to wait (e.g. using RDY). Ideally ~ML blocking should only happen whilst accessing shared RAM, for which there is a chip enable signal called ~SRCE.
Obviously this a multiprocessor system with shared RAM, so I need to use ML to protect the atomicity of RMW instructions (or ban their use on shared RAM); which is easy enough, I just connect ~ML into the ~BUSY signal going to the other CPU, which causes it to wait until ~ML is inactive. The problem is what happens if both Slave and Master happen to assert ~ML at the same time? They'd both be halted and never recover.
I guess I need a circuit or system of some kind whereby ~ML works as described above, EXCEPT if they're both asserted in the same cycle, in which case one is given priority and the relevant CPU allowed to run to completion whilst the other is made to wait (e.g. using RDY). Ideally ~ML blocking should only happen whilst accessing shared RAM, for which there is a chip enable signal called ~SRCE.
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
- jac_goudsmit
- Posts: 229
- Joined: 23 Jun 2011
- Location: Rancho Cucamonga, California
- Contact:
Re: Behaviour during reset low
Alarm Siren wrote:
The problem is what happens if both Slave and Master happen to assert ~ML at the same time? They'd both be halted and never recover.
If the CPUs run on opposite phases of the same clock, the first CPU that needs to do an atomic operation halts the second one, and there's no chance of a race condition where they both need to do an atomic operation at the same time because the start of an atomic operation on CPU A is always at least half a cycle away from any atomic operation on CPU B and vice versa. And you don't need dual-port RAM either, just multiplexers to select the address on the RAM between address bus A and address bus B.
===Jac
- Alarm Siren
- Posts: 363
- Joined: 25 Oct 2016
Re: Behaviour during reset low
Unfortunately there will be more than one slave CPU, so this approach won't work. That is also why I need the dual-port RAM, so that the slaves do not interfere with eachother.
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
- jac_goudsmit
- Posts: 229
- Joined: 23 Jun 2011
- Location: Rancho Cucamonga, California
- Contact:
Re: Behaviour during reset low
Alarm Siren wrote:
Unfortunately there will be more than one slave CPU, so this approach won't work. That is also why I need the dual-port RAM, so that the slaves do not interfere with eachother.
===Jac
- Alarm Siren
- Posts: 363
- Joined: 25 Oct 2016
Re: Behaviour during reset low
jac_goudsmit wrote:
The idea is not restrained to 2 CPUs. As long as only one CPU at a time has a clock that's in the HIGH state, you're good.
Also, I've thought about it a little more, and the high/low clock solution doesn't actually solve the underlying issue with RMW instructions (though I do agree is removes the need for dual-port RAM)....
Example:
CPU A enters an INC RMW cycle, reads out a '5' from memory.
CPU B, on the low half of the cycle, starts an INC RMW cycle, reads '5' from the same memory.
CPU A, writes back '5'+1 = '6'.
CPU B, writes back '5'+1 = '6'.
We now have '6' in the memory when we ought to have had '7'. Had ML been used to block CPU B, the answer would have been the correct '7'.
---
The circuit pictured in the attachment almost does what I need...
When the Slave attempts to access the shared RAM whilst the Master's ML is asserted then the BUSY signal to the slave is asserted, stopping it in its tracks until the Master releases its ML. The 7475 flip-flop ensures once one of the two BUSY signals are asserted, the other one cannot be asserted until both have been deasserted, since there's never a reason to block both simultaniously: this ensures forward progress is always made
All of the above is true of the reverse relationship as well.
There are two problems with this circuit: if the Master and Slave both assert their MLs or CEs in the same cycle with either or both of the other signals also asserted, then both BUSY outputs might be asserted, halting all forward progress. The other problem is that the circuit unecessarily stops the Slave when the Master's ML is asserted but it is not accessing the shared RAM (i.e. Master CE is not asserted), and vice-versa.
EDIT: ... and I just thought of another complication. Say Slave CE and Master ML are asserted, so the slave gets halted by BUSY. Now the Master continues and happens to access the same memory address that the Slave was in the middle of writing - because BUSY is hooked up to the 6502's RDY input, the address bus etc on the dual-port RAM is still on the same address. This causes the dual-port RAM to report a contention, which causes it to assert the Master's BUSY signal. Now both BUSYs are asserted and no forward progress is possible. Though actually this may not be possible since ML is asserted first during a read, so maybe the blocked side would always block on a read, which would be OK? .... maybe it would just be easier to ban RMW instructions on the shared RAM, this is getting complicated.
- Attachments
-
- Incomplete example circuit
- Circuit.png (5.75 KiB) Viewed 6871 times
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
- jac_goudsmit
- Posts: 229
- Joined: 23 Jun 2011
- Location: Rancho Cucamonga, California
- Contact:
Re: Behaviour during reset low
Alarm Siren wrote:
Good point, though it would somewhat defeat the point of having multiple cores (or at least, more than two), since they'd effectively be operating in a round-robin fashion rather than truly in parallel.
Quote:
Also, I've thought about it a little more, and the high/low clock solution doesn't actually solve the underlying issue with RMW instructions (though I do agree is removes the need for dual-port RAM)....
The RMW output of the WDC 65C02S can help, because it can tell the system when it's accessing a location that it's going to modify and write back. But any circuitry should also take the address into account: if CPU A is executing an INC absolute of a location, any other CPU should ONLY be halted if it tries to access the SAME address. Accessing any other address is fine. But that would be a complicated circuit.
I probably would design a much simpler circuit than one that compares the addresses of all CPU's and makes decisions on halting them.
I thought about it for a while and I'd probably do something like this: Let's say you have an up/down counter (e.g. 74HC193) and an address decoder.
- Upon system reset, the counter is set to 1111 binary (4 bits are enough for up to 16 CPU's).
- When one of the CPUs addresses matches the address of the locking circuit, and the corresponding clock goes high, the counter counts up by one if R/!W is high, and counts down if R/!W is low.
- The counter value is decoded to the data bus. If the counter value is 0000, the CPU should read 00000000 binary, otherwise it may read any other value. Keep in mind, the 6502 reads the the data bus when the clock goes from high to low, so there is no race condition with the incrementation or decrementation of the counter.
- Read from the lock address (which increments the counter by one)
- Test if the value that was read is 0 (use the Z flag). Reading value 0 means the CPU "owns" the lock.
- If the CPU owns the lock, it can do with the shared memory area or I/O device what it wants, without a chance that another CPU will use it (as long as all software follows the rules of course). If the CPU does NOT own the lock, it should not attempt to access the memory location or I/O device at all.
- The CPU should write to the lock's location (to decrement the counter by one) regardless of whether it owned it or not.
- If the CPU didn't get to own the lock and still wants it, go to step 1.
Code: Select all
JMP takeit
retry STA lock Decrease the counter
takeit LDA lock Increase counter. We own it if we made it 0
BNE retry
; Do whatever is needed with the shared memory
leaveit STA lock
; Now other CPUs can take the lock
Re: Behaviour during reset low
It might be worth thinking in terms of a memory system. The CPUs need access to the memory system, so they make requests. An arbiter in the memory system decides which CPUs get access. Other CPUs must be stalled.
In the case of a 6502 system, you'd try to do all that within one clock cycle - or, you'd use RDY to make the memory system multi-cycle and take more time. In general, you might have several memory cards or memory banks, which could have different access regimes. For example, if you design your software system such that shared memory is only a subset of memory, then that area gets more complex arbitration and possibly is a multi-cycle memory, whereas the remainder of memory has simpler arbitration and preferable can be a single-cycle memory.
In the case of a 6502 system, you'd try to do all that within one clock cycle - or, you'd use RDY to make the memory system multi-cycle and take more time. In general, you might have several memory cards or memory banks, which could have different access regimes. For example, if you design your software system such that shared memory is only a subset of memory, then that area gets more complex arbitration and possibly is a multi-cycle memory, whereas the remainder of memory has simpler arbitration and preferable can be a single-cycle memory.
- Alarm Siren
- Posts: 363
- Joined: 25 Oct 2016
Re: Behaviour during reset low
Quote:
if CPU A is executing an INC absolute of a location, any other CPU should ONLY be halted if it tries to access the SAME address. Accessing any other address is fine. But that would be a complicated circuit.
The dual-port RAM already has built-in bus arbitration based around memory contention: if both Master and Slave attempt to access the same address at the same time, the bus arbiter will allow the "first" one to finish and inhibit the second by pulling BUSY low (which is connected to the relevant CPU's RDY pin). The problem is that this is done on an access-by-access basis, so that atomicity of RMW instructions are not protected: although the RMW instruction might win on one bus cycle, on the next it might not.
I guess that that means the following:
If Master's BUSY and Slave's ML are asserted at the same time, then Master's BUSY must continue to be asserted until Slave's ML is released, in order to guarentee that Master's accesses always win on every subsequent cycle, thus protecting the RMW's atomicity. And vice-versa.
This is probably a much more efficient idea, since a stall will only happen on actual memory contention, and the RAM's BUSY signal already ensures that only one of the two BUSYs will be asserted at one time, so we won't get a deadlock by making the continued assertion of BUSY dependent on BUSY being asserted in the first place.
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Re: Behaviour during reset low
Sounds like a hardware semaphore might be needed. Can you have a flip-flop (or counter) set by a read operation to lock an address range for the memory operation ? Reading would return the previous value of the ff while setting it at the same time so that the next requester knows it’s busy. If the ff was clear then access the memory otherwise wait in a loop. Also requires the ability to write the ff to clear it. If the ff was on bit 7 of the databus then a BIT instruction could be used to test it.
Code: Select all
.busy
BIT LockFF ; the read will lock it
BMI .busy
< access the memory >
STZ LockFF ; clear semaphore
- Alarm Siren
- Posts: 363
- Joined: 25 Oct 2016
Re: Behaviour during reset low
There is a specific reason why I would like to guarentee the atomicity of RMW instructions, rather than simply banning their use on Shared RAM (or at least plastering it with warnings of "here be dragons"!)
Specifically, I want to ensure that TSB is always atomic, because I intend to use it as the basic operation for locking semaphores in software, see this page for explanation. This method only works if TSB is guarenteed to be atomic.
Specifically, I want to ensure that TSB is always atomic, because I intend to use it as the basic operation for locking semaphores in software, see this page for explanation. This method only works if TSB is guarenteed to be atomic.
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.