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);
126 mem[addr] = (uint8_t)((mem[addr] & 0x0F) | ((digit & 0xF) << 4));
128 mem[addr] = (uint8_t)((mem[addr] & 0xF0) | (digit & 0xF));
134 return mem[packed_addr] & 0x0F;
138static void dec_set_sign(uint8_t *mem, uint16_t packed_addr, uint8_t sign)
140 mem[packed_addr] = (uint8_t)((mem[packed_addr] & 0xF0) | (sign & 0x0F));
149 mem[packed_addr] &= 0x0F;
150 for (
int i = 1; i < packed_bytes; i++)
151 mem[(uint16_t)(packed_addr - i)] = 0x00;
174 for (
int i = 0; i < n_digits; i++) {
175 int sum = a[i] + b[i] + carry;
177 result[i] = (uint8_t)(sum % 10);
190 for (
int i = 0; i < n_digits; i++) {
191 int diff = (int)a[i] - (
int)b[i] - borrow;
198 result[i] = (uint8_t)diff;
209 for (
int i = n_digits - 1; i >= 0; i--) {
221 for (
int i = 0; i < n; i++)
231 int packed_bytes, uint8_t *digits,
int n_digits)
233 for (
int i = 0; i < n_digits; i++)
234 digits[i] =
dec_get_digit(mem, packed_addr, packed_bytes, i);
242 int packed_bytes,
const uint8_t *digits,
int n_digits)
245 for (
int i = 0; i < n_digits && i < (2 * packed_bytes - 1); i++)
253void alu_ap(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
261 int len_ovf = (alen < blen);
271 uint8_t a_d[33] = {0};
272 uint8_t b_d[33] = {0};
273 uint8_t r_d[33] = {0};
284 if (a_neg == b_neg) {
291 result_sign = a_neg ? 0xD : 0xC;
297 result_sign = a_neg ? 0xD : 0xC;
300 result_sign = b_neg ? 0xD : 0xC;
304 if (overflow || len_ovf) {
324void alu_sp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
358void alu_mp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
367 if (bb > 8 || blen >= alen)
373 uint8_t a_d[33] = {0};
374 uint8_t b_d[33] = {0};
395 for (
int i = bn; i < an; i++) {
401 uint8_t r_d[33] = {0};
402 for (
int i = 0; i < bn; i++) {
404 for (
int j = 0; j < an; j++) {
405 int prod = r_d[i + j] + a_d[j] * b_d[i] + carry;
407 r_d[i + j] = (uint8_t)(prod % 10);
411 r_d[i + an] += (uint8_t)carry;
415 for (
int i = an; i < 33; i++) {
423 uint8_t result_sign = (a_neg != b_neg) ? 0xD : 0xC;
435 for (
int k = 0; k < bb; k++)
459void alu_dp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
465 if (alen <= blen || blen > 7) {
473 uint8_t a_d[33] = {0};
474 uint8_t b_d[33] = {0};
496 int q_bytes = alen - blen;
497 int qn = 2 * q_bytes - 1;
505 unsigned __int128 dividend = 0, divisor = 0;
506 for (
int i = an - 1; i >= 0; i--) dividend = dividend * 10 + a_d[i];
507 for (
int i = bn - 1; i >= 0; i--) divisor = divisor * 10 + b_d[i];
510 unsigned __int128 quotient = dividend / divisor;
511 unsigned __int128 remainder = dividend % divisor;
514 unsigned __int128 qcap = 1;
515 for (
int i = 0; i < qn; i++) qcap *= 10;
516 if (quotient >= qcap) {
522 uint8_t q_lsf[33] = {0};
523 uint8_t r_lsf[33] = {0};
524 for (
int i = 0; i < qn; i++) { q_lsf[i] = (uint8_t)(quotient % 10); quotient /= 10; }
525 for (
int i = 0; i < bn; i++) { r_lsf[i] = (uint8_t)(remainder % 10); remainder /= 10; }
530 uint8_t q_sign = (a_neg != b_neg) ? 0xD : 0xC;
531 uint8_t r_sign = a_neg ? 0xD : 0xC;
540 uint16_t q_addr = (uint16_t)(a - bb);
559void alu_cmp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
572 uint8_t a_d[33] = {0};
573 uint8_t b_d[33] = {0};
587 if (a_zero && b_zero) {
592 if (a_neg != b_neg) {
614void alu_mvp(
struct ge *
ge, uint16_t a, uint8_t alen, uint16_t b, uint8_t blen)
621 uint8_t b_d[33] = {0};
626 int overflow = (alen < blen);
631 int copy_n = (bn < an) ? bn : an;
632 for (
int i = 0; i < copy_n; i++)
638 uint8_t result_sign = b_sign;
646 uint8_t r_d[33] = {0};
682void alu_pk(
struct ge *
ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
700 int total_digits = 2 * db;
702 for (
int d = 0; d < total_digits; d++) {
703 uint8_t digit =
ge->
mem[(uint16_t)(src + d)] & 0x0F;
704 uint16_t daddr = (uint16_t)(dst + d / 2);
705 uint8_t cur =
ge->
mem[daddr];
707 cur = (uint8_t)((cur & 0xF0) | digit);
709 cur = (uint8_t)((cur & 0x0F) | (uint8_t)(digit << 4));
728void alu_upk(
struct ge *
ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
734 for (
int d = 0; d < total; d++) {
735 uint8_t sbyte =
ge->
mem[(uint16_t)(src + d / 2)];
736 uint8_t digit = (d & 1) ? (uint8_t)(sbyte & 0x0F)
737 : (uint8_t)((sbyte >> 4) & 0x0F);
738 uint16_t daddr = (uint16_t)(dst + d);
761void alu_pks(
struct ge *
ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
765 int total_digits = 2 * db - 1;
768 uint8_t src_zone = (
ge->
mem[src] >> 4) & 0x0F;
769 uint8_t result_sign = (src_zone == 0xA) ? 0xD : 0xC;
772 for (
int d = 0; d < total_digits; d++) {
775 digit =
ge->
mem[(uint16_t)(src - d)] & 0x0F;
785 uint8_t r_d[33] = {0};
804void alu_upks(
struct ge *
ge, uint16_t dst, uint8_t dlen, uint16_t src, uint8_t slen)
810 for (
int i = 0; i < db; i++) {
817 uint16_t daddr = (uint16_t)(dst - i);
824 uint8_t s_d[33] = {0};
868void alu_edt(
struct ge *
ge, uint16_t pattern, uint8_t plen, uint16_t src)
873 uint8_t fill =
ge->
mem[pattern];
874 int zero_suppress = 1;
875 uint16_t src_ptr = src;
877 for (
int i = 0; i < plen; i++) {
878 uint16_t pat_addr = (uint16_t)(pattern + i);
879 uint8_t pc =
ge->
mem[pat_addr];
883 uint8_t digit =
ge->
mem[src_ptr] & 0x0F;
895 }
else if (pc == 0x21) {
900 }
else if (pc == 0x22) {
void alu_set_cc(struct ge *ge, uint8_t cc)
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.
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 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).
static void dec_set_digit(uint8_t *mem, 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 void dec_set_sign(uint8_t *mem, uint16_t packed_addr, uint8_t sign)
Set the sign nibble of a packed field.
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.
static void dec_zero_digits(uint8_t *mem, uint16_t packed_addr, int packed_bytes)
Clear all digits (not sign) in a packed field to zero.
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 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.
static void dec_write_digits(uint8_t *mem, 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_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.