X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/fa16f6d37b362288e3086fbb34344bc817c09796..f09e814abfcb58c0bb5423589e2940c205106e8d:/mpx.c diff --git a/mpx.c b/mpx.c index f89a89b..4097b3e 100644 --- a/mpx.c +++ b/mpx.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: mpx.c,v 1.11 2001/04/03 19:36:05 mdw Exp $ + * $Id: mpx.c,v 1.12 2002/10/06 22:52:50 mdw Exp $ * * Low-level multiprecision arithmetic * @@ -30,6 +30,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: mpx.c,v $ + * Revision 1.12 2002/10/06 22:52:50 mdw + * Pile of changes for supporting two's complement properly. + * * Revision 1.11 2001/04/03 19:36:05 mdw * Add some simple bitwise operations so that Perl can use them. * @@ -233,6 +236,186 @@ void mpx_loadb(mpw *v, mpw *vl, const void *pp, size_t sz) 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 = !b; + *p++ = b; + } + while (p < q) { + b = U8(~b + 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 = !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 = !b; + *--q = b; + } + while (q > p) { + b = ~b + 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 = !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@ --- * @@ -405,7 +588,7 @@ done:; /*----- Bitwise operations ------------------------------------------------*/ -/* --- @mpx_and@, @mpx_or@, @mpx_xor@, @mpx_not@ --- * +/* --- @mpx_bitop@ --- * * * Arguments: @mpw *dv, *dvl@ = destination vector * @const mpw *av, *avl@ = first source vector @@ -413,13 +596,13 @@ done:; * * Returns: --- * - * Use; Does the obvious bitwise operations. + * Use; Provides the dyadic boolean functions. */ -#define MPX_BITBINOP(name, op) \ +#define MPX_BITBINOP(string) \ \ -void mpx_##name(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, \ - const mpw *bv, const mpw *bvl) \ +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); \ @@ -428,13 +611,11 @@ void mpx_##name(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, \ mpw a, b; \ a = (av < avl) ? *av++ : 0; \ b = (bv < bvl) ? *bv++ : 0; \ - *dv++ = a op b; \ + *dv++ = MPX_B##string(a, b); \ } \ } -MPX_BITBINOP(and, &) -MPX_BITBINOP(or, |) -MPX_BITBINOP(xor, ^) +MPX_DOBIN(MPX_BITBINOP) void mpx_not(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl) { @@ -1130,6 +1311,84 @@ static int loadstore(dstr *v) 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); + } + + free(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); + } + + free(m); + dstr_destroy(&d); + + return (ok); +} + static int lsl(dstr *v) { mpw *a, *al; @@ -1320,6 +1579,8 @@ static int udiv(dstr *v) 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 } }, { "lsr", lsr, { &type_hex, &type_int, &type_hex, 0 } }, { "uadd", uadd, { &type_hex, &type_hex, &type_hex, 0 } },