GE-115 Emulator
An Emulator of the General Electrics GE-115 computer
Functions
alu_dec.c File Reference

GE-130 packed/signed decimal ALU helpers. More...

#include "alu_dec.h"
#include <string.h>

Go to the source code of this file.

Functions

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 (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 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 (struct ge *ge, uint16_t packed_addr, uint8_t sign)
 Set the sign nibble of a packed field.
 
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 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 (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_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.
 
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 unit to its low zone.
 

Detailed Description

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.

Function Documentation

◆ alu_ap()

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.

Definition at line 255 of file alu_dec.c.

◆ alu_cmp()

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.

Overflow if L1 < L2.

Definition at line 561 of file alu_dec.c.

◆ alu_dp()

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.

Overflow if: L1 <= L2, L2 > 7, divisor == 0, or result doesn't fit. On overflow, operation is NOT performed.

Definition at line 461 of file alu_dec.c.

◆ alu_edt()

void alu_edt ( struct ge ge,
uint16_t  pattern,
uint8_t  plen,
uint16_t  src 
)

EDT 0xDE Edit packed source into pattern at op1.

pattern: address of leftmost byte of pattern; plen = pattern length (bytes). src: address of RIGHTMOST byte of packed source field. Pattern control chars: 0x20 = SST (digit substitute + zero suppress), 0x21 = TSZ (digit substitute, ends zero suppress), 0x22 = RSZ (reset zero suppress start), other = insertion char (kept as-is). First byte of pattern is the fill character. CC: 1 0 = zero suppression still active (result = 0); 1 1 = active off. (manual §5.5.3.6 / §5.5.3.7 CC table; note "not possible" for 0/1.)

Definition at line 870 of file alu_dec.c.

◆ alu_mp()

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.

Constraints: blen <= 8, blen < alen; op1 must have ≥blen+1 leading zero digits; otherwise overflow (CC=0, operation not performed).

Definition at line 360 of file alu_dec.c.

◆ alu_mvp()

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.

Definition at line 616 of file alu_dec.c.

◆ alu_pk()

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).

Definition at line 684 of file alu_dec.c.

◆ alu_pks()

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).

CC set.

Definition at line 763 of file alu_dec.c.

◆ alu_sp()

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.

Definition at line 326 of file alu_dec.c.

◆ alu_upk()

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).

Definition at line 730 of file alu_dec.c.

◆ alu_upks()

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.

CC set (reflects sign/value of packed source).

Definition at line 806 of file alu_dec.c.

◆ bcd_add_digits()

static int bcd_add_digits ( uint8_t *  result,
const uint8_t *  a,
const uint8_t *  b,
int  n_digits 
)
static

BCD add two digit arrays (right-to-left, big-endian [0]=rightmost).

a_digits / b_digits: arrays of decimal digits (0-9), length = n_digits. Returns carry out (0 or 1).

Definition at line 172 of file alu_dec.c.

◆ bcd_cmp_digits()

static int bcd_cmp_digits ( const uint8_t *  a,
const uint8_t *  b,
int  n_digits 
)
static

Compare two unsigned BCD digit arrays (big-endian: [n-1]=most-significant).

Returns >0 if a>b, 0 if equal, <0 if a<b.

Definition at line 209 of file alu_dec.c.

◆ bcd_is_zero()

static int bcd_is_zero ( const uint8_t *  d,
int  n 
)
static

Returns 1 if digit array is all zeros.

Definition at line 221 of file alu_dec.c.

◆ bcd_sub_digits()

static int bcd_sub_digits ( uint8_t *  result,
const uint8_t *  a,
const uint8_t *  b,
int  n_digits 
)
static

BCD subtract b from a (right-to-left).

Assumes a >= b (unsigned). Returns 0 (no borrow should remain if a >= b).

Definition at line 188 of file alu_dec.c.

◆ dec_get_digit()

static uint8_t dec_get_digit ( const uint8_t *  mem,
uint16_t  packed_addr,
int  packed_bytes,
int  digit_idx 
)
static

Extract a single decimal digit from a packed field.

packed_addr = address of rightmost byte of packed field packed_bytes = total byte count (len+1) digit_idx = 0 = rightmost (most-significant of last byte hi nibble), 1 = next right-to-left, ... sign is NOT a digit

Digit layout within bytes (right to left, byte = packed_addr - byte_offset): byte 0 (rightmost): high nibble = digit[0], low nibble = sign byte 1: high nibble = digit[1], low nibble = digit[2] byte k>0: high nibble = digit[2k-1], low nibble = digit[2k]

Definition at line 76 of file alu_dec.c.

◆ dec_get_sign()

static uint8_t dec_get_sign ( const uint8_t *  mem,
uint16_t  packed_addr 
)
static

Get the sign nibble of a packed field.

Definition at line 133 of file alu_dec.c.

◆ dec_read_digits()

static void dec_read_digits ( const uint8_t *  mem,
uint16_t  packed_addr,
int  packed_bytes,
uint8_t *  digits,
int  n_digits 
)
static

Read a packed field into a digit array (right-to-left, [0]=rightmost digit).

Definition at line 232 of file alu_dec.c.

◆ dec_result_cc()

static uint8_t dec_result_cc ( int  is_zero,
uint8_t  result_sign 
)
static

Compute the CC value from a sign and whether the result is zero.

CC=1 neg, CC=2 zero, CC=3 pos — matching manual FA04/FA05 table.

Definition at line 160 of file alu_dec.c.

◆ dec_set_digit()

static void dec_set_digit ( struct ge ge,
uint16_t  packed_addr,
int  packed_bytes,
int  digit_idx,
uint8_t  digit 
)
static

Set a single digit in a packed field (same indexing as dec_get_digit).

Definition at line 108 of file alu_dec.c.

◆ dec_set_sign()

static void dec_set_sign ( struct ge ge,
uint16_t  packed_addr,
uint8_t  sign 
)
static

Set the sign nibble of a packed field.

Definition at line 139 of file alu_dec.c.

◆ dec_sign_is_neg()

static int dec_sign_is_neg ( uint8_t  sign_nibble)
static

Returns 1 if the sign nibble represents a negative value.

Definition at line 57 of file alu_dec.c.

◆ dec_write_digits()

static void dec_write_digits ( struct ge ge,
uint16_t  packed_addr,
int  packed_bytes,
const uint8_t *  digits,
int  n_digits 
)
static

Write a digit array back into a packed field.

Sign is NOT written by this function.

Definition at line 243 of file alu_dec.c.

◆ dec_zero_digits()

static void dec_zero_digits ( struct ge ge,
uint16_t  packed_addr,
int  packed_bytes 
)
static

Clear all digits (not sign) in a packed field to zero.

Definition at line 148 of file alu_dec.c.

◆ ge_ua_decimal()

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 unit to its low zone.

carry is URPE in and out. See the comment on the definition for why subtract shares the binary line.

Definition at line 939 of file alu_dec.c.