librarylibs/Fixed/src/Fixed.xtl

Fixed: fixed-width two's complement numbers at a stated width, the arithmetic a w-bit circuit does Import it with an alias of your choice: "fx:" u_se< "Fixed". Put libs/Fixed/src on XETAL_PATH ("just path"); the reference is libs/Fixed/docs. Names with l: are exported; the others are private to this file.

X_eTaL's Int is 64 bits wide; hardware is 8, 16 or 32. Until X_eTaL has sized integer types (ask F3 in docs/xetal-asks.md), the width is written in the program: 16 ᶠˣw̲rap x + y is what a 16-bit adder gives, and the evaluator computes exactly that, so it is the reference the circuit must match bit for bit. Every function takes the width first (one number) and works on whole arrays of any shape. A function of three arguments is used curried: bind the width once, ᵘa̲dd ← ᶠˣa̲dd 16, then x ᵘa̲dd y.

source

The ranges

ˡl̲owest : Num a => a -> a

function · line 21

l_owest w: the lowest signed value of w bits, -2^(w-1) (-128 at 8 bits).

      ᶠˣ⁼u̲se< "Fixed"
      ᶠˣl̲owest 8 16
-128 -32768
ˡl̲owest ← { w → n̲eg 2 ^ w − 1 }
Used in: ˡs̲at

ˡh̲ighest : Num a => a -> a

function · line 27

h_ighest w: the highest signed value of w bits, 2^(w-1) - 1 (127 at 8 bits).

      ᶠˣ⁼u̲se< "Fixed"
      ᶠˣh̲ighest 8 16
127 32767
ˡh̲ighest ← { w → (2 ^ w − 1) − 1 }
Used in: ˡs̲at

Wrapping

ˡu̲wrap : Int -> Int -> Int

function · line 36

w u_wrap x: x reduced to the unsigned range of w bits, 0 to 2^w - 1: the bit pattern a w-bit register holds, read unsigned.

      ᶠˣ⁼u̲se< "Fixed"
      8 ᶠˣu̲wrap 100 200 -1 256
100 200 255 0
ˡu̲wrap ← { w x → x m̲od 2 ^ w }

ˡw̲rap : Int -> Int -> Int

function · line 43

w w_rap x: x reduced to the signed range of w bits: the same bits, read as two's complement (a pattern at or above 2^(w-1) is negative).

      ᶠˣ⁼u̲se< "Fixed"
      8 ᶠˣw̲rap 100 200 -1 -129
100 -56 -1 127
ˡw̲rap ← { w x →
  u ← w ˡu̲wrap x
  u − (2 ^ w) × u ≥ 2 ^ w − 1
}

ˡo̲verflow? : Truthy a => Int -> Int -> a

function · line 53

w o_verflow? x: whether x does not fit in w signed bits, so a w-bit unit holding it has wrapped.

      ᶠˣ⁼u̲se< "Fixed"
      8 ᶠˣo̲verflow? 127 128
0 1
ˡo̲verflow? ← { w x → x ≠ w ˡw̲rap x }

ˡs̲at : Num a => a -> a -> a

function · line 60

w s_at x: x clamped to the signed range (saturating arithmetic: what a DSP does instead of wrapping).

      ᶠˣ⁼u̲se< "Fixed"
      8 ᶠˣs̲at 300 -300 5
127 -128 5
ˡs̲at ← { w x → (ˡl̲owest w) m̲ax x m̲in ˡh̲ighest w }

Arithmetic, wrapped: what a w-bit adder, subtractor, multiplier gives

ˡa̲dd : Int -> Int -> Int -> Int

function · line 71

w a_dd x y: the sum wrapped to w bits, item by item, with scalar extension: what a w-bit adder gives. Bind the width once: u:a_dd := fx:a_dd 16, then x u:a_dd y.

      ᶠˣ⁼u̲se< "Fixed"
      ᵘa̲dd ← ᶠˣa̲dd 8
      100 ᵘa̲dd 100
-56
ˡa̲dd ← { w x y → w ˡw̲rap x + y }

ˡs̲ub : Int -> Int -> Int -> Int

function · line 78

w s_ub x y: the difference wrapped to w bits (a w-bit subtractor).

      ᶠˣ⁼u̲se< "Fixed"
      ᵘs̲ub ← ᶠˣs̲ub 8
      -100 ᵘs̲ub 100
56
ˡs̲ub ← { w x y → w ˡw̲rap x − y }

ˡm̲ul : Int -> Int -> Int -> Int

function · line 86

w m_ul x y: the product wrapped to w bits (a w-bit multiplier keeps the low w bits).

      ᶠˣ⁼u̲se< "Fixed"
      ᵘm̲ul ← ᶠˣm̲ul 8
      16 ᵘm̲ul 16
0
ˡm̲ul ← { w x y → w ˡw̲rap x × y }

ˡn̲eg : Int -> Int -> Int

function · line 92

w n_eg x: the negation wrapped (the lowest value is its own negation).

      ᶠˣ⁼u̲se< "Fixed"
      8 ᶠˣn̲eg 5 -128
-5 -128
ˡn̲eg ← { w x → w ˡw̲rap n̲eg x }

Bits

ˡb̲its : Int -> Int -> Int

function · line 103

w b_its x: the two's complement bits of each number, most significant first: a vector for one number, a row per number for a vector (as Bits' b_its, which reads numbers unsigned).

      ᶠˣ⁼u̲se< "Fixed"
      8 ᶠˣb̲its 5 -1
0 0 0 0 0 1 0 1
1 1 1 1 1 1 1 1
ˡb̲its ← { w x → o̲\ (w r̲eshape 2) e̲ncode w ˡu̲wrap x }

ˡv̲alue : Int -> Int

function · line 110

v_alue bits: the signed number each row of bits (or the vector) stands for, the inverse of b_its; the width is the row's length.

      ᶠˣ⁼u̲se< "Fixed"
      ᶠˣv̲alue 1 1 1 1 1 0 1 1
-5
ˡv̲alue ← { bits → (t̲ally o̲\ bits) ˡw̲rap 2 d̲ecode o̲\ bits }

ˡh̲ex : Int -> Int -> Char

function · line 118

w h_ex x: the bit pattern of each number as hexadecimal text, w/4 digits: text for one number, a row per number for a vector.

      ᶠˣ⁼u̲se< "Fixed"
      16 ᶠˣh̲ex -1 48879
FFFF
BEEF
ˡh̲ex ← { w x → (1 + o̲\ ((w d̲iv 4) r̲eshape 16) e̲ncode w ˡu̲wrap x) s̲elect ⎕D c̲at 6 t̲ake ⎕A }