/* -*-c-*-
*
- * $Id: mpx.c,v 1.6 1999/11/20 22:43:44 mdw Exp $
+ * $Id$
*
* Low-level multiprecision arithmetic
*
* MA 02111-1307, USA.
*/
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: mpx.c,v $
- * Revision 1.6 1999/11/20 22:43:44 mdw
- * Integrate testing for MPX routines.
- *
- * Revision 1.5 1999/11/20 22:23:27 mdw
- * Add function versions of some low-level macros with wider use.
- *
- * Revision 1.4 1999/11/17 18:04:09 mdw
- * Add two's-complement functionality. Improve mpx_udiv a little by
- * performing the multiplication of the divisor by q with the subtraction
- * from r.
- *
- * Revision 1.3 1999/11/13 01:57:31 mdw
- * Remove stray debugging code.
- *
- * Revision 1.2 1999/11/13 01:50:59 mdw
- * Multiprecision routines finished and tested.
- *
- * Revision 1.1 1999/09/03 08:41:12 mdw
- * Initial import.
- *
- */
-
/*----- Header files ------------------------------------------------------*/
#include <assert.h>
#include "mptypes.h"
#include "mpx.h"
+#include "bitops.h"
/*----- Loading and storing -----------------------------------------------*/
MPX_ZERO(v, vl);
}
+/* --- @mpx_storel2cn@ --- *
+ *
+ * Arguments: @const mpw *v, *vl@ = base and limit of source vector
+ * @void *pp@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores a negative MP in an octet array, least significant
+ * octet first, as two's complement. High-end octets are
+ * silently discarded if there isn't enough space for them.
+ * This obviously makes the output bad.
+ */
+
+void mpx_storel2cn(const mpw *v, const mpw *vl, void *pp, size_t sz)
+{
+ unsigned c = 1;
+ unsigned b = 0;
+ mpw n, w = 0;
+ octet *p = pp, *q = p + sz;
+ unsigned bits = 0;
+
+ while (p < q) {
+ if (bits < 8) {
+ if (v >= vl) {
+ b = w;
+ break;
+ }
+ n = *v++;
+ b = w | n << bits;
+ w = n >> (8 - bits);
+ bits += MPW_BITS - 8;
+ } else {
+ b = w;
+ w >>= 8;
+ bits -= 8;
+ }
+ b = U8(~b + c);
+ c = c && !b;
+ *p++ = b;
+ }
+ while (p < q) {
+ b = U8(~b + c);
+ c = c && !b;
+ *p++ = b;
+ b = 0;
+ }
+}
+
+/* --- @mpx_loadl2cn@ --- *
+ *
+ * Arguments: @mpw *v, *vl@ = base and limit of destination vector
+ * @const void *pp@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads a negative MP in an octet array, least significant
+ * octet first, as two's complement. High-end octets are
+ * ignored if there isn't enough space for them. This probably
+ * means you made the wrong choice coming here.
+ */
+
+void mpx_loadl2cn(mpw *v, mpw *vl, const void *pp, size_t sz)
+{
+ unsigned n;
+ unsigned c = 1;
+ mpw w = 0;
+ const octet *p = pp, *q = p + sz;
+ unsigned bits = 0;
+
+ if (v >= vl)
+ return;
+ while (p < q) {
+ n = U8(~(*p++) + c);
+ c = c && !n;
+ w |= n << bits;
+ bits += 8;
+ if (bits >= MPW_BITS) {
+ *v++ = MPW(w);
+ w = n >> (MPW_BITS - bits + 8);
+ bits -= MPW_BITS;
+ if (v >= vl)
+ return;
+ }
+ }
+ *v++ = w;
+ MPX_ZERO(v, vl);
+}
+
+/* --- @mpx_storeb2cn@ --- *
+ *
+ * Arguments: @const mpw *v, *vl@ = base and limit of source vector
+ * @void *pp@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores a negative MP in an octet array, most significant
+ * octet first, as two's complement. High-end octets are
+ * silently discarded if there isn't enough space for them,
+ * which probably isn't what you meant.
+ */
+
+void mpx_storeb2cn(const mpw *v, const mpw *vl, void *pp, size_t sz)
+{
+ mpw n, w = 0;
+ unsigned b = 0;
+ unsigned c = 1;
+ octet *p = pp, *q = p + sz;
+ unsigned bits = 0;
+
+ while (q > p) {
+ if (bits < 8) {
+ if (v >= vl) {
+ b = w;
+ break;
+ }
+ n = *v++;
+ b = w | n << bits;
+ w = n >> (8 - bits);
+ bits += MPW_BITS - 8;
+ } else {
+ b = w;
+ w >>= 8;
+ bits -= 8;
+ }
+ b = U8(~b + c);
+ c = c && !b;
+ *--q = b;
+ }
+ while (q > p) {
+ b = ~b + c;
+ c = c && !(b & 0xff);
+ *--q = b;
+ b = 0;
+ }
+}
+
+/* --- @mpx_loadb2cn@ --- *
+ *
+ * Arguments: @mpw *v, *vl@ = base and limit of destination vector
+ * @const void *pp@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads a negative MP in an octet array, most significant octet
+ * first as two's complement. High-end octets are ignored if
+ * there isn't enough space for them. This probably means you
+ * chose this function wrongly.
+ */
+
+void mpx_loadb2cn(mpw *v, mpw *vl, const void *pp, size_t sz)
+{
+ unsigned n;
+ unsigned c = 1;
+ mpw w = 0;
+ const octet *p = pp, *q = p + sz;
+ unsigned bits = 0;
+
+ if (v >= vl)
+ return;
+ while (q > p) {
+ n = U8(~(*--q) + c);
+ c = c && !n;
+ w |= n << bits;
+ bits += 8;
+ if (bits >= MPW_BITS) {
+ *v++ = MPW(w);
+ w = n >> (MPW_BITS - bits + 8);
+ bits -= MPW_BITS;
+ if (v >= vl)
+ return;
+ }
+ }
+ *v++ = w;
+ MPX_ZERO(v, vl);
+}
+
/*----- Logical shifting --------------------------------------------------*/
/* --- @mpx_lsl@ --- *
/* --- Handle a shift by a multiple of the word size --- */
if (nb == 0) {
- MPX_COPY(dv + nw, dvl, av, avl);
- memset(dv, 0, MPWS(nw));
+ if (nw >= dvl - dv)
+ MPX_ZERO(dv, dvl);
+ else {
+ MPX_COPY(dv + nw, dvl, av, avl);
+ memset(dv, 0, MPWS(nw));
+ }
}
/* --- And finally the difficult case --- *
done:;
}
+/* --- @mpx_lslc@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = source vector base and limit
+ * @size_t n@ = number of bit positions to shift by
+ *
+ * Returns: ---
+ *
+ * Use: Performs a logical shift left operation on an integer, only
+ * it fills in the bits with ones instead of zeroes.
+ */
+
+void mpx_lslc(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, size_t n)
+{
+ size_t nw;
+ unsigned nb;
+
+ /* --- Trivial special case --- */
+
+ if (n == 0)
+ MPX_COPY(dv, dvl, av, avl);
+
+ /* --- Single bit shifting --- */
+
+ else if (n == 1) {
+ mpw w = 1;
+ while (av < avl) {
+ mpw t;
+ if (dv >= dvl)
+ goto done;
+ t = *av++;
+ *dv++ = MPW((t << 1) | w);
+ w = t >> (MPW_BITS - 1);
+ }
+ if (dv >= dvl)
+ goto done;
+ *dv++ = MPW(w);
+ MPX_ZERO(dv, dvl);
+ goto done;
+ }
+
+ /* --- Break out word and bit shifts for more sophisticated work --- */
+
+ nw = n / MPW_BITS;
+ nb = n % MPW_BITS;
+
+ /* --- Handle a shift by a multiple of the word size --- */
+
+ if (nb == 0) {
+ if (nw >= dvl - dv)
+ MPX_ONE(dv, dvl);
+ else {
+ MPX_COPY(dv + nw, dvl, av, avl);
+ MPX_ONE(dv, dv + nw);
+ }
+ }
+
+ /* --- And finally the difficult case --- *
+ *
+ * This is a little convoluted, because I have to start from the end and
+ * work backwards to avoid overwriting the source, if they're both the same
+ * block of memory.
+ */
+
+ else {
+ mpw w;
+ size_t nr = MPW_BITS - nb;
+ size_t dvn = dvl - dv;
+ size_t avn = avl - av;
+
+ if (dvn <= nw) {
+ MPX_ONE(dv, dvl);
+ goto done;
+ }
+
+ if (dvn > avn + nw) {
+ size_t off = avn + nw + 1;
+ MPX_ZERO(dv + off, dvl);
+ dvl = dv + off;
+ w = 0;
+ } else {
+ avl = av + dvn - nw;
+ w = *--avl << nb;
+ }
+
+ while (avl > av) {
+ mpw t = *--avl;
+ *--dvl = (t >> nr) | w;
+ w = t << nb;
+ }
+
+ *--dvl = (MPW_MAX >> nr) | w;
+ MPX_ONE(dv, dvl);
+ }
+
+done:;
+}
+
/* --- @mpx_lsr@ --- *
*
* Arguments: @mpw *dv, *dvl@ = destination vector base and limit
/* --- Single bit shifting --- */
else if (n == 1) {
- mpw w = *av++ >> 1;
+ mpw w = av < avl ? *av++ >> 1 : 0;
while (av < avl) {
mpw t;
if (dv >= dvl)
/* --- Handle a shift by a multiple of the word size --- */
- if (nb == 0)
- MPX_COPY(dv, dvl, av + nw, avl);
+ if (nb == 0) {
+ if (nw >= avl - av)
+ MPX_ZERO(dv, dvl);
+ else
+ MPX_COPY(dv, dvl, av + nw, avl);
+ }
/* --- And finally the difficult case --- */
size_t nr = MPW_BITS - nb;
av += nw;
- w = *av++;
+ w = av < avl ? *av++ : 0;
while (av < avl) {
mpw t;
if (dv >= dvl)
done:;
}
+/*----- Bitwise operations ------------------------------------------------*/
+
+/* --- @mpx_bitop@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector
+ * @const mpw *av, *avl@ = first source vector
+ * @const mpw *bv, *bvl@ = second source vector
+ *
+ * Returns: ---
+ *
+ * Use; Provides the dyadic boolean functions.
+ */
+
+#define MPX_BITBINOP(string) \
+ \
+void mpx_bit##string(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, \
+ const mpw *bv, const mpw *bvl) \
+{ \
+ MPX_SHRINK(av, avl); \
+ MPX_SHRINK(bv, bvl); \
+ \
+ while (dv < dvl) { \
+ mpw a, b; \
+ a = (av < avl) ? *av++ : 0; \
+ b = (bv < bvl) ? *bv++ : 0; \
+ *dv++ = B##string(a, b); \
+ } \
+}
+
+MPX_DOBIN(MPX_BITBINOP)
+
+void mpx_not(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl)
+{
+ MPX_SHRINK(av, avl);
+
+ while (dv < dvl) {
+ mpw a;
+ a = (av < avl) ? *av++ : 0;
+ *dv++ = ~a;
+ }
+}
+
/*----- Unsigned arithmetic -----------------------------------------------*/
/* --- @mpx_2c@ --- *
MPX_UADDN(dv, dvl, 1);
}
+/* --- @mpx_ueq@ --- *
+ *
+ * Arguments: @const mpw *av, *avl@ = first argument vector base and limit
+ * @const mpw *bv, *bvl@ = second argument vector base and limit
+ *
+ * Returns: Nonzero if the two vectors are equal.
+ *
+ * Use: Performs an unsigned integer test for equality.
+ */
+
+int mpx_ueq(const mpw *av, const mpw *avl, const mpw *bv, const mpw *bvl)
+{
+ MPX_SHRINK(av, avl);
+ MPX_SHRINK(bv, bvl);
+ if (avl - av != bvl - bv)
+ return (0);
+ while (av < avl) {
+ if (*av++ != *bv++)
+ return (0);
+ }
+ return (1);
+}
+
/* --- @mpx_ucmp@ --- *
*
* Arguments: @const mpw *av, *avl@ = first argument vector base and limit
}
return (0);
}
-
+
/* --- @mpx_uadd@ --- *
*
* Arguments: @mpw *dv, *dvl@ = destination vector base and limit
void mpx_uaddn(mpw *dv, mpw *dvl, mpw n) { MPX_UADDN(dv, dvl, n); }
+/* --- @mpx_uaddnlsl@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination and first argument vector
+ * @mpw a@ = second argument
+ * @unsigned o@ = offset in bits
+ *
+ * Returns: ---
+ *
+ * Use: Computes %$d + 2^o a$%. If the result overflows then
+ * high-order bits are discarded, as usual. We must have
+ * @0 < o < MPW_BITS@.
+ */
+
+void mpx_uaddnlsl(mpw *dv, mpw *dvl, mpw a, unsigned o)
+{
+ mpd x = (mpd)a << o;
+
+ while (x && dv < dvl) {
+ x += *dv;
+ *dv++ = MPW(x);
+ x >>= MPW_BITS;
+ }
+}
+
/* --- @mpx_usub@ --- *
*
* Arguments: @mpw *dv, *dvl@ = destination vector base and limit
void mpx_usubn(mpw *dv, mpw *dvl, mpw n) { MPX_USUBN(dv, dvl, n); }
+/* --- @mpx_uaddnlsl@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination and first argument vector
+ * @mpw a@ = second argument
+ * @unsigned o@ = offset in bits
+ *
+ * Returns: ---
+ *
+ * Use: Computes %$d + 2^o a$%. If the result overflows then
+ * high-order bits are discarded, as usual. We must have
+ * @0 < o < MPW_BITS@.
+ */
+
+void mpx_usubnlsl(mpw *dv, mpw *dvl, mpw a, unsigned o)
+{
+ mpw b = a >> (MPW_BITS - o);
+ a <<= o;
+
+ if (dv < dvl) {
+ mpd x = (mpd)*dv - (mpd)a;
+ *dv++ = MPW(x);
+ if (x >> MPW_BITS)
+ b++;
+ MPX_USUBN(dv, dvl, b);
+ }
+}
+
/* --- @mpx_umul@ --- *
*
* Arguments: @mpw *dv, *dvl@ = destination vector base and limit
d = dvl[-1];
for (b = MPW_BITS / 2; b; b >>= 1) {
- if (d < (MPW_MAX >> b)) {
+ if (d <= (MPW_MAX >> b)) {
d <<= b;
norm += b;
}
{
mpd yh = (mpd)d * q;
- mpd yl = (mpd)dd * q;
+ mpd yy = (mpd)dd * q;
+ mpw yl;
- if (yl > MPW_MAX) {
- yh += yl >> MPW_BITS;
- yl &= MPW_MAX;
- }
+ if (yy > MPW_MAX)
+ yh += yy >> MPW_BITS;
+ yl = MPW(yy);
while (yh > rh || (yh == rh && yl > rrr)) {
q--;
yh -= d;
- if (yl < dd) {
- yh++;
- yl += MPW_MAX;
- }
- yl -= dd;
+ if (yl < dd)
+ yh--;
+ yl = MPW(yl - dd);
}
}
mpx_lsr(rv, rvl, rv, rvl, norm);
}
+/* --- @mpx_udivn@ --- *
+ *
+ * Arguments: @mpw *qv, *qvl@ = storage for the quotient (may overlap
+ * dividend)
+ * @const mpw *rv, *rvl@ = dividend
+ * @mpw d@ = single-precision divisor
+ *
+ * Returns: Remainder after divison.
+ *
+ * Use: Performs a single-precision division operation.
+ */
+
+mpw mpx_udivn(mpw *qv, mpw *qvl, const mpw *rv, const mpw *rvl, mpw d)
+{
+ size_t i;
+ size_t ql = qvl - qv;
+ mpd r = 0;
+
+ i = rvl - rv;
+ while (i > 0) {
+ i--;
+ r = (r << MPW_BITS) | rv[i];
+ if (i < ql)
+ qv[i] = r / d;
+ r %= d;
+ }
+ return (MPW(r));
+}
+
/*----- Test rig ----------------------------------------------------------*/
#ifdef TEST_RIG
if (!ok)
dumpbits("input data", v->buf, v->len);
- free(m);
+ xfree(m);
dstr_destroy(&d);
return (ok);
}
+static int twocl(dstr *v)
+{
+ dstr d = DSTR_INIT;
+ mpw *m, *ml;
+ size_t sz;
+ int ok = 1;
+
+ sz = v[0].len; if (v[1].len > sz) sz = v[1].len;
+ dstr_ensure(&d, sz);
+
+ sz = MPW_RQ(sz);
+ m = xmalloc(MPWS(sz));
+ ml = m + sz;
+
+ mpx_loadl(m, ml, v[0].buf, v[0].len);
+ mpx_storel2cn(m, ml, d.buf, v[1].len);
+ if (memcmp(d.buf, v[1].buf, v[1].len)) {
+ dumpbits("\n*** storel2cn failed", d.buf, v[1].len);
+ ok = 0;
+ }
+
+ mpx_loadl2cn(m, ml, v[1].buf, v[1].len);
+ mpx_storel(m, ml, d.buf, v[0].len);
+ if (memcmp(d.buf, v[0].buf, v[0].len)) {
+ dumpbits("\n*** loadl2cn failed", d.buf, v[0].len);
+ ok = 0;
+ }
+
+ if (!ok) {
+ dumpbits("pos", v[0].buf, v[0].len);
+ dumpbits("neg", v[1].buf, v[1].len);
+ }
+
+ xfree(m);
+ dstr_destroy(&d);
+
+ return (ok);
+}
+
+static int twocb(dstr *v)
+{
+ dstr d = DSTR_INIT;
+ mpw *m, *ml;
+ size_t sz;
+ int ok = 1;
+
+ sz = v[0].len; if (v[1].len > sz) sz = v[1].len;
+ dstr_ensure(&d, sz);
+
+ sz = MPW_RQ(sz);
+ m = xmalloc(MPWS(sz));
+ ml = m + sz;
+
+ mpx_loadb(m, ml, v[0].buf, v[0].len);
+ mpx_storeb2cn(m, ml, d.buf, v[1].len);
+ if (memcmp(d.buf, v[1].buf, v[1].len)) {
+ dumpbits("\n*** storeb2cn failed", d.buf, v[1].len);
+ ok = 0;
+ }
+
+ mpx_loadb2cn(m, ml, v[1].buf, v[1].len);
+ mpx_storeb(m, ml, d.buf, v[0].len);
+ if (memcmp(d.buf, v[0].buf, v[0].len)) {
+ dumpbits("\n*** loadb2cn failed", d.buf, v[0].len);
+ ok = 0;
+ }
+
+ if (!ok) {
+ dumpbits("pos", v[0].buf, v[0].len);
+ dumpbits("neg", v[1].buf, v[1].len);
+ }
+
+ xfree(m);
+ dstr_destroy(&d);
+
+ return (ok);
+}
+
static int lsl(dstr *v)
{
mpw *a, *al;
ALLOC(d, dl, al - a + (n + MPW_BITS - 1) / MPW_BITS);
mpx_lsl(d, dl, a, al, n);
- if (MPX_UCMP(d, dl, !=, c, cl)) {
+ if (!mpx_ueq(d, dl, c, cl)) {
fprintf(stderr, "\n*** lsl(%i) failed\n", n);
dumpmp(" a", a, al);
dumpmp("expected", c, cl);
ok = 0;
}
- free(a); free(c); free(d);
+ xfree(a); xfree(c); xfree(d);
+ return (ok);
+}
+
+static int lslc(dstr *v)
+{
+ mpw *a, *al;
+ int n = *(int *)v[1].buf;
+ mpw *c, *cl;
+ mpw *d, *dl;
+ int ok = 1;
+
+ LOAD(a, al, &v[0]);
+ LOAD(c, cl, &v[2]);
+ ALLOC(d, dl, al - a + (n + MPW_BITS - 1) / MPW_BITS);
+
+ mpx_lslc(d, dl, a, al, n);
+ if (!mpx_ueq(d, dl, c, cl)) {
+ fprintf(stderr, "\n*** lslc(%i) failed\n", n);
+ dumpmp(" a", a, al);
+ dumpmp("expected", c, cl);
+ dumpmp(" result", d, dl);
+ ok = 0;
+ }
+
+ xfree(a); xfree(c); xfree(d);
return (ok);
}
ALLOC(d, dl, al - a + (n + MPW_BITS - 1) / MPW_BITS + 1);
mpx_lsr(d, dl, a, al, n);
- if (MPX_UCMP(d, dl, !=, c, cl)) {
+ if (!mpx_ueq(d, dl, c, cl)) {
fprintf(stderr, "\n*** lsr(%i) failed\n", n);
dumpmp(" a", a, al);
dumpmp("expected", c, cl);
ok = 0;
}
- free(a); free(c); free(d);
+ xfree(a); xfree(c); xfree(d);
return (ok);
}
ALLOC(d, dl, MAX(al - a, bl - b) + 1);
mpx_uadd(d, dl, a, al, b, bl);
- if (MPX_UCMP(d, dl, !=, c, cl)) {
+ if (!mpx_ueq(d, dl, c, cl)) {
fprintf(stderr, "\n*** uadd failed\n");
dumpmp(" a", a, al);
dumpmp(" b", b, bl);
ok = 0;
}
- free(a); free(b); free(c); free(d);
+ xfree(a); xfree(b); xfree(c); xfree(d);
return (ok);
}
ALLOC(d, dl, al - a);
mpx_usub(d, dl, a, al, b, bl);
- if (MPX_UCMP(d, dl, !=, c, cl)) {
+ if (!mpx_ueq(d, dl, c, cl)) {
fprintf(stderr, "\n*** usub failed\n");
dumpmp(" a", a, al);
dumpmp(" b", b, bl);
ok = 0;
}
- free(a); free(b); free(c); free(d);
+ xfree(a); xfree(b); xfree(c); xfree(d);
return (ok);
}
ALLOC(d, dl, (al - a) + (bl - b));
mpx_umul(d, dl, a, al, b, bl);
- if (MPX_UCMP(d, dl, !=, c, cl)) {
+ if (!mpx_ueq(d, dl, c, cl)) {
fprintf(stderr, "\n*** umul failed\n");
dumpmp(" a", a, al);
dumpmp(" b", b, bl);
ok = 0;
}
- free(a); free(b); free(c); free(d);
+ xfree(a); xfree(b); xfree(c); xfree(d);
return (ok);
}
ALLOC(d, dl, 2 * (al - a));
mpx_usqr(d, dl, a, al);
- if (MPX_UCMP(d, dl, !=, c, cl)) {
+ if (!mpx_ueq(d, dl, c, cl)) {
fprintf(stderr, "\n*** usqr failed\n");
dumpmp(" a", a, al);
dumpmp("expected", c, cl);
ok = 0;
}
- free(a); free(c); free(d);
+ xfree(a); xfree(c); xfree(d);
return (ok);
}
ALLOC(s, sl, (bl - b) + 1);
mpx_udiv(qq, qql, a, al, b, bl, s, sl);
- if (MPX_UCMP(qq, qql, !=, q, ql) ||
- MPX_UCMP(a, al, !=, r, rl)) {
+ if (!mpx_ueq(qq, qql, q, ql) ||
+ !mpx_ueq(a, al, r, rl)) {
fprintf(stderr, "\n*** udiv failed\n");
dumpmp(" divisor", b, bl);
dumpmp("expect r", r, rl);
ok = 0;
}
- free(a); free(b); free(r); free(q); free(s); free(qq);
+ xfree(a); xfree(b); xfree(r); xfree(q); xfree(s); xfree(qq);
return (ok);
}
static test_chunk defs[] = {
{ "load-store", loadstore, { &type_hex, 0 } },
+ { "2cl", twocl, { &type_hex, &type_hex, } },
+ { "2cb", twocb, { &type_hex, &type_hex, } },
{ "lsl", lsl, { &type_hex, &type_int, &type_hex, 0 } },
+ { "lslc", lslc, { &type_hex, &type_int, &type_hex, 0 } },
{ "lsr", lsr, { &type_hex, &type_int, &type_hex, 0 } },
{ "uadd", uadd, { &type_hex, &type_hex, &type_hex, 0 } },
{ "usub", usub, { &type_hex, &type_hex, &type_hex, 0 } },
return (0);
}
-
#endif
/*----- That's all, folks -------------------------------------------------*/