BigDumbDinosaur wrote:
the 65C02 does tell you when atomic access to RAM is needed during a R-M-W instruction. Your glue logic should be able to handle that.
Yes, via the ML pin, and the glue logic that relates to that is what I'm trying to figure out.
BigDumbDinosaur wrote:
That said, I surmise your problem has nothing to do with the atomicity of R-M-W instructions and everything to do with proper task-switching timing. Task-switching timing is going to take careful analysis and programming—for example, if a task is about to set a semaphore you have to inhibit task switching for the duration of the operation so conflict doesn't arise. You'd also need to account for what could happen if the semaphore was already being manipulated when your task tries to manipulate it. That can get tricky and result in deadlock if not carefully handled.
I... don't really see how. There isn't any task-switching. There are two separate processors that have access to a shared RAM, but each processors is single-threaded and running constantly, so there's no task-switcing per se. Just two tasks running in parallel. The beautiful thing about Test-and-Set as a semaphore primitive is that, provided the instruction itself is atomic, it guarentees mutual exclusion for two competing processes.
CPU A and CPU B both execute on the same semaphore memory location; CPU A arbitrarily gets in a fraction sooner and the bus arbiter holds CPU B. CPU A reads a zero, so Z is set, then it writes back a '1', all within one atomic instruction. It has acquired the lock and can proceed on its merry way. Now, CPU B is released by the bus arbiter. It reads the '1' left behind by the previous instruction, so Z=false. It also writes a '1', but that's not a problem because that's what it was already. The TSB instruction is followed by a BNE spinlock, so it just keeps looping back and trying to do that TSB over and over until CPU A clears the byte, so it reads a zero, acquires the lock, etc.
The key thing is that only works if TSB is guarenteed to be atomic, i.e. that CPU B won't be able to read a '0' out of the semaphore before CPU A has had a chance to change it to a '1'. Therefore to make this scheme work, I need to use ML to guarentee the atomicity of TSB (and by extension all R-M-W instructions). I guess what I'm getting at is I'm fully aware that higher level software will require semaphores to synchronise access to shared RAM. My intended solution is the Test-and-Set, which requires the TSB instruction itself be guarenteed atomic, so I need to make it atomic at the hardware level - software semaphores won't work because bus arbitration happens on a cycle-by-cycle basis, not instruction-by-instruction, so there's no way for the software to "know" in time.
Code:
db semaphore
spinlock:
LDA #1
TSB semaphore ; Acquire lock if available
BNE spinlock ; If not, keep trying
; do some work on the shared resource
STZ semaphore ; Clear the lock
Incidentally, perhaps a moderator would be kind enough to split this topic? It has now significantly diverged and the topic title is therefore misleading.
_________________
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.