|
| static int | dec_sign_is_neg (uint8_t sign_nibble) |
| | Returns 1 if the sign nibble represents a negative value.
|
| |
| 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 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 uint8_t | dec_get_sign (const uint8_t *mem, uint16_t packed_addr) |
| | Get the sign nibble of a packed field.
|
| |
| static void | dec_set_sign (uint8_t *mem, uint16_t packed_addr, uint8_t sign) |
| | Set the sign nibble of a packed field.
|
| |
| 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.
|
| |
| 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_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 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 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).
|
| |
| static int | bcd_is_zero (const uint8_t *d, int n) |
| | Returns 1 if digit array is all zeros.
|
| |
| 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).
|
| |
| 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_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.
|
| |
| 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.
|
| |
| 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.
|
| |
| 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.
|
| |
| 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_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_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 the pre-existing zone in ge->mem).
|
| |
| 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 → negative, else positive).
|
| |
| 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_edt (struct ge *ge, uint16_t pattern, uint8_t plen, uint16_t src) |
| | EDT 0xDE Edit packed source into pattern at op1.
|
| |
GE-130 packed/signed decimal ALU helpers.
Manual source: GE 130 P.D.S. (cpu_6.txt), specifically: §2.3.5 (packed operand format, sign codes, ~lines 3148-3169) §5.5.3.4 PK, §5.5.3.5 UPK, §5.5.3.6 EDT §5.6.1.1 AP, §5.6.1.2 SP, §5.6.1.3 MP, §5.6.1.4 DP §5.6.1.5 MVP, §5.6.1.6 CMP §5.6.2.1 PKS, §5.6.2.2 UPKS
OPERAND ADDRESSING CONVENTION Every function receives the address of the RIGHTMOST (highest-address, least-significant) byte. Length L means L+1 bytes = 2L+1 digits + sign. Processing goes right-to-left (rightmost byte first) exactly as the manual prescribes.
SIGN CODES (§2.3.5) 0xB or 0xD in low nibble of rightmost byte → negative anything else → positive Results always written as 0xC (+) or 0xD (-)
CONDITION CODE (§5.6.1, FA04/FA05) CC=0 overflow CC=1 result < 0 CC=2 result = 0 CC=3 result > 0
UNCERTAINTY NOTES MP / DP: The manual describes high-level constraints and the overflow rules. The digit-level multiplication/division algorithm is implemented here using standard BCD multi-precision arithmetic as described in §7 of the manual (DETAILED DESCRIPTION OF MP AND DP SEQUENCES) — that section is only in outline form in the available OCR. The implementation follows S/360-style packed-decimal semantics which are consistent with the GE-130 constraints given. Mark any MP/DP test results as "best-effort; verify against hardware traces." UPK: Manual says the zone of the result bytes is taken from the "pre-existing zone" in the destination field. This implementation preserves the high nibble of destination bytes. UPKS always uses zone 0x4 (confirmed in §5.6.2.2). EDT: Control char values SST=0x20, TSZ=0x21, RSZ=0x22 are verified in §5.5.3.6 ("code 00100000", "00100001", "00100010"). CC encoding follows §5.5.3.6 table (10=zero-suppress still active, 11=zero-suppress off).
Definition in file alu_dec.c.