(pretty much a copy of my post on maxcoderz but w/e)
I've been working on threading on the z80 a bit, and I don't really like hacking around with di/ei all the time. It's especially annoying when you don't know whether interrupts are disabled already or not and you want to nice and leave them disabled.
So I needed some atomic stuff to implement locks and the like (which are also hugely useful by themselves in a multithreaded context)
I have this one:
Code:
I suppose I use "ld (hl),$C9" instead but whatever.
It's nice for locks, but locks have "the lock problem" and otherwise TaS is a pretty weak routine with a consensus number of just 2.
The main question: Are more powerful atomic constructs possible on the z80?
In the mean time, here are some more "Test and Set"-like things.
Code:
Pro: puts the result in both the C and Z flag.
Con: kills B (could also load B with zero)
Code:
Pro: auto-loops while failed, so this really implements a binary semaphore instead of TaS. I also did some counting semaphores which you can see in the maxcoderz thread or I';; copy them over here if anyone wants that.
Con: kills C (could also load C with zero)
Code:
Pro: shortest (3 bytes vs 4 for the others) TaS sequence I know of
Con: kills H - but that's less annoying than killing B or C
Code:
You can change the xx bits to whatever, the jump has an offset of zero anyway so it's irrelevant.
The result is in both Z and C flags.
Downsides: kills A and B, and is pretty big (5 bytes if a ret is included)
But the pattern can be more useful than that. You know the condition is going to be Z+NC at that jump, and you can use any offset up to and including 7 (with 6 being a special nice case in that it isn't an autocopy and so doesn't destroy regs and 7 autocopying to A which is killed anyway - though in a different way)
You can use this to skip whatever is done after the rlc (up to 7 bytes anyway) and do whatever you want (such as, for example, marking the thread as Waiting)
I've been working on threading on the z80 a bit, and I don't really like hacking around with di/ei all the time. It's especially annoying when you don't know whether interrupts are disabled already or not and you want to nice and leave them disabled.
So I needed some atomic stuff to implement locks and the like (which are also hugely useful by themselves in a multithreaded context)
I have this one:
Code:
testandset:
ld hl,tas_thingy
scf
jp (hl)
tas_thingy:
res 1,(hl) ; changes itself to ret (res = 11001011)
or a
ret
I suppose I use "ld (hl),$C9" instead but whatever.
It's nice for locks, but locks have "the lock problem" and otherwise TaS is a pretty weak routine with a consensus number of just 2.
The main question: Are more powerful atomic constructs possible on the z80?
In the mean time, here are some more "Test and Set"-like things.
Code:
rlc (hl)
ret
ret
; changes itself into
sub a
ld b,$C9
ret
Pro: puts the result in both the C and Z flag.
Con: kills B (could also load B with zero)
Code:
rrc (hl)
ret
ret
; changes itself into
push hl
ld c,$C9
ret
Pro: auto-loops while failed, so this really implements a binary semaphore instead of TaS. I also did some counting semaphores which you can see in the maxcoderz thread or I';; copy them over here if anyone wants that.
Con: kills C (could also load C with zero)
Code:
sla (hl)
ret
; changes itself into
sub (hl)
ld h,(hl)
ret
Pro: shortest (3 bytes vs 4 for the others) TaS sequence I know of
Con: kills H - but that's less annoying than killing B or C
Code:
rlc b,(ix+%001xx000)
; becomes
sub a
jr xx,0
You can change the xx bits to whatever, the jump has an offset of zero anyway so it's irrelevant.
The result is in both Z and C flags.
Downsides: kills A and B, and is pretty big (5 bytes if a ret is included)
But the pattern can be more useful than that. You know the condition is going to be Z+NC at that jump, and you can use any offset up to and including 7 (with 6 being a special nice case in that it isn't an autocopy and so doesn't destroy regs and 7 autocopying to A which is killed anyway - though in a different way)
You can use this to skip whatever is done after the rlc (up to 7 bytes anyway) and do whatever you want (such as, for example, marking the thread as Waiting)