mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 15:38:22 +00:00
180 lines
8.4 KiB
C
180 lines
8.4 KiB
C
/*───────────────────────────────────────────────────────────────────────────│─╗
|
|
│ The LISP Challenge § Hardware Integration w/ x86_64 Linux & 8086 PC BIOS ─╬─│┼
|
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
|
|
|
#define CompilerBarrier() asm volatile("" ::: "memory");
|
|
|
|
#define ISATOM(x) /* a.k.a. !(x&1) */ \
|
|
({ \
|
|
_Bool IsAtom; \
|
|
asm("test%z1\t$1,%1" : "=@ccz"(IsAtom) : "Qm"((char)x)); \
|
|
IsAtom; \
|
|
})
|
|
|
|
#define OBJECT(t, v) /* a.k.a. v<<1|t */ \
|
|
({ \
|
|
__typeof(v) Val = (v); \
|
|
asm("shl\t%0" : "+r"(Val)); \
|
|
Val | (t); \
|
|
})
|
|
|
|
#define SUB(x, y) /* a.k.a. x-y */ \
|
|
({ \
|
|
__typeof(x) Reg = (x); \
|
|
asm("sub\t%1,%0" : "+rm"(Reg) : "g"(y)); \
|
|
Reg; \
|
|
})
|
|
|
|
#define STOS(di, c) asm("stos%z1" : "+D"(di), "=m"(*(di)) : "a"(c))
|
|
#define LODS(si) \
|
|
({ \
|
|
typeof(*(si)) c; \
|
|
asm("lods%z2" : "+S"(si), "=a"(c) : "m"(*(si))); \
|
|
c; \
|
|
})
|
|
|
|
#define PEEK_(REG, BASE, INDEX, DISP) \
|
|
({ \
|
|
__typeof(*(BASE)) Reg; \
|
|
if (__builtin_constant_p(INDEX) && !(INDEX)) { \
|
|
asm("mov\t%c2(%1),%0" \
|
|
: REG(Reg) \
|
|
: "bDS"(BASE), "i"((DISP) * sizeof(*(BASE))), \
|
|
"m"(BASE[(INDEX) + (DISP)])); \
|
|
} else { \
|
|
asm("mov\t%c3(%1,%2),%0" \
|
|
: REG(Reg) \
|
|
: "b"(BASE), "DS"((long)(INDEX) * sizeof(*(BASE))), \
|
|
"i"((DISP) * sizeof(*(BASE))), "m"(BASE[(INDEX) + (DISP)])); \
|
|
} \
|
|
Reg; \
|
|
})
|
|
|
|
#define PEEK(BASE, INDEX, DISP) /* a.k.a. b[i] */ \
|
|
(sizeof(*(BASE)) == 1 ? PEEK_("=Q", BASE, INDEX, DISP) \
|
|
: PEEK_("=r", BASE, INDEX, DISP))
|
|
|
|
#define PEEK_ARRAY_(REG, OBJECT, MEMBER, INDEX, DISP) \
|
|
({ \
|
|
__typeof(*(OBJECT->MEMBER)) Reg; \
|
|
if (!(OBJECT)) { \
|
|
asm("mov\t%c2(%1),%0" \
|
|
: REG(Reg) \
|
|
: "bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
|
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
|
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
|
|
"m"(OBJECT->MEMBER)); \
|
|
} else { \
|
|
asm("mov\t%c3(%1,%2),%0" \
|
|
: REG(Reg) \
|
|
: "b"(OBJECT), "DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
|
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
|
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
|
|
"m"(OBJECT->MEMBER)); \
|
|
} \
|
|
Reg; \
|
|
})
|
|
|
|
#define PEEK_ARRAY(OBJECT, MEMBER, INDEX, DISP) /* o->m[i] */ \
|
|
(sizeof(*(OBJECT->MEMBER)) == 1 \
|
|
? PEEK_ARRAY_("=Q", OBJECT, MEMBER, INDEX, DISP) \
|
|
: PEEK_ARRAY_("=r", OBJECT, MEMBER, INDEX, DISP))
|
|
|
|
#define POKE_ARRAY_(REG, OBJECT, MEMBER, INDEX, DISP, VALUE) \
|
|
do { \
|
|
if (!(OBJECT)) { \
|
|
asm("mov\t%1,%c3(%2)" \
|
|
: "=m"(OBJECT->MEMBER) \
|
|
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), \
|
|
"bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
|
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
|
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
|
|
} else { \
|
|
asm("mov\t%1,%c4(%2,%3)" \
|
|
: "=m"(OBJECT->MEMBER) \
|
|
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), "b"(OBJECT), \
|
|
"DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
|
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
|
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define POKE_ARRAY(OBJECT, MEMBER, INDEX, DISP, VALUE) /* o->m[i]=v */ \
|
|
do { \
|
|
__typeof(*(OBJECT->MEMBER)) Reg; \
|
|
switch (sizeof(*(OBJECT->MEMBER))) { \
|
|
case 1: \
|
|
POKE_ARRAY_("Q", OBJECT, MEMBER, INDEX, DISP, VALUE); \
|
|
break; \
|
|
default: \
|
|
POKE_ARRAY_("r", OBJECT, MEMBER, INDEX, DISP, VALUE); \
|
|
break; \
|
|
} \
|
|
} while (0)
|
|
|
|
static inline void *SetMemory(void *di, int al, unsigned long cx) {
|
|
asm("rep stosb"
|
|
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
|
|
: "0"(di), "1"(cx), "a"(al));
|
|
return di;
|
|
}
|
|
|
|
static inline void *CopyMemory(void *di, void *si, unsigned long cx) {
|
|
asm("rep movsb"
|
|
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
|
|
: "0"(di), "1"(si), "2"(cx));
|
|
return di;
|
|
}
|
|
|
|
static void RawMode(void) {
|
|
#ifndef __REAL_MODE__
|
|
int rc;
|
|
int c[14];
|
|
asm volatile("syscall"
|
|
: "=a"(rc)
|
|
: "0"(0x10), "D"(0), "S"(0x5401), "d"(c)
|
|
: "rcx", "r11", "memory");
|
|
c[0] &= ~0b0000010111111000; // INPCK|ISTRIP|PARMRK|INLCR|IGNCR|ICRNL|IXON
|
|
c[2] &= ~0b0000000100110000; // CSIZE|PARENB
|
|
c[2] |= 0b00000000000110000; // CS8
|
|
c[3] &= ~0b1000000001011010; // ECHONL|ECHO|ECHOE|IEXTEN|ICANON
|
|
asm volatile("syscall"
|
|
: "=a"(rc)
|
|
: "0"(0x10), "D"(0), "S"(0x5402), "d"(c)
|
|
: "rcx", "r11", "memory");
|
|
#endif
|
|
}
|
|
|
|
__attribute__((__noinline__)) static void PrintChar(long c) {
|
|
#ifdef __REAL_MODE__
|
|
asm volatile("mov\t$0x0E,%%ah\n\t"
|
|
"int\t$0x10"
|
|
: /* no outputs */
|
|
: "a"(c), "b"(7)
|
|
: "memory");
|
|
#else
|
|
static short buf;
|
|
int rc;
|
|
buf = c;
|
|
asm volatile("syscall"
|
|
: "=a"(rc)
|
|
: "0"(1), "D"(1), "S"(&buf), "d"(1)
|
|
: "rcx", "r11", "memory");
|
|
#endif
|
|
}
|
|
|
|
static int ReadChar(void) {
|
|
int c;
|
|
#ifdef __REAL_MODE__
|
|
asm volatile("int\t$0x16" : "=a"(c) : "0"(0) : "memory");
|
|
c &= 0xff;
|
|
#else
|
|
static int buf;
|
|
asm volatile("syscall"
|
|
: "=a"(c)
|
|
: "0"(0), "D"(0), "S"(&buf), "d"(1)
|
|
: "rcx", "r11", "memory");
|
|
c = buf;
|
|
#endif
|
|
return c;
|
|
}
|