Implementation
Future<void> testIntOperations() async {
await test("2's complement int operations", () async {
Model m = newModel();
m.wordSize = 16;
m.displayMode = DisplayMode.decimal;
m.integerSignMode = SignMode.twosComplement;
// -1 + 1 = 0, set carry
m.cFlag = false;
m.yI = BigInt.from(-1);
m.xI = BigInt.from(1);
Operations16.plus.intCalc!(m);
await expect(m.xI, BigInt.zero);
await expect(m.cFlag, true);
// 0 + 1 = 1, clear carry
m.cFlag = true;
m.yI = BigInt.from(0);
m.xI = BigInt.from(1);
Operations16.plus.intCalc!(m);
await expect(m.xI, BigInt.one);
await expect(m.cFlag, false);
// 32767 * 2 = 32766, set overflow
m.gFlag = false;
m.yI = BigInt.from(32767);
m.xI = BigInt.from(2);
Operations16.mult.intCalc!(m);
await expect(m.xI, BigInt.from(32766));
await expect(m.gFlag, true);
// 1440 / -12 = -120, clear carry
m.cFlag = true;
m.yI = BigInt.from(1440);
m.xI = BigInt.from(-12);
Operations16.div.intCalc!(m);
await expect(m.xI, BigInt.from(-120));
await expect(m.cFlag, false);
});
await test("1's complement int operations", () async {
Model m = newModel();
m.wordSize = 16;
m.integerSignMode = SignMode.onesComplement;
m.wordSize = 4;
// -1 + -1 = -2, set carry
m.cFlag = true;
m.yI = BigInt.from(-1);
m.xI = BigInt.from(-1);
Operations16.plus.intCalc!(m);
await expect(m.xI, BigInt.from(-2));
await expect(m.cFlag, true);
// 3 - 4 = -1, set borrow (that is, cFlag)
m.cFlag = false;
m.yI = BigInt.from(3);
m.xI = BigInt.from(4);
Operations16.minus.intCalc!(m);
await expect(m.xI, BigInt.from(-1));
await expect(m.cFlag, true);
// -3 + 3 = 0, no carry
m.cFlag = true;
m.yI = BigInt.from(-3);
m.xI = BigInt.from(3);
Operations16.plus.intCalc!(m);
await expect(m.xI, BigInt.from(0));
await expect(m.cFlag, false);
// 6 - 5 = 1, no borrow
m.cFlag = true;
m.yI = BigInt.from(6);
m.xI = BigInt.from(5);
Operations16.minus.intCalc!(m);
await expect(m.xI, BigInt.from(1));
await expect(m.cFlag, false);
});
await test("subtraction carry, 1's and 2's complement", () async {
Model m = newModel();
m.wordSize = 4;
for (final c in [SignMode.onesComplement, SignMode.twosComplement]) {
m.integerSignMode = c;
// -6 - -4 = -2, carry set
m.cFlag = false;
m.yI = BigInt.from(-6);
m.xI = BigInt.from(-4);
Operations16.minus.intCalc!(m);
await expect(m.xI, BigInt.from(-2));
await expect(m.cFlag, true);
// 6 - 1 = 5, carry cleared
m.cFlag = true;
m.yI = BigInt.from(6);
m.xI = BigInt.from(1);
Operations16.minus.intCalc!(m);
await expect(m.xI, BigInt.from(5));
await expect(m.cFlag, false);
}
});
await test("2's complement range", () async {
Model m = newModel();
m.wordSize = 4;
// 7 + 6 = -3, G set, C cleared
m.cFlag = true;
m.gFlag = false;
m.yI = BigInt.from(7);
m.xI = BigInt.from(6);
Operations16.plus.intCalc!(m);
await expect(m.xI, BigInt.from(-3));
await expect(m.cFlag, false);
await expect(m.gFlag, true);
});
await test('int rmd', () async {
Model m = newModel();
m.yI = BigInt.from(0x66);
m.xI = BigInt.from(7);
Operations16.div.intCalc!(m);
await expect(m.xI, BigInt.from(0xe));
m.pushStack();
m.xI = BigInt.from(2);
Operations16.div.intCalc!(m);
await expect(m.xI, BigInt.from(0x7));
m.pushStack();
m.xI = BigInt.from(4);
Operations16.rmd.intCalc!(m);
await expect(m.xI, BigInt.from(0x3));
});
await test('logical operations', () async {
// Not
Model m = newModel();
await expect(m.wordSize, 16); // default
m.displayMode = DisplayMode.bin;
m.x = m.tryParseValue('11111111')!;
Operations16.not.intCalc!(m);
await expect(m.x, m.tryParseValue('1111111100000000'));
// and
m.y = m.tryParseValue('10101')!;
m.x = m.tryParseValue('10011')!;
Operations16.and.intCalc!(m);
await expect(m.x, m.tryParseValue('10001'));
// or
m.y = m.tryParseValue('10101')!;
m.x = m.tryParseValue('10011')!;
Operations16.or.intCalc!(m);
await expect(m.x, m.tryParseValue('10111'));
// xor
m.y = m.tryParseValue('1010101')!;
m.x = m.tryParseValue('1011101')!;
Operations16.xor.intCalc!(m);
await expect(m.x, m.tryParseValue('1000'));
// sl (shift left)
m.wordSize = 8;
m.x = m.tryParseValue('10011100')!;
Operations16.sl.intCalc!(m);
await expect(m.x, m.tryParseValue('00111000'));
await expect(m.cFlag, true);
Operations16.sl.intCalc!(m);
await expect(m.x, m.tryParseValue('01110000'));
await expect(m.cFlag, false);
// sr (shift right)
Operations16.sr.intCalc!(m);
await expect(m.x, m.tryParseValue('00111000'));
await expect(m.cFlag, false);
Operations16.sr.intCalc!(m);
await expect(m.cFlag, false);
Operations16.sr.intCalc!(m);
await expect(m.cFlag, false);
Operations16.sr.intCalc!(m);
await expect(m.cFlag, false);
Operations16.sr.intCalc!(m);
await expect(m.x, m.tryParseValue('00000011'));
await expect(m.cFlag, true);
// lj (left justify)
m.xI = BigInt.from(0);
Operations16.lj.intCalc!(m);
await expect(m.x, m.tryParseValue('0'));
await expect(m.y, m.tryParseValue('0'));
m.x = m.tryParseValue('1111')!;
Operations16.lj.intCalc!(m);
await expect(m.x, m.tryParseValue('100'));
await expect(m.y, m.tryParseValue('11110000'));
// asr
m.integerSignMode = SignMode.unsigned;
m.x = m.tryParseValue('10011100')!;
Operations16.asr.intCalc!(m);
await expect(m.x, m.tryParseValue('01001110'));
m.integerSignMode = SignMode.twosComplement;
m.x = m.tryParseValue('10011100')!;
Operations16.asr.intCalc!(m);
await expect(m.x, m.tryParseValue('11001110'));
// rl
m.x = m.tryParseValue('10011100')!;
m.cFlag = false;
Operations16.rl.intCalc!(m);
await expect(m.cFlag, true);
await expect(m.x, m.tryParseValue('00111001'));
Operations16.rl.intCalc!(m);
await expect(m.cFlag, false);
await expect(m.x, m.tryParseValue('01110010'));
// rr
Operations16.rr.intCalc!(m);
await expect(m.cFlag, false);
await expect(m.x, m.tryParseValue('00111001'));
Operations16.rr.intCalc!(m);
await expect(m.cFlag, true);
await expect(m.x, m.tryParseValue('10011100'));
Operations16.rr.intCalc!(m);
await expect(m.cFlag, false);
await expect(m.x, m.tryParseValue('01001110'));
// rlc
m.x = m.tryParseValue('10011100')!;
m.cFlag = false;
Operations16.rlc.intCalc!(m);
await expect(m.cFlag, true);
await expect(m.x, m.tryParseValue('00111000'));
Operations16.rlc.intCalc!(m);
await expect(m.cFlag, false);
await expect(m.x, m.tryParseValue('01110001'));
// rrc
Operations16.rrc.intCalc!(m);
await expect(m.x, m.tryParseValue('00111000'));
m.cFlag = true;
Operations16.rrc.intCalc!(m);
await expect(m.x, m.tryParseValue('10011100'));
await expect(m.cFlag, false);
Operations16.rrc.intCalc!(m);
await expect(m.x, m.tryParseValue('01001110'));
await expect(m.cFlag, false);
// rln
m.x = m.tryParseValue('10011100')!;
m.pushStack();
m.xI = BigInt.one;
m.cFlag = false;
Operations16.rln.intCalc!(m);
await expect(m.cFlag, true);
await expect(m.x, m.tryParseValue('00111001'));
m.x = m.tryParseValue('10011100')!;
m.pushStack();
m.xI = BigInt.two;
m.cFlag = true;
Operations16.rln.intCalc!(m);
await expect(m.cFlag, false);
await expect(m.x, m.tryParseValue('01110010'));
// rrn
m.x = m.tryParseValue('01110010')!;
m.pushStack();
m.xI = BigInt.one;
Operations16.rrn.intCalc!(m);
await expect(m.cFlag, false);
await expect(m.x, m.tryParseValue('00111001'));
m.x = m.tryParseValue('01110010')!;
m.pushStack();
m.xI = BigInt.two;
Operations16.rrn.intCalc!(m);
await expect(m.cFlag, true);
await expect(m.x, m.tryParseValue('10011100'));
m.x = m.tryParseValue('01110010')!;
m.pushStack();
m.xI = BigInt.from(3);
Operations16.rrn.intCalc!(m);
await expect(m.cFlag, false);
await expect(m.x, m.tryParseValue('01001110'));
// rlcn
m.x = m.tryParseValue('10011100')!;
m.cFlag = false;
m.pushStack();
m.xI = BigInt.one;
Operations16.rlcn.intCalc!(m);
await expect(m.cFlag, true);
await expect(m.x, m.tryParseValue('00111000'));
m.x = m.tryParseValue('10011100')!;
m.cFlag = false;
m.pushStack();
m.xI = BigInt.two;
Operations16.rlcn.intCalc!(m);
await expect(m.cFlag, false);
await expect(m.x, m.tryParseValue('01110001'));
// rrcn
m.x = m.tryParseValue('01110001')!;
m.cFlag = false;
m.pushStack();
m.xI = BigInt.one;
Operations16.rrcn.intCalc!(m);
await expect(m.x, m.tryParseValue('00111000'));
await expect(m.cFlag, true);
m.x = m.tryParseValue('01110001')!;
m.cFlag = false;
m.pushStack();
m.xI = BigInt.two;
Operations16.rrcn.intCalc!(m);
await expect(m.x, m.tryParseValue('10011100'));
await expect(m.cFlag, false);
m.x = m.tryParseValue('01110001')!;
m.cFlag = false;
m.pushStack();
m.xI = BigInt.from(3);
Operations16.rrcn.intCalc!(m);
await expect(m.x, m.tryParseValue('01001110'));
await expect(m.cFlag, false);
// cb
m.y = m.tryParseValue('11111111')!;
m.x = m.tryParseValue('00000011')!;
Operations16.cb.intCalc!(m);
await expect(m.x, m.tryParseValue('11110111'));
// sb
m.y = m.tryParseValue('01110000')!;
m.x = m.tryParseValue('00000000')!;
Operations16.sb.intCalc!(m);
await expect(m.x, m.tryParseValue('01110001'));
m.pushStack();
m.xI = BigInt.from(7);
Operations16.sb.intCalc!(m);
await expect(m.x, m.tryParseValue('11110001'));
// maskr
m.xI = BigInt.from(4);
Operations16.maskr.intCalc!(m);
await expect(m.x, m.tryParseValue('00001111'));
m.xI = BigInt.from(0);
Operations16.maskr.intCalc!(m);
await expect(m.x, m.tryParseValue('00000000'));
m.xI = BigInt.from(8);
Operations16.maskr.intCalc!(m);
await expect(m.x, m.tryParseValue('11111111'));
// maskl
m.xI = BigInt.from(3);
Operations16.maskl.intCalc!(m);
await expect(m.x, m.tryParseValue('11100000'));
m.xI = BigInt.from(0);
Operations16.maskl.intCalc!(m);
await expect(m.x, m.tryParseValue('00000000'));
m.xI = BigInt.from(7);
Operations16.maskl.intCalc!(m);
await expect(m.x, m.tryParseValue('11111110'));
m.xI = BigInt.from(8);
Operations16.maskl.intCalc!(m);
await expect(m.x, m.tryParseValue('11111111'));
// #b
m.x = m.tryParseValue('01011101')!;
Operations16.poundB.intCalc!(m);
await expect(m.xI, BigInt.from(5));
m.x = m.tryParseValue('00000000')!;
Operations16.poundB.intCalc!(m);
await expect(m.xI, BigInt.from(0));
m.x = m.tryParseValue('11111111')!;
Operations16.poundB.intCalc!(m);
await expect(m.xI, BigInt.from(8));
});
await test('double operations', () async {
Model m = newModel();
m.wordSize = 5;
await expect(m.signMode, SignMode.twosComplement); // default
m.displayMode = DisplayMode.bin;
// double multiply: 7*6 = 42
m.y = m.tryParseValue('00111')!;
m.x = m.tryParseValue('00110')!;
Operations16.dblx.intCalc!(m);
await expect(m.x, m.tryParseValue('00001'));
await expect(m.y, m.tryParseValue('01010'));
// double divide: -88 / 11
m.x = m.tryParseValue('01000')!; // Z
m.pushStack();
m.x = m.tryParseValue('11101')!; // Y, YZ is -88
m.pushStack();
m.x = m.tryParseValue('01011')!; // X, 11
Operations16.dblDiv.intCalc!(m);
await expect(m.x, m.tryParseValue('11000'));
// double remainder: -87 remainder 11 = -10
m.x = m.tryParseValue('01001')!; // Z
m.pushStack();
m.x = m.tryParseValue('11101')!; // Y, YZ is -87
m.pushStack();
m.x = m.tryParseValue('01011')!; // X, 11
Operations16.dblr.intCalc!(m);
await expect(m.xI, BigInt.from(-10));
// double multiply: Unsigned f723eb313f123827 * a20175becabcde06
// is 9c6623a4aff98347_8e11697b49c322ea
m.wordSize = 64;
m.integerSignMode = SignMode.unsigned;
m.gFlag = true;
m.xI = BigInt.parse('f723eb313f123827', radix: 16);
m.yI = BigInt.parse('a20175becabcde06', radix: 16);
Operations16.dblx.intCalc!(m);
await expect(m.xI, BigInt.parse('9c6623a4aff98347', radix: 16));
await expect(m.yI, BigInt.parse('8e11697b49c322ea', radix: 16));
await expect(m.gFlag, false);
// double divide with above numbers
m.pushStack();
m.xI = BigInt.parse('a20175becabcde06', radix: 16);
Operations16.dblDiv.intCalc!(m);
await expect(m.xI, BigInt.parse('f723eb313f123827', radix: 16));
// double remainder with big numbers
m.xI = BigInt.parse('8e11697b49c322ec', radix: 16);
m.pushStack();
m.xI = BigInt.parse('9c6623a4aff98347', radix: 16);
m.pushStack();
m.xI = BigInt.parse('f723eb313f123827', radix: 16);
Operations16.dblr.intCalc!(m);
await expect(m.xI, BigInt.from(2));
});
await test('Unsigned add and subtract', _testUnsigned);
}