Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <iomanip>
- #include <cstdint>
- #include <sstream>
- using namespace std;
- struct Context {
- uint8_t X:1;
- uint8_t N:1;
- uint8_t Z:1;
- uint8_t V:1;
- uint8_t C:1;
- Context(uint8_t _X, uint8_t _Z)
- : X(_X != 0), N(0), Z(_Z != 0), V(0), C(_X != 0) {
- }
- bool operator==(const Context& other) {
- return X == other.X &&
- N == other.N &&
- Z == other.Z &&
- V == other.V &&
- C == other.C;
- }
- bool operator!=(const Context& other) {
- return !(*this == other);
- }
- };
- ostream& operator<<(ostream& out, const Context& ctx) {
- out << (ctx.X ? 'X' : 'x')
- << (ctx.N ? 'N' : 'n')
- << (ctx.Z ? 'Z' : 'z')
- << (ctx.V ? 'V' : 'v')
- << (ctx.C ? 'C' : 'c');
- return out;
- }
- uint8_t abcd(Context *ctx, uint8_t xx, uint8_t yy) {
- uint8_t ss = xx + yy + ctx->X;
- // Normal carry computation for addition:
- // (sm & dm) | (~rm & dm) | (sm & ~rm)
- uint8_t bc = ((xx & yy) | (~ss & xx) | (~ss & yy)) & 0x88;
- // Compute if we have a decimal carry in both nibbles:
- uint8_t dc = (((ss + 0x66) ^ ss) & 0x110) >> 1;
- uint8_t corf = (bc | dc) - ((bc | dc) >> 2);
- uint8_t rr = ss + corf;
- // Compute flags.
- // Carry has two parts: normal carry for addition
- // (computed above) OR'ed with normal carry for
- // addition with corf:
- // (sm & dm) | (~rm & dm) | (sm & ~rm)
- // but simplified because sm = 0 and ~sm = 1 for corf:
- ctx->X = ctx->C = (bc | (ss & ~rr)) >> 7;
- // Normal overflow computation for addition with corf:
- // (sm & dm & ~rm) | (~sm & ~dm & rm)
- // but simplified because sm = 0 and ~sm = 1 for corf:
- ctx->V = (~ss & rr) >> 7;
- // Accumulate zero flag:
- ctx->Z = ctx->Z & (rr == 0);
- ctx->N = rr >> 7;
- return rr;
- }
- uint8_t sbcd(Context *ctx, uint8_t xx, uint8_t yy) {
- uint8_t dd = xx - yy - ctx->X;
- // Normal carry computation for subtraction:
- // (sm & ~dm) | (rm & ~dm) | (sm & rm)
- uint8_t bc = ((~xx & yy) | (dd & ~xx) | (dd & yy)) & 0x88;
- uint8_t corf = bc - (bc >> 2);
- uint8_t rr = dd - corf;
- // Compute flags.
- // Carry has two parts: normal carry for subtraction
- // (computed above) OR'ed with normal carry for
- // subtraction with corf:
- // (sm & ~dm) | (rm & ~dm) | (sm & rm)
- // but simplified because sm = 0 and ~sm = 1 for corf:
- ctx->X = ctx->C = (bc | (~dd & rr)) >> 7;
- // Normal overflow computation for subtraction with corf:
- // (~sm & dm & ~rm) | (sm & ~dm & rm)
- // but simplified because sm = 0 and ~sm = 1 for corf:
- ctx->V = (dd & ~rr) >> 7;
- // Accumulate zero flag:
- ctx->Z = ctx->Z & (rr == 0);
- ctx->N = rr >> 7;
- return rr;
- }
- uint8_t abcd_emu(Context *ctx, uint8_t xx, uint8_t yy) {
- uint8_t n1, n2, res, sum;
- sum = xx + yy + ctx->X;
- n1 = (xx&0xF) + (yy&0xF) + (ctx->X);
- if (n1 > 9) {
- n1 += 6;
- }
- n2 = (xx>>4) + (yy>>4) + (n1>>4);
- if (n2 > 9) {
- ctx->X = ctx->C = 1; // X & C flags
- n2 += 6;
- } else {
- ctx->X = ctx->C = 0; // X & C flags
- }
- res = ((n1&0xF) + ((uint16_t)n2<<4));
- ctx->Z = (res & 0xff) ? 0 : ctx->Z; // Z flag
- ctx->N = (res & 0x80) ? 1 : 0; // N flag
- ctx->V = ((res & 0x80) != 0 && (sum & 0x80) == 0) ? 1 : 0; // V flag
- return res;
- }
- uint8_t sbcd_emu(Context *ctx, uint8_t xx, uint8_t yy) {
- uint8_t c = (xx&0xF) - (yy&0xF) - (ctx->X);
- uint16_t res = ((uint16_t)xx) - yy - (ctx->X);
- uint8_t corf = 0;
- if ((res & 0xF) >= 0xA || c > 0) {
- corf = 0x6;
- }
- if ((res & 0xF0) >= 0xA0 || res > 0xFF) {
- corf += 0x60;
- }
- ctx->X = ctx->C = (res > 0xff) ? 1 : 0; // X & C flags
- ctx->Z = (res & 0xff) ? 0 : ctx->Z; // Z flag
- ctx->N = (res & 0x80) ? 1 : 0; // N flag
- ctx->V = ((res & 0xff) + corf > 0xff) ? 1 : 0; // V flag
- return res & 0xFF;
- }
- int main() {
- stringstream sout;
- cout << setfill('0') << uppercase << hex;
- sout << setfill('0') << uppercase << hex;
- uint32_t results, flags;
- results = 0;
- flags = 0;
- cout << "\t\terrors value flags\n";
- for (int ii = 0; ii < 256; ii++) {
- for (int jj = 0; jj < 256; jj++) {
- for (int cin = 0; cin < 2; cin++) {
- for (int zin = 0; zin < 2; zin++) {
- Context ctx1(cin, zin), ctx2(cin, zin);
- uint8_t val1 = abcd(&ctx1, jj, ii);
- uint8_t val2 = abcd_emu(&ctx2, jj, ii);
- if (val1 != val2 || ctx1 != ctx2) {
- if (val1 != val2) {
- results++;
- }
- if (ctx1 != ctx2) {
- flags++;
- }
- sout << Context(cin, zin) << " abcd "
- << '$' << setw(2) << +jj << ','
- << '$' << setw(2) << +ii << '='
- << '$' << setw(2) << +val2 << ' '
- << ctx2 << " ("
- << '$' << setw(2) << +val1 << ' '
- << ctx1 << ")\n";
- }
- }
- }
- }
- }
- cout << "\t\tabcd $" << setw(5) << results
- << " $" << setw(5) << flags << '\n';
- results = 0;
- flags = 0;
- for (int ii = 0; ii < 256; ii++) {
- for (int jj = 0; jj < 256; jj++) {
- for (int cin = 0; cin < 2; cin++) {
- for (int zin = 0; zin < 2; zin++) {
- Context ctx1(cin, zin), ctx2(cin, zin);
- uint8_t val1 = sbcd(&ctx1, jj, ii);
- uint8_t val2 = sbcd_emu(&ctx2, jj, ii);
- if (val1 != val2 || ctx1 != ctx2) {
- if (val1 != val2) {
- results++;
- }
- if (ctx1 != ctx2) {
- flags++;
- }
- sout << Context(cin, zin) << " sbcd "
- << '$' << setw(2) << +jj << ','
- << '$' << setw(2) << +ii << '='
- << '$' << setw(2) << +val2 << ' '
- << ctx2 << " ("
- << '$' << setw(2) << +val1 << ' '
- << ctx1 << ")\n";
- }
- }
- }
- }
- }
- cout << "\t\tsbcd $" << setw(5) << results
- << " $" << setw(5) << flags << '\n';
- cout << sout.rdbuf();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement