59 return (sign_nibble == 0xB || sign_nibble == 0xD);
77 int packed_bytes,
int digit_idx)
80 int total_digits = 2 * packed_bytes - 1;
81 if (digit_idx < 0 || digit_idx >= total_digits)
99 byte_off = (digit_idx + 1) / 2;
100 hi = ((digit_idx + 1) % 2 == 0) ? 0 : 1;
103 uint8_t b = mem[(uint16_t)(packed_addr - byte_off)];
104 return hi ? (b >> 4) & 0xF : b & 0xF;
109 int packed_bytes,
int digit_idx, uint8_t digit)
111 int total_digits = 2 * packed_bytes - 1;
112 if (digit_idx < 0 || digit_idx >= total_digits)
116 if (digit_idx == 0) {
120 byte_off = (digit_idx + 1) / 2;
121 hi = ((digit_idx + 1) % 2 == 0) ? 0 : 1;
124 uint16_t addr = (uint16_t)(packed_addr - byte_off);
125 uint8_t cur =
ge->
mem[addr];
127 ge_mem_store8(
ge, addr, (uint8_t)((cur & 0x0F) | ((digit & 0xF) << 4)));
135 return mem[packed_addr] & 0x0F;
142 (uint8_t)((
ge->
mem[packed_addr] & 0xF0) | (sign & 0x0F)));
152 for (
int i = 1; i < packed_bytes; i++)
176 for (
int i = 0; i < n_digits; i++) {
177 int sum = a[i] + b[i] + carry;
179 result[i] = (uint8_t)(sum % 10);
192 for (
int i = 0; i < n_digits; i++) {
193 int diff = (int)a[i] - (
int)b[i] - borrow;
200 result[i] = (uint8_t)diff;
211 for (
int i = n_digits - 1; i >= 0; i--) {
223 for (
int i = 0; i < n; i++)
233 int packed_bytes, uint8_t *digits,
int n_digits)
235 for (
int i = 0; i < n_digits; i++)
236 digits[i] =
dec_get_digit(mem, packed_addr, packed_bytes, i);
244 int packed_bytes,
const uint8_t *digits,
int n_digits)
247 for (
int i = 0; i < n_digits && i < (2 * packed_bytes - 1); i++)
255void alu_ap(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
263 int len_ovf = (alen < blen);
273 uint8_t a_d[33] = {0};
274 uint8_t b_d[33] = {0};
275 uint8_t r_d[33] = {0};
286 if (a_neg == b_neg) {
293 result_sign = a_neg ? 0xD : 0xC;
299 result_sign = a_neg ? 0xD : 0xC;
302 result_sign = b_neg ? 0xD : 0xC;
306 if (overflow || len_ovf) {
326void alu_sp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
360void alu_mp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
369 if (bb > 8 || blen >= alen)
375 uint8_t a_d[33] = {0};
376 uint8_t b_d[33] = {0};
397 for (
int i = bn; i < an; i++) {
403 uint8_t r_d[33] = {0};
404 for (
int i = 0; i < bn; i++) {
406 for (
int j = 0; j < an; j++) {
407 int prod = r_d[i + j] + a_d[j] * b_d[i] + carry;
409 r_d[i + j] = (uint8_t)(prod % 10);
413 r_d[i + an] += (uint8_t)carry;
417 for (
int i = an; i < 33; i++) {
425 uint8_t result_sign = (a_neg != b_neg) ? 0xD : 0xC;
437 for (
int k = 0; k < bb; k++)
461void alu_dp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
467 if (alen <= blen || blen > 7) {
475 uint8_t a_d[33] = {0};
476 uint8_t b_d[33] = {0};
498 int q_bytes = alen - blen;
499 int qn = 2 * q_bytes - 1;
507 unsigned __int128 dividend = 0, divisor = 0;
508 for (
int i = an - 1; i >= 0; i--) dividend = dividend * 10 + a_d[i];
509 for (
int i = bn - 1; i >= 0; i--) divisor = divisor * 10 + b_d[i];
512 unsigned __int128 quotient = dividend / divisor;
513 unsigned __int128 remainder = dividend % divisor;
516 unsigned __int128 qcap = 1;
517 for (
int i = 0; i < qn; i++) qcap *= 10;
518 if (quotient >= qcap) {
524 uint8_t q_lsf[33] = {0};
525 uint8_t r_lsf[33] = {0};
526 for (
int i = 0; i < qn; i++) { q_lsf[i] = (uint8_t)(quotient % 10); quotient /= 10; }
527 for (
int i = 0; i < bn; i++) { r_lsf[i] = (uint8_t)(remainder % 10); remainder /= 10; }
532 uint8_t q_sign = (a_neg != b_neg) ? 0xD : 0xC;
533 uint8_t r_sign = a_neg ? 0xD : 0xC;
542 uint16_t q_addr = (uint16_t)(a - bb);
561void alu_cmp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
574 uint8_t a_d[33] = {0};
575 uint8_t b_d[33] = {0};
589 if (a_zero && b_zero) {
594 if (a_neg != b_neg) {
616void alu_mvp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
623 uint8_t b_d[33] = {0};
628 int overflow = (alen < blen);
633 int copy_n = (bn < an) ? bn : an;
634 for (
int i = 0; i < copy_n; i++)
640 uint8_t result_sign = b_sign;
648 uint8_t r_d[33] = {0};
684void alu_pk(
struct ge *
ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
702 int total_digits = 2 * db;
704 for (
int d = 0; d < total_digits; d++) {
705 uint8_t digit =
ge->
mem[(uint16_t)(src + d)] & 0x0F;
706 uint16_t daddr = (uint16_t)(dst + d / 2);
707 uint8_t cur =
ge->
mem[daddr];
709 cur = (uint8_t)((cur & 0xF0) | digit);
711 cur = (uint8_t)((cur & 0x0F) | (uint8_t)(digit << 4));
730void alu_upk(
struct ge *
ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
736 for (
int d = 0; d < total; d++) {
737 uint8_t sbyte =
ge->
mem[(uint16_t)(src + d / 2)];
738 uint8_t digit = (d & 1) ? (uint8_t)(sbyte & 0x0F)
739 : (uint8_t)((sbyte >> 4) & 0x0F);
740 uint16_t daddr = (uint16_t)(dst + d);
763void alu_pks(
struct ge *
ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
767 int total_digits = 2 * db - 1;
770 uint8_t src_zone = (
ge->
mem[src] >> 4) & 0x0F;
771 uint8_t result_sign = (src_zone == 0xA) ? 0xD : 0xC;
774 for (
int d = 0; d < total_digits; d++) {
777 digit =
ge->
mem[(uint16_t)(src - d)] & 0x0F;
787 uint8_t r_d[33] = {0};
806void alu_upks(
struct ge *
ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
812 for (
int i = 0; i < db; i++) {
819 uint16_t daddr = (uint16_t)(dst - i);
826 uint8_t s_d[33] = {0};
870void alu_edt(
struct ge *
ge, uint16_t pattern, uint8_t plen, uint16_t src)
875 uint8_t fill =
ge->
mem[pattern];
876 int zero_suppress = 1;
877 uint16_t src_ptr = src;
879 for (
int i = 0; i < plen; i++) {
880 uint16_t pat_addr = (uint16_t)(pattern + i);
881 uint8_t pc =
ge->
mem[pat_addr];
885 uint8_t digit =
ge->
mem[src_ptr] & 0x0F;
897 }
else if (pc == 0x21) {
902 }
else if (pc == 0x22) {
942 unsigned c = *carry ? 1 : 0;
944 int digits = one_digit ? 1 : 2;
946 for (
int i = 0; i < digits; i++) {
947 unsigned a = (ro >> (4 * i)) & 0xf;
948 unsigned b = (bo >> (4 * i)) & 0xf;
949 unsigned d = a + (subtract ? 9 - b : b) + c;
951 if (d > 9) { d -= 10; c = 1; }
else { c = 0; }
952 out |= (d & 0xf) << (4 * i);
void alu_set_cc(struct ge *ge, uint8_t cc)
uint8_t ge_ua_decimal(uint8_t bo, uint8_t ro, int subtract, int one_digit, uint8_t *carry)
Arithmetic unit in decimal mode – one byte (two BCD digits), or one digit when CI50 restricts the uni...
void alu_mvp(struct ge *ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
MVP 0xE8 Move Packed: op1 = op2 (sign preserved from op2); CC set.
void alu_sp(struct ge *ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
SP 0xEB Subtract Packed: op1 = op1 - op2; CC set.
static uint8_t dec_result_cc(int is_zero, uint8_t result_sign)
Compute the CC value from a sign and whether the result is zero.
static int bcd_cmp_digits(const uint8_t *a, const uint8_t *b, int n_digits)
Compare two unsigned BCD digit arrays (big-endian: [n-1]=most-significant).
void alu_upks(struct ge *ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
UPKS 0xEF Unpack with Sign: packed op2 → zoned op1; zone always 0x4.
static void dec_write_digits(struct ge *ge, uint16_t packed_addr, int packed_bytes, const uint8_t *digits, int n_digits)
Write a digit array back into a packed field.
void alu_upk(struct ge *ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
UPK 0xD8 Unpack: packed op2 → zoned op1 (no sign processing; zone of each result byte is taken from t...
static void dec_zero_digits(struct ge *ge, uint16_t packed_addr, int packed_bytes)
Clear all digits (not sign) in a packed field to zero.
static void dec_set_digit(struct ge *ge, uint16_t packed_addr, int packed_bytes, int digit_idx, uint8_t digit)
Set a single digit in a packed field (same indexing as dec_get_digit).
static int bcd_add_digits(uint8_t *result, const uint8_t *a, const uint8_t *b, int n_digits)
BCD add two digit arrays (right-to-left, big-endian [0]=rightmost).
void alu_pks(struct ge *ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
PKS 0xEE Pack with Sign: zoned op2 → packed op1; sign from zone of rightmost source byte (zone 0xA → ...
static int bcd_is_zero(const uint8_t *d, int n)
Returns 1 if digit array is all zeros.
void alu_mp(struct ge *ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
MP 0xEC Multiply Packed: op1 = op1 * op2; CC set.
static int bcd_sub_digits(uint8_t *result, const uint8_t *a, const uint8_t *b, int n_digits)
BCD subtract b from a (right-to-left).
static void dec_set_sign(struct ge *ge, uint16_t packed_addr, uint8_t sign)
Set the sign nibble of a packed field.
static uint8_t dec_get_digit(const uint8_t *mem, uint16_t packed_addr, int packed_bytes, int digit_idx)
Extract a single decimal digit from a packed field.
static uint8_t dec_get_sign(const uint8_t *mem, uint16_t packed_addr)
Get the sign nibble of a packed field.
void alu_cmp(struct ge *ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
CMP 0xE9 Compare Packed (algebraic, no operand change); CC set.
static int dec_sign_is_neg(uint8_t sign_nibble)
Returns 1 if the sign nibble represents a negative value.
static void dec_read_digits(const uint8_t *mem, uint16_t packed_addr, int packed_bytes, uint8_t *digits, int n_digits)
Read a packed field into a digit array (right-to-left, [0]=rightmost digit).
void alu_pk(struct ge *ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
PK 0xDA Pack: zoned op2 → packed op1 (no sign processing).
void alu_edt(struct ge *ge, uint16_t pattern, uint8_t plen, uint16_t src)
EDT 0xDE Edit packed source into pattern at op1.
void alu_ap(struct ge *ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
AP 0xEA Add Packed: op1 = op1 + op2; CC set.
void alu_dp(struct ge *ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
DP 0xED Divide Packed: op1[left L1-L2 chars] = quotient, op1[right L2+1 chars] = remainder; CC set.
GE-130 packed/signed decimal ALU helpers.
void ge_mem_store8(struct ge *ge, uint16_t addr, uint8_t val)
Store a byte with generated odd parity + mark-written (for the hybrid ALU/SS write paths that write g...
The entire state of the emulated system, including registers, memory, peripherals and timings.
uint8_t mem[MEM_SIZE]
The memory of the emulated system.