mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-25 07:19:02 +00:00
Add pseudoteletypewriter to emulator
https://justine.storage.googleapis.com/emulator628.mp4
This commit is contained in:
parent
e86cff8ba0
commit
5aabacb361
94 changed files with 3245 additions and 2179 deletions
|
@ -39,7 +39,7 @@ int ttyrestorecursor(int);
|
|||
int ttyenablealtbuf(int);
|
||||
int ttydisablealtbuf(int);
|
||||
int ttysend(int, const char *);
|
||||
int ttywrite(int, const void *, size_t);
|
||||
ssize_t ttywrite(int, const void *, size_t);
|
||||
int ttysendtitle(int, const char *, const struct TtyIdent *);
|
||||
int ttyident(struct TtyIdent *, int, int);
|
||||
void ttyidentclear(struct TtyIdent *);
|
||||
|
|
|
@ -101,7 +101,9 @@ static relegated void ttyraw_onsig(int sig, struct siginfo *info,
|
|||
if (g_ttyraw.sigs[i] == sig) {
|
||||
if (g_ttyraw.next[i] != SIG_IGN) {
|
||||
if (g_ttyraw.next[i] != SIG_DFL) {
|
||||
if (g_ttyraw.next[i]) {
|
||||
g_ttyraw.next[i](sig, info, ctx);
|
||||
}
|
||||
} else if (sig != SIGCONT) {
|
||||
_Exit(128 + sig);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int ttywrite(int fd, const void *data, size_t size) {
|
||||
ssize_t ttywrite(int fd, const void *data, size_t size) {
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
size_t wrote, n;
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
|
||||
#define kMessage "hello world\r\n"
|
||||
#define kMessage "hello \e[1mworld\e[0m\r\n"
|
||||
|
||||
int main() {
|
||||
/*
|
||||
|
|
|
@ -18,42 +18,36 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/fmt/bing.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define ALTCOUNT 21
|
||||
|
||||
static const struct Cp437Multimappings {
|
||||
unsigned char b[ALTCOUNT];
|
||||
char16_t c[ALTCOUNT];
|
||||
} kCp437iMultimappings = {
|
||||
#define ALT(I, C, B) .c[I] = C, .b[I] = B
|
||||
ALT(0, u'\n', '\n'),
|
||||
ALT(1, u'\r', '\r'),
|
||||
ALT(2, u'?', '?'), /* TRIGRAPH */
|
||||
ALT(3, u'\'', '\''), /* CHARACTER LITERAL */
|
||||
ALT(4, u'\"', '\"'), /* STRING LITERAL */
|
||||
ALT(5, u'\\', '\\'), /* ESCAPE LITERAL */
|
||||
ALT(6, u'∅', '\0'), /* EMPTY SET */
|
||||
ALT(7, u'␀', '\0'), /* SYMBOL FOR NULL [sic] */
|
||||
ALT(7, 0x20A7, 0x9E), /* PESETA SIGN */
|
||||
ALT(8, u'Π' /* 03A0: GREEK CAPITAL LETTER PI */, 0xE3),
|
||||
ALT(9, u'∏' /* 220F: N-ARY PRODUCT */, 0xE3),
|
||||
ALT(10, u'∑' /* 2211: N-ARY SUMMATION */, 0xE4),
|
||||
ALT(11, u'µ' /* 03BC: MICRO SIGN */, 0xE6),
|
||||
ALT(12, u'Ω' /* 2126: OHM SIGN */, 0xEA),
|
||||
ALT(13, u'∂' /* 2202: PARTIAL DIFFERENTIAL */, 0xEB),
|
||||
ALT(14, u'ε' /* 03D5: PHI SMALL (CLOSED FORM) */, 0xED),
|
||||
ALT(15, u'ϕ' /* 03D5: PHI SMALL (CLOSED FORM) */, 0xED),
|
||||
ALT(16, u'∈' /* 2208: ELEMENT-OF SIGN */, 0xED),
|
||||
ALT(17, u'∊' /* 220A: SMALL ELEMENT OF */, 0xEE),
|
||||
ALT(18, u'∈' /* 03B5: ELEMENT-OF SIGN */, 0xEE),
|
||||
ALT(19, u'β' /* 03B2: GREEK SMALL BETA */, 0xE1),
|
||||
ALT(20, u'ſ' /* 017F: LATIN SMALL LETTER LONG S */, 0xF4),
|
||||
#undef ALT
|
||||
static const int kCp437iMultimappings[] = {
|
||||
u'\n' << 8 | '\n', // NEWLINE
|
||||
u'\r' << 8 | '\r', // CARRIAGE RETURN
|
||||
u'?' << 8 | '?', // TRIGRAPH
|
||||
u'\'' << 8 | '\'', // CHARACTER LITERAL
|
||||
u'\"' << 8 | '\"', // STRING LITERAL
|
||||
u'\\' << 8 | '\\', // ESCAPE LITERAL
|
||||
u'∅' << 8 | '\0', // EMPTY SET
|
||||
u'␀' << 8 | '\0', // SYMBOL FOR NULL [sic]
|
||||
0x20A7 << 8 | 0x9E, // PESETA SIGN
|
||||
u'Π' << 8 | 0xE3, // GREEK CAPITAL LETTER PI
|
||||
u'∏' << 8 | 0xE3, // N-ARY PRODUCT
|
||||
u'∑' << 8 | 0xE4, // N-ARY SUMMATION
|
||||
u'µ' << 8 | 0xE6, // MICRO SIGN
|
||||
u'Ω' << 8 | 0xEA, // OHM SIGN
|
||||
u'∂' << 8 | 0xEB, // PARTIAL DIFFERENTIAL
|
||||
u'ϕ' << 8 | 0xED, // PHI SMALL (CLOSED FORM)
|
||||
u'ε' << 8 | 0xEE, // LATIN SMALL LETTER EPSILON
|
||||
u'∊' << 8 | 0xEE, // SMALL ELEMENT OF
|
||||
u'∈' << 8 | 0xEE, // ELEMENT-OF SIGN
|
||||
u'β' << 8 | 0xE1, // GREEK SMALL BETA
|
||||
u'ſ' << 8 | 0xF4, // LATIN SMALL LETTER LONG S
|
||||
};
|
||||
|
||||
static int g_cp437i[256 + ARRAYLEN(kCp437iMultimappings)];
|
||||
|
||||
/**
|
||||
* Turns CP437 unicode glyph into its binary representation.
|
||||
*
|
||||
|
@ -62,15 +56,24 @@ static const struct Cp437Multimappings {
|
|||
* @see bing()
|
||||
*/
|
||||
int unbing(int c) {
|
||||
int i;
|
||||
for (i = 0; i < 256; ++i) {
|
||||
if (c == kCp437[i]) {
|
||||
return i;
|
||||
int i, m, l, r;
|
||||
static bool once;
|
||||
if (!once) {
|
||||
for (i = 0; i < 256; ++i) g_cp437i[i] = kCp437[i] << 8 | i;
|
||||
memcpy(g_cp437i + 256, kCp437iMultimappings, sizeof(kCp437iMultimappings));
|
||||
insertionsort(ARRAYLEN(g_cp437i), g_cp437i);
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ALTCOUNT; ++i) {
|
||||
if (c == kCp437iMultimappings.c[i]) {
|
||||
return kCp437iMultimappings.b[i];
|
||||
l = 0;
|
||||
r = ARRAYLEN(g_cp437i) - 1;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
if ((g_cp437i[m] >> 8) < c) {
|
||||
l = m + 1;
|
||||
} else if ((g_cp437i[m] >> 8) > c) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return g_cp437i[m] & 0xff;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
|
|
@ -318,6 +318,15 @@ typedef uint64_t uintmax_t;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef noclone
|
||||
#if !defined(__STRICT_ANSI__) && \
|
||||
(__has_attribute(__noclone__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 405)
|
||||
#define noclone __attribute__((__noclone__))
|
||||
#else
|
||||
#define noclone
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Makes function behave as much like macro as possible, meaning:
|
||||
*
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#define kLogError 1u
|
||||
#define kLogWarn 2u
|
||||
#define kLogInfo 3u
|
||||
#define kLogDebug 4u
|
||||
#define kLogVerbose 4u
|
||||
#define kLogDebug 5u
|
||||
|
||||
/**
|
||||
* Log level for compile-time DCE.
|
||||
|
@ -20,7 +21,7 @@
|
|||
/* #elif IsTiny() */
|
||||
/* #define LOGGABLELEVEL kLogInfo */
|
||||
#else
|
||||
#define LOGGABLELEVEL kLogInfo
|
||||
#define LOGGABLELEVEL kLogVerbose
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -149,6 +150,13 @@ extern unsigned g_loglevel; /* log level for runtime check */
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define VERBOSEF(FMT, ...) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogVerbose)) { \
|
||||
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VDEBUGF(FMT, VA) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogDebug)) { \
|
||||
|
@ -163,6 +171,13 @@ extern unsigned g_loglevel; /* log level for runtime check */
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define VFVERBOSEF(F, FMT, VA) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogVerbose)) { \
|
||||
vfverbosef(kLogVerbose, __FILE__, __LINE__, F, FMT, VA); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VFDEBUGF(F, FMT, VA) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogDebug)) { \
|
||||
|
@ -203,6 +218,8 @@ void __logerrno(const char *, int, const char *) relegated;
|
|||
#define ATTRV paramsnonnull((5, 6))
|
||||
void flogf(ARGS, ...) ATTR libcesque;
|
||||
void vflogf(ARGS, va_list) ATTRV libcesque;
|
||||
void fverbosef(ARGS, ...) asm("flogf") ATTR relegated libcesque;
|
||||
void vfverbosef(ARGS, va_list) asm("vflogf") ATTRV relegated libcesque;
|
||||
void fdebugf(ARGS, ...) asm("flogf") ATTR relegated libcesque;
|
||||
void vfdebugf(ARGS, va_list) asm("vflogf") ATTRV relegated libcesque;
|
||||
void ffatalf(ARGS, ...) asm("flogf") ATTR relegated noreturn libcesque;
|
||||
|
|
|
@ -76,7 +76,6 @@ void vflogf_onfail(FILE *f) {
|
|||
void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
||||
const char *fmt, va_list va) {
|
||||
static struct timespec ts;
|
||||
bool flush;
|
||||
struct tm tm;
|
||||
long double t2;
|
||||
const char *prog;
|
||||
|
@ -95,12 +94,10 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
|||
timebufp = timebuf;
|
||||
zonebufp = zonebuf;
|
||||
dots = nsec;
|
||||
flush = true;
|
||||
} else {
|
||||
timebufp = "---------------";
|
||||
zonebufp = "---";
|
||||
dots = nsec - ts.tv_nsec;
|
||||
flush = true;
|
||||
}
|
||||
ts.tv_sec = secs;
|
||||
ts.tv_nsec = nsec;
|
||||
|
@ -113,7 +110,6 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
|||
(vfprintf)(f, fmt, va);
|
||||
va_end(va);
|
||||
fputc('\n', f);
|
||||
if (flush) fflush(f);
|
||||
if (level == kLogFatal) {
|
||||
startfatal(file, line);
|
||||
fprintf(stderr, "fatal error see logfile\n");
|
||||
|
|
24
libc/nexgen32e/bsf.c
Normal file
24
libc/nexgen32e/bsf.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
|
||||
int(bsf)(int x) {
|
||||
return bsf(x);
|
||||
}
|
|
@ -17,12 +17,15 @@ COSMOPOLITAN_C_START_
|
|||
* 0xffffffff 0 0 1 31 0
|
||||
*/
|
||||
|
||||
int bsf(int);
|
||||
int bsfl(long);
|
||||
int bsfll(long long);
|
||||
int bsfmax(uintmax_t);
|
||||
|
||||
#define bsf(u) __builtin_ctz(u)
|
||||
#define bsfl(u) __builtin_ctzl(u)
|
||||
#define bsfll(u) __builtin_ctzll(u)
|
||||
|
||||
unsigned bsfmax(uintmax_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_BSF_H_ */
|
||||
|
|
24
libc/nexgen32e/bsfl.c
Normal file
24
libc/nexgen32e/bsfl.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
|
||||
int(bsfl)(long x) {
|
||||
return bsfl(x);
|
||||
}
|
24
libc/nexgen32e/bsfll.c
Normal file
24
libc/nexgen32e/bsfll.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
|
||||
int(bsfll)(long long x) {
|
||||
return bsfll(x);
|
||||
}
|
24
libc/nexgen32e/bsr.c
Normal file
24
libc/nexgen32e/bsr.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
|
||||
int(bsr)(int x) {
|
||||
return bsr(x);
|
||||
}
|
|
@ -17,11 +17,14 @@ COSMOPOLITAN_C_START_
|
|||
* 0xffffffff 0 0 1 31 0
|
||||
*/
|
||||
|
||||
#define bsr(u) ((sizeof(unsigned) * 8 - 1) ^ __builtin_clz(u))
|
||||
#define bsrl(u) ((sizeof(unsigned long) * 8 - 1) ^ __builtin_clzl(u))
|
||||
#define bsrll(u) ((sizeof(unsigned long long) * 8 - 1) ^ __builtin_clzll(u))
|
||||
int bsr(int);
|
||||
int bsrl(long);
|
||||
int bsrll(long long);
|
||||
int bsrmax(uintmax_t);
|
||||
|
||||
unsigned bsrmax(uintmax_t);
|
||||
#define bsr(u) ((sizeof(int) * 8 - 1) ^ __builtin_clz(u))
|
||||
#define bsrl(u) ((sizeof(long) * 8 - 1) ^ __builtin_clzl(u))
|
||||
#define bsrll(u) ((sizeof(long long) * 8 - 1) ^ __builtin_clzll(u))
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
24
libc/nexgen32e/bsrl.c
Normal file
24
libc/nexgen32e/bsrl.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
|
||||
int(bsrl)(long x) {
|
||||
return bsrl(x);
|
||||
}
|
24
libc/nexgen32e/bsrll.c
Normal file
24
libc/nexgen32e/bsrll.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
|
||||
int(bsrll)(long long x) {
|
||||
return bsrll(x);
|
||||
}
|
|
@ -24,9 +24,9 @@
|
|||
void djbsort$avx2(int32_t *, long);
|
||||
|
||||
/**
|
||||
* D.J. Bernstein's fast integer sorting algorithm.
|
||||
* D.J. Bernstein's outrageously fast integer sorting algorithm.
|
||||
*/
|
||||
void djbsort(size_t n, int32_t *a) {
|
||||
void djbsort(size_t n, int32_t a[n]) {
|
||||
if (X86_HAVE(AVX2)) {
|
||||
djbsort$avx2(a, n);
|
||||
} else {
|
|
@ -49,11 +49,11 @@ CollectGarbage:
|
|||
sub $0x20,%rsp
|
||||
push %rax
|
||||
push %rdx
|
||||
movaps %xmm0,-0x20(%rbp)
|
||||
movaps %xmm1,-0x10(%rbp)
|
||||
movdqa %xmm0,-0x20(%rbp)
|
||||
movdqa %xmm1,-0x10(%rbp)
|
||||
call *%r9
|
||||
movaps -0x10(%rbp),%xmm1
|
||||
movaps -0x20(%rbp),%xmm0
|
||||
movdqa -0x10(%rbp),%xmm1
|
||||
movdqa -0x20(%rbp),%xmm0
|
||||
pop %rdx
|
||||
pop %rax
|
||||
leave
|
||||
|
|
|
@ -70,7 +70,7 @@ kCpuids:.long 0,0,0,0 # EAX=0 (Basic Processor Info)
|
|||
add $4*4,%rdi
|
||||
jmp 2b
|
||||
3: nop
|
||||
#if 0 && !X86_NEED(AVX2)
|
||||
#if !X86_NEED(AVX2)
|
||||
testb X86_HAVE(AVX)(%r8)
|
||||
jz 5f
|
||||
testb X86_HAVE(OSXSAVE)(%r8)
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
#define X86_AES 1H, ECX, 25, _X86_CC_AES, _ /* westmere c. 2010 */
|
||||
#define X86_APIC 1H, EDX, 9, 0, _
|
||||
#define X86_ARCH_CAPABILITIES 7H, EDX, 29, 0, _
|
||||
#define X86_AVX 1H, ECX, 28, _X86_CC_AVX, AVX /* sandybridge c. 2012 */
|
||||
#define X86_AVX2 7H, EBX, 5, _X86_CC_AVX2, AVX /* haswell c. 2013 */
|
||||
#define X86_AVX 1H, ECX, 28, _X86_CC_AVX, _ /* sandybridge c. 2012 */
|
||||
#define X86_AVX2 7H, EBX, 5, _X86_CC_AVX2, _ /* haswell c. 2013 */
|
||||
#define X86_AVX512BW 7H, EBX, 30, 0, _
|
||||
#define X86_AVX512CD 7H, EBX, 28, 0, _
|
||||
#define X86_AVX512DQ 7H, EBX, 17, 0, _
|
||||
|
@ -246,17 +246,5 @@
|
|||
#endif
|
||||
|
||||
#define _X86_HOOK__(X) X
|
||||
#define _X86_HOOK_AVX(X) \
|
||||
({ \
|
||||
YOINK(_init_enableavx); \
|
||||
X; \
|
||||
})
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int _init_enableavx(void) pureconst;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_X86FEATURE_H_ */
|
||||
|
|
|
@ -23,6 +23,11 @@
|
|||
.source __FILE__
|
||||
|
||||
/ Calls global initialization functions.
|
||||
/
|
||||
/ @param r12 is argc
|
||||
/ @param r13 is argv
|
||||
/ @param r14 is environ
|
||||
/ @param r15 is auxv
|
||||
_construct:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
|
|
|
@ -43,8 +43,8 @@ static struct CxaAtexitBlocks {
|
|||
*
|
||||
* Destructors are called in reverse order. They won't be called if the
|
||||
* program aborts or _exit() is called. Invocations of this function are
|
||||
* usually generated by the C++ compiler. Behavior is limitless if you
|
||||
* choose to link calloc() and free().
|
||||
* usually generated by the C++ compiler. Behavior is limitless if some
|
||||
* other module has linked calloc().
|
||||
*
|
||||
* @param fp is void(*)(T)
|
||||
* @param arg is passed to callback
|
||||
|
@ -78,8 +78,11 @@ int __cxa_atexit(void *fp, void *arg, void *pred) {
|
|||
/**
|
||||
* Triggers global destructors.
|
||||
*
|
||||
* They're called in LIFO order. If a destructor adds more destructors,
|
||||
* then those destructors will be called immediately following, before
|
||||
* iteration continues.
|
||||
*
|
||||
* @param pred can be null to match all
|
||||
* @note reentrant emptor
|
||||
*/
|
||||
void __cxa_finalize(void *pred) {
|
||||
unsigned i;
|
||||
|
|
|
@ -129,7 +129,7 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
|
|||
if (!CANONICAL(addr)) return VIP(einval());
|
||||
if (!(!!(flags & MAP_ANONYMOUS) ^ (fd != -1))) return VIP(einval());
|
||||
if (!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED))) return VIP(einval());
|
||||
if (!(IsWindows() && fd != -1)) size = ROUNDUP(size, FRAMESIZE);
|
||||
if (fd != -1) size = ROUNDUP(size, FRAMESIZE);
|
||||
if (flags & MAP_FIXED) {
|
||||
if (UntrackMemoryIntervals(addr, size) == -1) {
|
||||
return MAP_FAILED;
|
||||
|
|
|
@ -37,6 +37,7 @@ LIBC_RUNTIME_A_DIRECTDEPS = \
|
|||
LIBC_BITS \
|
||||
LIBC_CALLS \
|
||||
LIBC_CONV \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_NEXGEN32E \
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
#include "libc/macros.h"
|
||||
|
||||
/ Self-bootstraps process upon existence before calling main.
|
||||
/
|
||||
/ @param r12 is argc
|
||||
/ @param r13 is argv
|
||||
/ @param r14 is environ
|
||||
/ @param r15 is auxv
|
||||
_spawn: push %rbp
|
||||
mov %rsp,%rbp
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ void *isnotplaintext(const void *, size_t) nothrow nocallback nosideeffect;
|
|||
└──────────────3 Continuations follow */
|
||||
|
||||
#define INVALID_CODEPOINT 0xfffd
|
||||
|
||||
#define UTF16_MASK 0b1111110000000000
|
||||
#define UTF16_MOAR 0b1101100000000000 /* 0xD800..0xDBFF */
|
||||
#define UTF16_CONT 0b1101110000000000 /* 0xDC00..0xDBFF */
|
||||
|
|
8
libc/str/thompike.h
Normal file
8
libc/str/thompike.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_STR_THOMPIKE_H_
|
||||
#define COSMOPOLITAN_LIBC_STR_THOMPIKE_H_
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
|
||||
#define ThomPikeCont(x) ((x & 0b11000000) == 0b10000000)
|
||||
#define ThomPikeByte(x) (x & (((1 << (x < 252 ? bsr(~x & 0xff) : 1)) - 1) | 3))
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_STR_THOMPIKE_H_ */
|
|
@ -2611,7 +2611,7 @@ syscon ioctl FIONREAD 0x541b 0x4004667f 0x4004667f 0x4004667f 0x4004667f
|
|||
#syscon ioctl FIONWRITE 0x0 0x0 0x40046677 0x0 -1 # [FreeBSD Generalization] bytes queued in FD's output buffer (same as TIOCOUTQ for TTY FDs; see also SO_SNDBUF)
|
||||
#syscon ioctl FIONSPACE 0x0 0x0 0x40046676 0x0 -1 # [FreeBSD Generalization] capacity of FD's output buffer, e.g. equivalent to TIOCGSERIAL w/ UART
|
||||
syscon ioctl TIOCINQ 0x541b 0x4004667f 0x4004667f 0x4004667f 0x4004667f # [Linuxism] same as FIONREAD
|
||||
syscon ioctl TIOCOUTQ 0x5411 0x40047473 0x40047473 0x40047473 -1 # bytes queued in TTY's output buffer
|
||||
#syscon ioctl TIOCOUTQ 0x5411 0x40047473 0x40047473 0x40047473 -1 # bytes queued in TTY's output buffer
|
||||
|
||||
syscon misc FANOTIFY_METADATA_VERSION 3 0 0 0 0
|
||||
syscon misc FAPPEND 0x0400 8 8 8 0 # bsd consensus
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
__fpclassify:
|
||||
tinymath_fpclassify:
|
||||
.leafprologue
|
||||
movd %xmm0,%rax
|
||||
movd %xmm0,%rdx
|
||||
|
@ -41,4 +41,5 @@ __fpclassify:
|
|||
sal $12,%rdx
|
||||
sete %al
|
||||
1: .leafepilogue
|
||||
.endfn __fpclassify,globl
|
||||
.endfn tinymath_fpclassify,globl
|
||||
.alias tinymath_fpclassify,__fpclassify
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
__fpclassifyf:
|
||||
tinymath_fpclassifyf:
|
||||
.leafprologue
|
||||
movd %xmm0,%edx
|
||||
movd %xmm0,%eax
|
||||
|
@ -42,4 +42,5 @@ __fpclassifyf:
|
|||
sete %al
|
||||
movzbl %al,%eax
|
||||
1: .leafepilogue
|
||||
.endfn __fpclassifyf,globl
|
||||
.endfn tinymath_fpclassifyf,globl
|
||||
.alias tinymath_fpclassifyf,__fpclassifyf
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
__fpclassifyl:
|
||||
tinymath_fpclassifyl:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
mov 24(%rbp),%rax
|
||||
|
@ -50,4 +50,5 @@ __fpclassifyl:
|
|||
and $FP_NORMAL,%eax
|
||||
1: pop %rbp
|
||||
ret
|
||||
.endfn __fpclassifyl,globl
|
||||
.endfn tinymath_fpclassifyl,globl
|
||||
.alias tinymath_fpclassifyl,__fpclassifyl
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
/ Returns 𝑥 × 2ʸ.
|
||||
/
|
||||
/ @param 𝑥 is double passed in %xmm0
|
||||
/ @param 𝑦 is exponent via %edi
|
||||
tinymath_scalbn:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
/ Returns 𝑥 × 2ʸ.
|
||||
/
|
||||
/ @param 𝑥 is float passed in %xmm0
|
||||
/ @param 𝑦 is exponent via %edi
|
||||
tinymath_scalbnf:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
|
|
|
@ -20,11 +20,10 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
/ Returns 𝑥 × 𝑟ʸ where 𝑟 is radix of hardware architecture.
|
||||
/ Returns 𝑥 × 2ʸ.
|
||||
/
|
||||
/ @param 𝑥 is long double passed on stack
|
||||
/ @param 𝑦 is exponent via %edi
|
||||
/ @see FLT_RADIX
|
||||
tinymath_scalbnl:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
|
|
|
@ -19,12 +19,14 @@ TEST_LIBC_FMT_CHECKS = \
|
|||
$(TEST_LIBC_FMT_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
|
||||
|
||||
TEST_LIBC_FMT_DIRECTDEPS = \
|
||||
LIBC_ALG \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_CONV \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
|
|
|
@ -355,14 +355,14 @@ TEST(punpckhwd, test) {
|
|||
uint16_t b[8] = {9, 10, 11, 12, 13, 14, 15, 16};
|
||||
uint16_t c[8];
|
||||
punpckhwd(c, a, b);
|
||||
ASSERT_EQ(5, c[0]);
|
||||
ASSERT_EQ(13, c[1]);
|
||||
ASSERT_EQ(6, c[2]);
|
||||
ASSERT_EQ(14, c[3]);
|
||||
ASSERT_EQ(7, c[4]);
|
||||
ASSERT_EQ(15, c[5]);
|
||||
ASSERT_EQ(8, c[6]);
|
||||
ASSERT_EQ(16, c[7]);
|
||||
EXPECT_EQ(5, c[0]);
|
||||
EXPECT_EQ(13, c[1]);
|
||||
EXPECT_EQ(6, c[2]);
|
||||
EXPECT_EQ(14, c[3]);
|
||||
EXPECT_EQ(7, c[4]);
|
||||
EXPECT_EQ(15, c[5]);
|
||||
EXPECT_EQ(8, c[6]);
|
||||
EXPECT_EQ(16, c[7]);
|
||||
}
|
||||
|
||||
TEST(punpckhwd, pure) {
|
||||
|
@ -370,70 +370,70 @@ TEST(punpckhwd, pure) {
|
|||
uint16_t b[8] = {9, 10, 11, 12, 13, 14, 15, 16};
|
||||
uint16_t c[8];
|
||||
punpckhwd(c, a, b);
|
||||
ASSERT_EQ(5, c[0]);
|
||||
ASSERT_EQ(13, c[1]);
|
||||
ASSERT_EQ(6, c[2]);
|
||||
ASSERT_EQ(14, c[3]);
|
||||
ASSERT_EQ(7, c[4]);
|
||||
ASSERT_EQ(15, c[5]);
|
||||
ASSERT_EQ(8, c[6]);
|
||||
ASSERT_EQ(16, c[7]);
|
||||
EXPECT_EQ(5, c[0]);
|
||||
EXPECT_EQ(13, c[1]);
|
||||
EXPECT_EQ(6, c[2]);
|
||||
EXPECT_EQ(14, c[3]);
|
||||
EXPECT_EQ(7, c[4]);
|
||||
EXPECT_EQ(15, c[5]);
|
||||
EXPECT_EQ(8, c[6]);
|
||||
EXPECT_EQ(16, c[7]);
|
||||
}
|
||||
|
||||
TEST(punpckhwd, testAlias) {
|
||||
uint16_t a[8] = {1, 02, 03, 04, 05, 06, 07, 8};
|
||||
uint16_t b[8] = {9, 10, 11, 12, 13, 14, 15, 16};
|
||||
punpckhwd(a, a, b);
|
||||
ASSERT_EQ(5, a[0]);
|
||||
ASSERT_EQ(13, a[1]);
|
||||
ASSERT_EQ(6, a[2]);
|
||||
ASSERT_EQ(14, a[3]);
|
||||
ASSERT_EQ(7, a[4]);
|
||||
ASSERT_EQ(15, a[5]);
|
||||
ASSERT_EQ(8, a[6]);
|
||||
ASSERT_EQ(16, a[7]);
|
||||
EXPECT_EQ(5, a[0]);
|
||||
EXPECT_EQ(13, a[1]);
|
||||
EXPECT_EQ(6, a[2]);
|
||||
EXPECT_EQ(14, a[3]);
|
||||
EXPECT_EQ(7, a[4]);
|
||||
EXPECT_EQ(15, a[5]);
|
||||
EXPECT_EQ(8, a[6]);
|
||||
EXPECT_EQ(16, a[7]);
|
||||
}
|
||||
|
||||
TEST(punpckhwd, pureAlias) {
|
||||
uint16_t a[8] = {1, 02, 03, 04, 05, 06, 07, 8};
|
||||
uint16_t b[8] = {9, 10, 11, 12, 13, 14, 15, 16};
|
||||
(punpckhwd)(a, a, b);
|
||||
ASSERT_EQ(5, a[0]);
|
||||
ASSERT_EQ(13, a[1]);
|
||||
ASSERT_EQ(6, a[2]);
|
||||
ASSERT_EQ(14, a[3]);
|
||||
ASSERT_EQ(7, a[4]);
|
||||
ASSERT_EQ(15, a[5]);
|
||||
ASSERT_EQ(8, a[6]);
|
||||
ASSERT_EQ(16, a[7]);
|
||||
EXPECT_EQ(5, a[0]);
|
||||
EXPECT_EQ(13, a[1]);
|
||||
EXPECT_EQ(6, a[2]);
|
||||
EXPECT_EQ(14, a[3]);
|
||||
EXPECT_EQ(7, a[4]);
|
||||
EXPECT_EQ(15, a[5]);
|
||||
EXPECT_EQ(8, a[6]);
|
||||
EXPECT_EQ(16, a[7]);
|
||||
}
|
||||
|
||||
TEST(punpckhwd, testAlias2) {
|
||||
uint16_t a[8] = {1, 02, 03, 04, 05, 06, 07, 8};
|
||||
uint16_t b[8] = {9, 10, 11, 12, 13, 14, 15, 16};
|
||||
punpckhwd(b, a, b);
|
||||
ASSERT_EQ(5, b[0]);
|
||||
ASSERT_EQ(13, b[1]);
|
||||
ASSERT_EQ(6, b[2]);
|
||||
ASSERT_EQ(14, b[3]);
|
||||
ASSERT_EQ(7, b[4]);
|
||||
ASSERT_EQ(15, b[5]);
|
||||
ASSERT_EQ(8, b[6]);
|
||||
ASSERT_EQ(16, b[7]);
|
||||
EXPECT_EQ(5, b[0]);
|
||||
EXPECT_EQ(13, b[1]);
|
||||
EXPECT_EQ(6, b[2]);
|
||||
EXPECT_EQ(14, b[3]);
|
||||
EXPECT_EQ(7, b[4]);
|
||||
EXPECT_EQ(15, b[5]);
|
||||
EXPECT_EQ(8, b[6]);
|
||||
EXPECT_EQ(16, b[7]);
|
||||
}
|
||||
|
||||
TEST(punpckhwd, pureAlias2) {
|
||||
uint16_t a[8] = {1, 02, 03, 04, 05, 06, 07, 8};
|
||||
uint16_t b[8] = {9, 10, 11, 12, 13, 14, 15, 16};
|
||||
(punpckhwd)(b, a, b);
|
||||
ASSERT_EQ(5, b[0]);
|
||||
ASSERT_EQ(13, b[1]);
|
||||
ASSERT_EQ(6, b[2]);
|
||||
ASSERT_EQ(14, b[3]);
|
||||
ASSERT_EQ(7, b[4]);
|
||||
ASSERT_EQ(15, b[5]);
|
||||
ASSERT_EQ(8, b[6]);
|
||||
ASSERT_EQ(16, b[7]);
|
||||
EXPECT_EQ(5, b[0]);
|
||||
EXPECT_EQ(13, b[1]);
|
||||
EXPECT_EQ(6, b[2]);
|
||||
EXPECT_EQ(14, b[3]);
|
||||
EXPECT_EQ(7, b[4]);
|
||||
EXPECT_EQ(15, b[5]);
|
||||
EXPECT_EQ(8, b[6]);
|
||||
EXPECT_EQ(16, b[7]);
|
||||
}
|
||||
|
||||
TEST(punpckhqdq, test) {
|
||||
|
@ -441,8 +441,8 @@ TEST(punpckhqdq, test) {
|
|||
uint64_t b[2] = {3, 4};
|
||||
uint64_t c[2];
|
||||
punpckhqdq(c, a, b);
|
||||
ASSERT_EQ(2, c[0]);
|
||||
ASSERT_EQ(4, c[1]);
|
||||
EXPECT_EQ(2, c[0]);
|
||||
EXPECT_EQ(4, c[1]);
|
||||
}
|
||||
|
||||
TEST(punpckhqdq, pure) {
|
||||
|
@ -450,24 +450,24 @@ TEST(punpckhqdq, pure) {
|
|||
uint64_t b[2] = {3, 4};
|
||||
uint64_t c[2];
|
||||
(punpckhqdq)(c, a, b);
|
||||
ASSERT_EQ(2, c[0]);
|
||||
ASSERT_EQ(4, c[1]);
|
||||
EXPECT_EQ(2, c[0]);
|
||||
EXPECT_EQ(4, c[1]);
|
||||
}
|
||||
|
||||
TEST(punpckhqdq, testAlias) {
|
||||
uint64_t a[2] = {1, 2};
|
||||
uint64_t b[2] = {3, 4};
|
||||
punpckhqdq(a, a, b);
|
||||
ASSERT_EQ(2, a[0]);
|
||||
ASSERT_EQ(4, a[1]);
|
||||
EXPECT_EQ(2, a[0]);
|
||||
EXPECT_EQ(4, a[1]);
|
||||
}
|
||||
|
||||
TEST(punpckhqdq, pureAlias) {
|
||||
uint64_t a[2] = {1, 2};
|
||||
uint64_t b[2] = {3, 4};
|
||||
(punpckhqdq)(a, a, b);
|
||||
ASSERT_EQ(2, a[0]);
|
||||
ASSERT_EQ(4, a[1]);
|
||||
EXPECT_EQ(2, a[0]);
|
||||
EXPECT_EQ(4, a[1]);
|
||||
}
|
||||
|
||||
TEST(punpckhdq, test) {
|
||||
|
@ -475,10 +475,10 @@ TEST(punpckhdq, test) {
|
|||
uint32_t b[4] = {5, 6, 7, 8};
|
||||
uint32_t c[4];
|
||||
punpckhdq(c, a, b);
|
||||
ASSERT_EQ(3, c[0]);
|
||||
ASSERT_EQ(7, c[1]);
|
||||
ASSERT_EQ(4, c[2]);
|
||||
ASSERT_EQ(8, c[3]);
|
||||
EXPECT_EQ(3, c[0]);
|
||||
EXPECT_EQ(7, c[1]);
|
||||
EXPECT_EQ(4, c[2]);
|
||||
EXPECT_EQ(8, c[3]);
|
||||
}
|
||||
|
||||
TEST(punpckhdq, pure) {
|
||||
|
@ -486,50 +486,50 @@ TEST(punpckhdq, pure) {
|
|||
uint32_t b[4] = {5, 6, 7, 8};
|
||||
uint32_t c[4];
|
||||
punpckhdq(c, a, b);
|
||||
ASSERT_EQ(3, c[0]);
|
||||
ASSERT_EQ(7, c[1]);
|
||||
ASSERT_EQ(4, c[2]);
|
||||
ASSERT_EQ(8, c[3]);
|
||||
EXPECT_EQ(3, c[0]);
|
||||
EXPECT_EQ(7, c[1]);
|
||||
EXPECT_EQ(4, c[2]);
|
||||
EXPECT_EQ(8, c[3]);
|
||||
}
|
||||
|
||||
TEST(punpckhdq, testAlias) {
|
||||
uint32_t a[4] = {1, 2, 3, 4};
|
||||
uint32_t b[4] = {5, 6, 7, 8};
|
||||
punpckhdq(a, a, b);
|
||||
ASSERT_EQ(3, a[0]);
|
||||
ASSERT_EQ(7, a[1]);
|
||||
ASSERT_EQ(4, a[2]);
|
||||
ASSERT_EQ(8, a[3]);
|
||||
EXPECT_EQ(3, a[0]);
|
||||
EXPECT_EQ(7, a[1]);
|
||||
EXPECT_EQ(4, a[2]);
|
||||
EXPECT_EQ(8, a[3]);
|
||||
}
|
||||
|
||||
TEST(punpckhdq, pureAlias) {
|
||||
uint32_t a[4] = {1, 2, 3, 4};
|
||||
uint32_t b[4] = {5, 6, 7, 8};
|
||||
(punpckhdq)(a, a, b);
|
||||
ASSERT_EQ(3, a[0]);
|
||||
ASSERT_EQ(7, a[1]);
|
||||
ASSERT_EQ(4, a[2]);
|
||||
ASSERT_EQ(8, a[3]);
|
||||
EXPECT_EQ(3, a[0]);
|
||||
EXPECT_EQ(7, a[1]);
|
||||
EXPECT_EQ(4, a[2]);
|
||||
EXPECT_EQ(8, a[3]);
|
||||
}
|
||||
|
||||
TEST(punpckhdq, testAlias2) {
|
||||
uint32_t a[4] = {1, 2, 3, 4};
|
||||
uint32_t b[4] = {5, 6, 7, 8};
|
||||
punpckhdq(b, a, b);
|
||||
ASSERT_EQ(3, b[0]);
|
||||
ASSERT_EQ(7, b[1]);
|
||||
ASSERT_EQ(4, b[2]);
|
||||
ASSERT_EQ(8, b[3]);
|
||||
EXPECT_EQ(3, b[0]);
|
||||
EXPECT_EQ(7, b[1]);
|
||||
EXPECT_EQ(4, b[2]);
|
||||
EXPECT_EQ(8, b[3]);
|
||||
}
|
||||
|
||||
TEST(punpckhdq, pureAlias2) {
|
||||
uint32_t a[4] = {1, 2, 3, 4};
|
||||
uint32_t b[4] = {5, 6, 7, 8};
|
||||
(punpckhdq)(b, a, b);
|
||||
ASSERT_EQ(3, b[0]);
|
||||
ASSERT_EQ(7, b[1]);
|
||||
ASSERT_EQ(4, b[2]);
|
||||
ASSERT_EQ(8, b[3]);
|
||||
EXPECT_EQ(3, b[0]);
|
||||
EXPECT_EQ(7, b[1]);
|
||||
EXPECT_EQ(4, b[2]);
|
||||
EXPECT_EQ(8, b[3]);
|
||||
}
|
||||
|
||||
TEST(punpckhwd, fuzz) {
|
||||
|
|
|
@ -29,6 +29,7 @@ TEST_LIBC_RUNTIME_DIRECTDEPS = \
|
|||
LIBC_CALLS_HEFTY \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
|
|
|
@ -36,10 +36,9 @@ void SetUp(void) {
|
|||
TEST(bsr64, test) {
|
||||
bool zf;
|
||||
uint64_t i, w, x, a, b;
|
||||
m->xedd->op.rde = REXW;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, 0, x);
|
||||
a = AluBsr(m, REXW, 0, x);
|
||||
asm("bsrq\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
|
@ -49,10 +48,9 @@ TEST(bsr64, test) {
|
|||
TEST(bsr32, test) {
|
||||
bool zf;
|
||||
uint32_t i, w, x, a, b;
|
||||
m->xedd->op.rde = 0;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, 0, x);
|
||||
a = AluBsr(m, 0, 0, x);
|
||||
asm("bsrl\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
|
@ -62,10 +60,9 @@ TEST(bsr32, test) {
|
|||
TEST(bsr16, test) {
|
||||
bool zf;
|
||||
uint16_t i, w, x, a, b;
|
||||
m->xedd->op.rde = OSZ;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, 0, x);
|
||||
a = AluBsr(m, OSZ, 0, x);
|
||||
asm("bsrw\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
|
@ -75,10 +72,9 @@ TEST(bsr16, test) {
|
|||
TEST(bsf64, test) {
|
||||
bool zf;
|
||||
uint64_t i, w, x, a, b;
|
||||
m->xedd->op.rde = REXW;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, 0, x);
|
||||
a = AluBsf(m, REXW, 0, x);
|
||||
asm("bsfq\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
|
@ -88,10 +84,9 @@ TEST(bsf64, test) {
|
|||
TEST(bsf32, test) {
|
||||
bool zf;
|
||||
uint32_t i, w, x, a, b;
|
||||
m->xedd->op.rde = 0;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, 0, x);
|
||||
a = AluBsf(m, 0, 0, x);
|
||||
asm("bsfl\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
|
@ -101,10 +96,9 @@ TEST(bsf32, test) {
|
|||
TEST(bsf16, test) {
|
||||
bool zf;
|
||||
uint16_t i, w, x, a, b;
|
||||
m->xedd->op.rde = OSZ;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, 0, x);
|
||||
a = AluBsf(m, OSZ, 0, x);
|
||||
asm("bsfw\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b, "%#lx", x);
|
||||
|
|
|
@ -62,12 +62,11 @@ TEST(imul8, test) {
|
|||
int i, j;
|
||||
int16_t ax;
|
||||
bool cf, of;
|
||||
m->xedd->op.rde = MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write8(m->ax, A[i]);
|
||||
Write8(m->cx, A[j]);
|
||||
OpMulAxAlEbSigned(m);
|
||||
OpMulAxAlEbSigned(m, MOD(3) | RM(CX));
|
||||
asm volatile("imulb\t%3"
|
||||
: "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "q"(A[j]), "0"(A[i])
|
||||
|
@ -85,12 +84,11 @@ TEST(imul16, test) {
|
|||
int i, j;
|
||||
bool cf, of;
|
||||
uint16_t dx, ax;
|
||||
m->xedd->op.rde = OSZ | MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write16(m->ax, A[i]);
|
||||
Write16(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m);
|
||||
OpMulRdxRaxEvqpSigned(m, OSZ | MOD(3) | RM(CX));
|
||||
asm("imulw\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
|
@ -110,12 +108,11 @@ TEST(imul32, test) {
|
|||
int i, j;
|
||||
bool cf, of;
|
||||
uint32_t dx, ax;
|
||||
m->xedd->op.rde = MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write32(m->ax, A[i]);
|
||||
Write32(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m);
|
||||
OpMulRdxRaxEvqpSigned(m, MOD(3) | RM(CX));
|
||||
asm("imull\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
|
@ -135,12 +132,11 @@ TEST(imul64, test) {
|
|||
int i, j;
|
||||
bool cf, of;
|
||||
uint64_t dx, ax;
|
||||
m->xedd->op.rde = REXW | MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write64(m->ax, A[i]);
|
||||
Write64(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m);
|
||||
OpMulRdxRaxEvqpSigned(m, REXW | MOD(3) | RM(CX));
|
||||
asm("imulq\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
|
@ -158,12 +154,11 @@ TEST(mul8, test) {
|
|||
int i, j;
|
||||
uint16_t ax;
|
||||
bool cf, of;
|
||||
m->xedd->op.rde = MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write8(m->ax, A[i]);
|
||||
Write8(m->cx, A[j]);
|
||||
OpMulAxAlEbUnsigned(m);
|
||||
OpMulAxAlEbUnsigned(m, MOD(3) | RM(CX));
|
||||
asm volatile("mulb\t%3"
|
||||
: "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "q"(A[j]), "0"(A[i])
|
||||
|
@ -181,12 +176,11 @@ TEST(mul16, test) {
|
|||
int i, j;
|
||||
bool cf, of;
|
||||
uint16_t dx, ax;
|
||||
m->xedd->op.rde = OSZ | MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write16(m->ax, A[i]);
|
||||
Write16(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m);
|
||||
OpMulRdxRaxEvqpUnsigned(m, OSZ | MOD(3) | RM(CX));
|
||||
asm("mulw\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
|
@ -206,12 +200,11 @@ TEST(mul32, test) {
|
|||
int i, j;
|
||||
bool cf, of;
|
||||
uint32_t dx, ax;
|
||||
m->xedd->op.rde = MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write32(m->ax, A[i]);
|
||||
Write32(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m);
|
||||
OpMulRdxRaxEvqpUnsigned(m, MOD(3) | RM(CX));
|
||||
asm("mull\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
|
@ -231,12 +224,11 @@ TEST(mul64, test) {
|
|||
int i, j;
|
||||
bool cf, of;
|
||||
uint64_t dx, ax;
|
||||
m->xedd->op.rde = REXW | MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write64(m->ax, A[i]);
|
||||
Write64(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m);
|
||||
OpMulRdxRaxEvqpUnsigned(m, REXW | MOD(3) | RM(CX));
|
||||
asm("mulq\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
|
@ -255,7 +247,6 @@ TEST(idiv8, test) {
|
|||
bool gotthrow, gotsigfpe;
|
||||
int8_t i, j, k, w, x, a, b;
|
||||
int8_t quotient, remainder;
|
||||
m->xedd->op.rde = MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
|
@ -265,7 +256,7 @@ TEST(idiv8, test) {
|
|||
gotthrow = false;
|
||||
gotsigfpe = false;
|
||||
if (!setjmp(m->onhalt)) {
|
||||
OpDivAlAhAxEbSigned(m);
|
||||
OpDivAlAhAxEbSigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
|
@ -295,7 +286,6 @@ TEST(idiv16, test) {
|
|||
bool gotthrow, gotsigfpe;
|
||||
int16_t i, j, k, w, x, a, b;
|
||||
int16_t quotient, remainder;
|
||||
m->xedd->op.rde = OSZ | MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
|
@ -304,7 +294,7 @@ TEST(idiv16, test) {
|
|||
memcpy(m->cx, &A[k], 2);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m);
|
||||
OpDivRdxRaxEvqpSigned(m, OSZ | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
|
@ -333,7 +323,6 @@ TEST(idiv32, test) {
|
|||
bool gotthrow, gotsigfpe;
|
||||
int32_t i, j, k, w, x, a, b;
|
||||
int32_t quotient, remainder;
|
||||
m->xedd->op.rde = MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
|
@ -342,7 +331,7 @@ TEST(idiv32, test) {
|
|||
memcpy(m->cx, &A[k], 4);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m);
|
||||
OpDivRdxRaxEvqpSigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
|
@ -373,7 +362,6 @@ TEST(idiv64, test) {
|
|||
bool gotthrow, gotsigfpe;
|
||||
int64_t i, j, k, w, x, a, b;
|
||||
int64_t quotient, remainder;
|
||||
m->xedd->op.rde = REXW | MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
|
@ -382,7 +370,7 @@ TEST(idiv64, test) {
|
|||
memcpy(m->cx, &A[k], 8);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m);
|
||||
OpDivRdxRaxEvqpSigned(m, REXW | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
|
@ -411,7 +399,6 @@ TEST(div, test) {
|
|||
bool gotthrow, gotsigfpe;
|
||||
uint8_t i, j, k, w, x, a, b;
|
||||
uint8_t quotient, remainder;
|
||||
m->xedd->op.rde = MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
|
@ -421,7 +408,7 @@ TEST(div, test) {
|
|||
gotthrow = false;
|
||||
gotsigfpe = false;
|
||||
if (!setjmp(m->onhalt)) {
|
||||
OpDivAlAhAxEbUnsigned(m);
|
||||
OpDivAlAhAxEbUnsigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
|
@ -451,7 +438,6 @@ TEST(div16, test) {
|
|||
bool gotthrow, gotsigfpe;
|
||||
uint16_t i, j, k, w, x, a, b;
|
||||
uint16_t quotient, remainder;
|
||||
m->xedd->op.rde = OSZ | MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
|
@ -460,7 +446,7 @@ TEST(div16, test) {
|
|||
memcpy(m->cx, &A[k], 2);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m);
|
||||
OpDivRdxRaxEvqpUnsigned(m, OSZ | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
|
@ -489,7 +475,6 @@ TEST(div32, test) {
|
|||
bool gotthrow, gotsigfpe;
|
||||
uint32_t i, j, k, w, x, a, b;
|
||||
uint32_t quotient, remainder;
|
||||
m->xedd->op.rde = MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
|
@ -498,7 +483,7 @@ TEST(div32, test) {
|
|||
memcpy(m->cx, &A[k], 4);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m);
|
||||
OpDivRdxRaxEvqpUnsigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
|
@ -529,7 +514,6 @@ TEST(div64, test) {
|
|||
bool gotthrow, gotsigfpe;
|
||||
uint64_t i, j, k, w, x, a, b;
|
||||
uint64_t quotient, remainder;
|
||||
m->xedd->op.rde = REXW | MOD(3) | RM(CX);
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
|
@ -538,7 +522,7 @@ TEST(div64, test) {
|
|||
memcpy(m->cx, &A[k], 8);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m);
|
||||
OpDivRdxRaxEvqpUnsigned(m, REXW | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ TEST(modrm, testAddressSizeOverride_isNotPresent_keepsWholeExpression) {
|
|||
Write64(m->ax, 0xffffffff);
|
||||
xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(xedd, op, sizeof(op)));
|
||||
EXPECT_EQ(0x100000001, ComputeAddress(m));
|
||||
EXPECT_EQ(0x100000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testAddressSizeOverride_isPresent_modulesWholeExpression) {
|
||||
|
@ -46,7 +46,7 @@ TEST(modrm, testAddressSizeOverride_isPresent_modulesWholeExpression) {
|
|||
Write64(m->ax, 0xffffffff);
|
||||
xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(xedd, op, sizeof(op)));
|
||||
EXPECT_EQ(0x000000001, ComputeAddress(m));
|
||||
EXPECT_EQ(0x000000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testOverflow_doesntTriggerTooling) {
|
||||
|
@ -58,7 +58,8 @@ TEST(modrm, testOverflow_doesntTriggerTooling) {
|
|||
Write64(m->ax, 0x7fffffffffffffff);
|
||||
xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(xedd, op, sizeof(op)));
|
||||
EXPECT_EQ(0x8000000000000000ull, (uint64_t)ComputeAddress(m));
|
||||
EXPECT_EQ(0x8000000000000000ull,
|
||||
(uint64_t)ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testPuttingOnTheRiz) {
|
||||
|
@ -74,16 +75,16 @@ TEST(modrm, testPuttingOnTheRiz) {
|
|||
Write64(m->bp, 0x200000002);
|
||||
xed_decoded_inst_zero_set_mode(m->xedd, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(m->xedd, ops[0], sizeof(ops[0])));
|
||||
EXPECT_EQ(0x100000001, ComputeAddress(m));
|
||||
EXPECT_EQ(0x100000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
xed_decoded_inst_zero_set_mode(m->xedd, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(m->xedd, ops[1], sizeof(ops[1])));
|
||||
EXPECT_EQ(0x000000001, ComputeAddress(m));
|
||||
EXPECT_EQ(0x000000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
xed_decoded_inst_zero_set_mode(m->xedd, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(m->xedd, ops[2], sizeof(ops[2])));
|
||||
EXPECT_EQ(0x31339, ComputeAddress(m));
|
||||
EXPECT_EQ(0x31339, ComputeAddress(m, m->xedd->op.rde));
|
||||
xed_decoded_inst_zero_set_mode(m->xedd, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(m->xedd, ops[3], sizeof(ops[3])));
|
||||
EXPECT_EQ(0x31337, ComputeAddress(m));
|
||||
EXPECT_EQ(0x31337, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testSibIndexOnly) {
|
||||
|
@ -101,5 +102,5 @@ TEST(modrm, testSibIndexOnly) {
|
|||
Write64(m->cx, 0x123);
|
||||
xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(xedd, op, sizeof(op)));
|
||||
EXPECT_EQ(0x123 * 4, (uint64_t)ComputeAddress(m));
|
||||
EXPECT_EQ(0x123 * 4, (uint64_t)ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
|
2
third_party/compiler_rt/divmodti4.c
vendored
2
third_party/compiler_rt/divmodti4.c
vendored
|
@ -24,7 +24,7 @@ COMPILER_RT_ABI ti_int __divmodti4(ti_int a, ti_int b, tu_int *opt_out_rem) {
|
|||
tu_int r;
|
||||
ti_int sa, sb, sq, sr, x, y, q;
|
||||
k = sizeof(ti_int) * CHAR_BIT - 1;
|
||||
if (b < 0 && a == ((ti_int)1 << k)) {
|
||||
if (b == -1 && a == ((ti_int)1 << k)) {
|
||||
volatile int x = 0;
|
||||
x = 1 / x; // raise(SIGFPE)
|
||||
}
|
||||
|
|
7
third_party/xed/x86.h
vendored
7
third_party/xed/x86.h
vendored
|
@ -493,16 +493,15 @@ forceinline void xed_set_chip_modes(struct XedDecodedInst *d,
|
|||
extern const char kXedErrorNames[];
|
||||
extern const uint64_t xed_chip_features[XED_CHIP_LAST][3];
|
||||
|
||||
struct XedDecodedInst *xed_decoded_inst_zero_set_mode(struct XedDecodedInst *,
|
||||
enum XedMachineMode);
|
||||
|
||||
enum XedError xed_instruction_length_decode(struct XedDecodedInst *,
|
||||
const void *, size_t);
|
||||
enum XedError __xed_instruction_length_decode(struct XedDecodedInst *,
|
||||
const void *, size_t);
|
||||
|
||||
bool xed_isa_set_is_valid_for_chip(enum XedIsaSet, enum XedChip);
|
||||
bool xed_test_chip_features(struct XedChipFeatures *, enum XedIsaSet);
|
||||
void xed_get_chip_features(struct XedChipFeatures *, enum XedChip);
|
||||
struct XedDecodedInst *xed_decoded_inst_zero_set_mode(struct XedDecodedInst *,
|
||||
enum XedMachineMode);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
8
third_party/xed/x86ild.greg.c
vendored
8
third_party/xed/x86ild.greg.c
vendored
|
@ -375,19 +375,16 @@ privileged static void XED_LF_SIMM8_IMM_WIDTH_CONST_l2(
|
|||
privileged static void XED_LF_UIMM16_IMM_WIDTH_CONST_l2(
|
||||
struct XedDecodedInst *x) {
|
||||
x->op.imm_width = 16;
|
||||
x->op.imm_signed = false;
|
||||
}
|
||||
|
||||
privileged static void XED_LF_SE_IMM8_IMM_WIDTH_CONST_l2(
|
||||
struct XedDecodedInst *x) {
|
||||
x->op.imm_width = 8;
|
||||
x->op.imm_signed = false;
|
||||
}
|
||||
|
||||
privileged static void XED_LF_UIMM32_IMM_WIDTH_CONST_l2(
|
||||
struct XedDecodedInst *x) {
|
||||
x->op.imm_width = 32;
|
||||
x->op.imm_signed = false;
|
||||
}
|
||||
|
||||
privileged static void xed_set_simmz_imm_width_eosz(
|
||||
|
@ -401,18 +398,15 @@ privileged static void xed_set_uimmv_imm_width_eosz(
|
|||
struct XedDecodedInst *x, const xed_bits_t eosz[2][2][3]) {
|
||||
x->op.imm_width =
|
||||
kXed.UIMMv_IMM_WIDTH[eosz[x->op.rexw][x->op.osz][x->op.mode]];
|
||||
x->op.imm_signed = false;
|
||||
}
|
||||
|
||||
privileged static void XED_LF_UIMM8_IMM_WIDTH_CONST_l2(
|
||||
struct XedDecodedInst *x) {
|
||||
x->op.imm_width = 8;
|
||||
x->op.imm_signed = false;
|
||||
}
|
||||
|
||||
privileged static void XED_LF_0_IMM_WIDTH_CONST_l2(struct XedDecodedInst *x) {
|
||||
x->op.imm_width = 0;
|
||||
x->op.imm_signed = false;
|
||||
}
|
||||
|
||||
privileged static void XED_LF_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xc7_l1(
|
||||
|
@ -1212,7 +1206,7 @@ privileged static void xed_encode_rde(struct XedDecodedInst *x) {
|
|||
/**
|
||||
* Clears instruction decoder state.
|
||||
*/
|
||||
struct XedDecodedInst *xed_decoded_inst_zero_set_mode(
|
||||
privileged struct XedDecodedInst *xed_decoded_inst_zero_set_mode(
|
||||
struct XedDecodedInst *p, enum XedMachineMode mmode) {
|
||||
__builtin_memset(p, 0, sizeof(*p));
|
||||
xed_operands_set_mode(&p->op, mmode);
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
cmpxchg %ecx,(%rdx)
|
||||
|
||||
.section .start,"ax",@progbits
|
||||
emucrt: bofram 9f
|
||||
movslq (%rsp),%rdi # argc
|
||||
|
|
|
@ -22,7 +22,7 @@ ENTRY(_start)
|
|||
|
||||
SECTIONS {
|
||||
|
||||
.text : {
|
||||
.text IMAGE_BASE_VIRTUAL : {
|
||||
*(.start)
|
||||
KEEP(*(.initprologue))
|
||||
KEEP(*(SORT_BY_NAME(.init.*)))
|
||||
|
|
|
@ -5,7 +5,7 @@ PKGS += TOOL_BUILD_EMUCRT
|
|||
|
||||
TOOL_BUILD_EMUCRT = \
|
||||
o/$(MODE)/tool/build/emucrt/emucrt.o \
|
||||
tool/build/emucrt/emucrt.lds
|
||||
o/$(MODE)/tool/build/emucrt/emucrt.lds
|
||||
|
||||
.PHONY: o/$(MODE)/tool/build/emucrt
|
||||
o/$(MODE)/tool/build/emucrt: \
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
|
@ -51,6 +52,7 @@
|
|||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
|
@ -61,6 +63,7 @@
|
|||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/fds.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/fpu.h"
|
||||
#include "tool/build/lib/loader.h"
|
||||
|
@ -69,6 +72,7 @@
|
|||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/panel.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
#include "tool/build/lib/pty.h"
|
||||
#include "tool/build/lib/stats.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
|
@ -103,6 +107,15 @@ PERFORMANCE\n\
|
|||
\n\
|
||||
1500 MIPS w/ NOP loop\n\
|
||||
Over 9000 MIPS w/ SIMD & Algorithms\n\
|
||||
\n\
|
||||
PROTIP\n\
|
||||
\n\
|
||||
Fix SSH keyboard latency for debugger TUI in CONTINUE mode:\n\
|
||||
\n\
|
||||
sudo sh -c 'echo -n 8192 >/proc/sys/net/core/rmem_default'\n\
|
||||
sudo sh -c 'echo -n 8192 >/proc/sys/net/core/wmem_default'\n\
|
||||
\n\
|
||||
\n\
|
||||
\n"
|
||||
|
||||
#define DUMPWIDTH 64
|
||||
|
@ -115,8 +128,9 @@ PERFORMANCE\n\
|
|||
#define FINISH 0x020
|
||||
#define FAILURE 0x040
|
||||
#define WINCHED 0x080
|
||||
#define CTRLC 0x100
|
||||
#define INT 0x100
|
||||
#define QUIT 0x200
|
||||
#define EXIT 0x400
|
||||
|
||||
#define CTRL(C) ((C) ^ 0100)
|
||||
#define ALT(C) (('\e' << 010) | (C))
|
||||
|
@ -131,6 +145,8 @@ struct Panels {
|
|||
struct Panel maps;
|
||||
struct Panel tracehr;
|
||||
struct Panel trace;
|
||||
struct Panel terminalhr;
|
||||
struct Panel terminal;
|
||||
struct Panel registers;
|
||||
struct Panel ssehr;
|
||||
struct Panel sse;
|
||||
|
@ -143,7 +159,7 @@ struct Panels {
|
|||
struct Panel stackhr;
|
||||
struct Panel stack;
|
||||
};
|
||||
struct Panel p[18];
|
||||
struct Panel p[20];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -164,6 +180,7 @@ static bool colorize;
|
|||
static long codesize;
|
||||
static long ssewidth;
|
||||
static char *codepath;
|
||||
static void *onbusted;
|
||||
static unsigned focus;
|
||||
static unsigned opline;
|
||||
static bool printstats;
|
||||
|
@ -178,11 +195,15 @@ static int64_t writestart;
|
|||
static int64_t stackstart;
|
||||
static struct DisHigh high;
|
||||
static struct Machine m[2];
|
||||
static struct MachinePty *pty;
|
||||
static char logpath[PATH_MAX];
|
||||
static char systemfailure[128];
|
||||
static struct sigaction oldsig[4];
|
||||
static struct Breakpoints breakpoints;
|
||||
|
||||
static void SetupDraw(void);
|
||||
static void Redraw(void);
|
||||
|
||||
static uint64_t SignExtend(uint64_t x, uint8_t b) {
|
||||
uint64_t s;
|
||||
s = 1;
|
||||
|
@ -252,13 +273,28 @@ static uint8_t CycleSseWidth(uint8_t w) {
|
|||
}
|
||||
}
|
||||
|
||||
static int VirtualBing(int64_t v, int c) {
|
||||
uint8_t *p;
|
||||
if ((p = FindReal(m, v))) {
|
||||
return bing(p[0], 0);
|
||||
} else {
|
||||
return c;
|
||||
static void OnBusted(void) {
|
||||
LOGF("OnBusted");
|
||||
CHECK(onbusted);
|
||||
longjmp(onbusted, 1);
|
||||
}
|
||||
|
||||
static int VirtualBing(int64_t v) {
|
||||
int rc;
|
||||
uint8_t *p;
|
||||
jmp_buf busted;
|
||||
onbusted = busted;
|
||||
if ((p = FindReal(m, v))) {
|
||||
if (!setjmp(busted)) {
|
||||
rc = bing(p[0], 0);
|
||||
} else {
|
||||
rc = u'≀';
|
||||
}
|
||||
} else {
|
||||
rc = u'⋅';
|
||||
}
|
||||
onbusted = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ScrollOp(struct Panel *p, long op) {
|
||||
|
@ -283,29 +319,36 @@ static void GetTtySize(void) {
|
|||
static void TuiRejuvinate(void) {
|
||||
GetTtySize();
|
||||
ttyhidecursor(STDOUT_FILENO);
|
||||
ttyraw(kTtySigs);
|
||||
ttyraw(0);
|
||||
xsigaction(SIGBUS, OnBusted, SA_NODEFER, 0, NULL);
|
||||
}
|
||||
|
||||
static void OnCtrlC(void) {
|
||||
action |= CTRLC;
|
||||
LOGF("OnCtrlC");
|
||||
action |= INT;
|
||||
}
|
||||
|
||||
static void OnQ(void) {
|
||||
LOGF("OnQ");
|
||||
action |= INT;
|
||||
breakpoints.i = 0;
|
||||
}
|
||||
|
||||
static void OnWinch(void) {
|
||||
LOGF("OnWinch");
|
||||
action |= WINCHED;
|
||||
}
|
||||
|
||||
static void OnGdbHandoff(void) {
|
||||
static void OnCont(void) {
|
||||
LOGF("OnCont");
|
||||
TuiRejuvinate();
|
||||
}
|
||||
|
||||
static void OnUsr1(void) {
|
||||
if (g_logfile) fflush(g_logfile);
|
||||
SetupDraw();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
static void TuiCleanup(void) {
|
||||
sigaction(SIGWINCH, oldsig + 0, NULL);
|
||||
sigaction(SIGCONT, oldsig + 2, NULL);
|
||||
sigaction(SIGUSR1, oldsig + 3, NULL);
|
||||
ttyraw((enum TtyRawFlags)(-1u));
|
||||
ttyshowcursor(STDOUT_FILENO);
|
||||
CHECK_NE(-1, close(ttyfd));
|
||||
|
@ -329,7 +372,7 @@ static void ResolveBreakpoints(void) {
|
|||
|
||||
static void BreakAtNextInstruction(void) {
|
||||
struct Breakpoint b = {.addr = m->ip + m->xedd->length, .oneshot = true};
|
||||
AddBreakpoint(&breakpoints, &b);
|
||||
PushBreakpoint(&breakpoints, &b);
|
||||
}
|
||||
|
||||
static void LoadSyms(void) {
|
||||
|
@ -347,13 +390,23 @@ static void TuiSetup(void) {
|
|||
once = true;
|
||||
}
|
||||
CHECK_NE(-1, (ttyfd = open("/dev/tty", O_RDWR)));
|
||||
xsigaction(SIGWINCH, (void *)OnWinch, 0, 0, oldsig + 0);
|
||||
xsigaction(SIGCONT, (void *)OnGdbHandoff, 0, 0, oldsig + 2);
|
||||
xsigaction(SIGUSR1, (void *)OnUsr1, 0, 0, oldsig + 3);
|
||||
xsigaction(SIGWINCH, OnWinch, 0, 0, oldsig + 0);
|
||||
xsigaction(SIGCONT, OnCont, SA_RESTART, 0, oldsig + 2);
|
||||
memcpy(&m[1], &m[0], sizeof(m[0]));
|
||||
TuiRejuvinate();
|
||||
}
|
||||
|
||||
static void ExecSetup(void) {
|
||||
static bool once;
|
||||
if (!once) {
|
||||
if (breakpoints.i) {
|
||||
LoadSyms();
|
||||
ResolveBreakpoints();
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void AppendPanel(struct Panel *p, long line, const char *s) {
|
||||
if (0 <= line && line < p->bottom - p->top) {
|
||||
AppendStr(&p->lines[line], s);
|
||||
|
@ -384,8 +437,8 @@ static int PickNumberOfXmmRegistersToShow(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void StartDraw(void) {
|
||||
int i, j, n, a, b, cpuy, ssey, dx[2], c2y[2], c3y[5];
|
||||
static void SetupDraw(void) {
|
||||
int i, j, n, a, b, cpuy, ssey, dx[2], c2y[3], c3y[5];
|
||||
|
||||
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
||||
n = pan.p[i].bottom - pan.p[i].top;
|
||||
|
@ -404,9 +457,11 @@ static void StartDraw(void) {
|
|||
dx[1] = txn >= a + b ? txn - a : txn;
|
||||
dx[0] = txn >= a + b + b ? txn - a - b : dx[1];
|
||||
|
||||
a = tyn / 3;
|
||||
a = 1 / 8. * tyn;
|
||||
b = 3 / 8. * tyn;
|
||||
c2y[0] = a;
|
||||
c2y[1] = a * 2;
|
||||
c2y[2] = a * 2 + b;
|
||||
|
||||
a = (tyn - (cpuy + ssey) - 3) / 4;
|
||||
c3y[0] = cpuy;
|
||||
|
@ -422,7 +477,7 @@ static void StartDraw(void) {
|
|||
pan.disassembly.bottom = tyn;
|
||||
pan.disassembly.right = dx[0];
|
||||
|
||||
/* COLUMN #2: BREAKPOINTS, MEMORY MAPS, BACKTRACE */
|
||||
/* COLUMN #2: BREAKPOINTS, MEMORY MAPS, BACKTRACE, TERMINAL */
|
||||
|
||||
pan.breakpointshr.top = 0;
|
||||
pan.breakpointshr.left = dx[0];
|
||||
|
@ -451,9 +506,19 @@ static void StartDraw(void) {
|
|||
|
||||
pan.trace.top = c2y[1] + 1;
|
||||
pan.trace.left = dx[0];
|
||||
pan.trace.bottom = tyn;
|
||||
pan.trace.bottom = c2y[2];
|
||||
pan.trace.right = dx[1] - 1;
|
||||
|
||||
pan.terminalhr.top = c2y[2];
|
||||
pan.terminalhr.left = dx[0];
|
||||
pan.terminalhr.bottom = c2y[2] + 1;
|
||||
pan.terminalhr.right = dx[1] - 1;
|
||||
|
||||
pan.terminal.top = c2y[2] + 1;
|
||||
pan.terminal.left = dx[0];
|
||||
pan.terminal.bottom = tyn;
|
||||
pan.terminal.right = dx[1] - 1;
|
||||
|
||||
/* COLUMN #3: REGISTERS, VECTORS, CODE, MEMORY READS, MEMORY WRITES, STACK */
|
||||
|
||||
pan.registers.top = 0;
|
||||
|
@ -517,6 +582,14 @@ static void StartDraw(void) {
|
|||
pan.p[i].lines =
|
||||
xcalloc(pan.p[i].bottom - pan.p[i].top, sizeof(struct Buffer));
|
||||
}
|
||||
|
||||
if (pty->yn != pan.terminal.bottom - pan.terminal.top ||
|
||||
pty->xn != pan.terminal.right - pan.terminal.left) {
|
||||
LOGF("MachinePtyNew");
|
||||
MachinePtyFree(pty);
|
||||
pty = MachinePtyNew(pan.terminal.bottom - pan.terminal.top,
|
||||
pan.terminal.right - pan.terminal.left);
|
||||
}
|
||||
}
|
||||
|
||||
static long GetDisIndex(int64_t addr) {
|
||||
|
@ -541,6 +614,13 @@ static void DrawDisassembly(struct Panel *p) {
|
|||
}
|
||||
}
|
||||
|
||||
static void DrawTerminal(struct Panel *p) {
|
||||
long y, yn;
|
||||
for (yn = MIN(pty->yn, p->bottom - p->top), y = 0; y < yn; ++y) {
|
||||
MachinePtyAppendLine(pty, p->lines + y, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawFlag(struct Panel *p, long i, char *name, bool value,
|
||||
bool previous) {
|
||||
AppendPanel(p, i, " ");
|
||||
|
@ -599,30 +679,14 @@ static void DrawHr(struct Panel *p, const char *s) {
|
|||
|
||||
static void DrawCpu(struct Panel *p) {
|
||||
char buf[48];
|
||||
DrawRegister(p, 0, 7);
|
||||
DrawRegister(p, 0, 0);
|
||||
DrawSt(p, 0, 0);
|
||||
DrawRegister(p, 1, 6);
|
||||
DrawRegister(p, 1, 3);
|
||||
DrawSt(p, 1, 1);
|
||||
DrawRegister(p, 2, 2);
|
||||
DrawRegister(p, 2, 5);
|
||||
DrawSt(p, 2, 2);
|
||||
DrawRegister(p, 3, 1);
|
||||
DrawRegister(p, 3, 4);
|
||||
DrawSt(p, 3, 3);
|
||||
DrawRegister(p, 4, 8);
|
||||
DrawRegister(p, 4, 12);
|
||||
DrawSt(p, 4, 4);
|
||||
DrawRegister(p, 5, 9);
|
||||
DrawRegister(p, 5, 13);
|
||||
DrawSt(p, 5, 5);
|
||||
DrawRegister(p, 6, 10);
|
||||
DrawRegister(p, 6, 14);
|
||||
DrawSt(p, 6, 6);
|
||||
DrawRegister(p, 7, 11);
|
||||
DrawRegister(p, 7, 15);
|
||||
DrawSt(p, 7, 7);
|
||||
DrawRegister(p, 0, 7), DrawRegister(p, 0, 0), DrawSt(p, 0, 0);
|
||||
DrawRegister(p, 1, 6), DrawRegister(p, 1, 3), DrawSt(p, 1, 1);
|
||||
DrawRegister(p, 2, 2), DrawRegister(p, 2, 5), DrawSt(p, 2, 2);
|
||||
DrawRegister(p, 3, 1), DrawRegister(p, 3, 4), DrawSt(p, 3, 3);
|
||||
DrawRegister(p, 4, 8), DrawRegister(p, 4, 12), DrawSt(p, 4, 4);
|
||||
DrawRegister(p, 5, 9), DrawRegister(p, 5, 13), DrawSt(p, 5, 5);
|
||||
DrawRegister(p, 6, 10), DrawRegister(p, 6, 14), DrawSt(p, 6, 6);
|
||||
DrawRegister(p, 7, 11), DrawRegister(p, 7, 15), DrawSt(p, 7, 7);
|
||||
snprintf(buf, sizeof(buf), "RIP 0x%016x FLG", m[0].ip);
|
||||
AppendPanel(p, 8, buf);
|
||||
DrawFlag(p, 8, "C", GetFlag(m[0].flags, FLAGS_CF),
|
||||
|
@ -766,7 +830,7 @@ static void DrawMemory(struct Panel *p, long beg, long a, long b) {
|
|||
AppendStr(&p->lines[i], buf);
|
||||
for (j = 0; j < DUMPWIDTH; ++j) {
|
||||
k = (beg + i) * DUMPWIDTH + j;
|
||||
c = VirtualBing(k, L'⋅');
|
||||
c = VirtualBing(k);
|
||||
changed = a <= k && k < b;
|
||||
if (changed && !high) {
|
||||
high = true;
|
||||
|
@ -800,7 +864,7 @@ static void DrawBreakpoints(struct Panel *p) {
|
|||
char buf[128];
|
||||
const char *name;
|
||||
long i, line, sym;
|
||||
for (line = i = 0; i < breakpoints.i; ++i) {
|
||||
for (line = 0, i = breakpoints.i; i--;) {
|
||||
if (breakpoints.p[i].disable) continue;
|
||||
addr = breakpoints.p[i].addr;
|
||||
sym = DisFindSym(dis, addr);
|
||||
|
@ -885,7 +949,14 @@ forceinline void CheckFramePointer(void) {
|
|||
}
|
||||
|
||||
static void Redraw(void) {
|
||||
int i, j;
|
||||
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
||||
for (j = 0; j < pan.p[i].bottom - pan.p[i].top; ++j) {
|
||||
pan.p[i].lines[j].i = 0;
|
||||
}
|
||||
}
|
||||
DrawDisassembly(&pan.disassembly);
|
||||
DrawTerminal(&pan.terminal);
|
||||
DrawCpu(&pan.registers);
|
||||
DrawSse(&pan.sse);
|
||||
ScrollCode(&pan.code);
|
||||
|
@ -895,6 +966,7 @@ static void Redraw(void) {
|
|||
DrawHr(&pan.breakpointshr, "BREAKPOINTS");
|
||||
DrawHr(&pan.mapshr, "MAPS");
|
||||
DrawHr(&pan.tracehr, m->bofram[0] ? "PROTECTED FRAMES" : "FRAMES");
|
||||
DrawHr(&pan.terminalhr, "TELETYPEWRITER");
|
||||
DrawHr(&pan.ssehr, "SSE");
|
||||
DrawHr(&pan.codehr, "CODE");
|
||||
DrawHr(&pan.readhr, "READ");
|
||||
|
@ -908,8 +980,34 @@ static void Redraw(void) {
|
|||
DrawMemory(&pan.writedata, writestart, m->writeaddr,
|
||||
m->writeaddr + m->writesize);
|
||||
DrawMemory(&pan.stack, stackstart, Read64(m->sp), Read64(m->sp) + 8);
|
||||
CHECK_NE(-1, PrintPanels(ttyfd, ARRAYLEN(pan.p), pan.p, tyn, txn));
|
||||
if (PrintPanels(ttyfd, ARRAYLEN(pan.p), pan.p, tyn, txn) == -1) {
|
||||
LOGF("PrintPanels Interrupted");
|
||||
CHECK_EQ(EINTR, errno);
|
||||
}
|
||||
}
|
||||
|
||||
static int OnPtyFdClose(int fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t OnPtyFdRead(int fd, void *data, size_t size) {
|
||||
return read(fd, data, size);
|
||||
}
|
||||
|
||||
static ssize_t OnPtyFdWrite(int fd, const void *data, size_t size) {
|
||||
if (tuimode) {
|
||||
return MachinePtyWrite(pty, data, size);
|
||||
} else {
|
||||
MachinePtyWrite(pty, data, size);
|
||||
return write(fd, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct MachineFdCb kMachineFdCbPty = {
|
||||
.close = OnPtyFdClose,
|
||||
.read = OnPtyFdRead,
|
||||
.write = OnPtyFdWrite,
|
||||
};
|
||||
|
||||
static void LaunchDebuggerReactively(void) {
|
||||
LOGF("%s", systemfailure);
|
||||
|
@ -948,6 +1046,7 @@ static void OnSimdException(void) {
|
|||
}
|
||||
|
||||
static void OnUndefinedInstruction(void) {
|
||||
die();
|
||||
strcpy(systemfailure, "UNDEFINED INSTRUCTION");
|
||||
LaunchDebuggerReactively();
|
||||
}
|
||||
|
@ -968,6 +1067,11 @@ static void OnFpuException(void) {
|
|||
LaunchDebuggerReactively();
|
||||
}
|
||||
|
||||
static void OnExit(int rc) {
|
||||
exitcode = rc;
|
||||
action |= EXIT;
|
||||
}
|
||||
|
||||
static void OnHalt(int interrupt) {
|
||||
switch (interrupt) {
|
||||
case 1:
|
||||
|
@ -998,8 +1102,7 @@ static void OnHalt(int interrupt) {
|
|||
case kMachineExit:
|
||||
case kMachineHalt:
|
||||
default:
|
||||
exitcode = interrupt;
|
||||
action |= QUIT;
|
||||
OnExit(interrupt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1134,7 +1237,7 @@ static void ReadKeyboard(void) {
|
|||
if ((rc = read(ttyfd, b, 16)) != -1) {
|
||||
for (n = rc, i = 0; i < n; ++i) {
|
||||
switch (b[i++]) {
|
||||
CASE('q', OnQuit());
|
||||
CASE('q', OnQ());
|
||||
CASE('s', OnStep());
|
||||
CASE('n', OnNext());
|
||||
CASE('f', OnFinish());
|
||||
|
@ -1145,9 +1248,14 @@ static void ReadKeyboard(void) {
|
|||
CASE('w', OnSseWidth());
|
||||
CASE('u', OnUp());
|
||||
CASE('d', OnDown());
|
||||
CASE('B', PopBreakpoint(&breakpoints));
|
||||
CASE('\t', OnTab());
|
||||
CASE('\r', OnEnter());
|
||||
CASE('\n', OnEnter());
|
||||
CASE(CTRL('C'), OnCtrlC());
|
||||
CASE(CTRL('D'), OnCtrlC());
|
||||
CASE(CTRL('\\'), OnQuit());
|
||||
CASE(CTRL('Z'), raise(SIGSTOP));
|
||||
CASE(CTRL('L'), OnFeed());
|
||||
CASE(CTRL('P'), OnUpArrow());
|
||||
CASE(CTRL('N'), OnDownArrow());
|
||||
|
@ -1215,8 +1323,13 @@ static void ReadKeyboard(void) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else if (errno == EINTR) {
|
||||
LOGF("ReadKeyboard Interrupted");
|
||||
} else if (errno == EAGAIN) {
|
||||
poll((struct pollfd[]){{ttyfd, POLLIN}}, 1, -1);
|
||||
} else {
|
||||
CHECK_EQ(EINTR, errno);
|
||||
perror("ReadKeyboard");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1240,7 +1353,7 @@ static void HandleBreakpointFlag(const char *s) {
|
|||
} else {
|
||||
b.symbol = optarg;
|
||||
}
|
||||
AddBreakpoint(&breakpoints, &b);
|
||||
PushBreakpoint(&breakpoints, &b);
|
||||
}
|
||||
|
||||
static noreturn void PrintUsage(int rc, FILE *f) {
|
||||
|
@ -1253,13 +1366,170 @@ static void LeaveScreen(void) {
|
|||
write(ttyfd, buf, sprintf(buf, "\e[%d;%dH\e[S\r\n", tyn - 1, txn - 1));
|
||||
}
|
||||
|
||||
static void Exec(void) {
|
||||
long op;
|
||||
ssize_t bp;
|
||||
int interrupt;
|
||||
ExecSetup();
|
||||
if (!(interrupt = setjmp(m->onhalt))) {
|
||||
if ((bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) {
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
tuimode = true;
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
CheckFramePointer();
|
||||
ops++;
|
||||
} else {
|
||||
for (;;) {
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
CheckFramePointer();
|
||||
ops++;
|
||||
if (action || breakpoints.i) {
|
||||
if (action & EXIT) {
|
||||
LOGF("EXEC EXIT");
|
||||
break;
|
||||
}
|
||||
if (action & INT) {
|
||||
LOGF("EXEC INT");
|
||||
if (react) {
|
||||
LOGF("REACT");
|
||||
action &= ~(INT | STEP | FINISH | NEXT);
|
||||
tuimode = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) {
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
tuimode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OnHalt(interrupt);
|
||||
}
|
||||
}
|
||||
|
||||
static void Tui(void) {
|
||||
long op;
|
||||
ssize_t bp;
|
||||
int interrupt;
|
||||
LOGF("TUI");
|
||||
TuiSetup();
|
||||
SetupDraw();
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
if (!(interrupt = setjmp(m->onhalt))) {
|
||||
for (;;) {
|
||||
if (!(action & FAILURE)) {
|
||||
LoadInstruction(m);
|
||||
} else {
|
||||
m->xedd = m->icache;
|
||||
m->xedd->length = 1;
|
||||
m->xedd->bytes[0] = 0xCC;
|
||||
m->xedd->op.opcode = 0xCC;
|
||||
}
|
||||
if (action & WINCHED) {
|
||||
LOGF("WINCHED");
|
||||
GetTtySize();
|
||||
action &= ~WINCHED;
|
||||
}
|
||||
SetupDraw();
|
||||
Redraw();
|
||||
if (action & FAILURE) {
|
||||
LOGF("TUI FAILURE");
|
||||
PrintMessageBox(ttyfd, systemfailure, tyn, txn);
|
||||
ReadKeyboard();
|
||||
} else if (!IsExecuting() || HasPendingKeyboard()) {
|
||||
ReadKeyboard();
|
||||
}
|
||||
if (action & INT) {
|
||||
LOGF("TUI INT");
|
||||
action &= ~INT;
|
||||
if (action & (CONTINUE | NEXT | FINISH)) {
|
||||
action &= ~(CONTINUE | NEXT | FINISH);
|
||||
} else {
|
||||
tuimode = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (action & EXIT) {
|
||||
LeaveScreen();
|
||||
LOGF("TUI EXIT");
|
||||
break;
|
||||
}
|
||||
if (action & QUIT) {
|
||||
LOGF("TUI QUIT");
|
||||
action &= ~QUIT;
|
||||
raise(SIGQUIT);
|
||||
continue;
|
||||
}
|
||||
if (action & RESTART) {
|
||||
LOGF("TUI RESTART");
|
||||
break;
|
||||
}
|
||||
if (IsExecuting()) {
|
||||
op = GetDisIndex(m->ip);
|
||||
ScrollOp(&pan.disassembly, op);
|
||||
VERBOSEF("%s", dis->ops.p[op].s);
|
||||
memcpy(&m[1], &m[0], sizeof(m[0]));
|
||||
if (!(action & CONTINUE)) {
|
||||
action &= ~STEP;
|
||||
if (action & NEXT) {
|
||||
action &= ~NEXT;
|
||||
if (IsCall()) {
|
||||
BreakAtNextInstruction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (action & FINISH) {
|
||||
if (IsCall()) {
|
||||
BreakAtNextInstruction();
|
||||
break;
|
||||
} else if (IsRet()) {
|
||||
action &= ~FINISH;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!IsDebugBreak()) {
|
||||
ExecuteInstruction(m);
|
||||
} else {
|
||||
m->ip += m->xedd->length;
|
||||
action &= ~NEXT;
|
||||
action &= ~FINISH;
|
||||
action &= ~CONTINUE;
|
||||
}
|
||||
CheckFramePointer();
|
||||
ops++;
|
||||
if (!(action & CONTINUE)) {
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
if ((action & FINISH) && IsRet()) action &= ~FINISH;
|
||||
if (((action & NEXT) && IsRet()) || (action & FINISH)) {
|
||||
action &= ~NEXT;
|
||||
}
|
||||
}
|
||||
if ((action & (FINISH | NEXT | CONTINUE)) &&
|
||||
(bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) {
|
||||
action &= ~(FINISH | NEXT | CONTINUE);
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OnHalt(interrupt);
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
}
|
||||
TuiCleanup();
|
||||
}
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
stpcpy(stpcpy(stpcpy(logpath, kTmpPath), basename(argv[0])), ".log");
|
||||
while ((opt = getopt(argc, argv, "?hvtrsb:HL:")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
react = true;
|
||||
tuimode = true;
|
||||
break;
|
||||
case 'r':
|
||||
|
@ -1288,166 +1558,44 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
g_logfile = fopen(logpath, "a");
|
||||
setvbuf(g_logfile, xmalloc(PAGESIZE), _IOLBF, PAGESIZE);
|
||||
}
|
||||
|
||||
int Emulator(int argc, char *argv[]) {
|
||||
long op;
|
||||
void *code;
|
||||
ssize_t bp;
|
||||
int rc, fd, interrupt;
|
||||
|
||||
int rc, fd;
|
||||
codepath = argv[optind++];
|
||||
|
||||
pty = MachinePtyNew(20, 80);
|
||||
InitMachine(m);
|
||||
m->fds.p = xcalloc((m->fds.n = 8), sizeof(struct MachineFd));
|
||||
Restart:
|
||||
action = 0;
|
||||
LoadProgram(m, codepath, argv + optind, environ, elf);
|
||||
|
||||
if (!tuimode && breakpoints.i) {
|
||||
LoadSyms();
|
||||
ResolveBreakpoints();
|
||||
}
|
||||
|
||||
while (!(action & QUIT)) {
|
||||
m->fds.i = 3;
|
||||
m->fds.p[0].fd = STDIN_FILENO;
|
||||
m->fds.p[0].cb = &kMachineFdCbPty;
|
||||
m->fds.p[1].fd = STDOUT_FILENO;
|
||||
m->fds.p[1].cb = &kMachineFdCbPty;
|
||||
m->fds.p[2].fd = STDERR_FILENO;
|
||||
m->fds.p[2].cb = &kMachineFdCbPty;
|
||||
while (!(action & EXIT)) {
|
||||
if (!tuimode) {
|
||||
if (!(interrupt = setjmp(m->onhalt))) {
|
||||
for (;;) {
|
||||
if (action || breakpoints.i) {
|
||||
if (action & QUIT) {
|
||||
break;
|
||||
}
|
||||
if (action & CTRLC) {
|
||||
if (react) {
|
||||
LOGF("CTRLC EXEC REACT");
|
||||
action &= ~(CTRLC | STEP | FINISH | NEXT);
|
||||
tuimode = true;
|
||||
Exec();
|
||||
} else {
|
||||
LOGF("CTRLC EXEC");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) {
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
tuimode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
CheckFramePointer();
|
||||
ops++;
|
||||
}
|
||||
} else {
|
||||
OnHalt(interrupt);
|
||||
}
|
||||
} else {
|
||||
LOGF("TUI");
|
||||
TuiSetup();
|
||||
StartDraw();
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
if (!(interrupt = setjmp(m->onhalt))) {
|
||||
for (;;) {
|
||||
if (!(action & FAILURE)) {
|
||||
LoadInstruction(m);
|
||||
} else {
|
||||
m->xedd = m->icache;
|
||||
m->xedd->length = 1;
|
||||
m->xedd->bytes[0] = 0xCC;
|
||||
m->xedd->op.opcode = 0xCC;
|
||||
}
|
||||
if (action & WINCHED) {
|
||||
LOGF("WINCHED");
|
||||
GetTtySize();
|
||||
action &= ~WINCHED;
|
||||
}
|
||||
StartDraw();
|
||||
Redraw();
|
||||
if (action & FAILURE) {
|
||||
LOGF("FAILURE");
|
||||
PrintMessageBox(ttyfd, systemfailure, tyn, txn);
|
||||
ReadKeyboard();
|
||||
} else if (!IsExecuting() || HasPendingKeyboard()) {
|
||||
ReadKeyboard();
|
||||
}
|
||||
if (action & CTRLC) {
|
||||
LOGF("CTRLC TUI");
|
||||
action |= QUIT;
|
||||
}
|
||||
if (action & QUIT) {
|
||||
LeaveScreen();
|
||||
LOGF("QUIT2");
|
||||
break;
|
||||
Tui();
|
||||
}
|
||||
if (action & RESTART) {
|
||||
LOGF("RESTART");
|
||||
goto Restart;
|
||||
}
|
||||
if (action & CONTINUE) {
|
||||
LOGF("CONTINUE");
|
||||
action &= ~CONTINUE;
|
||||
tuimode = false;
|
||||
break;
|
||||
}
|
||||
if (IsExecuting()) {
|
||||
op = GetDisIndex(m->ip);
|
||||
ScrollOp(&pan.disassembly, op);
|
||||
LOGF("%s", dis->ops.p[op].s);
|
||||
memcpy(&m[1], &m[0], sizeof(m[0]));
|
||||
action &= ~STEP;
|
||||
if (action & NEXT) {
|
||||
action &= ~NEXT;
|
||||
if (IsCall()) {
|
||||
BreakAtNextInstruction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (action & FINISH) {
|
||||
if (IsCall()) {
|
||||
BreakAtNextInstruction();
|
||||
break;
|
||||
} else if (IsRet()) {
|
||||
action &= ~FINISH;
|
||||
}
|
||||
}
|
||||
if (!IsDebugBreak()) {
|
||||
ExecuteInstruction(m);
|
||||
} else {
|
||||
m->ip += m->xedd->length;
|
||||
action &= ~NEXT;
|
||||
action &= ~FINISH;
|
||||
}
|
||||
CheckFramePointer();
|
||||
ops++;
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
if ((action & FINISH) && IsRet()) action &= ~FINISH;
|
||||
if (((action & NEXT) && IsRet()) || (action & FINISH)) {
|
||||
action &= ~NEXT;
|
||||
}
|
||||
if ((action & (FINISH | NEXT)) &&
|
||||
(bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) {
|
||||
action &= ~(FINISH | NEXT);
|
||||
LOGF("BREAK %p", breakpoints.p[bp].addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OnHalt(interrupt);
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
}
|
||||
TuiCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
if (tuimode) {
|
||||
LeaveScreen();
|
||||
}
|
||||
|
||||
if (printstats) {
|
||||
fprintf(stderr, "taken: %,ld\n", taken);
|
||||
fprintf(stderr, "ntaken: %,ld\n", ntaken);
|
||||
fprintf(stderr, "ops: %,ld\n", ops);
|
||||
}
|
||||
|
||||
munmap(elf->ehdr, elf->size);
|
||||
DisFree(dis);
|
||||
return exitcode;
|
||||
|
@ -1462,8 +1610,7 @@ static void OnlyRunOnFirstCpu(void) {
|
|||
int main(int argc, char *argv[]) {
|
||||
int rc;
|
||||
ssewidth = 2; /* 16-bit is best bit */
|
||||
showcrashreports();
|
||||
xsigaction(SIGINT, (void *)OnCtrlC, 0, 0, NULL);
|
||||
if (!NoDebug()) showcrashreports();
|
||||
// OnlyRunOnFirstCpu();
|
||||
if ((colorize = cancolor())) {
|
||||
high.keyword = 155;
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#define ALU_CMP 7
|
||||
#define ALU_TEST 8
|
||||
#define ALU_FLIP 16
|
||||
#define ALU_XCHG 64
|
||||
#define ALU_BYTE 128
|
||||
|
||||
#define BSU_ROL 0
|
||||
#define BSU_ROR 1
|
||||
|
@ -27,8 +25,8 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
typedef uint64_t (*aluop1_f)(struct Machine *, uint64_t);
|
||||
typedef uint64_t (*aluop2_f)(struct Machine *, uint64_t, uint64_t);
|
||||
typedef uint64_t (*aluop1_f)(struct Machine *, uint32_t, uint64_t);
|
||||
typedef uint64_t (*aluop2_f)(struct Machine *, uint32_t, uint64_t, uint64_t);
|
||||
|
||||
int64_t Alu(int, int, uint64_t, uint64_t, uint32_t *);
|
||||
int64_t Bsu(int, int, uint64_t, uint64_t, uint32_t *);
|
||||
|
|
|
@ -22,14 +22,14 @@
|
|||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
uint64_t AluBsr(struct Machine *m, uint64_t _, uint64_t x) {
|
||||
uint64_t AluBsr(struct Machine *m, uint32_t rde, uint64_t _, uint64_t x) {
|
||||
unsigned i;
|
||||
if (Rexw(m->xedd)) {
|
||||
if (Rexw(rde)) {
|
||||
x &= 0xffffffffffffffff;
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
return 63 ^ __builtin_clzll(x);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
} else if (!Osz(rde)) {
|
||||
x &= 0xffffffff;
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
|
@ -43,14 +43,14 @@ uint64_t AluBsr(struct Machine *m, uint64_t _, uint64_t x) {
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t AluBsf(struct Machine *m, uint64_t _, uint64_t x) {
|
||||
uint64_t AluBsf(struct Machine *m, uint32_t rde, uint64_t _, uint64_t x) {
|
||||
unsigned i;
|
||||
if (Rexw(m->xedd)) {
|
||||
if (Rexw(rde)) {
|
||||
x &= 0xffffffffffffffff;
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
return __builtin_ctzll(x);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
} else if (!Osz(rde)) {
|
||||
x &= 0xffffffff;
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
if (!x) return 0;
|
||||
|
@ -64,7 +64,7 @@ uint64_t AluBsf(struct Machine *m, uint64_t _, uint64_t x) {
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t AluPopcnt(struct Machine *m, uint64_t _, uint64_t x) {
|
||||
uint64_t AluPopcnt(struct Machine *m, uint32_t rde, uint64_t _, uint64_t x) {
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, !x);
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_SF, false);
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
uint64_t AluBsr(struct Machine *, uint64_t, uint64_t);
|
||||
uint64_t AluBsf(struct Machine *, uint64_t, uint64_t);
|
||||
uint64_t AluPopcnt(struct Machine *, uint64_t, uint64_t);
|
||||
uint64_t AluBsr(struct Machine *, uint32_t, uint64_t, uint64_t);
|
||||
uint64_t AluBsf(struct Machine *, uint32_t, uint64_t, uint64_t);
|
||||
uint64_t AluPopcnt(struct Machine *, uint32_t, uint64_t, uint64_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -21,7 +21,13 @@
|
|||
#include "libc/assert.h"
|
||||
#include "tool/build/lib/breakpoint.h"
|
||||
|
||||
ssize_t AddBreakpoint(struct Breakpoints *bps, struct Breakpoint *b) {
|
||||
void PopBreakpoint(struct Breakpoints *bps) {
|
||||
if (bps->i) {
|
||||
--bps->i;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t PushBreakpoint(struct Breakpoints *bps, struct Breakpoint *b) {
|
||||
int i;
|
||||
for (i = 0; i < bps->i; ++i) {
|
||||
if (bps->p[i].disable) {
|
||||
|
|
|
@ -14,7 +14,8 @@ struct Breakpoints {
|
|||
};
|
||||
|
||||
ssize_t IsAtBreakpoint(struct Breakpoints *, int64_t);
|
||||
ssize_t AddBreakpoint(struct Breakpoints *, struct Breakpoint *);
|
||||
ssize_t PushBreakpoint(struct Breakpoints *, struct Breakpoint *);
|
||||
void PopBreakpoint(struct Breakpoints *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
@ -57,12 +58,5 @@ void AppendFmt(struct Buffer *b, const char *fmt, ...) {
|
|||
* Writes buffer until completion, interrupt, or error occurs.
|
||||
*/
|
||||
ssize_t WriteBuffer(struct Buffer *b, int fd) {
|
||||
size_t i;
|
||||
ssize_t rc;
|
||||
for (i = 0; i < b->i; i += rc) {
|
||||
if ((rc = write(fd, b->p + i, b->i - i)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
return ttywrite(fd, b->p, b->i);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ TOOL_BUILD_LIB_A_OBJS = \
|
|||
$(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_BUILD_LIB_A_DIRECTDEPS = \
|
||||
DSP_TTY \
|
||||
LIBC_ALG \
|
||||
LIBC_BITS \
|
||||
LIBC_CONV \
|
||||
|
|
|
@ -26,287 +26,287 @@
|
|||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
static void OpGdqpWssCvttss2si(struct Machine *m) {
|
||||
static void OpGdqpWssCvttss2si(struct Machine *m, uint32_t rde) {
|
||||
float f;
|
||||
int64_t n;
|
||||
memcpy(&f, GetModrmRegisterXmmPointerRead4(m), 4);
|
||||
memcpy(&f, GetModrmRegisterXmmPointerRead4(m, rde), 4);
|
||||
n = f;
|
||||
if (!Rexw(m->xedd)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m), n);
|
||||
if (!Rexw(rde)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m, rde), n);
|
||||
}
|
||||
|
||||
static void OpGdqpWsdCvttsd2si(struct Machine *m) {
|
||||
static void OpGdqpWsdCvttsd2si(struct Machine *m, uint32_t rde) {
|
||||
double d;
|
||||
int64_t n;
|
||||
memcpy(&d, GetModrmRegisterXmmPointerRead8(m), 8);
|
||||
memcpy(&d, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
n = d;
|
||||
if (!Rexw(m->xedd)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m), n);
|
||||
if (!Rexw(rde)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m, rde), n);
|
||||
}
|
||||
|
||||
static void OpGdqpWssCvtss2si(struct Machine *m) {
|
||||
static void OpGdqpWssCvtss2si(struct Machine *m, uint32_t rde) {
|
||||
float f;
|
||||
int64_t n;
|
||||
memcpy(&f, GetModrmRegisterXmmPointerRead4(m), 4);
|
||||
memcpy(&f, GetModrmRegisterXmmPointerRead4(m, rde), 4);
|
||||
n = rintf(f);
|
||||
if (!Rexw(m->xedd)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m), n);
|
||||
if (!Rexw(rde)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m, rde), n);
|
||||
}
|
||||
|
||||
static void OpGdqpWsdCvtsd2si(struct Machine *m) {
|
||||
static void OpGdqpWsdCvtsd2si(struct Machine *m, uint32_t rde) {
|
||||
double d;
|
||||
int64_t n;
|
||||
memcpy(&d, GetModrmRegisterXmmPointerRead8(m), 8);
|
||||
memcpy(&d, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
n = nearbyint(d);
|
||||
if (!Rexw(m->xedd)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m), n);
|
||||
if (!Rexw(rde)) n &= 0xffffffff;
|
||||
Write64(RegRexrReg(m, rde), n);
|
||||
}
|
||||
|
||||
static void OpVssEdqpCvtsi2ss(struct Machine *m) {
|
||||
static void OpVssEdqpCvtsi2ss(struct Machine *m, uint32_t rde) {
|
||||
float f;
|
||||
int64_t n;
|
||||
uint8_t *p;
|
||||
if (Rexw(m->xedd)) {
|
||||
n = (int64_t)Read64(GetModrmRegisterWordPointerRead8(m));
|
||||
if (Rexw(rde)) {
|
||||
n = (int64_t)Read64(GetModrmRegisterWordPointerRead8(m, rde));
|
||||
} else {
|
||||
n = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m));
|
||||
n = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde));
|
||||
}
|
||||
f = n;
|
||||
memcpy(XmmRexrReg(m), &f, 4);
|
||||
memcpy(XmmRexrReg(m, rde), &f, 4);
|
||||
}
|
||||
|
||||
static void OpVsdEdqpCvtsi2sd(struct Machine *m) {
|
||||
static void OpVsdEdqpCvtsi2sd(struct Machine *m, uint32_t rde) {
|
||||
double d;
|
||||
int64_t n;
|
||||
uint8_t *p;
|
||||
if (Rexw(m->xedd)) {
|
||||
n = (int64_t)Read64(GetModrmRegisterWordPointerRead8(m));
|
||||
if (Rexw(rde)) {
|
||||
n = (int64_t)Read64(GetModrmRegisterWordPointerRead8(m, rde));
|
||||
} else {
|
||||
n = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m));
|
||||
n = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde));
|
||||
}
|
||||
d = n;
|
||||
memcpy(XmmRexrReg(m), &d, 8);
|
||||
memcpy(XmmRexrReg(m, rde), &d, 8);
|
||||
}
|
||||
|
||||
static void OpVpsQpiCvtpi2ps(struct Machine *m) {
|
||||
static void OpVpsQpiCvtpi2ps(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
float f[2];
|
||||
int32_t i[2];
|
||||
p = GetModrmRegisterMmPointerRead8(m);
|
||||
p = GetModrmRegisterMmPointerRead8(m, rde);
|
||||
i[0] = Read32(p + 0);
|
||||
i[1] = Read32(p + 4);
|
||||
f[0] = i[0];
|
||||
f[1] = i[1];
|
||||
memcpy(XmmRexrReg(m), f, 8);
|
||||
memcpy(XmmRexrReg(m, rde), f, 8);
|
||||
}
|
||||
|
||||
static void OpVpdQpiCvtpi2pd(struct Machine *m) {
|
||||
static void OpVpdQpiCvtpi2pd(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
double f[2];
|
||||
int32_t n[2];
|
||||
p = GetModrmRegisterMmPointerRead8(m);
|
||||
p = GetModrmRegisterMmPointerRead8(m, rde);
|
||||
n[0] = Read32(p + 0);
|
||||
n[1] = Read32(p + 4);
|
||||
f[0] = n[0];
|
||||
f[1] = n[1];
|
||||
memcpy(XmmRexrReg(m), f, 16);
|
||||
memcpy(XmmRexrReg(m, rde), f, 16);
|
||||
}
|
||||
|
||||
static void OpPpiWpsqCvtps2pi(struct Machine *m) {
|
||||
static void OpPpiWpsqCvtps2pi(struct Machine *m, uint32_t rde) {
|
||||
float f[2];
|
||||
int32_t n[2];
|
||||
memcpy(f, GetModrmRegisterXmmPointerRead8(m), 8);
|
||||
memcpy(f, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
n[0] = nearbyintf(f[0]);
|
||||
n[1] = nearbyintf(f[1]);
|
||||
Write32(MmReg(m) + 0, n[0]);
|
||||
Write32(MmReg(m) + 4, n[1]);
|
||||
Write32(MmReg(m, rde) + 0, n[0]);
|
||||
Write32(MmReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpPpiWpsqCvttps2pi(struct Machine *m) {
|
||||
static void OpPpiWpsqCvttps2pi(struct Machine *m, uint32_t rde) {
|
||||
float f[2];
|
||||
int32_t n[2];
|
||||
memcpy(&f, GetModrmRegisterXmmPointerRead8(m), 8);
|
||||
memcpy(&f, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
n[0] = f[0];
|
||||
n[1] = f[1];
|
||||
Write32(MmReg(m) + 0, n[0]);
|
||||
Write32(MmReg(m) + 4, n[1]);
|
||||
Write32(MmReg(m, rde) + 0, n[0]);
|
||||
Write32(MmReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpPpiWpdCvtpd2pi(struct Machine *m) {
|
||||
static void OpPpiWpdCvtpd2pi(struct Machine *m, uint32_t rde) {
|
||||
double d[2];
|
||||
int32_t n[2];
|
||||
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
|
||||
memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
n[0] = nearbyint(d[0]);
|
||||
n[1] = nearbyint(d[1]);
|
||||
Write32(MmReg(m) + 0, n[0]);
|
||||
Write32(MmReg(m) + 4, n[1]);
|
||||
Write32(MmReg(m, rde) + 0, n[0]);
|
||||
Write32(MmReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpPpiWpdCvttpd2pi(struct Machine *m) {
|
||||
static void OpPpiWpdCvttpd2pi(struct Machine *m, uint32_t rde) {
|
||||
double d[2];
|
||||
int32_t n[2];
|
||||
memcpy(&d, GetModrmRegisterXmmPointerRead16(m), 16);
|
||||
memcpy(&d, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
n[0] = d[0];
|
||||
n[1] = d[1];
|
||||
Write32(MmReg(m) + 0, n[0]);
|
||||
Write32(MmReg(m) + 4, n[1]);
|
||||
Write32(MmReg(m, rde) + 0, n[0]);
|
||||
Write32(MmReg(m, rde) + 4, n[1]);
|
||||
}
|
||||
|
||||
static void OpVpdWpsCvtps2pd(struct Machine *m) {
|
||||
static void OpVpdWpsCvtps2pd(struct Machine *m, uint32_t rde) {
|
||||
float f[2];
|
||||
double d[2];
|
||||
memcpy(f, GetModrmRegisterXmmPointerRead8(m), 8);
|
||||
memcpy(f, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
d[0] = f[0];
|
||||
d[1] = f[1];
|
||||
memcpy(XmmRexrReg(m), d, 16);
|
||||
memcpy(XmmRexrReg(m, rde), d, 16);
|
||||
}
|
||||
|
||||
static void OpVpsWpdCvtpd2ps(struct Machine *m) {
|
||||
static void OpVpsWpdCvtpd2ps(struct Machine *m, uint32_t rde) {
|
||||
float f[2];
|
||||
double d[2];
|
||||
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
|
||||
memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
f[0] = d[0];
|
||||
f[1] = d[1];
|
||||
memcpy(XmmRexrReg(m), f, 8);
|
||||
memcpy(XmmRexrReg(m, rde), f, 8);
|
||||
}
|
||||
|
||||
static void OpVssWsdCvtsd2ss(struct Machine *m) {
|
||||
static void OpVssWsdCvtsd2ss(struct Machine *m, uint32_t rde) {
|
||||
float f;
|
||||
double d;
|
||||
memcpy(&d, GetModrmRegisterXmmPointerRead8(m), 8);
|
||||
memcpy(&d, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
f = d;
|
||||
memcpy(XmmRexrReg(m), &f, 4);
|
||||
memcpy(XmmRexrReg(m, rde), &f, 4);
|
||||
}
|
||||
|
||||
static void OpVsdWssCvtss2sd(struct Machine *m) {
|
||||
static void OpVsdWssCvtss2sd(struct Machine *m, uint32_t rde) {
|
||||
float f;
|
||||
double d;
|
||||
memcpy(&f, GetModrmRegisterXmmPointerRead4(m), 4);
|
||||
memcpy(&f, GetModrmRegisterXmmPointerRead4(m, rde), 4);
|
||||
d = f;
|
||||
memcpy(XmmRexrReg(m), &d, 8);
|
||||
memcpy(XmmRexrReg(m, rde), &d, 8);
|
||||
}
|
||||
|
||||
static void OpVpsWdqCvtdq2ps(struct Machine *m) {
|
||||
static void OpVpsWdqCvtdq2ps(struct Machine *m, uint32_t rde) {
|
||||
unsigned i;
|
||||
float f[4];
|
||||
int32_t n[4];
|
||||
memcpy(n, GetModrmRegisterXmmPointerRead16(m), 16);
|
||||
memcpy(n, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
for (i = 0; i < 4; ++i) f[i] = n[i];
|
||||
memcpy(XmmRexrReg(m), f, 16);
|
||||
memcpy(XmmRexrReg(m, rde), f, 16);
|
||||
}
|
||||
|
||||
static void OpVpdWdqCvtdq2pd(struct Machine *m) {
|
||||
static void OpVpdWdqCvtdq2pd(struct Machine *m, uint32_t rde) {
|
||||
unsigned i;
|
||||
double d[2];
|
||||
int32_t n[2];
|
||||
memcpy(n, GetModrmRegisterXmmPointerRead8(m), 8);
|
||||
memcpy(n, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
for (i = 0; i < 2; ++i) d[i] = n[i];
|
||||
memcpy(XmmRexrReg(m), d, 16);
|
||||
memcpy(XmmRexrReg(m, rde), d, 16);
|
||||
}
|
||||
|
||||
static void OpVdqWpsCvttps2dq(struct Machine *m) {
|
||||
static void OpVdqWpsCvttps2dq(struct Machine *m, uint32_t rde) {
|
||||
unsigned i;
|
||||
float f[4];
|
||||
int32_t n[4];
|
||||
memcpy(f, GetModrmRegisterXmmPointerRead16(m), 16);
|
||||
memcpy(f, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
for (i = 0; i < 4; ++i) n[i] = f[i];
|
||||
memcpy(XmmRexrReg(m), n, 16);
|
||||
memcpy(XmmRexrReg(m, rde), n, 16);
|
||||
}
|
||||
|
||||
static void OpVdqWpsCvtps2dq(struct Machine *m) {
|
||||
static void OpVdqWpsCvtps2dq(struct Machine *m, uint32_t rde) {
|
||||
unsigned i;
|
||||
float f[4];
|
||||
int32_t n[4];
|
||||
memcpy(f, GetModrmRegisterXmmPointerRead16(m), 16);
|
||||
memcpy(f, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
for (i = 0; i < 4; ++i) n[i] = nearbyintf(f[i]);
|
||||
memcpy(XmmRexrReg(m), n, 16);
|
||||
memcpy(XmmRexrReg(m, rde), n, 16);
|
||||
}
|
||||
|
||||
static void OpVdqWpdCvttpd2dq(struct Machine *m) {
|
||||
static void OpVdqWpdCvttpd2dq(struct Machine *m, uint32_t rde) {
|
||||
unsigned i;
|
||||
double d[2];
|
||||
int32_t n[2];
|
||||
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
|
||||
memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
for (i = 0; i < 2; ++i) n[i] = d[i];
|
||||
memcpy(XmmRexrReg(m), n, 8);
|
||||
memcpy(XmmRexrReg(m, rde), n, 8);
|
||||
}
|
||||
|
||||
static void OpVdqWpdCvtpd2dq(struct Machine *m) {
|
||||
static void OpVdqWpdCvtpd2dq(struct Machine *m, uint32_t rde) {
|
||||
unsigned i;
|
||||
double d[2];
|
||||
int32_t n[2];
|
||||
memcpy(d, GetModrmRegisterXmmPointerRead16(m), 16);
|
||||
memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16);
|
||||
for (i = 0; i < 2; ++i) n[i] = nearbyintf(d[i]);
|
||||
memcpy(XmmRexrReg(m), n, 8);
|
||||
memcpy(XmmRexrReg(m, rde), n, 8);
|
||||
}
|
||||
|
||||
void OpCvt(struct Machine *m, unsigned long op) {
|
||||
switch (op | Rep(m->xedd) | Osz(m->xedd)) {
|
||||
void OpCvt(struct Machine *m, uint32_t rde, unsigned long op) {
|
||||
switch (op | Rep(rde) | Osz(rde)) {
|
||||
case kOpCvt0f2a + 0:
|
||||
OpVpsQpiCvtpi2ps(m);
|
||||
OpVpsQpiCvtpi2ps(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2a + 1:
|
||||
OpVpdQpiCvtpi2pd(m);
|
||||
OpVpdQpiCvtpi2pd(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2a + 2:
|
||||
OpVsdEdqpCvtsi2sd(m);
|
||||
OpVsdEdqpCvtsi2sd(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2a + 3:
|
||||
OpVssEdqpCvtsi2ss(m);
|
||||
OpVssEdqpCvtsi2ss(m, rde);
|
||||
break;
|
||||
case kOpCvtt0f2c + 0:
|
||||
OpPpiWpsqCvttps2pi(m);
|
||||
OpPpiWpsqCvttps2pi(m, rde);
|
||||
break;
|
||||
case kOpCvtt0f2c + 1:
|
||||
OpPpiWpdCvttpd2pi(m);
|
||||
OpPpiWpdCvttpd2pi(m, rde);
|
||||
break;
|
||||
case kOpCvtt0f2c + 2:
|
||||
OpGdqpWsdCvttsd2si(m);
|
||||
OpGdqpWsdCvttsd2si(m, rde);
|
||||
break;
|
||||
case kOpCvtt0f2c + 3:
|
||||
OpGdqpWssCvttss2si(m);
|
||||
OpGdqpWssCvttss2si(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2d + 0:
|
||||
OpPpiWpsqCvtps2pi(m);
|
||||
OpPpiWpsqCvtps2pi(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2d + 1:
|
||||
OpPpiWpdCvtpd2pi(m);
|
||||
OpPpiWpdCvtpd2pi(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2d + 2:
|
||||
OpGdqpWsdCvtsd2si(m);
|
||||
OpGdqpWsdCvtsd2si(m, rde);
|
||||
break;
|
||||
case kOpCvt0f2d + 3:
|
||||
OpGdqpWssCvtss2si(m);
|
||||
OpGdqpWssCvtss2si(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5a + 0:
|
||||
OpVpdWpsCvtps2pd(m);
|
||||
OpVpdWpsCvtps2pd(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5a + 1:
|
||||
OpVpsWpdCvtpd2ps(m);
|
||||
OpVpsWpdCvtpd2ps(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5a + 2:
|
||||
OpVssWsdCvtsd2ss(m);
|
||||
OpVssWsdCvtsd2ss(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5a + 3:
|
||||
OpVsdWssCvtss2sd(m);
|
||||
OpVsdWssCvtss2sd(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5b + 0:
|
||||
OpVpsWdqCvtdq2ps(m);
|
||||
OpVpsWdqCvtdq2ps(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5b + 1:
|
||||
OpVdqWpsCvtps2dq(m);
|
||||
OpVdqWpsCvtps2dq(m, rde);
|
||||
break;
|
||||
case kOpCvt0f5b + 3:
|
||||
OpVdqWpsCvttps2dq(m);
|
||||
OpVdqWpsCvttps2dq(m, rde);
|
||||
break;
|
||||
case kOpCvt0fE6 + 1:
|
||||
OpVdqWpdCvtpd2dq(m);
|
||||
OpVdqWpdCvtpd2dq(m, rde);
|
||||
break;
|
||||
case kOpCvt0fE6 + 2:
|
||||
OpVdqWpdCvttpd2dq(m);
|
||||
OpVdqWpdCvttpd2dq(m, rde);
|
||||
break;
|
||||
case kOpCvt0fE6 + 3:
|
||||
OpVpdWdqCvtdq2pd(m);
|
||||
OpVpdWdqCvtdq2pd(m, rde);
|
||||
break;
|
||||
default:
|
||||
OpUd(m);
|
||||
|
|
|
@ -11,7 +11,7 @@ COSMOPOLITAN_C_START_
|
|||
#define kOpCvt0f5b 16
|
||||
#define kOpCvt0fE6 20
|
||||
|
||||
void OpCvt(struct Machine *, unsigned long);
|
||||
void OpCvt(struct Machine *, uint32_t, unsigned long);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
#define ADDRLEN 8
|
||||
|
|
|
@ -61,7 +61,7 @@ static int64_t RipRelative(struct DisBuilder b, int64_t d) {
|
|||
}
|
||||
|
||||
static const char *GetAddrReg(struct DisBuilder b, uint8_t x, uint8_t r) {
|
||||
return kRegisterName[0][!Asz(b.xedd)][x & 1][r & 7];
|
||||
return kRegisterName[0][!Asz(b.xedd->op.rde)][x & 1][r & 7];
|
||||
}
|
||||
|
||||
static char *DisRegister(char *p, const char *s) {
|
||||
|
@ -87,24 +87,25 @@ static char *DisComment(char *p, const char *s) {
|
|||
}
|
||||
|
||||
static char *DisRegisterByte(struct DisBuilder b, char *p, bool g, int r) {
|
||||
return DisRegister(p, kRegisterName8[g][Rex(b.xedd)][r]);
|
||||
return DisRegister(p, kRegisterName8[g][Rex(b.xedd->op.rde)][r]);
|
||||
}
|
||||
|
||||
static char *DisRegisterWord(struct DisBuilder b, char *p, bool g, int r) {
|
||||
return DisRegister(p, kRegisterName[Osz(b.xedd)][Rexw(b.xedd)][g][r]);
|
||||
return DisRegister(
|
||||
p, kRegisterName[Osz(b.xedd->op.rde)][Rexw(b.xedd->op.rde)][g][r]);
|
||||
}
|
||||
|
||||
static char *DisGvqp(struct DisBuilder b, char *p) {
|
||||
return DisRegisterWord(b, p, Rexr(b.xedd), ModrmReg(b.xedd));
|
||||
return DisRegisterWord(b, p, Rexr(b.xedd->op.rde), ModrmReg(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static char *DisGdqp(struct DisBuilder b, char *p) {
|
||||
return DisRegister(
|
||||
p, kRegisterName[0][Rexw(b.xedd)][Rexr(b.xedd)][ModrmReg(b.xedd)]);
|
||||
return DisRegister(p, kRegisterName[0][Rexw(b.xedd->op.rde)][Rexr(
|
||||
b.xedd->op.rde)][ModrmReg(b.xedd->op.rde)]);
|
||||
}
|
||||
|
||||
static char *DisGb(struct DisBuilder b, char *p) {
|
||||
return DisRegisterByte(b, p, Rexr(b.xedd), ModrmReg(b.xedd));
|
||||
return DisRegisterByte(b, p, Rexr(b.xedd->op.rde), ModrmReg(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static uint8_t DisSeg(struct DisBuilder b) {
|
||||
|
@ -154,30 +155,29 @@ static char *DisM(struct DisBuilder b, char *p) {
|
|||
p = DisRegister(p, seg);
|
||||
*p++ = ':';
|
||||
}
|
||||
if (ModrmMod(b.xedd) == 0b01 || ModrmMod(b.xedd) == 0b10 ||
|
||||
IsRipRelative(b.xedd) ||
|
||||
(ModrmMod(b.xedd) == 0b00 && ModrmRm(b.xedd) == 0b100 &&
|
||||
SibBase(b.xedd) == 0b101)) {
|
||||
if (ModrmMod(b.xedd->op.rde) == 0b01 || ModrmMod(b.xedd->op.rde) == 0b10 ||
|
||||
IsRipRelative(b.xedd->op.rde) ||
|
||||
(ModrmMod(b.xedd->op.rde) == 0b00 && ModrmRm(b.xedd->op.rde) == 0b100 &&
|
||||
SibBase(b.xedd->op.rde) == 0b101)) {
|
||||
disp = b.xedd->op.disp;
|
||||
if (IsRipRelative(b.xedd)) disp = RipRelative(b, disp);
|
||||
if (IsRipRelative(b.xedd->op.rde)) disp = RipRelative(b, disp);
|
||||
p = DisSym(b, p, disp);
|
||||
}
|
||||
if (!SibExists(b.xedd)) {
|
||||
if (!SibExists(b.xedd->op.rde)) {
|
||||
DCHECK(!b.xedd->op.has_sib);
|
||||
if (IsRipRelative(b.xedd)) {
|
||||
if (IsRipRelative(b.xedd->op.rde)) {
|
||||
base = "rip";
|
||||
} else {
|
||||
base = GetAddrReg(b, Rexb(b.xedd), ModrmRm(b.xedd));
|
||||
base = GetAddrReg(b, Rexb(b.xedd->op.rde), ModrmRm(b.xedd->op.rde));
|
||||
}
|
||||
} else if (!SibIsAbsolute(b.xedd)) {
|
||||
DCHECK(b.xedd->op.has_sib);
|
||||
if (SibHasBase(b.xedd)) {
|
||||
base = GetAddrReg(b, Rexb(b.xedd), SibBase(b.xedd));
|
||||
} else if (!SibIsAbsolute(b.xedd->op.rde)) {
|
||||
if (SibHasBase(b.xedd->op.rde)) {
|
||||
base = GetAddrReg(b, Rexb(b.xedd->op.rde), SibBase(b.xedd->op.rde));
|
||||
}
|
||||
if (SibHasIndex(b.xedd)) {
|
||||
index = GetAddrReg(b, Rexx(b.xedd), SibIndex(b.xedd));
|
||||
if (SibHasIndex(b.xedd->op.rde)) {
|
||||
index = GetAddrReg(b, Rexx(b.xedd->op.rde), SibIndex(b.xedd->op.rde));
|
||||
} else if (b.xedd->op.scale) {
|
||||
index = Asz(b.xedd) ? "eiz" : "riz";
|
||||
index = Asz(b.xedd->op.rde) ? "eiz" : "riz";
|
||||
}
|
||||
scale = kScale[b.xedd->op.scale];
|
||||
}
|
||||
|
@ -198,25 +198,25 @@ static char *DisM(struct DisBuilder b, char *p) {
|
|||
}
|
||||
|
||||
static char *DisEb(struct DisBuilder b, char *p) {
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
return DisRegisterByte(b, p, Rexb(b.xedd), ModrmRm(b.xedd));
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
return DisRegisterByte(b, p, Rexb(b.xedd->op.rde), ModrmRm(b.xedd->op.rde));
|
||||
} else {
|
||||
return DisM(b, p);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisEvqp(struct DisBuilder b, char *p) {
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
return DisRegisterWord(b, p, Rexb(b.xedd), ModrmRm(b.xedd));
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
return DisRegisterWord(b, p, Rexb(b.xedd->op.rde), ModrmRm(b.xedd->op.rde));
|
||||
} else {
|
||||
return DisM(b, p);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisEdqp(struct DisBuilder b, char *p) {
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
return DisRegister(
|
||||
p, kRegisterName[0][Rexw(b.xedd)][Rexb(b.xedd)][ModrmRm(b.xedd)]);
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
return DisRegister(p, kRegisterName[0][Rexw(b.xedd->op.rde)][Rexb(
|
||||
b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)]);
|
||||
} else {
|
||||
return DisM(b, p);
|
||||
}
|
||||
|
@ -224,11 +224,11 @@ static char *DisEdqp(struct DisBuilder b, char *p) {
|
|||
|
||||
static char *DisEvq(struct DisBuilder b, char *p) {
|
||||
const char *s;
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
if (Osz(b.xedd)) {
|
||||
s = kRegisterName[1][0][Rexb(b.xedd)][ModrmRm(b.xedd)];
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
if (Osz(b.xedd->op.rde)) {
|
||||
s = kRegisterName[1][0][Rexb(b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)];
|
||||
} else {
|
||||
s = kRegisterName[0][1][Rexb(b.xedd)][ModrmRm(b.xedd)];
|
||||
s = kRegisterName[0][1][Rexb(b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)];
|
||||
}
|
||||
return DisRegister(p, s);
|
||||
} else {
|
||||
|
@ -237,47 +237,53 @@ static char *DisEvq(struct DisBuilder b, char *p) {
|
|||
}
|
||||
|
||||
static char *DisEd(struct DisBuilder b, char *p) {
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
return DisRegister(p, kRegisterName[0][0][Rexb(b.xedd)][ModrmRm(b.xedd)]);
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
return DisRegister(
|
||||
p, kRegisterName[0][0][Rexb(b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)]);
|
||||
} else {
|
||||
return DisM(b, p);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisEq(struct DisBuilder b, char *p) {
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
return DisRegister(p, kRegisterName[0][1][Rexb(b.xedd)][ModrmRm(b.xedd)]);
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
return DisRegister(
|
||||
p, kRegisterName[0][1][Rexb(b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)]);
|
||||
} else {
|
||||
return DisM(b, p);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisZvq(struct DisBuilder b, char *p) {
|
||||
if (Osz(b.xedd)) {
|
||||
return DisRegister(p, kRegisterName[1][0][Rexb(b.xedd)][ModrmSrm(b.xedd)]);
|
||||
if (Osz(b.xedd->op.rde)) {
|
||||
return DisRegister(
|
||||
p, kRegisterName[1][0][Rexb(b.xedd->op.rde)][ModrmSrm(b.xedd->op.rde)]);
|
||||
} else {
|
||||
return DisRegister(p, kRegisterName[0][1][Rexb(b.xedd)][ModrmSrm(b.xedd)]);
|
||||
return DisRegister(
|
||||
p, kRegisterName[0][1][Rexb(b.xedd->op.rde)][ModrmSrm(b.xedd->op.rde)]);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisZvqp(struct DisBuilder b, char *p) {
|
||||
return DisRegisterWord(b, p, Rexb(b.xedd), ModrmSrm(b.xedd));
|
||||
return DisRegisterWord(b, p, Rexb(b.xedd->op.rde), ModrmSrm(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static char *DisZb(struct DisBuilder b, char *p) {
|
||||
return DisRegisterByte(b, p, Rexb(b.xedd), ModrmSrm(b.xedd));
|
||||
return DisRegisterByte(b, p, Rexb(b.xedd->op.rde), ModrmSrm(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static char *DisEax(struct DisBuilder b, char *p) {
|
||||
return DisRegister(p, kRegisterName[Osz(b.xedd)][0][0][0]);
|
||||
return DisRegister(p, kRegisterName[Osz(b.xedd->op.rde)][0][0][0]);
|
||||
}
|
||||
|
||||
static char *DisRax(struct DisBuilder b, char *p) {
|
||||
return DisRegister(p, kRegisterName[Osz(b.xedd)][Rexw(b.xedd)][0][0]);
|
||||
return DisRegister(
|
||||
p, kRegisterName[Osz(b.xedd->op.rde)][Rexw(b.xedd->op.rde)][0][0]);
|
||||
}
|
||||
|
||||
static char *DisRdx(struct DisBuilder b, char *p) {
|
||||
return DisRegister(p, kRegisterName[Osz(b.xedd)][Rexw(b.xedd)][0][2]);
|
||||
return DisRegister(
|
||||
p, kRegisterName[Osz(b.xedd->op.rde)][Rexw(b.xedd->op.rde)][0][2]);
|
||||
}
|
||||
|
||||
static char *DisImm(struct DisBuilder b, char *p) {
|
||||
|
@ -309,8 +315,8 @@ static char *DisAbs(struct DisBuilder b, char *p) {
|
|||
}
|
||||
|
||||
static char *DisSw(struct DisBuilder b, char *p) {
|
||||
if (kSegName[ModrmReg(b.xedd)][0]) {
|
||||
p = DisRegister(p, kSegName[ModrmReg(b.xedd)]);
|
||||
if (kSegName[ModrmReg(b.xedd->op.rde)][0]) {
|
||||
p = DisRegister(p, kSegName[ModrmReg(b.xedd->op.rde)]);
|
||||
}
|
||||
*p = '\0';
|
||||
return p;
|
||||
|
@ -318,7 +324,7 @@ static char *DisSw(struct DisBuilder b, char *p) {
|
|||
|
||||
static char *DisY(struct DisBuilder b, char *p) {
|
||||
*p++ = '(';
|
||||
p = DisRegister(p, Asz(b.xedd) ? "edi" : "rdi");
|
||||
p = DisRegister(p, Asz(b.xedd->op.rde) ? "edi" : "rdi");
|
||||
*p++ = ')';
|
||||
*p = '\0';
|
||||
return p;
|
||||
|
@ -329,7 +335,7 @@ static char *DisX(struct DisBuilder b, char *p) {
|
|||
p = DisRegister(p, kSegOverride[b.xedd->op.seg_ovd]);
|
||||
}
|
||||
*p++ = '(';
|
||||
p = DisRegister(p, Asz(b.xedd) ? "esi" : "rsi");
|
||||
p = DisRegister(p, Asz(b.xedd->op.rde) ? "esi" : "rsi");
|
||||
*p++ = ')';
|
||||
*p = '\0';
|
||||
return p;
|
||||
|
@ -340,7 +346,7 @@ static char *DisBBb(struct DisBuilder b, char *p) {
|
|||
p = DisRegister(p, kSegOverride[b.xedd->op.seg_ovd]);
|
||||
}
|
||||
*p++ = '(';
|
||||
p = DisRegister(p, Asz(b.xedd) ? "ebx" : "rbx");
|
||||
p = DisRegister(p, Asz(b.xedd->op.rde) ? "ebx" : "rbx");
|
||||
*p++ = ')';
|
||||
*p = '\0';
|
||||
return p;
|
||||
|
@ -350,33 +356,33 @@ static char *DisXmm(struct DisBuilder b, char *p, const char *s, int reg) {
|
|||
if (g_dis_high) p = DisHigh(p, g_dis_high->reg);
|
||||
*p++ = '%';
|
||||
p = stpcpy(p, s);
|
||||
p += uint64toarray_radix10(Rexr(b.xedd) << 3 | reg, p);
|
||||
p += uint64toarray_radix10(Rexr(b.xedd->op.rde) << 3 | reg, p);
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisNq(struct DisBuilder b, char *p) {
|
||||
return DisXmm(b, p, "mm", ModrmRm(b.xedd));
|
||||
return DisXmm(b, p, "mm", ModrmRm(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static char *DisUq(struct DisBuilder b, char *p) {
|
||||
return DisXmm(b, p, "mm", ModrmRm(b.xedd));
|
||||
return DisXmm(b, p, "mm", ModrmRm(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static char *DisPq(struct DisBuilder b, char *p) {
|
||||
return DisXmm(b, p, "mm", ModrmReg(b.xedd));
|
||||
return DisXmm(b, p, "mm", ModrmReg(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static char *DisUdq(struct DisBuilder b, char *p) {
|
||||
return DisXmm(b, p, "xmm", ModrmRm(b.xedd));
|
||||
return DisXmm(b, p, "xmm", ModrmRm(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static char *DisVdq(struct DisBuilder b, char *p) {
|
||||
return DisXmm(b, p, "xmm", ModrmReg(b.xedd));
|
||||
return DisXmm(b, p, "xmm", ModrmReg(b.xedd->op.rde));
|
||||
}
|
||||
|
||||
static char *DisQq(struct DisBuilder b, char *p) {
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
return DisNq(b, p);
|
||||
} else {
|
||||
return DisM(b, p);
|
||||
|
@ -385,9 +391,9 @@ static char *DisQq(struct DisBuilder b, char *p) {
|
|||
|
||||
static char *DisEst(struct DisBuilder b, char *p) {
|
||||
p = DisRegister(p, "st");
|
||||
if (ModrmRm(b.xedd) != 0) {
|
||||
if (ModrmRm(b.xedd->op.rde) != 0) {
|
||||
*p++ = '(';
|
||||
*p++ = '0' + ModrmRm(b.xedd);
|
||||
*p++ = '0' + ModrmRm(b.xedd->op.rde);
|
||||
*p++ = ')';
|
||||
*p = '\0';
|
||||
}
|
||||
|
@ -395,7 +401,7 @@ static char *DisEst(struct DisBuilder b, char *p) {
|
|||
}
|
||||
|
||||
static char *DisEst1(struct DisBuilder b, char *p) {
|
||||
if (ModrmRm(b.xedd) != 1) {
|
||||
if (ModrmRm(b.xedd->op.rde) != 1) {
|
||||
p = DisEst(b, p);
|
||||
} else {
|
||||
*p = '\0';
|
||||
|
@ -404,7 +410,7 @@ static char *DisEst1(struct DisBuilder b, char *p) {
|
|||
}
|
||||
|
||||
static char *DisEssr(struct DisBuilder b, char *p) {
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
return DisEst(b, p);
|
||||
} else {
|
||||
return DisM(b, p);
|
||||
|
@ -412,7 +418,7 @@ static char *DisEssr(struct DisBuilder b, char *p) {
|
|||
}
|
||||
|
||||
static char *DisWps(struct DisBuilder b, char *p) {
|
||||
if (IsModrmRegister(b.xedd)) {
|
||||
if (IsModrmRegister(b.xedd->op.rde)) {
|
||||
return DisUdq(b, p);
|
||||
} else {
|
||||
return DisM(b, p);
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/log/check.h"
|
||||
#include "libc/nexgen32e/tinystrcmp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
|
@ -29,15 +28,26 @@ static const char kAluOp[8][4] = {"add", "or", "adc", "sbb",
|
|||
static const char kBitOp[8][4] = {"rol", "ror", "rcl", "rcr",
|
||||
"shl", "shr", "sal", "sar"};
|
||||
|
||||
static bool IsProbablyByteOp(struct XedDecodedInst *x) {
|
||||
return !(x->op.opcode & 1);
|
||||
}
|
||||
|
||||
static int IsRepOpcode(struct DisBuilder b) {
|
||||
switch (b.xedd->op.opcode & ~1u) {
|
||||
CASE(0x6C /*INS */, return 1);
|
||||
CASE(0x6E /*OUTS*/, return 1);
|
||||
CASE(0xA4 /*MOVS*/, return 1);
|
||||
CASE(0xAA /*STOS*/, return 1);
|
||||
CASE(0xAC /*LODS*/, return 1);
|
||||
CASE(0xA6 /*CMPS*/, return 2);
|
||||
CASE(0xAE /*SCAS*/, return 2);
|
||||
case 0x6C: /* INS */
|
||||
return 1;
|
||||
case 0x6E: /* OUTS */
|
||||
return 1;
|
||||
case 0xA4: /* MOVS */
|
||||
return 1;
|
||||
case 0xAA: /* STOS */
|
||||
return 1;
|
||||
case 0xAC: /* LODS */
|
||||
return 1;
|
||||
case 0xA6: /* CMPS */
|
||||
return 2;
|
||||
case 0xAE: /* SCAS */
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -45,7 +55,7 @@ static int IsRepOpcode(struct DisBuilder b) {
|
|||
|
||||
static char *DisRepPrefix(struct DisBuilder b, char *p) {
|
||||
const char *s;
|
||||
if (Rep(b.xedd) && b.xedd->op.map == XED_ILD_MAP0) {
|
||||
if (Rep(b.xedd->op.rde) && b.xedd->op.map == XED_ILD_MAP0) {
|
||||
switch (IsRepOpcode(b)) {
|
||||
case 0:
|
||||
break;
|
||||
|
@ -53,7 +63,7 @@ static char *DisRepPrefix(struct DisBuilder b, char *p) {
|
|||
p = stpcpy(p, "rep ");
|
||||
break;
|
||||
case 2:
|
||||
p = stpcpy(p, Rep(b.xedd) == 2 ? "repnz " : "repz ");
|
||||
p = stpcpy(p, Rep(b.xedd->op.rde) == 2 ? "repnz " : "repz ");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -81,30 +91,30 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
|||
if (b.xedd->op.lock) p = stpcpy(p, "lock ");
|
||||
p = DisRepPrefix(b, p);
|
||||
if (tinystrcmp(name, "BIT") == 0) {
|
||||
p = stpcpy(p, kBitOp[ModrmReg(b.xedd)]);
|
||||
p = stpcpy(p, kBitOp[ModrmReg(b.xedd->op.rde)]);
|
||||
} else if (tinystrcmp(name, "CALL") == 0) {
|
||||
p = stpcpy(p, "call");
|
||||
} else if (tinystrcmp(name, "JMP") == 0) {
|
||||
p = stpcpy(p, "jmp");
|
||||
} else if (tinystrcmp(name, "jcxz") == 0) {
|
||||
p = stpcpy(p, Asz(b.xedd) ? "jecxz" : "jrcxz");
|
||||
p = stpcpy(p, Asz(b.xedd->op.rde) ? "jecxz" : "jrcxz");
|
||||
p = DisBranchTaken(b, p);
|
||||
} else if (tinystrcmp(name, "loop") == 0) {
|
||||
p = stpcpy(p, Asz(b.xedd) ? "loopl" : "loop");
|
||||
p = stpcpy(p, Asz(b.xedd->op.rde) ? "loopl" : "loop");
|
||||
p = DisBranchTaken(b, p);
|
||||
} else if (tinystrcmp(name, "loope") == 0) {
|
||||
p = stpcpy(p, Asz(b.xedd) ? "loopel" : "loope");
|
||||
p = stpcpy(p, Asz(b.xedd->op.rde) ? "loopel" : "loope");
|
||||
p = DisBranchTaken(b, p);
|
||||
} else if (tinystrcmp(name, "loopne") == 0) {
|
||||
p = stpcpy(p, Asz(b.xedd) ? "loopnel" : "loopne");
|
||||
p = stpcpy(p, Asz(b.xedd->op.rde) ? "loopnel" : "loopne");
|
||||
p = DisBranchTaken(b, p);
|
||||
} else if (tinystrcmp(name, "cwtl") == 0) {
|
||||
if (Osz(b.xedd)) name = "cbtw";
|
||||
if (Rexw(b.xedd)) name = "cltq";
|
||||
if (Osz(b.xedd->op.rde)) name = "cbtw";
|
||||
if (Rexw(b.xedd->op.rde)) name = "cltq";
|
||||
p = stpcpy(p, name);
|
||||
} else if (tinystrcmp(name, "cltd") == 0) {
|
||||
if (Osz(b.xedd)) name = "cwtd";
|
||||
if (Rexw(b.xedd)) name = "cqto";
|
||||
if (Osz(b.xedd->op.rde)) name = "cwtd";
|
||||
if (Rexw(b.xedd->op.rde)) name = "cqto";
|
||||
p = stpcpy(p, name);
|
||||
} else {
|
||||
notbyte = false;
|
||||
|
@ -115,7 +125,7 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
|||
*p++ = *np;
|
||||
}
|
||||
if (tinystrcmp(name, "ALU") == 0) {
|
||||
p = stpcpy(p, kAluOp[ModrmReg(b.xedd)]);
|
||||
p = stpcpy(p, kAluOp[ModrmReg(b.xedd->op.rde)]);
|
||||
} else if (tinystrcmp(np, "WLQ") == 0) {
|
||||
notbyte = true;
|
||||
wantsuffix = true;
|
||||
|
@ -130,21 +140,21 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
|||
notbyte = true;
|
||||
wantsuffixsd = true;
|
||||
} else if (tinystrcmp(np, "ABS") == 0) {
|
||||
if (Rexw(b.xedd)) p = stpcpy(p, "abs");
|
||||
if (Rexw(b.xedd->op.rde)) p = stpcpy(p, "abs");
|
||||
} else if (tinystrcmp(np, "BT") == 0) {
|
||||
p = DisBranchTaken(b, p);
|
||||
}
|
||||
if (wantsuffixsd) {
|
||||
if (Osz(b.xedd)) {
|
||||
if (Osz(b.xedd->op.rde)) {
|
||||
*p++ = 'd';
|
||||
} else {
|
||||
*p++ = 's';
|
||||
}
|
||||
} else if (wantsuffix || (ambiguous && !startswith(name, "f") &&
|
||||
!startswith(name, "set"))) {
|
||||
if (Osz(b.xedd)) {
|
||||
if (Osz(b.xedd->op.rde)) {
|
||||
*p++ = 'w';
|
||||
} else if (Rexw(b.xedd)) {
|
||||
} else if (Rexw(b.xedd->op.rde)) {
|
||||
*p++ = 'q';
|
||||
} else if (ambiguous && !notbyte && IsProbablyByteOp(b.xedd)) {
|
||||
*p++ = 'b';
|
||||
|
@ -169,11 +179,12 @@ char *DisInst(struct DisBuilder b, char *p, const char *spec) {
|
|||
char args[4][64];
|
||||
char *s, *name, *state;
|
||||
bool hasarg, hasmodrm, hasregister, hasmemory;
|
||||
CHECK_EQ(0, (int)b.xedd->op.error);
|
||||
DCHECK_LT(strlen(spec), 128);
|
||||
hasarg = false;
|
||||
hasmodrm = b.xedd->op.has_modrm;
|
||||
hasmemory = hasmodrm && !IsModrmRegister(b.xedd);
|
||||
hasregister = hasmodrm && IsModrmRegister(b.xedd);
|
||||
hasmemory = hasmodrm && !IsModrmRegister(b.xedd->op.rde);
|
||||
hasregister = hasmodrm && IsModrmRegister(b.xedd->op.rde);
|
||||
name = strtok_r(strcpy(sbuf, spec), " ", &state);
|
||||
for (n = 0; (s = strtok_r(NULL, " ", &state)); ++n) {
|
||||
hasarg = true;
|
||||
|
|
|
@ -38,18 +38,18 @@ static const char kFpuName[][8][8] = {
|
|||
|
||||
char *DisOpFpu0(struct XedDecodedInst *x, int group) {
|
||||
const char *s;
|
||||
s = kFpuName[group][ModrmRm(x)];
|
||||
s = kFpuName[group][ModrmRm(x->op.rde)];
|
||||
return *s ? s : UNKNOWN;
|
||||
}
|
||||
|
||||
char *DisOpFpu1(struct XedDecodedInst *x, char *p, const char *extra) {
|
||||
stpcpy(stpcpy(p, kFpuName[0][ModrmReg(x)]), extra);
|
||||
stpcpy(stpcpy(p, kFpuName[0][ModrmReg(x->op.rde)]), extra);
|
||||
return p;
|
||||
}
|
||||
|
||||
char *DisOp66(struct XedDecodedInst *x, char *p, const char *s, const char *a,
|
||||
const char *b) {
|
||||
stpcpy(stpcpy(p, s), !Osz(x) ? a : b);
|
||||
stpcpy(stpcpy(p, s), !Osz(x->op.rde) ? a : b);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -76,11 +76,11 @@ char *DisOpNqIbUdqIb(struct XedDecodedInst *x, char *p, const char *s) {
|
|||
char *DisOpVpsWpsVssWssVpdWpdVsdWsd(struct XedDecodedInst *x, char *p,
|
||||
const char *s) {
|
||||
char *q = stpcpy(p, s);
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
stpcpy(q, "ss %Vss Wss");
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
stpcpy(q, "sd %Vsd Wsd");
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
stpcpy(q, "pd %Vpd Wpd");
|
||||
} else {
|
||||
stpcpy(q, "ps %Vps Wps");
|
||||
|
@ -265,53 +265,53 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0xFC, "cld");
|
||||
RCASE(0xFD, "std");
|
||||
case 0x8F:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "popWQ Evq");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xD9:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(1, "fxch EST1");
|
||||
RCASE(3, "fstps Msr %st");
|
||||
case 0:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "fld EST";
|
||||
} else {
|
||||
return "flds Msr";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "fnop";
|
||||
} else {
|
||||
return "fsts Msr %st";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu0(x, 1);
|
||||
} else {
|
||||
return "fldenv Me";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu0(x, 2);
|
||||
} else {
|
||||
return "fldcw Mw";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu0(x, 3);
|
||||
} else {
|
||||
return "fnstenv M";
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu0(x, 4);
|
||||
} else {
|
||||
return "fnstcw Mw";
|
||||
|
@ -320,58 +320,58 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xDA:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
case 0:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fiaddl Mdi";
|
||||
} else {
|
||||
return "fcmovb %st EST";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fimull Mdi";
|
||||
} else {
|
||||
return "fcmove %st EST";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "ficoml Mdi";
|
||||
} else {
|
||||
return "fcmovbe %st EST";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "ficompl Mdi";
|
||||
} else {
|
||||
return "fcmovu %st EST";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fisubl Mdi";
|
||||
} else {
|
||||
return "fisubr Mdi";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fisubrl Mdi";
|
||||
} else {
|
||||
return "fucompp";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fidivl Mdi";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fidivrl Mdi";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
|
@ -380,30 +380,30 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xDB:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
case 0:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fildl Mdi";
|
||||
} else {
|
||||
return "fcmovnb %st EST";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fisttpl Mdi";
|
||||
} else {
|
||||
return "fcmovne %st EST";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fistl Mdi";
|
||||
} else {
|
||||
return "fcmovnbe %st EST";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fistpl Mdi";
|
||||
} else {
|
||||
return "fcmovnu %st EST";
|
||||
|
@ -412,21 +412,21 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
case 4:
|
||||
return DisOpFpu0(x, 5);
|
||||
case 5:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fldt Mer";
|
||||
} else {
|
||||
return "fucomi %st EST";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "fcomi %st EST";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fstpt Mer";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
|
@ -435,12 +435,12 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
return DisOpFpu1(x, p, !IsModrmRegister(x) ? "s Msr" : " EST1");
|
||||
return DisOpFpu1(x, p, !IsModrmRegister(x->op.rde) ? "s Msr" : " EST1");
|
||||
case 0xDC:
|
||||
if (!IsModrmRegister(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu1(x, p, "l Mdr");
|
||||
} else {
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "fadd EST %st");
|
||||
RCASE(1, "fmul EST %st");
|
||||
RCASE(2, "fcom %st EST");
|
||||
|
@ -453,8 +453,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xDD:
|
||||
if (!IsModrmRegister(x)) {
|
||||
switch (ModrmReg(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "fldl Mdr");
|
||||
RCASE(1, "fisttpll Mqi");
|
||||
RCASE(2, "fstl Mdr");
|
||||
|
@ -464,7 +464,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(7, "fnstsw Mst");
|
||||
}
|
||||
} else {
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "ffree EST");
|
||||
RCASE(1, "fxch EST");
|
||||
RCASE(2, "fst EST");
|
||||
|
@ -475,8 +475,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xDE:
|
||||
if (!IsModrmRegister(x)) {
|
||||
switch (ModrmReg(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "fiadds Mwi");
|
||||
RCASE(1, "fimuls Mwi");
|
||||
RCASE(2, "ficoms Mwi");
|
||||
|
@ -487,7 +487,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(7, "fidivrs Mwi");
|
||||
}
|
||||
} else {
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "faddp EST1");
|
||||
RCASE(1, "fmulp EST1");
|
||||
RCASE(2, "fcomp EST1");
|
||||
|
@ -500,8 +500,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xDF:
|
||||
if (!IsModrmRegister(x)) {
|
||||
switch (ModrmReg(x)) {
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "filds Mwi");
|
||||
RCASE(1, "fisttps Mwi");
|
||||
RCASE(2, "fists Mwi");
|
||||
|
@ -512,7 +512,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(7, "fistpll Mqi");
|
||||
}
|
||||
} else {
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "ffreep EST");
|
||||
RCASE(1, "fxch");
|
||||
RCASE(2, "fstp EST");
|
||||
|
@ -524,7 +524,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xF6:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "test Eb Ib");
|
||||
RCASE(1, "test Eb Ib");
|
||||
RCASE(2, "not Eb");
|
||||
|
@ -536,7 +536,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "test Evqp Ivds");
|
||||
RCASE(1, "test Evqp Ivds");
|
||||
RCASE(2, "not Evqp");
|
||||
|
@ -548,13 +548,13 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xFE:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "inc Eb");
|
||||
RCASE(1, "dec Eb");
|
||||
}
|
||||
break;
|
||||
case 0xFF:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "inc Evqp");
|
||||
RCASE(1, "dec Evqp");
|
||||
RCASE(2, "CALL Eq");
|
||||
|
@ -580,8 +580,8 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0x28, "movapSD %Vps Wps");
|
||||
RCASE(0x29, "movapSD Wps %Vps");
|
||||
RCASE(0x2B, "movntpSD Mps %Vps");
|
||||
RCASE(0x2E, Osz(x) ? "ucomisd %Vsd Wsd" : "ucomiss %Vss Wss");
|
||||
RCASE(0x2F, Osz(x) ? "comisd %Vsd Wsd" : "comiss %Vss Wss");
|
||||
RCASE(0x2E, Osz(x->op.rde) ? "ucomisd %Vsd Wsd" : "ucomiss %Vss Wss");
|
||||
RCASE(0x2F, Osz(x->op.rde) ? "comisd %Vsd Wsd" : "comiss %Vss Wss");
|
||||
RCASE(0x31, "rdtsc");
|
||||
RCASE(0x40, "cmovo %Gvqp Evqp");
|
||||
RCASE(0x41, "cmovno %Gvqp Evqp");
|
||||
|
@ -693,7 +693,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0xD3, DisOpPqQqVdqWdq(x, p, "psrlq"));
|
||||
RCASE(0xD4, DisOpPqQqVdqWdq(x, p, "paddq"));
|
||||
RCASE(0xD5, DisOpPqQqVdqWdq(x, p, "pmullw"));
|
||||
RCASE(0xD7, Osz(x) ? "pmovmskb %Gdqp %Udq" : "pmovmskb %Gdqp %Nq");
|
||||
RCASE(0xD7, Osz(x->op.rde) ? "pmovmskb %Gdqp %Udq" : "pmovmskb %Gdqp %Nq");
|
||||
RCASE(0xD8, DisOpPqQqVdqWdq(x, p, "psubusb"));
|
||||
RCASE(0xD9, DisOpPqQqVdqWdq(x, p, "psubusw"));
|
||||
RCASE(0xDA, DisOpPqQqVdqWdq(x, p, "pminub"));
|
||||
|
@ -708,7 +708,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0xE3, DisOpPqQqVdqWdq(x, p, "pavgw"));
|
||||
RCASE(0xE4, DisOpPqQqVdqWdq(x, p, "pmulhuw"));
|
||||
RCASE(0xE5, DisOpPqQqVdqWdq(x, p, "pmulhw"));
|
||||
RCASE(0xE7, Osz(x) ? "movntdq Mdq %Vdq" : "movntq Mq %Pq");
|
||||
RCASE(0xE7, Osz(x->op.rde) ? "movntdq Mdq %Vdq" : "movntq Mq %Pq");
|
||||
RCASE(0xE8, DisOpPqQqVdqWdq(x, p, "psubsb"));
|
||||
RCASE(0xE9, DisOpPqQqVdqWdq(x, p, "psubsw"));
|
||||
RCASE(0xEA, DisOpPqQqVdqWdq(x, p, "pminsw"));
|
||||
|
@ -740,7 +740,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0x70:
|
||||
switch (Rep(x) | Osz(x)) {
|
||||
switch (Rep(x->op.rde) | Osz(x->op.rde)) {
|
||||
RCASE(0, "pshufw %Pq Qq Ib");
|
||||
RCASE(1, "pshufd %Vdq Wdq Ib");
|
||||
RCASE(2, "pshuflw %Vdq Wdq Ib");
|
||||
|
@ -748,21 +748,21 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0x71:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(2, DisOpNqIbUdqIb(x, p, "psrlw"));
|
||||
RCASE(4, DisOpNqIbUdqIb(x, p, "psraw"));
|
||||
RCASE(6, DisOpNqIbUdqIb(x, p, "psllw"));
|
||||
}
|
||||
break;
|
||||
case 0x72:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(2, DisOpNqIbUdqIb(x, p, "psrld"));
|
||||
RCASE(4, DisOpNqIbUdqIb(x, p, "psrad"));
|
||||
RCASE(6, DisOpNqIbUdqIb(x, p, "pslld"));
|
||||
}
|
||||
break;
|
||||
case 0x73:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(2, DisOpNqIbUdqIb(x, p, "psrlq"));
|
||||
RCASE(3, DisOpNqIbUdqIb(x, p, "psrldq"));
|
||||
RCASE(6, DisOpNqIbUdqIb(x, p, "psllq"));
|
||||
|
@ -770,7 +770,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xAE:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(0, "fxsave Mstx %st %st(1)");
|
||||
RCASE(1, "fxrstor Mstx %st %st(1)");
|
||||
RCASE(2, "ldmxcsr Md");
|
||||
|
@ -787,7 +787,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xBA:
|
||||
switch (ModrmReg(x)) {
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(4, "btWLQ Evqp Ib");
|
||||
RCASE(5, "btsWLQ Evqp Ib");
|
||||
RCASE(6, "btrWLQ Evqp Ib");
|
||||
|
@ -795,36 +795,36 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0x10:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "movss %Vss Wss";
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
return "movsd %Vsd Wsd";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "movupd %Vpd Wpd";
|
||||
} else {
|
||||
return "movups %Vps Wps";
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "movss Wss %Vss";
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
return "movsd Wsd %Vsd";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "movupd Wpd %Vpd";
|
||||
} else {
|
||||
return "movups Wps %Vps";
|
||||
}
|
||||
break;
|
||||
case 0xC4:
|
||||
if (!Osz(x)) {
|
||||
if (IsModrmRegister(x)) {
|
||||
if (!Osz(x->op.rde)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "pinsrw %Pq %Rdqp Ib";
|
||||
} else {
|
||||
return "pinsrw %Pq Mw Ib";
|
||||
}
|
||||
} else {
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "pinsrw %Vdq %Rdqp Ib";
|
||||
} else {
|
||||
return "pinsrw %Vdq Mw Ib";
|
||||
|
@ -832,39 +832,39 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0xC5:
|
||||
if (!Osz(x)) {
|
||||
if (!Osz(x->op.rde)) {
|
||||
return "pextrw %Gdqp %Nq Ib";
|
||||
} else {
|
||||
return "pextrw %Gdqp %Udq Ib";
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
if (!Osz(x)) {
|
||||
if (!Osz(x->op.rde)) {
|
||||
return "shufps %Vps Wps Ib";
|
||||
} else {
|
||||
return "shufpd %Vpd Wpd Ib";
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
if (Rexw(x)) {
|
||||
if (Rexw(x->op.rde)) {
|
||||
return "cmpxchg16b Mdq";
|
||||
} else {
|
||||
return "cmpxchg8b Mq";
|
||||
}
|
||||
break;
|
||||
case 0xD6:
|
||||
if (Osz(x)) {
|
||||
if (Osz(x->op.rde)) {
|
||||
return "movq Wq %Vq";
|
||||
} else if (x->op.ild_f3) {
|
||||
} else if (Rep(x->op.rde) == 3) {
|
||||
return "movq2dq %Vdq %Nq";
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
return "movq2dq %Pq %Uq";
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
switch (Rep(x) | Osz(x)) {
|
||||
switch (Rep(x->op.rde) | Osz(x->op.rde)) {
|
||||
case 0:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "movhlps %Vq %Uq";
|
||||
} else {
|
||||
return "movlps %Vq Mq";
|
||||
|
@ -881,16 +881,16 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0x13:
|
||||
if (Osz(x)) {
|
||||
if (Osz(x->op.rde)) {
|
||||
return "movlpd Mq %Vq";
|
||||
} else {
|
||||
return "movlps Mq %Vq";
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
switch (Rep(x) | Osz(x)) {
|
||||
switch (Rep(x->op.rde) | Osz(x->op.rde)) {
|
||||
case 0:
|
||||
if (IsModrmRegister(x)) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "movlhps %Vq %Uq";
|
||||
} else {
|
||||
return "movhps %Vq Mq";
|
||||
|
@ -905,85 +905,85 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0x17:
|
||||
if (Osz(x)) {
|
||||
if (Osz(x->op.rde)) {
|
||||
return "movhpd Mq %Vq";
|
||||
} else {
|
||||
return "movhps Mq %Vq";
|
||||
}
|
||||
break;
|
||||
case 0x2A:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "cvtsi2ss %Vss Edqp";
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
return "cvtsi2sd %Vsd Edqp";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "cvtpi2pd %Vpd Qpi";
|
||||
} else {
|
||||
return "cvtpi2ps %Vps Qpi";
|
||||
}
|
||||
break;
|
||||
case 0x2C:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "cvttss2si %Gdqp Wss";
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
return "cvttsd2si %Gdqp Wsd";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "cvttpd2pi %Ppi Wpd";
|
||||
} else {
|
||||
return "cvttps2pi %Ppi Wpsq";
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "cvtss2si %Gdqp Wss";
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
return "cvtsd2si %Gdqp Wsd";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "cvtpd2pi %Ppi Wpd";
|
||||
} else {
|
||||
return "cvtps2pi %Ppi Wpsq";
|
||||
}
|
||||
break;
|
||||
case 0x5a:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "cvtss2sd %Vsd Wss";
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
return "cvtsd2ss %Vss Wsd";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "cvtpd2ps %Vps Wpd";
|
||||
} else {
|
||||
return "cvtps2pd %Vpd Wps";
|
||||
}
|
||||
break;
|
||||
case 0x5b:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "cvttps2dq %Vdq Wps";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "cvtps2dq %Vdq Wps";
|
||||
} else {
|
||||
return "cvtdq2ps %Vps Wdq";
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "sqrtss %Vss Wss";
|
||||
} else if (x->op.ild_f2) {
|
||||
} else if (Rep(x->op.rde) == 2) {
|
||||
return "sqrtsd %Vsd Wsd";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "sqrtpd %Vpd Wpd";
|
||||
} else {
|
||||
return "sqrtps %Vps Wps";
|
||||
}
|
||||
break;
|
||||
case 0x6E:
|
||||
if (Osz(x)) {
|
||||
if (Rexw(x)) {
|
||||
if (Osz(x->op.rde)) {
|
||||
if (Rexw(x->op.rde)) {
|
||||
return "movq %Vdq Eqp";
|
||||
} else {
|
||||
return "movd %Vdq Ed";
|
||||
}
|
||||
} else {
|
||||
if (Rexw(x)) {
|
||||
if (Rexw(x->op.rde)) {
|
||||
return "movq %Pq Eqp";
|
||||
} else {
|
||||
return "movd %Pq Ed";
|
||||
|
@ -991,25 +991,25 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0x6F:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "movdqu %Vdq Wdq";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "movdqa %Vdq Wdq";
|
||||
} else {
|
||||
return "movq %Pq Qq";
|
||||
}
|
||||
break;
|
||||
case 0x7E:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "movq %Vq Wq";
|
||||
} else if (Osz(x)) {
|
||||
if (Rexw(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
if (Rexw(x->op.rde)) {
|
||||
return "movq Eqp %Vdq";
|
||||
} else {
|
||||
return "movd Ed %Vdq";
|
||||
}
|
||||
} else {
|
||||
if (Rexw(x)) {
|
||||
if (Rexw(x->op.rde)) {
|
||||
return "movq Eqp %Pq";
|
||||
} else {
|
||||
return "movd Ed %Pq";
|
||||
|
@ -1017,20 +1017,20 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
if (x->op.ild_f3) {
|
||||
if (Rep(x->op.rde) == 3) {
|
||||
return "movdqu Wdq %Vdq";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "movdqa Wdq %Vdq";
|
||||
} else {
|
||||
return "movq Qq %Pq";
|
||||
}
|
||||
break;
|
||||
case 0xE6:
|
||||
if (x->op.ild_f2) {
|
||||
if (Rep(x->op.rde) == 2) {
|
||||
return "cvtpd2dq %Vdq Wpd";
|
||||
} else if (Osz(x)) {
|
||||
} else if (Osz(x->op.rde)) {
|
||||
return "cvttpd2dq %Vdq Wpd";
|
||||
} else if (x->op.ild_f3) {
|
||||
} else if (Rep(x->op.rde) == 3) {
|
||||
return "cvtdq2pd %Vpd Wdq";
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
void OpDivAlAhAxEbSigned(struct Machine *m) {
|
||||
void OpDivAlAhAxEbSigned(struct Machine *m, uint32_t rde) {
|
||||
int8_t y, rem;
|
||||
int16_t x, quo;
|
||||
x = Read16(m->ax);
|
||||
y = Read8(GetModrmRegisterBytePointerRead(m));
|
||||
if (!y || (x == INT16_MIN && y < 0)) ThrowDivideError(m);
|
||||
y = Read8(GetModrmRegisterBytePointerRead(m, rde));
|
||||
if (!y || (x == INT16_MIN && y == -1)) ThrowDivideError(m);
|
||||
quo = x / y;
|
||||
rem = x % y;
|
||||
if (!(INT8_MIN <= quo && quo <= INT8_MAX)) ThrowDivideError(m);
|
||||
|
@ -38,11 +38,11 @@ void OpDivAlAhAxEbSigned(struct Machine *m) {
|
|||
m->ax[1] = rem & 0xff;
|
||||
}
|
||||
|
||||
void OpDivAlAhAxEbUnsigned(struct Machine *m) {
|
||||
void OpDivAlAhAxEbUnsigned(struct Machine *m, uint32_t rde) {
|
||||
uint8_t y, rem;
|
||||
uint16_t x, quo;
|
||||
x = Read16(m->ax);
|
||||
y = Read8(GetModrmRegisterBytePointerRead(m));
|
||||
y = Read8(GetModrmRegisterBytePointerRead(m, rde));
|
||||
if (!y) ThrowDivideError(m);
|
||||
quo = x / y;
|
||||
rem = x % y;
|
||||
|
@ -51,12 +51,13 @@ void OpDivAlAhAxEbUnsigned(struct Machine *m) {
|
|||
m->ax[1] = rem & 0xff;
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpSigned64(struct Machine *m, uint8_t *p) {
|
||||
static void OpDivRdxRaxEvqpSigned64(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
int64_t y, rem;
|
||||
int128_t x, quo;
|
||||
x = (uint128_t)Read64(m->dx) << 64 | Read64(m->ax);
|
||||
y = Read64(p);
|
||||
if (!y || (x == INT128_MIN && y < 0)) ThrowDivideError(m);
|
||||
if (!y || (x == INT128_MIN && y == -1)) ThrowDivideError(m);
|
||||
quo = x / y;
|
||||
rem = x % y;
|
||||
if (!(INT64_MIN <= quo && quo <= INT64_MAX)) ThrowDivideError(m);
|
||||
|
@ -64,12 +65,13 @@ static void OpDivRdxRaxEvqpSigned64(struct Machine *m, uint8_t *p) {
|
|||
Write64(m->dx, rem);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpSigned32(struct Machine *m, uint8_t *p) {
|
||||
static void OpDivRdxRaxEvqpSigned32(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
int32_t y, rem;
|
||||
int64_t x, quo;
|
||||
x = (uint64_t)Read32(m->dx) << 32 | Read32(m->ax);
|
||||
y = Read32(p);
|
||||
if (!y || (x == INT64_MIN && y < 0)) ThrowDivideError(m);
|
||||
if (!y || (x == INT64_MIN && y == -1)) ThrowDivideError(m);
|
||||
quo = x / y;
|
||||
rem = x % y;
|
||||
if (!(INT32_MIN <= quo && quo <= INT32_MAX)) ThrowDivideError(m);
|
||||
|
@ -77,12 +79,13 @@ static void OpDivRdxRaxEvqpSigned32(struct Machine *m, uint8_t *p) {
|
|||
Write64(m->dx, rem & 0xffffffff);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpSigned16(struct Machine *m, uint8_t *p) {
|
||||
static void OpDivRdxRaxEvqpSigned16(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
int16_t y, rem;
|
||||
int32_t x, quo;
|
||||
x = (uint32_t)Read16(m->dx) << 16 | Read16(m->ax);
|
||||
y = Read16(p);
|
||||
if (!y || (x == INT32_MIN && y < 0)) ThrowDivideError(m);
|
||||
if (!y || (x == INT32_MIN && y == -1)) ThrowDivideError(m);
|
||||
quo = x / y;
|
||||
rem = x % y;
|
||||
if (!(INT16_MIN <= quo && quo <= INT16_MAX)) ThrowDivideError(m);
|
||||
|
@ -90,7 +93,8 @@ static void OpDivRdxRaxEvqpSigned16(struct Machine *m, uint8_t *p) {
|
|||
Write16(m->dx, rem);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpUnsigned16(struct Machine *m, uint8_t *p) {
|
||||
static void OpDivRdxRaxEvqpUnsigned16(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
uint16_t y, rem;
|
||||
uint32_t x, quo;
|
||||
x = (uint32_t)Read16(m->dx) << 16 | Read16(m->ax);
|
||||
|
@ -103,7 +107,8 @@ static void OpDivRdxRaxEvqpUnsigned16(struct Machine *m, uint8_t *p) {
|
|||
Write16(m->dx, rem);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpUnsigned32(struct Machine *m, uint8_t *p) {
|
||||
static void OpDivRdxRaxEvqpUnsigned32(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
uint32_t y, rem;
|
||||
uint64_t x, quo;
|
||||
x = (uint64_t)Read32(m->dx) << 32 | Read32(m->ax);
|
||||
|
@ -116,7 +121,8 @@ static void OpDivRdxRaxEvqpUnsigned32(struct Machine *m, uint8_t *p) {
|
|||
Write64(m->dx, rem & 0xffffffff);
|
||||
}
|
||||
|
||||
static void OpDivRdxRaxEvqpUnsigned64(struct Machine *m, uint8_t *p) {
|
||||
static void OpDivRdxRaxEvqpUnsigned64(struct Machine *m, uint32_t rde,
|
||||
uint8_t *p) {
|
||||
uint64_t y, rem;
|
||||
uint128_t x, quo;
|
||||
x = (uint128_t)Read64(m->dx) << 64 | Read64(m->ax);
|
||||
|
@ -129,35 +135,35 @@ static void OpDivRdxRaxEvqpUnsigned64(struct Machine *m, uint8_t *p) {
|
|||
Write64(m->dx, rem);
|
||||
}
|
||||
|
||||
void OpDivRdxRaxEvqpSigned(struct Machine *m) {
|
||||
void OpDivRdxRaxEvqpSigned(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m);
|
||||
if (Rexw(m->xedd)) {
|
||||
OpDivRdxRaxEvqpSigned64(m, p);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
OpDivRdxRaxEvqpSigned32(m, p);
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m, rde);
|
||||
if (Rexw(rde)) {
|
||||
OpDivRdxRaxEvqpSigned64(m, rde, p);
|
||||
} else if (!Osz(rde)) {
|
||||
OpDivRdxRaxEvqpSigned32(m, rde, p);
|
||||
} else {
|
||||
OpDivRdxRaxEvqpSigned16(m, p);
|
||||
OpDivRdxRaxEvqpSigned16(m, rde, p);
|
||||
}
|
||||
}
|
||||
|
||||
void OpDivRdxRaxEvqpUnsigned(struct Machine *m) {
|
||||
void OpDivRdxRaxEvqpUnsigned(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m);
|
||||
if (Rexw(m->xedd)) {
|
||||
OpDivRdxRaxEvqpUnsigned64(m, p);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
OpDivRdxRaxEvqpUnsigned32(m, p);
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m, rde);
|
||||
if (Rexw(rde)) {
|
||||
OpDivRdxRaxEvqpUnsigned64(m, rde, p);
|
||||
} else if (!Osz(rde)) {
|
||||
OpDivRdxRaxEvqpUnsigned32(m, rde, p);
|
||||
} else {
|
||||
OpDivRdxRaxEvqpUnsigned16(m, p);
|
||||
OpDivRdxRaxEvqpUnsigned16(m, rde, p);
|
||||
}
|
||||
}
|
||||
|
||||
void OpMulAxAlEbSigned(struct Machine *m) {
|
||||
void OpMulAxAlEbSigned(struct Machine *m, uint32_t rde) {
|
||||
bool of;
|
||||
int16_t ax;
|
||||
uint8_t *p;
|
||||
p = GetModrmRegisterBytePointerRead(m);
|
||||
p = GetModrmRegisterBytePointerRead(m, rde);
|
||||
__builtin_mul_overflow((int8_t)Read8(m->ax), (int8_t)Read8(p), &ax);
|
||||
of = (int)ax != (int8_t)ax;
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, of);
|
||||
|
@ -165,11 +171,11 @@ void OpMulAxAlEbSigned(struct Machine *m) {
|
|||
Write16(m->ax, ax);
|
||||
}
|
||||
|
||||
void OpMulAxAlEbUnsigned(struct Machine *m) {
|
||||
void OpMulAxAlEbUnsigned(struct Machine *m, uint32_t rde) {
|
||||
int ax;
|
||||
bool of;
|
||||
uint8_t *p;
|
||||
p = GetModrmRegisterBytePointerRead(m);
|
||||
p = GetModrmRegisterBytePointerRead(m, rde);
|
||||
__builtin_mul_overflow(Read8(m->ax), Read8(p), &ax);
|
||||
of = (uint8_t)ax != ax;
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, of);
|
||||
|
@ -177,20 +183,20 @@ void OpMulAxAlEbUnsigned(struct Machine *m) {
|
|||
Write16(m->ax, ax);
|
||||
}
|
||||
|
||||
void OpMulRdxRaxEvqpSigned(struct Machine *m) {
|
||||
void OpMulRdxRaxEvqpSigned(struct Machine *m, uint32_t rde) {
|
||||
bool of;
|
||||
uint8_t *p;
|
||||
int32_t dxax;
|
||||
int64_t edxeax;
|
||||
int128_t rdxrax;
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m);
|
||||
if (Rexw(m->xedd)) {
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m, rde);
|
||||
if (Rexw(rde)) {
|
||||
__builtin_mul_overflow((int128_t)(int64_t)Read64(m->ax), (int64_t)Read64(p),
|
||||
&rdxrax);
|
||||
of = (int128_t)rdxrax != (int64_t)rdxrax;
|
||||
Write64(m->ax, rdxrax);
|
||||
Write64(m->dx, rdxrax >> 64);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
} else if (!Osz(rde)) {
|
||||
__builtin_mul_overflow((int64_t)(int32_t)Read32(m->ax), (int32_t)Read32(p),
|
||||
&edxeax);
|
||||
of = (int64_t)edxeax != (int32_t)edxeax;
|
||||
|
@ -207,19 +213,19 @@ void OpMulRdxRaxEvqpSigned(struct Machine *m) {
|
|||
m->flags = SetFlag(m->flags, FLAGS_OF, of);
|
||||
}
|
||||
|
||||
void OpMulRdxRaxEvqpUnsigned(struct Machine *m) {
|
||||
void OpMulRdxRaxEvqpUnsigned(struct Machine *m, uint32_t rde) {
|
||||
bool of;
|
||||
uint8_t *p;
|
||||
uint32_t dxax;
|
||||
uint64_t edxeax;
|
||||
uint128_t rdxrax;
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m);
|
||||
if (Rexw(m->xedd)) {
|
||||
p = GetModrmRegisterWordPointerReadOszRexw(m, rde);
|
||||
if (Rexw(rde)) {
|
||||
__builtin_mul_overflow((uint128_t)Read64(m->ax), Read64(p), &rdxrax);
|
||||
of = (uint64_t)rdxrax != rdxrax;
|
||||
Write64(m->ax, rdxrax);
|
||||
Write64(m->dx, rdxrax >> 64);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
} else if (!Osz(rde)) {
|
||||
__builtin_mul_overflow((uint64_t)Read32(m->ax), Read32(p), &edxeax);
|
||||
of = (uint32_t)edxeax != edxeax;
|
||||
Write64(m->ax, edxeax);
|
||||
|
@ -235,37 +241,38 @@ void OpMulRdxRaxEvqpUnsigned(struct Machine *m) {
|
|||
m->flags = SetFlag(m->flags, FLAGS_OF, of);
|
||||
}
|
||||
|
||||
static void AluImul(struct Machine *m, uint8_t *a, uint8_t *b) {
|
||||
static void AluImul(struct Machine *m, uint32_t rde, uint8_t *a, uint8_t *b) {
|
||||
unsigned of;
|
||||
if (Rexw(m->xedd)) {
|
||||
if (Rexw(rde)) {
|
||||
int64_t x, y, z;
|
||||
x = Read64(a);
|
||||
y = Read64(b);
|
||||
of = __builtin_mul_overflow(x, y, &z);
|
||||
Write64(RegRexrReg(m), z);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
Write64(RegRexrReg(m, rde), z);
|
||||
} else if (!Osz(rde)) {
|
||||
int32_t x, y, z;
|
||||
x = Read32(a);
|
||||
y = Read32(b);
|
||||
of = __builtin_mul_overflow(x, y, &z);
|
||||
Write64(RegRexrReg(m), z & 0xffffffff);
|
||||
Write64(RegRexrReg(m, rde), z & 0xffffffff);
|
||||
} else {
|
||||
int16_t x, y, z;
|
||||
x = Read16(a);
|
||||
y = Read16(b);
|
||||
of = __builtin_mul_overflow(x, y, &z);
|
||||
Write16(RegRexrReg(m), z);
|
||||
Write16(RegRexrReg(m, rde), z);
|
||||
}
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, of);
|
||||
m->flags = SetFlag(m->flags, FLAGS_OF, of);
|
||||
}
|
||||
|
||||
void OpImulGvqpEvqp(struct Machine *m) {
|
||||
AluImul(m, RegRexrReg(m), GetModrmRegisterWordPointerReadOszRexw(m));
|
||||
void OpImulGvqpEvqp(struct Machine *m, uint32_t rde) {
|
||||
AluImul(m, rde, RegRexrReg(m, rde),
|
||||
GetModrmRegisterWordPointerReadOszRexw(m, rde));
|
||||
}
|
||||
|
||||
void OpImulGvqpEvqpImm(struct Machine *m) {
|
||||
void OpImulGvqpEvqpImm(struct Machine *m, uint32_t rde) {
|
||||
uint8_t b[8];
|
||||
Write64(b, m->xedd->op.uimm0);
|
||||
AluImul(m, GetModrmRegisterWordPointerReadOszRexw(m), b);
|
||||
AluImul(m, rde, GetModrmRegisterWordPointerReadOszRexw(m, rde), b);
|
||||
}
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void OpDivAlAhAxEbSigned(struct Machine *);
|
||||
void OpDivAlAhAxEbUnsigned(struct Machine *);
|
||||
void OpDivRdxRaxEvqpSigned(struct Machine *);
|
||||
void OpDivRdxRaxEvqpUnsigned(struct Machine *);
|
||||
void OpImulGvqpEvqp(struct Machine *);
|
||||
void OpImulGvqpEvqpImm(struct Machine *);
|
||||
void OpMulAxAlEbSigned(struct Machine *);
|
||||
void OpMulAxAlEbUnsigned(struct Machine *);
|
||||
void OpMulRdxRaxEvqpSigned(struct Machine *);
|
||||
void OpMulRdxRaxEvqpUnsigned(struct Machine *);
|
||||
void OpDivAlAhAxEbSigned(struct Machine *, uint32_t);
|
||||
void OpDivAlAhAxEbUnsigned(struct Machine *, uint32_t);
|
||||
void OpDivRdxRaxEvqpSigned(struct Machine *, uint32_t);
|
||||
void OpDivRdxRaxEvqpUnsigned(struct Machine *, uint32_t);
|
||||
void OpImulGvqpEvqp(struct Machine *, uint32_t);
|
||||
void OpImulGvqpEvqpImm(struct Machine *, uint32_t);
|
||||
void OpMulAxAlEbSigned(struct Machine *, uint32_t);
|
||||
void OpMulAxAlEbUnsigned(struct Machine *, uint32_t);
|
||||
void OpMulRdxRaxEvqpSigned(struct Machine *, uint32_t);
|
||||
void OpMulRdxRaxEvqpUnsigned(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
55
tool/build/lib/fds.c
Normal file
55
tool/build/lib/fds.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/fds.h"
|
||||
|
||||
int MachineFdAdd(struct MachineFds *mf) {
|
||||
int fd;
|
||||
struct MachineFdClosed *closed;
|
||||
if ((closed = mf->closed)) {
|
||||
DCHECK_LT(closed->fd, mf->i);
|
||||
fd = closed->fd;
|
||||
mf->closed = closed->next;
|
||||
free(closed);
|
||||
} else {
|
||||
DCHECK_LE(mf->i, mf->n);
|
||||
if (mf->i == mf->n) {
|
||||
if (!grow(&mf->p, &mf->n, sizeof(struct MachineFd), 0)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
fd = mf->i++;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void MachineFdRemove(struct MachineFds *mf, int fd) {
|
||||
struct MachineFdClosed *closed;
|
||||
DCHECK_GE(fd, 0);
|
||||
DCHECK_LT(fd, mf->i);
|
||||
mf->p[fd].cb = NULL;
|
||||
if ((closed = malloc(sizeof(struct MachineFdClosed)))) {
|
||||
closed->fd = fd;
|
||||
closed->next = mf->closed;
|
||||
mf->closed = closed;
|
||||
}
|
||||
}
|
27
tool/build/lib/fds.h
Normal file
27
tool/build/lib/fds.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct MachineFds {
|
||||
size_t i, n;
|
||||
struct MachineFd {
|
||||
int fd;
|
||||
struct MachineFdCb {
|
||||
int (*close)(int);
|
||||
ssize_t (*read)(int, void *, size_t);
|
||||
ssize_t (*write)(int, const void *, size_t);
|
||||
} * cb;
|
||||
} * p;
|
||||
struct MachineFdClosed {
|
||||
unsigned fd;
|
||||
struct MachineFdClosed *next;
|
||||
} * closed;
|
||||
};
|
||||
|
||||
int MachineFdAdd(struct MachineFds *);
|
||||
void MachineFdRemove(struct MachineFds *, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_ */
|
|
@ -50,26 +50,6 @@ static long double OnFpuStackUnderflow(struct Machine *m) {
|
|||
return -NAN;
|
||||
}
|
||||
|
||||
void FpuPush(struct Machine *m, long double x) {
|
||||
if (FpuGetTag(m, -1) != kFpuTagEmpty) OnFpuStackOverflow(m);
|
||||
m->fpu.sp -= 1;
|
||||
*FpuSt(m, 0) = x;
|
||||
FpuSetTag(m, 0, kFpuTagValid);
|
||||
}
|
||||
|
||||
long double FpuPop(struct Machine *m) {
|
||||
long double x;
|
||||
if (FpuGetTag(m, 0) != kFpuTagEmpty) {
|
||||
x = *FpuSt(m, 0);
|
||||
FpuSetTag(m, 0, kFpuTagEmpty);
|
||||
/* *FpuSt(m, 0) = -NAN; */
|
||||
} else {
|
||||
x = OnFpuStackUnderflow(m);
|
||||
}
|
||||
m->fpu.sp += 1;
|
||||
return x;
|
||||
}
|
||||
|
||||
static long double St(struct Machine *m, int i) {
|
||||
if (FpuGetTag(m, i) == kFpuTagEmpty) OnFpuStackUnderflow(m);
|
||||
return *FpuSt(m, i);
|
||||
|
@ -84,7 +64,7 @@ static long double St1(struct Machine *m) {
|
|||
}
|
||||
|
||||
static long double StRm(struct Machine *m) {
|
||||
return St(m, ModrmRm(m->xedd));
|
||||
return St(m, ModrmRm(m->xedd->op.rde));
|
||||
}
|
||||
|
||||
static void FpuClearRoundup(struct Machine *m) {
|
||||
|
@ -100,7 +80,7 @@ static void FpuSetSt0(struct Machine *m, long double x) {
|
|||
}
|
||||
|
||||
static void FpuSetStRm(struct Machine *m, long double x) {
|
||||
*FpuSt(m, ModrmRm(m->xedd)) = x;
|
||||
*FpuSt(m, ModrmRm(m->xedd->op.rde)) = x;
|
||||
}
|
||||
|
||||
static void FpuSetStPop(struct Machine *m, int i, long double x) {
|
||||
|
@ -109,7 +89,7 @@ static void FpuSetStPop(struct Machine *m, int i, long double x) {
|
|||
}
|
||||
|
||||
static void FpuSetStRmPop(struct Machine *m, long double x) {
|
||||
FpuSetStPop(m, ModrmRm(m->xedd), x);
|
||||
FpuSetStPop(m, ModrmRm(m->xedd->op.rde), x);
|
||||
}
|
||||
|
||||
static int16_t GetMemoryShort(struct Machine *m) {
|
||||
|
@ -414,11 +394,11 @@ static void OpFmulEstSt(struct Machine *m) {
|
|||
}
|
||||
|
||||
static void OpFsubEstSt(struct Machine *m) {
|
||||
FpuSetStRm(m, StRm(m) - St0(m));
|
||||
FpuSetStRm(m, St0(m) - StRm(m));
|
||||
}
|
||||
|
||||
static void OpFsubrEstSt(struct Machine *m) {
|
||||
FpuSetStRm(m, St0(m) - StRm(m));
|
||||
FpuSetStRm(m, StRm(m) - St0(m));
|
||||
}
|
||||
|
||||
static void OpFdivEstSt(struct Machine *m) {
|
||||
|
@ -666,8 +646,7 @@ static void OpFstp(struct Machine *m) {
|
|||
}
|
||||
|
||||
static void OpFxch(struct Machine *m) {
|
||||
long double t;
|
||||
t = StRm(m);
|
||||
long double t = StRm(m);
|
||||
FpuSetStRm(m, St0(m));
|
||||
FpuSetSt0(m, t);
|
||||
}
|
||||
|
@ -686,7 +665,7 @@ static void OpFldl(struct Machine *m) {
|
|||
|
||||
static void OpFldConstant(struct Machine *m) {
|
||||
long double x;
|
||||
switch (ModrmRm(m->xedd)) {
|
||||
switch (ModrmRm(m->xedd->op.rde)) {
|
||||
case 0:
|
||||
x = fld1();
|
||||
break;
|
||||
|
@ -769,7 +748,7 @@ static void OpFistps(struct Machine *m) {
|
|||
FpuPop(m);
|
||||
}
|
||||
|
||||
void OpFcomi(struct Machine *m) {
|
||||
static void OpFcomi(struct Machine *m) {
|
||||
long double x, y;
|
||||
x = St0(m);
|
||||
y = StRm(m);
|
||||
|
@ -808,7 +787,7 @@ static void OpFucomip(struct Machine *m) {
|
|||
}
|
||||
|
||||
static void OpFfree(struct Machine *m) {
|
||||
FpuSetTag(m, ModrmRm(m->xedd), kFpuTagEmpty);
|
||||
FpuSetTag(m, ModrmRm(m->xedd->op.rde), kFpuTagEmpty);
|
||||
}
|
||||
|
||||
static void OpFfreep(struct Machine *m) {
|
||||
|
@ -890,6 +869,10 @@ static void OpFnclex(struct Machine *m) {
|
|||
m->fpu.bf = false;
|
||||
}
|
||||
|
||||
static void OpFnop(struct Machine *m) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
void OpFinit(struct Machine *m) {
|
||||
m->fpu.cw = X87_NORMAL;
|
||||
m->fpu.sw = 0;
|
||||
|
@ -905,18 +888,59 @@ void OpFwait(struct Machine *m) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OpFnop(struct Machine *m) {
|
||||
/* do nothing */
|
||||
long double *FpuSt(struct Machine *m, unsigned i) {
|
||||
i += m->fpu.sp;
|
||||
i &= 0b111;
|
||||
return m->fpu.st + i;
|
||||
}
|
||||
|
||||
int FpuGetTag(struct Machine *m, unsigned i) {
|
||||
unsigned t;
|
||||
t = m->fpu.tw;
|
||||
i += m->fpu.sp;
|
||||
i &= 0b111;
|
||||
i *= 2;
|
||||
t &= 0b11 << i;
|
||||
t >>= i;
|
||||
return t;
|
||||
}
|
||||
|
||||
void FpuSetTag(struct Machine *m, unsigned i, unsigned t) {
|
||||
i += m->fpu.sp;
|
||||
t &= 0b11;
|
||||
i &= 0b111;
|
||||
i *= 2;
|
||||
m->fpu.tw &= ~(0b11 << i);
|
||||
m->fpu.tw |= t << i;
|
||||
}
|
||||
|
||||
void FpuPush(struct Machine *m, long double x) {
|
||||
if (FpuGetTag(m, -1) != kFpuTagEmpty) OnFpuStackOverflow(m);
|
||||
m->fpu.sp -= 1;
|
||||
*FpuSt(m, 0) = x;
|
||||
FpuSetTag(m, 0, kFpuTagValid);
|
||||
}
|
||||
|
||||
long double FpuPop(struct Machine *m) {
|
||||
long double x;
|
||||
if (FpuGetTag(m, 0) != kFpuTagEmpty) {
|
||||
x = *FpuSt(m, 0);
|
||||
FpuSetTag(m, 0, kFpuTagEmpty);
|
||||
} else {
|
||||
x = OnFpuStackUnderflow(m);
|
||||
}
|
||||
m->fpu.sp += 1;
|
||||
return x;
|
||||
}
|
||||
|
||||
void OpFpu(struct Machine *m) {
|
||||
unsigned op;
|
||||
bool ismemory;
|
||||
op = m->xedd->op.opcode & 0b111;
|
||||
ismemory = ModrmMod(m->xedd) != 0b11;
|
||||
ismemory = ModrmMod(m->xedd->op.rde) != 0b11;
|
||||
m->fpu.ip = m->ip - m->xedd->length;
|
||||
m->fpu.op = op << 8 | m->xedd->op.modrm;
|
||||
m->fpu.dp = ismemory ? ComputeAddress(m) : 0;
|
||||
m->fpu.dp = ismemory ? ComputeAddress(m, m->xedd->op.rde) : 0;
|
||||
switch (DISP(op, ismemory, m->xedd->op.reg)) {
|
||||
CASE(DISP(0xD8, FPUREG, 0), OpFaddStEst(m));
|
||||
CASE(DISP(0xD8, FPUREG, 1), OpFmulStEst(m));
|
||||
|
@ -1029,7 +1053,7 @@ void OpFpu(struct Machine *m) {
|
|||
CASE(DISP(0xDf, MEMORY, 5), OpFildll(m));
|
||||
CASE(DISP(0xDf, MEMORY, 7), OpFistpll(m));
|
||||
case DISP(0xD9, FPUREG, 4):
|
||||
switch (ModrmRm(m->xedd)) {
|
||||
switch (ModrmRm(m->xedd->op.rde)) {
|
||||
CASE(0, OpFchs(m));
|
||||
CASE(1, OpFabs(m));
|
||||
CASE(4, OpFtst(m));
|
||||
|
@ -1039,7 +1063,7 @@ void OpFpu(struct Machine *m) {
|
|||
}
|
||||
break;
|
||||
case DISP(0xD9, FPUREG, 6):
|
||||
switch (ModrmRm(m->xedd)) {
|
||||
switch (ModrmRm(m->xedd->op.rde)) {
|
||||
CASE(0, OpF2xm1(m));
|
||||
CASE(1, OpFyl2x(m));
|
||||
CASE(2, OpFptan(m));
|
||||
|
@ -1053,7 +1077,7 @@ void OpFpu(struct Machine *m) {
|
|||
}
|
||||
break;
|
||||
case DISP(0xD9, FPUREG, 7):
|
||||
switch (ModrmRm(m->xedd)) {
|
||||
switch (ModrmRm(m->xedd->op.rde)) {
|
||||
CASE(0, OpFprem(m));
|
||||
CASE(1, OpFyl2xp1(m));
|
||||
CASE(2, OpFsqrt(m));
|
||||
|
@ -1067,7 +1091,7 @@ void OpFpu(struct Machine *m) {
|
|||
}
|
||||
break;
|
||||
case DISP(0xDb, FPUREG, 4):
|
||||
switch (ModrmRm(m->xedd)) {
|
||||
switch (ModrmRm(m->xedd->op.rde)) {
|
||||
CASE(2, OpFnclex(m));
|
||||
CASE(3, OpFinit(m));
|
||||
default:
|
||||
|
|
|
@ -15,32 +15,9 @@ void OpFinit(struct Machine *);
|
|||
void OpFwait(struct Machine *);
|
||||
void FpuPush(struct Machine *, long double);
|
||||
long double FpuPop(struct Machine *);
|
||||
|
||||
forceinline long double *FpuSt(struct Machine *m, unsigned i) {
|
||||
i += m->fpu.sp;
|
||||
i &= 0b111;
|
||||
return m->fpu.st + i;
|
||||
}
|
||||
|
||||
forceinline int FpuGetTag(struct Machine *m, unsigned i) {
|
||||
unsigned t;
|
||||
t = m->fpu.tw;
|
||||
i += m->fpu.sp;
|
||||
i &= 0b111;
|
||||
i *= 2;
|
||||
t &= 0b11 << i;
|
||||
t >>= i;
|
||||
return t;
|
||||
}
|
||||
|
||||
forceinline void FpuSetTag(struct Machine *m, unsigned i, unsigned t) {
|
||||
i += m->fpu.sp;
|
||||
t &= 0b11;
|
||||
i &= 0b111;
|
||||
i *= 2;
|
||||
m->fpu.tw &= ~(0b11 << i);
|
||||
m->fpu.tw |= t << i;
|
||||
}
|
||||
long double *FpuSt(struct Machine *, unsigned);
|
||||
int FpuGetTag(struct Machine *, unsigned);
|
||||
void FpuSetTag(struct Machine *, unsigned, unsigned);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -17,13 +17,34 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "tool/build/lib/ioports.h"
|
||||
|
||||
static int OpE9Read(struct Machine *m) {
|
||||
int fd;
|
||||
uint8_t b;
|
||||
fd = STDIN_FILENO;
|
||||
if (fd >= m->fds.i) return -1;
|
||||
if (!m->fds.p[fd].cb) return -1;
|
||||
if (m->fds.p[fd].cb->read(m->fds.p[fd].fd, &b, 1) == 1) {
|
||||
return b;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void OpE9Write(struct Machine *m, uint8_t b) {
|
||||
int fd;
|
||||
fd = STDOUT_FILENO;
|
||||
if (fd >= m->fds.i) return;
|
||||
if (!m->fds.p[fd].cb) return;
|
||||
m->fds.p[fd].cb->write(m->fds.p[fd].fd, &b, 1);
|
||||
}
|
||||
|
||||
uint64_t OpIn(struct Machine *m, uint16_t p) {
|
||||
switch (p) {
|
||||
case 0xE9:
|
||||
return getc(stdin);
|
||||
return OpE9Read(m);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -32,9 +53,7 @@ uint64_t OpIn(struct Machine *m, uint16_t p) {
|
|||
void OpOut(struct Machine *m, uint16_t p, uint32_t x) {
|
||||
switch (p) {
|
||||
case 0xE9:
|
||||
do {
|
||||
putc(x, stdout);
|
||||
} while (x >> 8);
|
||||
OpE9Write(m, x);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,6 +3,7 @@
|
|||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/fds.h"
|
||||
#include "tool/build/lib/pml4t.h"
|
||||
|
||||
#define kXmmIntegral 0
|
||||
|
@ -136,6 +137,7 @@ struct Machine {
|
|||
uint8_t stash[4096];
|
||||
uint8_t xmmtype[2][8];
|
||||
struct XedDecodedInst icache[512];
|
||||
struct MachineFds fds;
|
||||
};
|
||||
|
||||
void ResetCpu(struct Machine *);
|
||||
|
|
|
@ -26,207 +26,223 @@
|
|||
/**
|
||||
* Computes virtual address based on modrm and sib bytes.
|
||||
*/
|
||||
int64_t ComputeAddress(const struct Machine *m) {
|
||||
int64_t ComputeAddress(const struct Machine *m, uint32_t rde) {
|
||||
uint64_t i;
|
||||
DCHECK(m->xedd->op.has_modrm);
|
||||
DCHECK(!IsModrmRegister(m->xedd));
|
||||
DCHECK(!IsModrmRegister(rde));
|
||||
i = m->xedd->op.disp;
|
||||
if (!SibExists(m->xedd)) {
|
||||
i += IsRipRelative(m->xedd) ? m->ip : Read64(RegRexbRm(m));
|
||||
if (!SibExists(rde)) {
|
||||
if (IsRipRelative(rde)) {
|
||||
i += m->ip;
|
||||
} else {
|
||||
i += Read64(RegRexbRm(m, rde));
|
||||
}
|
||||
} else {
|
||||
DCHECK(m->xedd->op.has_sib);
|
||||
if (SibHasBase(m->xedd)) i += Read64(RegRexbBase(m));
|
||||
if (SibHasIndex(m->xedd)) i += Read64(RegRexxIndex(m)) << m->xedd->op.scale;
|
||||
if (SibHasBase(rde)) {
|
||||
i += Read64(RegRexbBase(m, rde));
|
||||
}
|
||||
if (SibHasIndex(rde)) {
|
||||
i += Read64(RegRexxIndex(m, rde)) << m->xedd->op.scale;
|
||||
}
|
||||
}
|
||||
i += GetSegment(m);
|
||||
if (Asz(m->xedd)) i &= 0xffffffff;
|
||||
if (Asz(rde)) i &= 0xffffffff;
|
||||
return i;
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressRead(struct Machine *m, size_t n) {
|
||||
void *ComputeReserveAddressRead(struct Machine *m, uint32_t rde, size_t n) {
|
||||
int64_t v;
|
||||
v = ComputeAddress(m);
|
||||
v = ComputeAddress(m, rde);
|
||||
SetReadAddr(m, v, n);
|
||||
return ReserveAddress(m, v, n);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressRead1(struct Machine *m) {
|
||||
return ComputeReserveAddressRead(m, 1);
|
||||
void *ComputeReserveAddressRead1(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressRead(m, rde, 1);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressRead8(struct Machine *m) {
|
||||
return ComputeReserveAddressRead(m, 8);
|
||||
void *ComputeReserveAddressRead8(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressRead(m, rde, 8);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressWrite(struct Machine *m, size_t n) {
|
||||
void *ComputeReserveAddressWrite(struct Machine *m, uint32_t rde, size_t n) {
|
||||
int64_t v;
|
||||
v = ComputeAddress(m);
|
||||
v = ComputeAddress(m, rde);
|
||||
SetWriteAddr(m, v, n);
|
||||
return ReserveAddress(m, v, n);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressWrite1(struct Machine *m) {
|
||||
return ComputeReserveAddressWrite(m, 1);
|
||||
void *ComputeReserveAddressWrite1(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressWrite(m, rde, 1);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressWrite4(struct Machine *m) {
|
||||
return ComputeReserveAddressWrite(m, 4);
|
||||
void *ComputeReserveAddressWrite4(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressWrite(m, rde, 4);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressWrite8(struct Machine *m) {
|
||||
return ComputeReserveAddressWrite(m, 8);
|
||||
void *ComputeReserveAddressWrite8(struct Machine *m, uint32_t rde) {
|
||||
return ComputeReserveAddressWrite(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *m, size_t n) {
|
||||
if (IsModrmRegister(m->xedd)) {
|
||||
return MmRm(m);
|
||||
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return MmRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressRead(m, n);
|
||||
return ComputeReserveAddressRead(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterMmPointerRead8(struct Machine *m) {
|
||||
return GetModrmRegisterMmPointerRead(m, 8);
|
||||
uint8_t *GetModrmRegisterMmPointerRead8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterMmPointerRead(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterMmPointerWrite(struct Machine *m, size_t n) {
|
||||
if (IsModrmRegister(m->xedd)) {
|
||||
return MmRm(m);
|
||||
uint8_t *GetModrmRegisterMmPointerWrite(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return MmRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressWrite(m, n);
|
||||
return ComputeReserveAddressWrite(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterMmPointerWrite8(struct Machine *m) {
|
||||
return GetModrmRegisterMmPointerWrite(m, 8);
|
||||
uint8_t *GetModrmRegisterMmPointerWrite8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterMmPointerWrite(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *m) {
|
||||
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *m, uint32_t rde) {
|
||||
int64_t v;
|
||||
if (IsModrmRegister(m->xedd)) {
|
||||
return ByteRexbRm(m);
|
||||
if (IsModrmRegister(rde)) {
|
||||
return ByteRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressRead1(m);
|
||||
return ComputeReserveAddressRead1(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *m) {
|
||||
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *m, uint32_t rde) {
|
||||
int64_t v;
|
||||
if (IsModrmRegister(m->xedd)) {
|
||||
return ByteRexbRm(m);
|
||||
if (IsModrmRegister(rde)) {
|
||||
return ByteRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressWrite1(m);
|
||||
return ComputeReserveAddressWrite1(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerRead(struct Machine *m, size_t n) {
|
||||
if (IsModrmRegister(m->xedd)) {
|
||||
return RegRexbRm(m);
|
||||
uint8_t *GetModrmRegisterWordPointerRead(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return RegRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressRead(m, n);
|
||||
return ComputeReserveAddressRead(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerRead2(struct Machine *m) {
|
||||
return GetModrmRegisterWordPointerRead(m, 2);
|
||||
uint8_t *GetModrmRegisterWordPointerRead2(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerRead(m, rde, 2);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerRead4(struct Machine *m) {
|
||||
return GetModrmRegisterWordPointerRead(m, 4);
|
||||
uint8_t *GetModrmRegisterWordPointerRead4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerRead(m, rde, 4);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *m) {
|
||||
return GetModrmRegisterWordPointerRead(m, 8);
|
||||
uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerRead(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *m) {
|
||||
if (!Osz(m->xedd)) {
|
||||
return GetModrmRegisterWordPointerRead8(m);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *m, uint32_t rde) {
|
||||
if (!Osz(rde)) {
|
||||
return GetModrmRegisterWordPointerRead8(m, rde);
|
||||
} else {
|
||||
return GetModrmRegisterWordPointerRead2(m);
|
||||
return GetModrmRegisterWordPointerRead2(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *m) {
|
||||
if (Rexw(m->xedd)) {
|
||||
return GetModrmRegisterWordPointerRead8(m);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
return GetModrmRegisterWordPointerRead4(m);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *m,
|
||||
uint32_t rde) {
|
||||
if (Rexw(rde)) {
|
||||
return GetModrmRegisterWordPointerRead8(m, rde);
|
||||
} else if (!Osz(rde)) {
|
||||
return GetModrmRegisterWordPointerRead4(m, rde);
|
||||
} else {
|
||||
return GetModrmRegisterWordPointerRead2(m);
|
||||
return GetModrmRegisterWordPointerRead2(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *m, size_t n) {
|
||||
if (IsModrmRegister(m->xedd)) {
|
||||
return RegRexbRm(m);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return RegRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressWrite(m, n);
|
||||
return ComputeReserveAddressWrite(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *m) {
|
||||
return GetModrmRegisterWordPointerWrite(m, 4);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 4);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *m) {
|
||||
return GetModrmRegisterWordPointerWrite(m, 8);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOszRexw(struct Machine *m) {
|
||||
if (Rexw(m->xedd)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, 8);
|
||||
} else if (!Osz(m->xedd)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, 4);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOszRexw(struct Machine *m,
|
||||
uint32_t rde) {
|
||||
if (Rexw(rde)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 8);
|
||||
} else if (!Osz(rde)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 4);
|
||||
} else {
|
||||
return GetModrmRegisterWordPointerWrite(m, 2);
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 2);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *m) {
|
||||
if (!Osz(m->xedd)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, 8);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *m, uint32_t rde) {
|
||||
if (!Osz(rde)) {
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 8);
|
||||
} else {
|
||||
return GetModrmRegisterWordPointerWrite(m, 2);
|
||||
return GetModrmRegisterWordPointerWrite(m, rde, 2);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerRead(struct Machine *m, size_t n) {
|
||||
if (IsModrmRegister(m->xedd)) {
|
||||
return XmmRexbRm(m);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return XmmRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressRead(m, n);
|
||||
return ComputeReserveAddressRead(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerRead4(struct Machine *m) {
|
||||
return GetModrmRegisterXmmPointerRead(m, 4);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerRead(m, rde, 4);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerRead8(struct Machine *m) {
|
||||
return GetModrmRegisterXmmPointerRead(m, 8);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerRead(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerRead16(struct Machine *m) {
|
||||
return GetModrmRegisterXmmPointerRead(m, 16);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead16(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerRead(m, rde, 16);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite(struct Machine *m, size_t n) {
|
||||
if (IsModrmRegister(m->xedd)) {
|
||||
return XmmRexbRm(m);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite(struct Machine *m, uint32_t rde,
|
||||
size_t n) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return XmmRexbRm(m, rde);
|
||||
} else {
|
||||
return ComputeReserveAddressWrite(m, n);
|
||||
return ComputeReserveAddressWrite(m, rde, n);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite4(struct Machine *m) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, 4);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite4(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, rde, 4);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite8(struct Machine *m) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, 8);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite8(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, rde, 8);
|
||||
}
|
||||
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite16(struct Machine *m) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, 16);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite16(struct Machine *m, uint32_t rde) {
|
||||
return GetModrmRegisterXmmPointerWrite(m, rde, 16);
|
||||
}
|
||||
|
|
|
@ -2,80 +2,80 @@
|
|||
#define COSMOPOLITAN_TOOL_BUILD_LIB_MODRM_H_
|
||||
#include "tool/build/lib/abp.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define SibBase(x) ((x & 000007000000) >> 022)
|
||||
#define SibIndex(x) ((x & 000700000000) >> 030)
|
||||
#define ModrmRm(x) ((x & 000000000700) >> 006)
|
||||
#define ModrmReg(x) ((x & 000000000007) >> 000)
|
||||
#define ModrmSrm(x) ((x & 000000070000) >> 014)
|
||||
#define ModrmMod(x) ((x & 000060000000) >> 026)
|
||||
#define RegLog2(x) ((x & 006000000000) >> 034)
|
||||
#define Rexx(x) ((x & 001000000000) >> 033)
|
||||
#define Asz(x) ((x & 000000400000) >> 021)
|
||||
#define Rexw(x) ((x & 000000004000) >> 013)
|
||||
#define Rexr(x) ((x & 000000000010) >> 003)
|
||||
#define Rexb(x) ((x & 000010000000) >> 025)
|
||||
#define Rex(x) ((x & 000000000020) >> 004)
|
||||
#define Osz(x) ((x & 000000000040) >> 005)
|
||||
#define Rep(x) ((x & 030000000000) >> 036)
|
||||
|
||||
#define IsModrmRegister(x) (ModrmMod(x) == 3)
|
||||
#define IsProbablyByteOp(x) !((x)->op.opcode & 1)
|
||||
#define SibExists(x) (ModrmRm(x) == 4)
|
||||
#define SibHasIndex(x) (SibIndex(x) != 4 || Rexx(x))
|
||||
#define SibHasBase(x) (SibBase(x) != 5 || ModrmMod(x))
|
||||
#define SibIsAbsolute(x) (!SibHasBase(x) && !SibHasIndex(x))
|
||||
#define IsRipRelative(x) (ModrmRm(x) == 5 && !ModrmMod(x))
|
||||
#define SibBase(x) (((x)->op.rde & 000007000000) >> 18)
|
||||
#define SibIndex(x) (((x)->op.rde & 000700000000) >> 24)
|
||||
#define ModrmRm(x) (((x)->op.rde & 000000000700) >> 6)
|
||||
#define ModrmReg(x) (((x)->op.rde & 000000000007) >> 0)
|
||||
#define ModrmSrm(x) (((x)->op.rde & 000000070000) >> 12)
|
||||
#define ModrmMod(x) (((x)->op.rde & 000060000000) >> 22)
|
||||
#define RegLog2(x) (((x)->op.rde & 006000000000) >> 28)
|
||||
#define Rexx(x) (((x)->op.rde & 001000000000) >> 27)
|
||||
#define Asz(x) (((x)->op.rde & 000000400000) >> 17)
|
||||
#define Rexw(x) (((x)->op.rde & 000000004000) >> 11)
|
||||
#define Rexr(x) (((x)->op.rde & 000000000010) >> 3)
|
||||
#define Rexb(x) (((x)->op.rde & 000010000000) >> 21)
|
||||
#define Rex(x) (((x)->op.rde & 000000000020) >> 4)
|
||||
#define Osz(x) (((x)->op.rde & 000000000040) >> 5)
|
||||
#define Rep(x) (((x)->op.rde & 030000000000) >> 30)
|
||||
#define ByteRexrReg(m) m->beg[(m->xedd->op.rde & 00000000037) >> 0]
|
||||
#define ByteRexbRm(m) m->beg[(m->xedd->op.rde & 00000003700) >> 6]
|
||||
#define ByteRexbSrm(m) m->beg[(m->xedd->op.rde & 00000370000) >> 12]
|
||||
#define RegRexrReg(m) Abp8(m->reg[(m->xedd->op.rde & 00000000017) >> 0])
|
||||
#define RegRexbRm(m) Abp8(m->reg[(m->xedd->op.rde & 00000001700) >> 6])
|
||||
#define RegRexbSrm(m) Abp8(m->reg[(m->xedd->op.rde & 00000170000) >> 12])
|
||||
#define RegRexbBase(m) Abp8(m->reg[(m->xedd->op.rde & 00017000000) >> 18])
|
||||
#define RegRexxIndex(m) Abp8(m->reg[(m->xedd->op.rde & 01700000000) >> 24])
|
||||
#define XmmRexrReg(m) Abp16(m->veg[(m->xedd->op.rde & 00000000017) >> 0])
|
||||
#define XmmRexbRm(m) Abp16(m->veg[(m->xedd->op.rde & 00000001700) >> 6])
|
||||
#define MmReg(m) Abp16(m->veg[(m->xedd->op.rde & 00000000007) >> 0])
|
||||
#define MmRm(m) Abp16(m->veg[(m->xedd->op.rde & 00000000700) >> 6])
|
||||
|
||||
int64_t ComputeAddress(const struct Machine *) nosideeffect;
|
||||
#define ByteRexrReg(m, x) m->beg[(x & 00000000037) >> 0]
|
||||
#define ByteRexbRm(m, x) m->beg[(x & 00000003700) >> 6]
|
||||
#define ByteRexbSrm(m, x) m->beg[(x & 00000370000) >> 12]
|
||||
#define RegRexbSrm(m, x) Abp8(m->reg[(x & 00000170000) >> 12])
|
||||
#define RegRexrReg(m, x) Abp8(m->reg[(x & 00000000017) >> 0])
|
||||
#define RegRexbRm(m, x) Abp8(m->reg[(x & 00000001700) >> 6])
|
||||
#define RegRexbBase(m, x) Abp8(m->reg[(x & 00017000000) >> 18])
|
||||
#define RegRexxIndex(m, x) Abp8(m->reg[(x & 01700000000) >> 24])
|
||||
#define XmmRexrReg(m, x) Abp16(m->veg[(x & 00000000017) >> 0])
|
||||
#define XmmRexbRm(m, x) Abp16(m->veg[(x & 00000001700) >> 6])
|
||||
#define MmReg(m, x) Abp16(m->veg[(x & 00000000007) >> 0])
|
||||
#define MmRm(m, x) Abp16(m->veg[(x & 00000000700) >> 6])
|
||||
|
||||
void *ComputeReserveAddressRead(struct Machine *, size_t);
|
||||
void *ComputeReserveAddressRead1(struct Machine *);
|
||||
void *ComputeReserveAddressRead8(struct Machine *);
|
||||
void *ComputeReserveAddressWrite(struct Machine *, size_t);
|
||||
void *ComputeReserveAddressWrite1(struct Machine *);
|
||||
void *ComputeReserveAddressWrite4(struct Machine *);
|
||||
void *ComputeReserveAddressWrite8(struct Machine *);
|
||||
int64_t ComputeAddress(const struct Machine *, uint32_t) nosideeffect;
|
||||
|
||||
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *);
|
||||
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *);
|
||||
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *, size_t);
|
||||
uint8_t *GetModrmRegisterMmPointerRead8(struct Machine *);
|
||||
uint8_t *GetModrmRegisterMmPointerWrite(struct Machine *, size_t);
|
||||
uint8_t *GetModrmRegisterMmPointerWrite8(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerRead(struct Machine *, size_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead2(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerRead4(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *, size_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOszRexw(struct Machine *);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead(struct Machine *, size_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead16(struct Machine *);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead4(struct Machine *);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead8(struct Machine *);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite(struct Machine *, size_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite16(struct Machine *);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite4(struct Machine *);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite8(struct Machine *);
|
||||
void *ComputeReserveAddressRead(struct Machine *, uint32_t, size_t);
|
||||
void *ComputeReserveAddressRead1(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressRead8(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressWrite(struct Machine *, uint32_t, size_t);
|
||||
void *ComputeReserveAddressWrite1(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressWrite4(struct Machine *, uint32_t);
|
||||
void *ComputeReserveAddressWrite8(struct Machine *, uint32_t);
|
||||
|
||||
uint8_t *GetModrmRegisterBytePointerRead(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterMmPointerRead(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterMmPointerRead8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterMmPointerWrite(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterMmPointerWrite8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead2(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterWordPointerWriteOszRexw(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead16(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerRead8(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite(struct Machine *, uint32_t, size_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite16(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite4(struct Machine *, uint32_t);
|
||||
uint8_t *GetModrmRegisterXmmPointerWrite8(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
512
tool/build/lib/pty.c
Normal file
512
tool/build/lib/pty.c
Normal file
|
@ -0,0 +1,512 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/pty.h"
|
||||
|
||||
struct MachinePty *MachinePtyNew(unsigned yn, unsigned xn) {
|
||||
struct MachinePty *pty;
|
||||
DCHECK_GT(yn, 0);
|
||||
DCHECK_GT(xn, 0);
|
||||
pty = xcalloc(1, sizeof(struct MachinePty));
|
||||
pty->yn = yn;
|
||||
pty->xn = xn;
|
||||
pty->wcs = xcalloc(yn * xn, sizeof(pty->wcs[0]));
|
||||
pty->fgs = xcalloc(yn * xn, sizeof(pty->fgs[0]));
|
||||
pty->bgs = xcalloc(yn * xn, sizeof(pty->bgs[0]));
|
||||
pty->prs = xcalloc(yn * xn, sizeof(pty->prs[0]));
|
||||
return pty;
|
||||
}
|
||||
|
||||
void MachinePtyFree(struct MachinePty *pty) {
|
||||
if (pty) {
|
||||
free(pty->wcs);
|
||||
free(pty->fgs);
|
||||
free(pty->bgs);
|
||||
free(pty->prs);
|
||||
free(pty);
|
||||
}
|
||||
}
|
||||
|
||||
static void MachinePtyScrollPlane(struct MachinePty *pty, uint32_t *p) {
|
||||
memcpy(p, p + pty->xn, sizeof(p[0]) * pty->xn * (pty->yn - 1));
|
||||
memset(p + pty->xn * (pty->yn - 1), 0, sizeof(p[0]) * pty->xn);
|
||||
}
|
||||
|
||||
static void MachinePtyScroll(struct MachinePty *pty) {
|
||||
MachinePtyScrollPlane(pty, pty->wcs);
|
||||
MachinePtyScrollPlane(pty, pty->fgs);
|
||||
MachinePtyScrollPlane(pty, pty->bgs);
|
||||
MachinePtyScrollPlane(pty, pty->prs);
|
||||
}
|
||||
|
||||
static void MachinePtyNewline(struct MachinePty *pty) {
|
||||
pty->x = 0;
|
||||
if (++pty->y == pty->yn) {
|
||||
--pty->y;
|
||||
MachinePtyScroll(pty);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetMachinePtyCell(struct MachinePty *pty, wint_t wc) {
|
||||
uint32_t w, i;
|
||||
if ((w = MAX(0, wcwidth(wc))) > 0) {
|
||||
i = pty->y * pty->xn + pty->x;
|
||||
pty->wcs[i] = wc;
|
||||
pty->fgs[i] = pty->fg;
|
||||
pty->bgs[i] = pty->bg;
|
||||
pty->prs[i] = pty->pr;
|
||||
if ((pty->x += w) >= pty->xn) {
|
||||
pty->x = 0;
|
||||
MachinePtyNewline(pty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void MachinePtyTab(struct MachinePty *pty) {
|
||||
unsigned x, x2;
|
||||
x2 = pty->x + ROUNDUP(pty->x + 1, 8);
|
||||
if (x2 >= pty->xn) x2 = pty->xn - 1;
|
||||
for (x = pty->x; x < x2; ++x) {
|
||||
pty->wcs[pty->y * pty->xn + x] = 0;
|
||||
}
|
||||
pty->x = x2;
|
||||
}
|
||||
|
||||
static void MachinePtyCursorSet(struct MachinePty *pty, int y, int x) {
|
||||
pty->y = MAX(0, MIN(pty->yn - 1, y));
|
||||
pty->x = MAX(0, MIN(pty->xn - 1, x));
|
||||
}
|
||||
|
||||
static void MachinePtyCursorMove(struct MachinePty *pty, int dy, int dx) {
|
||||
int n;
|
||||
if (pty->esc.i > 1) {
|
||||
n = atoi(pty->esc.s);
|
||||
dy *= n;
|
||||
dx *= n;
|
||||
}
|
||||
MachinePtyCursorSet(pty, pty->y + dy, pty->x + dx);
|
||||
}
|
||||
|
||||
static void MachinePtyCursorPosition(struct MachinePty *pty) {
|
||||
int row, col;
|
||||
row = MAX(1, atoi(pty->esc.s));
|
||||
col = MAX(1, atoi((char *)firstnonnull(strchr(pty->esc.s, ';'), "x") + 1));
|
||||
MachinePtyCursorSet(pty, row - 1, col - 1);
|
||||
}
|
||||
|
||||
static void MachinePtyEraseRange(struct MachinePty *pty, size_t i, size_t j) {
|
||||
size_t n;
|
||||
n = (j - i) * sizeof(uint32_t);
|
||||
memset(pty->wcs + i, 0, n);
|
||||
memset(pty->fgs + i, 0, n);
|
||||
memset(pty->bgs + i, 0, n);
|
||||
memset(pty->prs + i, 0, n);
|
||||
}
|
||||
|
||||
static void MachinePtyEraseDisplay(struct MachinePty *pty) {
|
||||
switch (atoi(pty->esc.s)) {
|
||||
case 3:
|
||||
case 2:
|
||||
pty->y = 0;
|
||||
pty->x = 0;
|
||||
case 0:
|
||||
MachinePtyEraseRange(pty, pty->y * pty->xn + pty->x, pty->yn * pty->xn);
|
||||
break;
|
||||
case 1:
|
||||
MachinePtyEraseRange(pty, 0, pty->y * pty->xn + pty->x);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void MachinePtyEraseLine(struct MachinePty *pty) {
|
||||
switch (atoi(pty->esc.s)) {
|
||||
case 0:
|
||||
MachinePtyEraseRange(pty, pty->y * pty->xn + pty->x,
|
||||
pty->y * pty->xn + pty->xn);
|
||||
break;
|
||||
case 1:
|
||||
MachinePtyEraseRange(pty, pty->y * pty->xn + pty->xn,
|
||||
pty->y * pty->xn + pty->x);
|
||||
break;
|
||||
case 2:
|
||||
MachinePtyEraseRange(pty, pty->y * pty->xn, pty->y * pty->xn + pty->xn);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) {
|
||||
char *p, c;
|
||||
unsigned x;
|
||||
uint8_t code[4];
|
||||
enum {
|
||||
kSgr,
|
||||
kSgrFg = 010,
|
||||
kSgrFgTrue = 012,
|
||||
kSgrFgXterm = 015,
|
||||
kSgrBg = 020,
|
||||
kSgrBgTrue = 022,
|
||||
kSgrBgXterm = 025,
|
||||
} t;
|
||||
x = 0;
|
||||
t = kSgr;
|
||||
p = pty->esc.s;
|
||||
memset(code, 0, sizeof(code));
|
||||
for (;;) {
|
||||
c = *p++;
|
||||
switch (c) {
|
||||
case '\0':
|
||||
return;
|
||||
case '0' ... '9':
|
||||
x *= 10;
|
||||
x += c - '0';
|
||||
break;
|
||||
case ';':
|
||||
case 'm':
|
||||
code[code[3]] = x;
|
||||
x = 0;
|
||||
switch (t) {
|
||||
case kSgr:
|
||||
switch (code[0]) {
|
||||
case 0:
|
||||
pty->fg = 0;
|
||||
pty->bg = 0;
|
||||
pty->pr = 0;
|
||||
break;
|
||||
case 1:
|
||||
pty->pr |= kMachinePtyBold;
|
||||
break;
|
||||
case 21:
|
||||
pty->pr &= ~kMachinePtyBold;
|
||||
break;
|
||||
case 2:
|
||||
pty->pr |= kMachinePtyFaint;
|
||||
break;
|
||||
case 22:
|
||||
pty->pr &= ~kMachinePtyFaint;
|
||||
break;
|
||||
case 7:
|
||||
pty->pr |= kMachinePtyFlip;
|
||||
break;
|
||||
case 27:
|
||||
pty->pr &= ~kMachinePtyFlip;
|
||||
break;
|
||||
case 90 ... 97:
|
||||
code[0] -= 90 - 30;
|
||||
code[0] += 8;
|
||||
case 30 ... 37:
|
||||
pty->fg = code[0] - 30;
|
||||
pty->pr |= kMachinePtyFg;
|
||||
pty->pr &= ~kMachinePtyTrue;
|
||||
break;
|
||||
case 38:
|
||||
t = kSgrFg;
|
||||
break;
|
||||
case 39:
|
||||
pty->pr &= kMachinePtyFg;
|
||||
break;
|
||||
case 100 ... 107:
|
||||
code[0] -= 100 - 40;
|
||||
code[0] += 8;
|
||||
case 40 ... 47:
|
||||
pty->bg = code[0] - 40;
|
||||
pty->pr |= kMachinePtyBg;
|
||||
pty->pr &= ~kMachinePtyTrue;
|
||||
break;
|
||||
case 48:
|
||||
t = kSgrBg;
|
||||
break;
|
||||
case 49:
|
||||
pty->pr &= kMachinePtyBg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kSgrFg:
|
||||
case kSgrBg:
|
||||
switch (code[0]) {
|
||||
case 2:
|
||||
case 5:
|
||||
t += code[0];
|
||||
break;
|
||||
default:
|
||||
t = kSgr;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kSgrFgTrue:
|
||||
if (++code[3] == 3) {
|
||||
code[3] = 0;
|
||||
t = kSgr;
|
||||
pty->fg = READ32LE(code);
|
||||
pty->pr |= kMachinePtyFg;
|
||||
pty->pr |= kMachinePtyTrue;
|
||||
}
|
||||
break;
|
||||
case kSgrBgTrue:
|
||||
if (++code[3] == 3) {
|
||||
code[3] = 0;
|
||||
t = kSgr;
|
||||
pty->bg = READ32LE(code);
|
||||
pty->pr |= kMachinePtyBg;
|
||||
pty->pr |= kMachinePtyTrue;
|
||||
}
|
||||
break;
|
||||
case kSgrFgXterm:
|
||||
t = kSgr;
|
||||
pty->fg = code[0];
|
||||
pty->pr |= kMachinePtyFg;
|
||||
pty->pr &= ~kMachinePtyTrue;
|
||||
break;
|
||||
case kSgrBgXterm:
|
||||
t = kSgr;
|
||||
pty->bg = code[0];
|
||||
pty->pr |= kMachinePtyBg;
|
||||
pty->pr &= ~kMachinePtyTrue;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void MachinePtyHideCursor(struct MachinePty *pty) {
|
||||
pty->conf |= kMachinePtyNocursor;
|
||||
}
|
||||
|
||||
static void MachinePtyShowCursor(struct MachinePty *pty) {
|
||||
pty->conf &= ~kMachinePtyNocursor;
|
||||
}
|
||||
|
||||
static void MachinePtyCsi(struct MachinePty *pty) {
|
||||
switch (pty->esc.s[pty->esc.i - 1]) {
|
||||
case 'A':
|
||||
MachinePtyCursorMove(pty, -1, +0);
|
||||
break;
|
||||
case 'B':
|
||||
MachinePtyCursorMove(pty, +1, +0);
|
||||
break;
|
||||
case 'C':
|
||||
MachinePtyCursorMove(pty, +0, +1);
|
||||
break;
|
||||
case 'D':
|
||||
MachinePtyCursorMove(pty, +0, -1);
|
||||
break;
|
||||
case 'f':
|
||||
case 'H':
|
||||
MachinePtyCursorPosition(pty);
|
||||
break;
|
||||
case 'J':
|
||||
MachinePtyEraseDisplay(pty);
|
||||
break;
|
||||
case 'K':
|
||||
MachinePtyEraseLine(pty);
|
||||
break;
|
||||
case 'm':
|
||||
MachinePtySelectGraphicsRendition(pty);
|
||||
break;
|
||||
case 'l':
|
||||
if (strcmp(pty->esc.s, "?25l") == 0) {
|
||||
MachinePtyHideCursor(pty);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (strcmp(pty->esc.s, "?25h") == 0) {
|
||||
MachinePtyShowCursor(pty);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void MachinePtyEsc(struct MachinePty *pty) {
|
||||
}
|
||||
|
||||
static void MachinePtyEscAppend(struct MachinePty *pty, char c) {
|
||||
pty->esc.i = MIN(pty->esc.i + 1, ARRAYLEN(pty->esc.s) - 1);
|
||||
pty->esc.s[pty->esc.i - 1] = c;
|
||||
pty->esc.s[pty->esc.i - 0] = '\0';
|
||||
}
|
||||
|
||||
ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
|
||||
int i;
|
||||
const uint8_t *p;
|
||||
for (p = data, i = 0; i < n; ++i) {
|
||||
switch (pty->state) {
|
||||
case kMachinePtyAscii:
|
||||
if (p[i] < 0b10000000) {
|
||||
switch (p[i]) {
|
||||
case '\e':
|
||||
pty->state = kMachinePtyEsc;
|
||||
pty->esc.i = 0;
|
||||
break;
|
||||
case '\t':
|
||||
MachinePtyTab(pty);
|
||||
break;
|
||||
case '\r':
|
||||
pty->x = 0;
|
||||
break;
|
||||
case '\n':
|
||||
MachinePtyNewline(pty);
|
||||
break;
|
||||
default:
|
||||
SetMachinePtyCell(pty, p[i]);
|
||||
break;
|
||||
}
|
||||
} else if (!ThomPikeCont(p[i])) {
|
||||
pty->state = kMachinePtyUtf8;
|
||||
pty->u8 = ThomPikeByte(p[i]);
|
||||
}
|
||||
break;
|
||||
case kMachinePtyUtf8:
|
||||
if (ThomPikeCont(p[i])) {
|
||||
pty->u8 <<= 6;
|
||||
pty->u8 |= p[i] & 0b00111111;
|
||||
} else {
|
||||
SetMachinePtyCell(pty, pty->u8);
|
||||
pty->state = kMachinePtyAscii;
|
||||
pty->u8 = 0;
|
||||
--i;
|
||||
}
|
||||
break;
|
||||
case kMachinePtyEsc:
|
||||
if (p[i] == '[') {
|
||||
pty->state = kMachinePtyCsi;
|
||||
} else if (0x30 <= p[i] && p[i] <= 0x7e) {
|
||||
MachinePtyEscAppend(pty, p[i]);
|
||||
MachinePtyEsc(pty);
|
||||
pty->state = kMachinePtyAscii;
|
||||
} else if (0x20 <= p[i] && p[i] <= 0x2f) {
|
||||
MachinePtyEscAppend(pty, p[i]);
|
||||
} else {
|
||||
pty->state = kMachinePtyAscii;
|
||||
}
|
||||
break;
|
||||
case kMachinePtyCsi:
|
||||
MachinePtyEscAppend(pty, p[i]);
|
||||
switch (p[i]) {
|
||||
case ':':
|
||||
case ';':
|
||||
case '<':
|
||||
case '=':
|
||||
case '>':
|
||||
case '?':
|
||||
case '0' ... '9':
|
||||
break;
|
||||
case '`':
|
||||
case '~':
|
||||
case '^':
|
||||
case '@':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}':
|
||||
case '_':
|
||||
case '|':
|
||||
case '\\':
|
||||
case 'A' ... 'Z':
|
||||
case 'a' ... 'z':
|
||||
MachinePtyCsi(pty);
|
||||
pty->state = kMachinePtyAscii;
|
||||
break;
|
||||
default:
|
||||
pty->state = kMachinePtyAscii;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (pty->u8) {
|
||||
SetMachinePtyCell(pty, pty->u8);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void MachinePtyAppendLine(struct MachinePty *pty, struct Buffer *buf,
|
||||
unsigned y) {
|
||||
uint32_t x, i, fg, bg, pr, wc, w;
|
||||
CHECK_LT(y, pty->yn);
|
||||
for (fg = bg = pr = x = 0; x < pty->xn; x += w) {
|
||||
i = y * pty->xn + x;
|
||||
wc = pty->wcs[i];
|
||||
w = MAX(0, wcwidth(wc));
|
||||
if (w) {
|
||||
if (pty->prs[i] != pr || pty->fgs[i] != fg || pty->bgs[i] != bg) {
|
||||
fg = pty->fgs[i];
|
||||
bg = pty->bgs[i];
|
||||
pr = pty->prs[i];
|
||||
AppendStr(buf, "\e[0");
|
||||
if (pr & kMachinePtyBold) AppendStr(buf, ";1");
|
||||
if (pr & kMachinePtyFaint) AppendStr(buf, ";2");
|
||||
if (pr & kMachinePtyFlip) AppendStr(buf, ";7");
|
||||
if (pr & kMachinePtyFg) {
|
||||
if (pr & kMachinePtyTrue) {
|
||||
AppendFmt(buf, ";38;2;%d;%d;%d", (fg & 0x0000ff) >> 000,
|
||||
(fg & 0x00ff00) >> 010, (fg & 0xff0000) >> 020);
|
||||
} else {
|
||||
AppendFmt(buf, ";38;5;%d", fg);
|
||||
}
|
||||
}
|
||||
if (pr & kMachinePtyBg) {
|
||||
if (pr & kMachinePtyTrue) {
|
||||
AppendFmt(buf, ";48;2;%d;%d;%d", (bg & 0x0000ff) >> 000,
|
||||
(bg & 0x00ff00) >> 010, (bg & 0xff0000) >> 020);
|
||||
} else {
|
||||
AppendFmt(buf, ";48;5;%d", bg);
|
||||
}
|
||||
}
|
||||
AppendStr(buf, "m");
|
||||
}
|
||||
AppendWide(buf, wc);
|
||||
} else {
|
||||
w = 1;
|
||||
if (y == pty->y && x == pty->x) {
|
||||
if (!(pty->conf & kMachinePtyNocursor)) {
|
||||
AppendStr(buf, "\e[5m▂\e[25m");
|
||||
}
|
||||
} else {
|
||||
AppendChar(buf, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
AppendStr(buf, "\e[0m");
|
||||
}
|
50
tool/build/lib/pty.h
Normal file
50
tool/build/lib/pty.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_
|
||||
#include "tool/build/lib/buffer.h"
|
||||
|
||||
#define kMachinePtyFg 0x01
|
||||
#define kMachinePtyBg 0x02
|
||||
#define kMachinePtyTrue 0x04
|
||||
#define kMachinePtyBold 0x08
|
||||
#define kMachinePtyFaint 0x10
|
||||
#define kMachinePtyFlip 0x20
|
||||
|
||||
#define kMachinePtyNocursor 0x01
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct MachinePty {
|
||||
uint32_t yn;
|
||||
uint32_t xn;
|
||||
uint32_t y;
|
||||
uint32_t x;
|
||||
uint32_t pr;
|
||||
uint32_t fg;
|
||||
uint32_t bg;
|
||||
uint32_t u8;
|
||||
uint32_t *wcs;
|
||||
uint32_t *fgs;
|
||||
uint32_t *bgs;
|
||||
uint32_t *prs;
|
||||
uint32_t conf;
|
||||
enum MachinePtyState {
|
||||
kMachinePtyAscii,
|
||||
kMachinePtyUtf8,
|
||||
kMachinePtyEsc,
|
||||
kMachinePtyCsi,
|
||||
} state;
|
||||
struct MachinePtyEsc {
|
||||
unsigned i;
|
||||
char s[64];
|
||||
} esc;
|
||||
};
|
||||
|
||||
struct MachinePty *MachinePtyNew(unsigned, unsigned) nodiscard;
|
||||
void MachinePtyFree(struct MachinePty *);
|
||||
ssize_t MachinePtyWrite(struct MachinePty *, const void *, size_t);
|
||||
void MachinePtyAppendLine(struct MachinePty *, struct Buffer *, unsigned);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_ */
|
|
@ -17,8 +17,10 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
@ -61,8 +63,25 @@ static void ResetSse(struct Machine *m) {
|
|||
memset(m->xmmtype, 0, sizeof(m->xmmtype));
|
||||
}
|
||||
|
||||
static void ResetTlb(struct Machine *m) {
|
||||
m->tlbindex = 0;
|
||||
memset(m->tlb, 0, sizeof(m->tlb));
|
||||
}
|
||||
|
||||
static void ResetMem(struct Machine *m) {
|
||||
FreePml4t(m->cr3, -0x800000000000, 0x800000000000, free, munmap);
|
||||
}
|
||||
|
||||
void ResetCpu(struct Machine *m) {
|
||||
InitMachine(m);
|
||||
m->codevirt = 0;
|
||||
m->codereal = NULL;
|
||||
m->faultaddr = 0;
|
||||
m->stashsize = 0;
|
||||
m->stashaddr = 0;
|
||||
m->writeaddr = 0;
|
||||
m->readaddr = 0;
|
||||
m->writesize = 0;
|
||||
m->readsize = 0;
|
||||
m->flags = SetFlag(m->flags, FLAGS_DF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, false);
|
||||
m->flags = SetFlag(m->flags, FLAGS_ZF, false);
|
||||
|
@ -73,6 +92,9 @@ void ResetCpu(struct Machine *m) {
|
|||
m->flags = SetFlag(m->flags, FLAGS_IOPL, 3);
|
||||
memset(m->reg, 0, sizeof(m->reg));
|
||||
memset(m->bofram, 0, sizeof(m->bofram));
|
||||
memset(&m->freelist, 0, sizeof(m->freelist));
|
||||
ResetTlb(m);
|
||||
ResetSse(m);
|
||||
ResetFpu(m);
|
||||
ResetMem(m);
|
||||
}
|
||||
|
|
|
@ -114,19 +114,19 @@ union MachineVector {
|
|||
uint64_t u64[2];
|
||||
};
|
||||
|
||||
void OpSse(struct Machine *m, enum OpSseKernel kernel) {
|
||||
void OpSse(struct Machine *m, uint32_t rde, enum OpSseKernel kernel) {
|
||||
int i;
|
||||
uint8_t *p;
|
||||
union MachineVector x, y, t;
|
||||
p = GetModrmRegisterXmmPointerRead16(m);
|
||||
if (Osz(m->xedd)) {
|
||||
p = GetModrmRegisterXmmPointerRead16(m, rde);
|
||||
if (Osz(rde)) {
|
||||
memcpy(&y, p, 16);
|
||||
} else {
|
||||
memset(&t, 0, 16);
|
||||
memcpy(&t, p, 8);
|
||||
memcpy(&y, &t, 16);
|
||||
}
|
||||
memcpy(&x, XmmRexrReg(m), 16);
|
||||
memcpy(&x, XmmRexrReg(m, rde), 16);
|
||||
switch (kernel) {
|
||||
CASE(kOpSsePsubb, psubb(x.i8, x.i8, y.i8));
|
||||
CASE(kOpSsePaddb, paddb(x.i8, x.i8, y.i8));
|
||||
|
@ -204,18 +204,18 @@ void OpSse(struct Machine *m, enum OpSseKernel kernel) {
|
|||
default:
|
||||
unreachable;
|
||||
}
|
||||
if (Osz(m->xedd)) {
|
||||
memcpy(XmmRexrReg(m), &x, 16);
|
||||
if (Osz(rde)) {
|
||||
memcpy(XmmRexrReg(m, rde), &x, 16);
|
||||
} else {
|
||||
memcpy(XmmRexrReg(m), &x, 8);
|
||||
memcpy(XmmRexrReg(m, rde), &x, 8);
|
||||
}
|
||||
}
|
||||
|
||||
void OpSseUdqIb(struct Machine *m, enum OpSseUdqIbKernel kernel) {
|
||||
void OpSseUdqIb(struct Machine *m, uint32_t rde, enum OpSseUdqIbKernel kernel) {
|
||||
uint8_t i;
|
||||
union MachineVector x;
|
||||
i = m->xedd->op.uimm0;
|
||||
memcpy(&x, XmmRexbRm(m), 16);
|
||||
memcpy(&x, XmmRexbRm(m, rde), 16);
|
||||
switch (kernel) {
|
||||
CASE(kOpSseUdqIbPsrlw, (psrlw)(x.u16, x.u16, i));
|
||||
CASE(kOpSseUdqIbPsraw, (psraw)(x.i16, x.i16, i));
|
||||
|
@ -230,26 +230,26 @@ void OpSseUdqIb(struct Machine *m, enum OpSseUdqIbKernel kernel) {
|
|||
default:
|
||||
unreachable;
|
||||
}
|
||||
if (Osz(m->xedd)) {
|
||||
memcpy(XmmRexbRm(m), &x, 16);
|
||||
if (Osz(rde)) {
|
||||
memcpy(XmmRexbRm(m, rde), &x, 16);
|
||||
} else {
|
||||
memcpy(XmmRexbRm(m), &x, 8);
|
||||
memcpy(XmmRexbRm(m, rde), &x, 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void OpSsePalignrMmx(struct Machine *m) {
|
||||
static void OpSsePalignrMmx(struct Machine *m, uint32_t rde) {
|
||||
char t[24];
|
||||
memcpy(t, GetModrmRegisterXmmPointerRead8(m), 8);
|
||||
memcpy(t + 8, XmmRexrReg(m), 8);
|
||||
memcpy(t, GetModrmRegisterXmmPointerRead8(m, rde), 8);
|
||||
memcpy(t + 8, XmmRexrReg(m, rde), 8);
|
||||
memset(t + 16, 0, 8);
|
||||
memcpy(XmmRexrReg(m), t + MIN(m->xedd->op.uimm0, 16), 8);
|
||||
memcpy(XmmRexrReg(m, rde), t + MIN(m->xedd->op.uimm0, 16), 8);
|
||||
}
|
||||
|
||||
void OpSsePalignr(struct Machine *m) {
|
||||
if (Osz(m->xedd)) {
|
||||
palignr(XmmRexrReg(m), XmmRexrReg(m), GetModrmRegisterXmmPointerRead8(m),
|
||||
m->xedd->op.uimm0);
|
||||
void OpSsePalignr(struct Machine *m, uint32_t rde) {
|
||||
if (Osz(rde)) {
|
||||
palignr(XmmRexrReg(m, rde), XmmRexrReg(m, rde),
|
||||
GetModrmRegisterXmmPointerRead8(m, rde), m->xedd->op.uimm0);
|
||||
} else {
|
||||
OpSsePalignrMmx(m);
|
||||
OpSsePalignrMmx(m, rde);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,9 +93,9 @@ enum OpSseUdqIbKernel {
|
|||
kOpSseUdqIbPslldq,
|
||||
};
|
||||
|
||||
void OpSse(struct Machine *, enum OpSseKernel);
|
||||
void OpSseUdqIb(struct Machine *, enum OpSseUdqIbKernel);
|
||||
void OpSsePalignr(struct Machine *);
|
||||
void OpSse(struct Machine *, uint32_t, enum OpSseKernel);
|
||||
void OpSseUdqIb(struct Machine *, uint32_t, enum OpSseUdqIbKernel);
|
||||
void OpSsePalignr(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -76,12 +76,12 @@ void OpCallJvds(struct Machine *m) {
|
|||
OpCall(m, m->ip + m->xedd->op.disp);
|
||||
}
|
||||
|
||||
void OpCallEq(struct Machine *m) {
|
||||
void OpCallEq(struct Machine *m, uint32_t rde) {
|
||||
void *p[2];
|
||||
uint8_t b[8];
|
||||
OpCall(m, Read64(IsModrmRegister(m->xedd)
|
||||
? RegRexbRm(m)
|
||||
: AccessRam(m, ComputeAddress(m), 8, p, b, true)));
|
||||
OpCall(m, Read64(IsModrmRegister(rde)
|
||||
? RegRexbRm(m, rde)
|
||||
: AccessRam(m, ComputeAddress(m, rde), 8, p, b, true)));
|
||||
}
|
||||
|
||||
void OpLeave(struct Machine *m) {
|
||||
|
@ -93,10 +93,20 @@ void OpRet(struct Machine *m, uint16_t n) {
|
|||
m->ip = Pop64(m, n);
|
||||
}
|
||||
|
||||
void PushOsz(struct Machine *m, uint64_t x) {
|
||||
if (!Osz(m->xedd)) {
|
||||
void PushOsz(struct Machine *m, uint32_t rde, uint64_t x) {
|
||||
if (!Osz(rde)) {
|
||||
Push64(m, x);
|
||||
} else {
|
||||
Push16(m, x);
|
||||
}
|
||||
}
|
||||
|
||||
void OpBofram(struct Machine *m) {
|
||||
if (m->xedd->op.disp) {
|
||||
m->bofram[0] = m->ip;
|
||||
m->bofram[1] = m->ip + (m->xedd->op.disp & 0xff);
|
||||
} else {
|
||||
m->bofram[0] = 0;
|
||||
m->bofram[1] = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,9 @@ uint16_t Pop16(struct Machine *, uint16_t);
|
|||
void OpCallJvds(struct Machine *);
|
||||
void OpRet(struct Machine *, uint16_t);
|
||||
void OpLeave(struct Machine *);
|
||||
void PushOsz(struct Machine *, uint64_t);
|
||||
void OpCallEq(struct Machine *);
|
||||
void PushOsz(struct Machine *, uint32_t, uint64_t);
|
||||
void OpCallEq(struct Machine *, uint32_t);
|
||||
void OpBofram(struct Machine *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -65,7 +65,7 @@ static void WriteInt(uint8_t p[8], uint64_t x, unsigned long w) {
|
|||
}
|
||||
}
|
||||
|
||||
void OpString(struct Machine *m, int op) {
|
||||
void OpString(struct Machine *m, uint32_t rde, int op) {
|
||||
void *p[2];
|
||||
bool compare;
|
||||
int64_t sgn, v;
|
||||
|
@ -73,12 +73,12 @@ void OpString(struct Machine *m, int op) {
|
|||
unsigned n, lg2;
|
||||
uint64_t asz, seg;
|
||||
sgn = GetFlag(m->flags, FLAGS_DF) ? -1 : 1;
|
||||
asz = Asz(m->xedd) ? 0xffffffff : 0xffffffffffffffff;
|
||||
asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff;
|
||||
seg = GetSegment(m);
|
||||
lg2 = RegLog2(m->xedd);
|
||||
lg2 = RegLog2(rde);
|
||||
n = 1 << lg2;
|
||||
for (;;) {
|
||||
if (Rep(m->xedd) && !Read64(m->cx)) break;
|
||||
if (Rep(rde) && !Read64(m->cx)) break;
|
||||
v = 0;
|
||||
*p = NULL;
|
||||
compare = false;
|
||||
|
@ -125,16 +125,16 @@ void OpString(struct Machine *m, int op) {
|
|||
abort();
|
||||
}
|
||||
EndStore(m, v, n, p, s[0]);
|
||||
if (!Rep(m->xedd)) break;
|
||||
if (!Rep(rde)) break;
|
||||
Write64(m->cx, Read64(m->cx) - 1);
|
||||
if (compare) {
|
||||
if (Rep(m->xedd) == 2 && GetFlag(m->flags, FLAGS_ZF)) break;
|
||||
if (Rep(m->xedd) == 3 && !GetFlag(m->flags, FLAGS_ZF)) break;
|
||||
if (Rep(rde) == 2 && GetFlag(m->flags, FLAGS_ZF)) break;
|
||||
if (Rep(rde) == 3 && !GetFlag(m->flags, FLAGS_ZF)) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpRepMovsbEnhanced(struct Machine *m) {
|
||||
void OpRepMovsbEnhanced(struct Machine *m, uint32_t rde) {
|
||||
bool failed;
|
||||
uint8_t *direal, *sireal;
|
||||
unsigned diremain, siremain, i, n;
|
||||
|
@ -143,7 +143,7 @@ void OpRepMovsbEnhanced(struct Machine *m) {
|
|||
failed = false;
|
||||
failaddr = 0;
|
||||
seg = GetSegment(m);
|
||||
asz = Asz(m->xedd) ? 0xffffffff : 0xffffffffffffffff;
|
||||
asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff;
|
||||
divirtual = Read64(m->di) & asz;
|
||||
sivirtual = Read64(m->si) & asz;
|
||||
SetWriteAddr(m, (seg + divirtual) & asz, cx);
|
||||
|
@ -177,7 +177,7 @@ void OpRepMovsbEnhanced(struct Machine *m) {
|
|||
if (failed) ThrowSegmentationFault(m, failaddr);
|
||||
}
|
||||
|
||||
void OpRepStosbEnhanced(struct Machine *m) {
|
||||
void OpRepStosbEnhanced(struct Machine *m, uint32_t rde) {
|
||||
bool failed;
|
||||
uint8_t *direal, al;
|
||||
unsigned diremain, i, n;
|
||||
|
@ -187,7 +187,7 @@ void OpRepStosbEnhanced(struct Machine *m) {
|
|||
failed = false;
|
||||
al = Read8(m->ax);
|
||||
seg = GetSegment(m);
|
||||
asz = Asz(m->xedd) ? 0xffffffff : 0xffffffffffffffff;
|
||||
asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff;
|
||||
divirtual = Read64(m->di) & asz;
|
||||
SetWriteAddr(m, (seg + divirtual) & asz, cx);
|
||||
do {
|
||||
|
@ -210,18 +210,18 @@ void OpRepStosbEnhanced(struct Machine *m) {
|
|||
if (failed) ThrowSegmentationFault(m, failaddr);
|
||||
}
|
||||
|
||||
void OpMovsb(struct Machine *m) {
|
||||
if (Rep(m->xedd) && !GetFlag(m->flags, FLAGS_DF)) {
|
||||
OpRepMovsbEnhanced(m);
|
||||
void OpMovsb(struct Machine *m, uint32_t rde) {
|
||||
if (Rep(rde) && !GetFlag(m->flags, FLAGS_DF)) {
|
||||
OpRepMovsbEnhanced(m, rde);
|
||||
} else {
|
||||
OpString(m, STRING_MOVS);
|
||||
OpString(m, rde, STRING_MOVS);
|
||||
}
|
||||
}
|
||||
|
||||
void OpStosb(struct Machine *m) {
|
||||
if (Rep(m->xedd) && !GetFlag(m->flags, FLAGS_DF)) {
|
||||
OpRepStosbEnhanced(m);
|
||||
void OpStosb(struct Machine *m, uint32_t rde) {
|
||||
if (Rep(rde) && !GetFlag(m->flags, FLAGS_DF)) {
|
||||
OpRepStosbEnhanced(m, rde);
|
||||
} else {
|
||||
OpString(m, STRING_STOS);
|
||||
OpString(m, rde, STRING_STOS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void OpString(struct Machine *, int);
|
||||
void OpMovsb(struct Machine *);
|
||||
void OpStosb(struct Machine *);
|
||||
void OpString(struct Machine *, uint32_t, int);
|
||||
void OpMovsb(struct Machine *, uint32_t);
|
||||
void OpStosb(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/struct/timezone.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
@ -65,6 +66,12 @@
|
|||
#define P(x) ((x) ? PNN(x) : 0)
|
||||
#define ASSIGN(D, S) memcpy(&D, &S, MIN(sizeof(S), sizeof(D)))
|
||||
|
||||
static const struct MachineFdCb kMachineFdCbHost = {
|
||||
.close = close,
|
||||
.read = read,
|
||||
.write = write,
|
||||
};
|
||||
|
||||
static int XlatSignal(int sig) {
|
||||
switch (sig) {
|
||||
XLAT(1, SIGHUP);
|
||||
|
@ -188,9 +195,15 @@ static int XlatTcp(int x) {
|
|||
}
|
||||
}
|
||||
|
||||
static int XlatAfd(int x) {
|
||||
if (x == AT_FDCWD_LINUX) x = AT_FDCWD;
|
||||
return x;
|
||||
static int XlatFd(struct Machine *m, int fd) {
|
||||
if (!(0 <= fd && fd < m->fds.i)) return ebadf();
|
||||
if (!m->fds.p[fd].cb) return ebadf();
|
||||
return m->fds.p[fd].fd;
|
||||
}
|
||||
|
||||
static int XlatAfd(struct Machine *m, int fd) {
|
||||
if (fd == AT_FDCWD_LINUX) return AT_FDCWD;
|
||||
return XlatFd(m, fd);
|
||||
}
|
||||
|
||||
static int XlatAtf(int x) {
|
||||
|
@ -264,6 +277,7 @@ static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
|
|||
int flags, int fd, int64_t off) {
|
||||
void *real;
|
||||
flags = XlatMapFlags(flags);
|
||||
if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1;
|
||||
real = mmap(NULL, size, prot, flags & ~MAP_FIXED, fd, off);
|
||||
if (real == MAP_FAILED) return -1;
|
||||
if (!(flags & MAP_FIXED)) {
|
||||
|
@ -297,19 +311,70 @@ static void *GetDirectBuf(struct Machine *m, int64_t addr, size_t *size) {
|
|||
return page;
|
||||
}
|
||||
|
||||
static int OpClose(struct Machine *m, int fd) {
|
||||
int rc;
|
||||
struct FdClosed *closed;
|
||||
if (!(0 <= fd && fd < m->fds.i)) return ebadf();
|
||||
if (!m->fds.p[fd].cb) return ebadf();
|
||||
rc = m->fds.p[fd].cb->close(m->fds.p[fd].fd);
|
||||
MachineFdRemove(&m->fds, fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags,
|
||||
int mode) {
|
||||
int fd, i;
|
||||
flags = XlatOpenFlags(flags);
|
||||
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
|
||||
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
|
||||
if ((fd = openat(dirfd, LoadStr(m, path), flags, mode)) != -1) {
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
m->fds.p[i].fd = fd;
|
||||
fd = i;
|
||||
} else {
|
||||
MachineFdRemove(&m->fds, i);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int OpPipe(struct Machine *m, int64_t pipefds_addr) {
|
||||
void *p[2];
|
||||
uint8_t b[8];
|
||||
int rc, i, j, *pipefds;
|
||||
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
|
||||
if ((j = MachineFdAdd(&m->fds)) == -1) return -1;
|
||||
if ((rc = pipe((pipefds = BeginStoreNp(m, pipefds_addr, 8, p, b)))) != -1) {
|
||||
EndStoreNp(m, pipefds_addr, 8, p, b);
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
m->fds.p[i].fd = pipefds[0];
|
||||
m->fds.p[j].cb = &kMachineFdCbHost;
|
||||
m->fds.p[j].fd = pipefds[1];
|
||||
} else {
|
||||
MachineFdRemove(&m->fds, i);
|
||||
MachineFdRemove(&m->fds, j);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) {
|
||||
void *data;
|
||||
ssize_t rc;
|
||||
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
|
||||
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
|
||||
if ((rc = read(fd, data, size)) != -1) SetWriteAddr(m, addr, rc);
|
||||
if ((rc = m->fds.p[fd].cb->read(m->fds.p[fd].fd, data, size)) != -1) {
|
||||
SetWriteAddr(m, addr, rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
|
||||
void *data;
|
||||
ssize_t rc;
|
||||
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
|
||||
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
|
||||
if ((rc = write(fd, data, size)) != -1) SetReadAddr(m, addr, size);
|
||||
if ((rc = m->fds.p[fd].cb->write(m->fds.p[fd].fd, data, size)) != -1) {
|
||||
SetReadAddr(m, addr, size);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -317,6 +382,7 @@ static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
|
|||
int64_t offset) {
|
||||
void *data;
|
||||
ssize_t rc;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
|
||||
if ((rc = pread(fd, data, size, offset)) != -1) SetWriteAddr(m, addr, rc);
|
||||
return rc;
|
||||
|
@ -326,20 +392,31 @@ static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size,
|
|||
int64_t offset) {
|
||||
void *data;
|
||||
ssize_t rc;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
|
||||
if ((rc = pwrite(fd, data, size, offset)) != -1) SetReadAddr(m, addr, size);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode,
|
||||
int flags) {
|
||||
flags = XlatAtf(flags);
|
||||
mode = XlatAccess(mode);
|
||||
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
|
||||
return faccessat(dirfd, LoadStr(m, path), mode, flags);
|
||||
}
|
||||
|
||||
static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t st,
|
||||
int flags) {
|
||||
int rc;
|
||||
void *stp[2];
|
||||
uint8_t *stbuf;
|
||||
flags = XlatAtf(flags);
|
||||
if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1;
|
||||
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
|
||||
if ((rc = fstatat(XlatAfd(dirfd), LoadStr(m, path),
|
||||
BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf),
|
||||
XlatAtf(flags))) != -1) {
|
||||
if ((rc = fstatat(dirfd, LoadStr(m, path),
|
||||
BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf), flags)) !=
|
||||
-1) {
|
||||
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
|
||||
}
|
||||
free(stbuf);
|
||||
|
@ -350,6 +427,7 @@ static int OpFstat(struct Machine *m, int fd, int64_t st) {
|
|||
int rc;
|
||||
void *stp[2];
|
||||
uint8_t *stbuf;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
|
||||
if ((rc = fstat(fd, BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf))) != -1) {
|
||||
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
|
||||
|
@ -358,17 +436,6 @@ static int OpFstat(struct Machine *m, int fd, int64_t st) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags,
|
||||
int mode) {
|
||||
return openat(XlatAfd(dirfd), LoadStr(m, path), XlatOpenFlags(flags), mode);
|
||||
}
|
||||
|
||||
static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode,
|
||||
int flags) {
|
||||
return faccessat(XlatAfd(dirfd), LoadStr(m, path), XlatAccess(mode),
|
||||
XlatAtf(flags));
|
||||
}
|
||||
|
||||
static int OpChdir(struct Machine *m, int64_t path) {
|
||||
return chdir(LoadStr(m, path));
|
||||
}
|
||||
|
@ -449,16 +516,6 @@ static int OpSigaction(struct Machine *m, int sig, int64_t act, int64_t old) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int OpPipe(struct Machine *m, int64_t pipefds_addr) {
|
||||
int rc;
|
||||
void *p[2];
|
||||
uint8_t b[8];
|
||||
if ((rc = pipe(BeginStoreNp(m, pipefds_addr, 8, p, b))) != -1) {
|
||||
EndStoreNp(m, pipefds_addr, 8, p, b);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int OpNanosleep(struct Machine *m, int64_t req, int64_t rem) {
|
||||
int rc;
|
||||
void *p[2];
|
||||
|
@ -536,7 +593,7 @@ void OpSyscall(struct Machine *m) {
|
|||
SYSCALL(0x000, OpRead(m, di, si, dx));
|
||||
SYSCALL(0x001, OpWrite(m, di, si, dx));
|
||||
SYSCALL(0x002, DoOpen(m, di, si, dx));
|
||||
SYSCALL(0x003, close(di));
|
||||
SYSCALL(0x003, OpClose(m, di));
|
||||
SYSCALL(0x004, DoStat(m, di, si));
|
||||
SYSCALL(0x005, OpFstat(m, di, si));
|
||||
SYSCALL(0x006, DoLstat(m, di, si));
|
||||
|
@ -624,16 +681,16 @@ void OpSyscall(struct Machine *m) {
|
|||
SYSCALL(0x0DD, fadvise(di, si, dx, r0));
|
||||
SYSCALL(0x0E4, OpClockGettime(m, di, si));
|
||||
SYSCALL(0x101, OpOpenat(m, di, si, dx, r0));
|
||||
SYSCALL(0x102, mkdirat(XlatAfd(di), P(si), dx));
|
||||
SYSCALL(0x104, fchownat(XlatAfd(di), P(si), dx, r0, XlatAtf(r8)));
|
||||
SYSCALL(0x105, futimesat(XlatAfd(di), P(si), P(dx)));
|
||||
SYSCALL(0x102, mkdirat(XlatAfd(m, di), P(si), dx));
|
||||
SYSCALL(0x104, fchownat(XlatAfd(m, di), P(si), dx, r0, XlatAtf(r8)));
|
||||
SYSCALL(0x105, futimesat(XlatAfd(m, di), P(si), P(dx)));
|
||||
SYSCALL(0x106, OpFstatat(m, di, si, dx, r0));
|
||||
SYSCALL(0x107, unlinkat(XlatAfd(di), P(si), XlatAtf(dx)));
|
||||
SYSCALL(0x108, renameat(XlatAfd(di), P(si), XlatAfd(dx), P(r0)));
|
||||
SYSCALL(0x107, unlinkat(XlatAfd(m, di), P(si), XlatAtf(dx)));
|
||||
SYSCALL(0x108, renameat(XlatAfd(m, di), P(si), XlatAfd(m, dx), P(r0)));
|
||||
SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0));
|
||||
SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9)));
|
||||
SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0)));
|
||||
SYSCALL(0x118, utimensat(XlatAfd(di), P(si), P(dx), XlatAtf(r0)));
|
||||
SYSCALL(0x118, utimensat(XlatAfd(m, di), P(si), P(dx), XlatAtf(r0)));
|
||||
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
|
||||
CASE(0xE7, HaltMachine(m, di | 0x100));
|
||||
default:
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
enum MachineStatus;
|
||||
|
||||
void OpSyscall(struct Machine *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -17,55 +17,24 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/lib/pc.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nt/struct/context.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
|
||||
#define kNtContextXstate 0x00100040
|
||||
#define kNtXstateAvx 2
|
||||
#define kNtXstateMaskAvx (1ull << kNtXstateAvx)
|
||||
|
||||
static void EnableAvx(void) {
|
||||
asm volatile("mov\t%%cr4,%%rax\n\t"
|
||||
"or\t%0,%%rax\n\t"
|
||||
"mov\t%%rax,%%cr4\n\t"
|
||||
"xor\t%%ecx,%%ecx\n\t"
|
||||
"xgetbv\n\t"
|
||||
"or\t%1,%%eax\n\t"
|
||||
"xsetbv"
|
||||
: /* no outputs */
|
||||
: "i"(CR4_OSXSAVE), "i"(XCR0_X87 | XCR0_SSE | XCR0_AVX)
|
||||
: "rax", "rcx", "rdx", "memory", "cc");
|
||||
}
|
||||
|
||||
static void EnableAvxOnWindows(void) {
|
||||
/* typedef uint64_t (*getenabledxstatefeatures_f)(void) __msabi; */
|
||||
/* typedef bool32 (*initializecontext_f)(void *buffer, uint32_t flags, */
|
||||
/* struct NtContext **out_context, */
|
||||
/* uint32_t *inout_buffersize) __msabi;
|
||||
*/
|
||||
/* typedef bool32 (*getxstatefeaturesmask_f)(struct NtContext * context, */
|
||||
/* uint64_t * out_featuremask)
|
||||
* __msabi; */
|
||||
/* typedef bool32 (*setxstatefeaturesmask_f)(struct NtContext * context, */
|
||||
/* uint64_t featuremask) __msabi; */
|
||||
/* getenabledxstatefeatures_f GetEnabledXStateFeatures; */
|
||||
/* initializecontext_f InitializeContext; */
|
||||
/* getxstatefeaturesmask_f GetXStateFeaturesMask; */
|
||||
/* setxstatefeaturesmask_f SetXStateFeaturesMask; */
|
||||
}
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/time.h"
|
||||
|
||||
/**
|
||||
* Requests authorization from operating system to do 256-bit math.
|
||||
* @assume avx cpuid check performed by caller
|
||||
* I am the timelorde.
|
||||
*/
|
||||
int _init_enableavx(void) {
|
||||
if (IsMetal()) {
|
||||
EnableAvx();
|
||||
} else if (IsWindows()) {
|
||||
EnableAvxOnWindows();
|
||||
}
|
||||
return 0;
|
||||
void OpRdtsc(struct Machine *m) {
|
||||
uint64_t c;
|
||||
#ifdef __x86_64__
|
||||
c = rdtsc();
|
||||
#else
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
c = ts.tv_sec * 1000000000 + ts.tv_nsec;
|
||||
#endif
|
||||
Write64(m->ax, (c >> 000) & 0xffffffff);
|
||||
Write64(m->dx, (c >> 040) & 0xffffffff);
|
||||
}
|
11
tool/build/lib/time.h
Normal file
11
tool/build/lib/time.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_TIME_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_TIME_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void OpRdtsc(struct Machine *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_TIME_H_ */
|
|
@ -36,6 +36,7 @@ int main(int argc, char *argv[]) {
|
|||
fputs(" PROG [ARGS...]\n", stderr);
|
||||
return EX_USAGE;
|
||||
}
|
||||
InitMachine(m);
|
||||
LoadProgram(m, argv[1], argv + 2, environ, &elf);
|
||||
if (!(rc = setjmp(m->onhalt))) {
|
||||
for (;;) {
|
||||
|
|
|
@ -134,6 +134,7 @@
|
|||
"textexit"
|
||||
"externinline"
|
||||
"noinline"
|
||||
"noclone"
|
||||
"donothing"
|
||||
"byanymeansnecessary"
|
||||
"threadlocal"
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_ANSITRINSICS_H_
|
||||
#define COSMOPOLITAN_TOOL_VIZ_LIB_ANSITRINSICS_H_
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/str/str.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
static unsigned char avgb(unsigned char a, unsigned char b) {
|
||||
return (a + b + 1) / 2;
|
||||
}
|
||||
|
||||
static void pavgb(const unsigned char *restrict c,
|
||||
const unsigned char *restrict b, unsigned char *restrict a) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 16; ++i) a[i] = avgb(c[i], b[i]);
|
||||
}
|
||||
|
||||
static void vpavgb(const unsigned char *restrict c,
|
||||
const unsigned char *restrict b, unsigned char *restrict a) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 32; ++i) a[i] = avgb(c[i], b[i]);
|
||||
}
|
||||
|
||||
static void paddsw(const short c[8], const short b[8], short a[8]) {
|
||||
size_t j;
|
||||
for (j = 0; j < 8; ++j) {
|
||||
a[j] = MIN(SHRT_MAX, MAX(SHRT_MIN, b[j] + c[j]));
|
||||
}
|
||||
}
|
||||
|
||||
static void vpaddsw(const short c[16], const short b[16], short a[16]) {
|
||||
size_t j;
|
||||
for (j = 0; j < 16; ++j) {
|
||||
a[j] = MAX(SHRT_MIN, MIN(SHRT_MAX, b[j] + c[j]));
|
||||
}
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_ANSITRINSICS_H_ */
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_VIZ_LIB_SCALE_H_
|
||||
#define COSMOPOLITAN_TOOL_VIZ_LIB_SCALE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void *Scale(long dcw, long dyw, long dxw, float dst[dcw][dyw][dxw], long scw,
|
||||
long syw, long sxw, const float src[scw][syw][sxw], long, long,
|
||||
long, long, long, long, double, double, double, double);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_VIZ_LIB_SCALE_H_ */
|
|
@ -49,7 +49,6 @@
|
|||
#include "third_party/avir/lanczos.h"
|
||||
#include "tool/viz/lib/graphic.h"
|
||||
#include "tool/viz/lib/knobs.h"
|
||||
#include "tool/viz/lib/scale.h"
|
||||
#include "tool/viz/lib/ycbcr.h"
|
||||
|
||||
#define M 15
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
#include "third_party/stb/stb_image.h"
|
||||
#include "tool/viz/lib/bilinearscale.h"
|
||||
#include "tool/viz/lib/graphic.h"
|
||||
#include "tool/viz/lib/scale.h"
|
||||
|
||||
#define LONG long
|
||||
#define CHAR char
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/half.h"
|
||||
#include "dsp/core/twixt8.h"
|
||||
#include "dsp/scale/scale.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
|
@ -59,6 +60,7 @@ static struct Flags {
|
|||
bool unsharp;
|
||||
bool dither;
|
||||
bool ruler;
|
||||
bool trailingnewline;
|
||||
long half;
|
||||
bool full;
|
||||
long width;
|
||||
|
@ -129,9 +131,11 @@ static void GetOpts(int *argc, char *argv[]) {
|
|||
g_flags.unsharp = true;
|
||||
break;
|
||||
case 'w':
|
||||
g_flags.trailingnewline = true;
|
||||
g_flags.width = ParseNumberOption(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
g_flags.trailingnewline = true;
|
||||
g_flags.height = ParseNumberOption(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
|
@ -202,19 +206,19 @@ static unsigned char OutOfBoundsBackground(unsigned y, unsigned x) {
|
|||
static void PrintRulerRight(long yn, long xn, long y, long x,
|
||||
bool *inout_didhalfy) {
|
||||
if (y == 0) {
|
||||
printf("\e[0m‾0");
|
||||
printf("‾0");
|
||||
} else if (yn / 2 <= y && y <= yn / 2 + 1 && !*inout_didhalfy) {
|
||||
printf("\e[0m‾%s%s", "yn/2", y % 2 ? "+1" : "");
|
||||
printf("‾%s%s", "yn/2", y % 2 ? "+1" : "");
|
||||
*inout_didhalfy = true;
|
||||
} else if (y + 1 == yn / 2 && !*inout_didhalfy) {
|
||||
printf("\e[0m⎯yn/2");
|
||||
printf("⎯yn/2");
|
||||
*inout_didhalfy = true;
|
||||
} else if (y + 1 == yn) {
|
||||
printf("\e[0m⎯yn");
|
||||
printf("⎯yn");
|
||||
} else if (y + 2 == yn) {
|
||||
printf("\e[0m_yn");
|
||||
printf("_yn");
|
||||
} else if (!(y % 10)) {
|
||||
printf("\e[0m‾%,u", y);
|
||||
printf("‾%,u", y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,11 +247,12 @@ static void PrintImageImpl(long syn, long sxn, unsigned char RGB[3][syn][sxn],
|
|||
b[2], dy > 1 ? u'▄' : u'▐');
|
||||
didfirstx = true;
|
||||
}
|
||||
printf("\e[0m");
|
||||
if (g_flags.ruler) {
|
||||
PrintRulerRight(yn, xn, y, x, &didhalfy);
|
||||
}
|
||||
}
|
||||
printf("\e[0m\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void PrintImage(long syn, long sxn, unsigned char RGB[3][syn][sxn],
|
||||
|
@ -334,7 +339,9 @@ static void PrintImageSerious(long yn, long xn, unsigned char RGB[3][yn][xn],
|
|||
}
|
||||
}
|
||||
p = ttyraster(vt, (void *)TTY, yn, xn, bg, fg);
|
||||
p = stpcpy(p, "\r\e[0m");
|
||||
*p++ = '\r';
|
||||
if (g_flags.trailingnewline) *p++ = '\n';
|
||||
p = stpcpy(p, "\e[0m");
|
||||
ttywrite(STDOUT_FILENO, vt, p - vt);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue