aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2018-10-30 12:25:52 -0700
committerH. Peter Anvin <hpa@zytor.com>2018-10-30 12:31:33 -0700
commit62f3d3636d01521207dd14e6ff984668eb643caf (patch)
treee09d0457162eb2e1216f0e9bd71d295de822d1de
parent073ef33cce472e95b705c879f8b30ef9f1437562 (diff)
downloadabc80sim-62f3d3636d01521207dd14e6ff984668eb643caf.tar.gz
abc80sim-62f3d3636d01521207dd14e6ff984668eb643caf.tar.xz
abc80sim-62f3d3636d01521207dd14e6ff984668eb643caf.zip
Avoid cmpxchg() for bit set/bit clear on non-x86
We can use an atomic and/or instead. As a result, inline z80_[clear_]interrupt().
-rw-r--r--Makefile.in2
-rw-r--r--compiler.h23
-rw-r--r--z80irq.c61
-rw-r--r--z80irq.h10
4 files changed, 30 insertions, 66 deletions
diff --git a/Makefile.in b/Makefile.in
index af1feee..90636fe 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -33,7 +33,7 @@ SRCS = abc80.c clock.c sdlscrn.c screenshot.c z80.c z80irq.c abcmem.c abcio.c \
abcfont.c disk.c rtc.c simprint.c print.c fileop.c z80dis.c \
nstime.c hostfile.c console.c cas.c abcfile.c filelist.c \
clib/asprintf.c $(GENC)
-HDRS = clock.h screen.h z80.h patchlevel.h screenshot.h abcio.h \
+HDRS = clock.h screen.h z80.h z80irq.h patchlevel.h screenshot.h abcio.h \
abcprintd.h rom.h nstime.h hostfile.h trace.h \
compiler.h console.h clib/inttypes.h config/config.h
diff --git a/compiler.h b/compiler.h
index 5367fdc..6f48eb5 100644
--- a/compiler.h
+++ b/compiler.h
@@ -195,9 +195,28 @@ typedef int mode_t;
__ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
# define xchg(p, v) \
__atomic_exchange_n((p), (v), __ATOMIC_ACQ_REL)
-#define barrier() __atomic_thread_fence(__ATOMIC_ACQ_REL)
+# define barrier() __atomic_thread_fence(__ATOMIC_ACQ_REL)
-#else
+# if defined(__i386__) || defined(__x86_64__)
+static inline void atomic_set_bit(volatile unsigned int *p, int v)
+{
+ asm volatile("lock btsl %1,%0" : "+m" (*p) : "rN" (v));
+}
+static inline void atomic_clear_bit(volatile unsigned int *p, int v)
+{
+ asm volatile("lock btrl %1,%0" : "+m" (*p) : "rN" (v));
+}
+# else
+static inline void atomic_set_bit(volatile unsigned int *p, int v)
+{
+ __atomic_or_fetch(p, 1U << v, __ATOMIC_ACQ_REL);
+}
+static inline void atomic_clear_bit(volatile unsigned int *p, int v)
+{
+ __atomic_and_fetch(p, ~(1U << v), __ATOMIC_ACQ_REL);
+}
+# endif
+#else /* __GNUC__ */
/* ? */
#endif
diff --git a/z80irq.c b/z80irq.c
index 829ee45..29cecc9 100644
--- a/z80irq.c
+++ b/z80irq.c
@@ -71,64 +71,3 @@ void z80_eoi(void)
irq->eoi(irq);
}
}
-
-/*
- * Raise an interrupt with specific priority level; return true if
- * interrupt raised, false if the interrupt was already pending or
- * the argument is invalid.
- */
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-
-bool z80_interrupt(struct z80_irq *irq)
-{
- bool raised;
-
- asm volatile("lock btsl %2,%0"
- : "+m" (irq_pending), "=@ccnc" (raised)
- : "rN" ((unsigned int)irq->prio));
-
- return raised;
-}
-
-bool z80_clear_interrupt(struct z80_irq *irq)
-{
- bool cleared;
-
- asm volatile("lock btrl %2,%0"
- : "+m" (irq_pending), "=@ccc" (cleared)
- : "rN" ((unsigned int)irq->prio));
-
- return cleared;
-}
-
-#else
-
-bool z80_interrupt(struct z80_irq *irq)
-{
- unsigned int irqmask, irqpend;
-
- irqmask = 1U << irq->prio;
- irqpend = irq_pending;
- do {
- if (irqpend & irqmask)
- return false;
- } while (!cmpxchg(&irq_pending, &irqpend, irqpend | irqmask));
-
- return true;
-}
-
-bool z80_clear_interrupt(struct z80_irq *irq)
-{
- unsigned int irqmask, irqpend;
-
- irqmask = 1U << irq->prio;
- irqpend = irq_pending;
- do {
- if (!(irqpend & irqmask))
- return false;
- } while (!cmpxchg(&irq_pending, &irqpend, irqpend & ~irqmask));
-
- return true;
-}
-
-#endif
diff --git a/z80irq.h b/z80irq.h
index 74386b2..9555ef9 100644
--- a/z80irq.h
+++ b/z80irq.h
@@ -31,7 +31,13 @@ static inline bool poll_irq(void)
void z80_register_irq(struct z80_irq *irq);
int z80_intack(void);
void z80_eoi(void);
-bool z80_interrupt(struct z80_irq *irq);
-bool z80_clear_interrupt(struct z80_irq *irq);
+static inline void z80_interrupt(struct z80_irq *irq)
+{
+ atomic_set_bit(&irq_pending, irq->prio);
+}
+static inline void z80_clear_interrupt(struct z80_irq *irq)
+{
+ atomic_clear_bit(&irq_pending, irq->prio);
+}
#endif /* Z80IRQ_H */