AVMA should assert if writing CC#7
Conversation
|
Hi Chuck, Sorry for just a quick glance, but can you describe the issue in more detail? AVMA is an indication about the next cycle's use or disuse by the 6809. (There are tons of people who use a 6800 and confuse it with VMA, which is the current cycle on those CPUs.) I shouldn't be using it to control anything; it should be a signal to outside of the CPU that the bus will be occupied or not occupied on the next cycle (by the CPU). Any more description you can give me would be appreciated! Thanks, Greg |
|
Right, and so I have a wrapper defining output enable for the CPU...for example: wire OE = (~RnW) && (~BA) && AVMA; With this signal defined this way, at the last stack write of the push for a full IRQ, which is CC, OE will be false because AVMA will be low. This is what my fix corrects. Again, not sure if this is technically correct, but I spent weeks trying to figure out why I had what appeared to me to be "stack corruption". Turns out CC would never be written in this scenario (though S would decrement). And I think this is a "next cycle" thing because it is the next cycle that CC would be written. I can append or zip some more code to illustrate if that would be helpful. |
|
I guess I have a more direct question: was it intentional that the wrap-up logic below, the My logic is...rAVMA is being set to 1 at the top of the state transition, which means it is active because every "next" state will be a write. But the "next" state transition for writing CC gets a rAVMA set to 0 if NextState != CPUSTATE_FETCH_I1. For the normal IRQ, it clearly is not equal, because otherwise I would not have hit this problem. But the write for CC must still happen, regardless. A more deliberate way to fix the problem would be to have the wrapup logic execute at the next cycle after writing CC (putting it in as the last else to the big if/elseif block). But again, I'm not sure what the silicon actually does. |
|
Hi Chuck, I'm taking a look at your first code change, and I'm trying to understand the situation you're looking at. You said "on a full interrupt return"; okay, (almost) everything's coming off of the stack, and the PC will be last. Okay, gotcha. You're looking at the code for CPUSTATE_PUL_ACTION. Gotcha. I think? Your text says "stack write for the CC register". Are you talking about entering an interrupt? In which case, you're looking at CPUSTATE_PSH_ACTION instead? Your comment confuses me as it seems to be talking about "full interrupt return", which is pulling registers from the stack, and "stack write for the CC register", which isn't an interrupt return, it's an entry. You kind of mention in a later comment that you aren't certain what the real CPU does. I can't answer that quite yet - I don't know exactly what situation we're looking at. I did spend an obscene amount of time with an analyzer watching what the silicon did in ridiculous edge cases. I've had folks complain that this implementation is "inefficient". They're right. It is. There are many-cycle-delays in here where multiple cycles are used to do things that I could easily do in a single cycle. That's intentional, though - the cycle-accurate part, and all. It sounds like you're saying the AVMA isn't being set correctly, and in your particular application I'm (the CPU is) trying to write something on the next cycle and you're also trying to use the next cycle - because, it sounds like you're saying that I'm using the bus in a scenario and AVMA on the cycle before was unasserted. I certainly could have made a mistake - although I do know others who're using the core and using AVMA. Another question: Your example: wire OE = (~RnW) && (~BA) && AVMA; Is confusing me. AVMA never ever talks about the current cycle. It's always 1 cycle ahead. Motorola made a big deal about it due to that. The 6800/6805/68HC11/etc. all had VMA, which was talking about the same cycle. The 6809 gives other hardware more time to "prepare" as you had a whole cycle's notice that the bus would or would not be in use. The way you're using AVMA looks more like someone trying to use VMA, not AVMA. To use it the way you seem to be, you'd want the latch it on the falling edge of E, and always be using the latched copy (i.e., the signal at the prior cycle). Help me understand exactly what you're seeing, what you're doing, what you're expecting, and I'll eagerly see if I made an error. |
|
Yeah, the problem is tricky. And I am not a verilog/HDL expert by any stretch. Less so of 6809 internals. You can see a wrapper I have coded based on a clone of your repo here: https://github.com/chuckb/mc6809/blob/master/rrw_mc6809e.v. Line 90 seems to be the culprit. It may well be I am misusing AVMA. I am clocking my the design at 12mhz, and use CEs to strobe E/Q at 1mhz. You can also see those changes in the clone. I am clocking sync bram at the root and sneaking in address latching so data can assert on the data bus at the fall of E for reads. My problem in a nutshell is during a return from interrupt, registers are not being restored correctly. The culprit is that during the CPUSTATE_PSH_ACTION, CC is being written as 0, and I believed it to be because of incorrect AVMA signaling for that one register. But as I read your comment now, I can see how my OE derivation would need to be Second question...assuming above is correct, I am confused as to how any of my memory writing was working, because I was only seeing this trouble for interrupts. The other test assembly code I ran through the model, writing to/reading from bram, seemed to be working fine. I guess this is what tripped me up because had none of my writes worked, it would have been obvious I was doing something wrong. Sooooo, what I will do is latch AVMA and if it works, close the PR. Your feedback tho is appreciated. It's amazing that work like this is just available to use. Thanks! |
|
I apologize if this sounds odd, but are you trying to bus master, or merely implement a peripheral? AVMA (or VMA) is only useful if you're attempting to drive the bus during cycles when the CPU isn't using it. If you're implementing a peripheral - that is, a component that is accessed by the 6809, then you really don't need to care about AVMA or BA at all. BA is used to differentiate when the CPU is running normally. AVMA changes are separated from BS/BA changes. You seem to be mixing several different things, and I'm unclear what you're pursuing. 1: AVMA is intended to permit you to use bus cycles that the 6809 is not using, but without stopping the 6809. The 6809 might be processing internally and be off of the bus, and AVMA is permitted to let you plan in advance to use the bus the next cycle. 2: You can also HALT the CPU, and when you do so, BS and BA will both go high. I seem to recall that the CPU takes N cycles to stop (I don't remember how many.) Number 1 is for you using 'spare' cycles. The CPU isn't slowed down or impacted at all, and you get a bit of "free" bus time that otherwise would be wasted. It's good for doing things in the background that don't cause the CPU to stall or stop. Number 2 is used when you need complete ownership of the bus. You HALT (as in stop) the CPU with /HALT and after N cycles, BS and BA both go high, indicating that the CPU is stopped (and remains stopped as long as you keep /HALT low). It has high costs: The CPU is totally off of the bus, not running at all, but the bus is entirely yours. The address bus is High-Z, as is R/nW, the data bus, etc. If you're not trying to control the bus, you don't need to do any of this. Say that you're trying to implement a UART, for instance, and the 6809 will read and write from/to UART registers. In that case, none of these things are required. In the docs, I do give an email address that you can contact me on if you'd like to talk further - happy to chat about how you might accomplish your goals. |
On a full interrupt return, if AVMA is being used to inhibit DOut access, then this signal is being lowered prematurely during the stack write for the CC register. This causes a zero write (if that is what is being driven if bus is inhibited) for CC, causing the subsequent pull to fail to recover registers (since the E bit would return as 0), thus causing PC to not return from whence it came. I am not sure which way the silicon actually works, but it seems like a bug to me.