# ABS - Absolute Value (RRR), pg. 246.
:abs ar, at is op2 = 0b0110 & op1 = 0 & ar & as = 0b0001 & at & op0 = 0 {
    ar = at;
    if (ar s> 0)
      goto inst_next;
    ar = -ar;
}

# ABS.S - Absolute Single Value (RRR), pg. 247.
:abs.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0b0001 & op0 = 0b0000 {
    fr = abs(fs);
}

# ADD - Add (RRR), pg. 248.
:add ar, as, at is op2 = 0b1000 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = as + at;
}

# ADD.N - Narrow Add (RRRN), pg. 249.
:add.n n_ar, n_as, n_at is n_ar & n_as & n_at & n_op0 = 0b1010 {
    n_ar = n_as + n_at;
}

# ADD.S - Add Single (RRR), pg. 250.
:add.s fr, fs, ft is op2 = 0 & op1 = 0b1010 & fr & fs & ft & op0 = 0 {
    fr = fs f+ ft;
}

# ADDI - Add Immediate (RRI8), pg. 251.
:addi at, as, s8_16.23 is s8_16.23 & ar = 0b1100 & as & at & op0 = 0b0010 {
    at = as + sext(s8_16.23:1);
}

# ADDI.N - Narrow Add Immediate (RRRN), pg. 252.
:addi.n n_ar, n_as, n_s4_4.7_nozero is n_ar & n_as & n_s4_4.7_nozero & n_op0 = 0b1011 {
    n_ar = n_as + n_s4_4.7_nozero;
}

# ADDMI - Add Immediate with Shift by 8, pg. 253.
:addmi at, as, s16_16.23_sb8 is s16_16.23_sb8 & ar = 0b1101 & as & at & op0 = 0b0010 {
    at = as + sext(s16_16.23_sb8);
}

# ADDX2 - Add with Shift by 1, pg. 254.
:addx2 ar, as, at is op2 = 0b1001 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = (as << 1) + at;
}

# ADDX4 - Add with Shift by 2, pg. 255.
:addx4 ar, as, at is op2 = 0b1010 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = (as << 2) + at;
}

# ADDX8 - Add with Shift by 4, pg. 256.
:addx8 ar, as, at is op2 = 0b1011 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = (as << 3) + at;
}

# ALL4 - All 4 Booleans True, pg. 257.
:all4 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1001 & bs & bt & op0 = 0 {
    local b = *[register]:1 &:4 bs+1;
    local c = *[register]:1 &:4 bs+2;
    local d = *[register]:1 &:4 bs+3;
    bt = bs && b && c && d;
}

# ALL8 - All 8 Booleans True, pg. 258.
:all8 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1011 & bs & bt & op0 = 0 {
    local b = *[register]:1 &:4 bs+1;
    local c = *[register]:1 &:4 bs+2;
    local d = *[register]:1 &:4 bs+3;
    local e = *[register]:1 &:4 bs+4;
    local f = *[register]:1 &:4 bs+5;
    local g = *[register]:1 &:4 bs+6;
    local h = *[register]:1 &:4 bs+7;
    bt = bs && b && c && d && e && f && g && h;
}

# AND - Bitwise Logical And, pg. 259.
:and ar, as, at is op2 = 0b0001 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = as & at;
}

# ANDB - Boolean And, pg. 260.
:andb br, bs, bt is op2 = 0 & op1 = 0b0010 & br & bs & bt & op0 = 0 {
    br = bs && bt;
}

# ANDBC - Boolean And with Complement, pg. 261.
:andbc br, bs, bt is op2 = 0b0001 & op1 = 0b0010 & br & bs & bt & op0 = 0 {
    br = bs && !bt;
}

# ANY4 - Any 4 Booleans True, pg. 262.
:any4 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1000 & bs & bt & op0 = 0 {
    local b = *[register]:1 &:4 bs+1;
    local c = *[register]:1 &:4 bs+2;
    local d = *[register]:1 &:4 bs+3;
    bt = bs || b || c || d;
}

# ANY8 - Any 8 Booleans True, pg. 263.
:any8 bt, bs is op2 = 0 & op1 = 0 & ar = 0b1010 & bs & bt & op0 = 0 {
    local b = *[register]:1 &:4 bs+1;
    local c = *[register]:1 &:4 bs+2;
    local d = *[register]:1 &:4 bs+3;
    local e = *[register]:1 &:4 bs+4;
    local f = *[register]:1 &:4 bs+5;
    local g = *[register]:1 &:4 bs+6;
    local h = *[register]:1 &:4 bs+7;
    bt = bs || b || c || d || e || f || g || h;
}

# BALL - Branch if All Bits Set, pg. 264.
:ball srel_16.23, as, at is srel_16.23 & ar = 0b0100 & as & at & op0 = 0b0111 {
    if ((~as & at) == 0)
        goto srel_16.23;
}

# BANY - Branch if Any Bit Set, pg. 265.
:bany srel_16.23, as, at, is srel_16.23 & ar = 0b1000 & as & at & op0 = 0b0111 {
    if ((as & at) != 0)
        goto srel_16.23;
}

macro extract_bit(val, bit, result) {
    result = (val >> bit)&1;
}

# BBC - Branch if Bit Clear, pg. 266.
:bbc as, at, srel_16.23 is srel_16.23 & ar = 0b0101 & as & at & op0 = 0b0111 {
    local bval;
    extract_bit(as, at[0,5], bval);
    if (bval == 0)
        goto srel_16.23;
}

# BBCI - Branch if Bit Clear immediate, pg. 267
:bbci as, u5_4.7_12, srel_16.23 is srel_16.23 & u3_13.15 = 0b011 & as & u5_4.7_12 & op0 = 0b0111 {
    local bval;
    extract_bit(as, u5_4.7_12, bval);
    if (bval == 0)
        goto srel_16.23;
}

# BBS - Branch if Bit Set, pg. 269.
:bbs as, at, srel_16.23 is srel_16.23 & ar = 0b1101 & as & at & op0 = 0b0111 {
    local bval;
    extract_bit(as, at[0,5], bval);
    if (bval != 0)
        goto srel_16.23;
}

# BBSI - Branch if Bit Set immediate, pg. 270.
:bbsi as, u5_4.7_12, srel_16.23 is srel_16.23 & u3_13.15 = 0b111 & as & u5_4.7_12 & op0 = 0b0111 {
    local bval;
    extract_bit(as, u5_4.7_12, bval);
    if (bval != 0)
        goto srel_16.23;
}

# BEQ - Branch if Equal, pg. 272.
:beq as, at, srel_16.23 is srel_16.23 & ar = 0b0001 & as & at & op0 = 0b0111 {
    if (as == at)
        goto srel_16.23;
}

# BEQI - Branch if Equal Immediate, pg. 273.
:beqi as, r_b4const, srel_16.23 is srel_16.23 & r_b4const & as & u2_6.7 = 0 & u2_4.5 = 0b10 & op0 = 0b0110 {
    if (as == r_b4const)
        goto srel_16.23;
}

# BEQZ - Branch if Equal Zero, pg. 274.
:beqz as, srel_12.23 is srel_12.23 & as & u2_6.7 = 0 & u2_4.5 = 0b01 & op0 = 0b0110 {
    if (as == 0)
        goto srel_12.23;
}

# BEQZ.N - Narrow Branch if Equal Zero, pg. 275.
:beqz.n n_as, urel_12.15_4.5 is urel_12.15_4.5 & n_as & n_u2_6.7 = 0b10 & n_op0 = 0b1100 {
    if (n_as == 0)
        goto urel_12.15_4.5;
}

# BF - Branch if False, pg. 276.
:bf bs, srel_16.23 is srel_16.23 & ar = 0 & bs & at = 0b0111 & op0 = 0b0110 {
    if (!bs)
        goto srel_16.23;
}

# BGE - Branch if Greater Than or Equal, pg. 277.
:bge as, at, srel_16.23 is srel_16.23 & ar = 0b1010 & as & at & op0 = 0b0111 {
    if (as s>= at)
        goto srel_16.23;
}

# BGEI - Branch if Greater Than or Equal Immediate, pg. 278.
:bgei as, r_b4const, srel_16.23 is srel_16.23 & r_b4const & as & u2_6.7 = 0b11 & u2_4.5 = 0b10 & op0 = 0b0110 {
    if (as s>= r_b4const)
        goto srel_16.23;
}

# BGEU - Branch if Greater Than or Equal Unsigned, pg. 279.
:bgeu as, at, srel_16.23 is srel_16.23 & ar = 0b1011 & as & at & op0 = 0b0111 {
    if (as >= at)
        goto srel_16.23;
}

# BGEUI - Branch if Greater Than or Equal Unsigned Immediate, pg. 280.
:bgeui as, r_b4constu, srel_16.23 is srel_16.23 & r_b4constu & as & u2_6.7 = 0b11 & u2_4.5 = 0b11 & op0 = 0b0110 {
    if (as >= r_b4constu)
        goto srel_16.23;
}

# BGEZ - Branch if Greater Than or Equal Zero, pg. 281.
:bgez as, srel_12.23 is srel_12.23 & as & u2_6.7 = 0b11 & u2_4.5 = 0b01 & op0 = 0b0110 {
    if (as s>= 0)
        goto srel_12.23;
}

# BLT - Branch if Less Than, pg. 282.
:blt as, at, srel_16.23 is srel_16.23 & ar = 0b0010 & as & at & op0 = 0b0111 {
    if (as s< at)
        goto srel_16.23;
}

# BLTI - Branch if Less Than Immediate, pg. 283.
:blti as, r_b4const, srel_16.23 is srel_16.23 & r_b4const & as & u2_6.7 = 0b10 & u2_4.5 = 0b10 & op0 = 0b0110 {
    if (as s< r_b4const)
        goto srel_16.23;
}

# BLTU - Branch if Less Than Unsigned, pg. 284.
:bltu as, at, srel_16.23 is srel_16.23 & ar = 0b0011 & as & at & op0 = 0b0111 {
    if (as < at)
        goto srel_16.23;
}

# BLTUI - Branch if Less Than Unsigned Immediate, pg. 285.
:bltui as, r_b4constu, srel_16.23 is srel_16.23 & r_b4constu & as & u2_6.7 = 0b10 & u2_4.5 = 0b11 & op0 = 0b0110 {
    if (as < r_b4constu)
        goto srel_16.23;
}

# BLTZ - Branch if Less Than Zero, pg. 286.
:bltz as, srel_12.23 is srel_12.23 & as & u2_6.7 = 0b10 & u2_4.5 = 0b01 & op0 = 0b0110 {
    if (as s< 0)
        goto srel_12.23;
}

# BNALL - Branch if Not-All Bits Set, pg. 287.
:bnall srel_16.23, as, at is srel_16.23 & ar = 0b1100 & as & at & op0 = 0b0111 {
    if ((~as & at) != 0)
        goto srel_16.23;
}

# BNE - Branch if Not Equal, pg. 288.
:bne as, at, srel_16.23 is srel_16.23 & ar = 0b1001 & as & at & op0 = 0b0111 {
    if (as != at)
        goto srel_16.23;
}

# BNEI - Branch if Not EquaL Immediate, pg. 289.
:bnei as, r_b4const, srel_16.23 is srel_16.23 & r_b4const & as & u2_6.7 = 0b01 & u2_4.5 = 0b10 & op0 = 0b0110 {
    if (as != r_b4const)
        goto srel_16.23;
}

# BNEZ - Branch if Not Equal Zero, pg. 290.
:bnez as, srel_12.23 is srel_12.23 & as & u2_6.7 = 0b01 & u2_4.5 = 0b01 & op0 = 0b0110 {
    if (as != 0)
        goto srel_12.23;
}

# BNEZ.N - Narrow Branch if Not Equal Zero, pg. 291.
:bnez.n n_as, urel_12.15_4.5 is urel_12.15_4.5 & n_as & n_u2_6.7 = 0b11 & n_op0 = 0b1100 {
    if (n_as != 0)
        goto urel_12.15_4.5;
}

# BNONE - Branch if No Bit Set, pg. 292.
:bnone srel_16.23, as, at, is srel_16.23 & ar = 0 & as & at & op0 = 0b0111 {
    if ((as & at) == 0)
        goto srel_16.23;
}

# BREAK - Breakpoint, pg. 293.
:break u4_8.11, u4_4.7 is op2 = 0 & op1 = 0 & ar = 0b0100 & u4_8.11 & u4_4.7 & op0 = 0 {
    breakpoint(0x001000:4, u4_8.11:1, u4_4.7:1);
}

# BREAK.N - Narrow Breakpoint, pg. 295.
:break.n n_u4_8.11 is n_ar = 0b1111 & n_u4_8.11 & n_at = 0b0010 & n_op0 = 0b1101 {
    breakpoint(0x010000:4, n_u4_8.11:1, 0:1);
}

# BT - Branch if True, pg. 296.
:bt bs, srel_16.23 is srel_16.23 & ar = 0b0001 & bs & at = 0b0111 & op0 = 0b0110 {
    if (bs)
        goto srel_16.23;
}

# CALL0 - Non-windowed Call, pg. 297.
:call0 srel_6.23_sb2 is srel_6.23_sb2 & u2_4.5 = 0 & op0 = 0b0101 {
    #local dst = srel_6.23_sb2;
    i2 = a2;
    i3 = a3;
    i4 = a4;
    i5 = a5;
    i6 = a6;
    i7 = a7;     
    a0 = inst_start + 3;
    call srel_6.23_sb2;
}

# CALLX0 - Non-windowed Call Register, pg. 304.
:callx0 as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6.7 = 0b11 & u2_4.5 = 0 & op0 = 0 {
    local dst = as;
    i2 = a2;
    i3 = a3;
    i4 = a4;
    i5 = a5;
    i6 = a6;
    i7 = a7;      
    a0 = inst_start + 3;
    call [dst];
}

# CEIL.S - Ceiling Single to Fixed, pg. 311.
:ceil.s ar, fs, u4_4.7 is op2 = 0b1011 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 {
    local scale:4 = int2float(1:1 << u4_4.7:1);
    ar = ceil(fs f* scale);
}

# CLAMPS - Signed Clamp, pg. 312.
:clamps ar, as, u5_4.7_plus7 is op2 = 0b0011 & op1 = 0b0011 & ar & as & u5_4.7_plus7 & op0 = 0 {
    # ar ← min(max(as, -2^{u5_4.7_plus7}), 2^{u5_4.7_plus7}-1)
    local maxval:4 =  (1 << u5_4.7_plus7) - 1;
    local minval:4 = -(1 << u5_4.7_plus7);
    if (as s< minval)
        goto <write_minval>;
    if (as s> maxval)
        goto <write_maxval>;

    ar = as;
    goto inst_next;

    <write_minval>
    ar = minval;
    goto inst_next;

    <write_maxval>
    ar = maxval;
    # fallthrough inst_next
}

# DHI - Data Cache Hit Invalidate, pg. 313.
:dhi as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0110 & op0 = 0b0010 {
    dhi(as + zext(u10_16.23_sb2));
}

# DHU - Data Cache Hit Unlock, pg. 315.
:dhu as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0010 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 {
    dhu(as + zext(u8_20.23_sb4));
}

# DHWB - Data Cache Hit Writeback, pg. 317.
:dhwb as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0100 & op0 = 0b0010 {
    dhwb(as + zext(u10_16.23_sb2));
}

# DHWBI - Data Cache Hit Writeback Invalidate, pg. 319.
:dhwbi as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0101 & op0 = 0b0010 {
    dhwbi(as + zext(u10_16.23_sb2));
}

# DII - Data Cache Index Invalidate, pg. 321.
:dii as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0111 & op0 = 0b0010 {
    dii(as + zext(u10_16.23_sb2));
}

# DIU - Data Cache Index Unlock, pg. 323.
:diu as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0011 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 {
    diu(as + zext(u8_20.23_sb4));
}

# DIWB - Data Cache Index Write Back, pg. 325.
:diwb as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0100 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 {
    diwb(as + zext(u8_20.23_sb4));
}

# DIWBI - Data Cache Index Write Back Invalidate, pg. 327.
:diwbi as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0101 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 {
    diwbi(as + zext(u8_20.23_sb4));
}

# DPFL - Data Cache Prefetch and Lock, pg. 329.
:dpfl as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0 & ar = 0b0111 & as & at = 0b1000 & op0 = 0b0010 {
    dpfl(as + zext(u8_20.23_sb4));
}

# DPFR - Data Cache Prefetch for Read, pg. 331.
:dpfr as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0 & op0 = 0b0010 {
    dpfr(as + zext(u10_16.23_sb2));
}

# DPFRO - Data Cache Prefetch for Read Once, pg. 333.
:dpfro as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0010 & op0 = 0b0010 {
    dpfro(as + zext(u10_16.23_sb2));
}

# DPFW - Data Cache Prefetch for Write, pg. 335.
:dpfw as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0001 & op0 = 0b0010 {
    dpfw(as + zext(u10_16.23_sb2));
}

# DPFWO - Data Cache Prefetch for Write Once, pg. 337.
:dpfwo as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b0011 & op0 = 0b0010 {
    dpfwo(as + zext(u10_16.23_sb2));
}

# DSYNC - Load/Store Synchronize, pg. 339.
:dsync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0011 & op0 = 0 {
    dsync();
}

# ESYNC - Execute Synchronize, pg. 342.
:esync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0010 & op0 = 0 {
    esync();
}

# EXCW - Exception Wait, pg. 343.
:excw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1000 & op0 = 0 {
    excw();
}

# EXTUI - Extract Unsigned Immediate, pg. 344.
:extui ar, at, u5_8.11_16, u5_20.23_plus1 is u5_20.23_plus1 & u3_17.19 = 0b010 & u5_8.11_16 & ar & at & op0 = 0 {
    local shifted:4 = at >> u5_8.11_16;
    local mask:4 = (1:4 << (u5_20.23_plus1))-1;
    ar = shifted & mask;
}

# EXTW - External Wait, pg. 345.
:extw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1101 & op0 = 0 {
    extw();
}

# FLOAT.S - Convert Fixed to Single, pg. 346.
:float.s fr, as, u4_4.7 is op2 = 0b1100 & op1 = 0b1010 & fr & as & u4_4.7 & op0 = 0 {
    local f = int2float(as);
    local d = int2float(1:2 << u4_4.7:2);
    fr = d f/ f;
}

# FLOOR.S - Floor Single to Fixed, pg. 347.
:floor.s ar, fs, u4_4.7 is op2 = 0b1010 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 {
    local scale:4 = int2float(1:2 << u4_4.7:2);
    ar = floor(fs f* scale);
}

# IDTLB - Invalidate Data TLB Entry, pg. 348.
:idtlb as is op2 = 0b0101 & op1 = 0 & ar = 0b1100 & as & at = 0 & op0 = 0 {
    idtlb();
}

# IHI - Instruction Cache Hit Invalidate, pg. 349.
:ihi as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b1110 & op0 = 0b0010 {
    ihi(as + zext(u10_16.23_sb2));
}

# IHU - Instruction Cache Hit Unlock, pg. 351.
:ihu as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0010 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 {
    ihu(as + zext(u8_20.23_sb4));
}

# III - Instruction Cache Index Invalidate, pg. 353.
:iii as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b1111 & op0 = 0b0010 {
    iii(as + zext(u10_16.23_sb2));
}

# IITLB - Invalidate Instruction TLB Entry, pg. 355.
:iitlb as is op2 = 0b0101 & op1 = 0 & ar = 0b0100 & as & at = 0 & op0 = 0 {
    iitlb(as);
}

# IIU - Instruction Cache Index Unlock, pg. 356.
:iiu as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0b0011 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 {
    iiu(as + zext(u8_20.23_sb4));
}

# ILL - Illegal Instruction, pg. 358.
:ill is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & at = 0 & op0 = 0 {
    ill();
    goto inst_start;
}

# ILL.N - Narrow Illegal Instruction, pg. 359.
:ill.n is n_ar = 0b1111 & n_as = 0 & n_at = 0b0110 & n_op0 = 0b1101 {
    ill();
    goto inst_start;
}

# IPF - Instruction Cache Prefetch, pg. 360.
:ipf as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0111 & as & at = 0b1100 & op0 = 0b0010 {
    ipf(as + zext(u10_16.23_sb2));
}

# IPFL - Instruction Cache Prefetch and Lock, pg. 362.
:ipfl as, u8_20.23_sb4 is u8_20.23_sb4 & op1 = 0 & ar = 0b0111 & as & at = 0b1101 & op0 = 0b0010 {
    ipfl(as + zext(u8_20.23_sb4));
}

# ISYNC - Instruction Fetch Synchronize, pg. 364.
:isync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0 & op0 = 0 {
    isync();
}

# J - Unconditional Jump, pg. 366.
:j srel_6.23 is srel_6.23 & u2_4.5 = 0 & op0 = 0b0110 {
    goto srel_6.23;
}

# J.L is a macro.

# RET (JX A0) - Non-Windowed Return, pg. 478.
:ret is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & u2_6.7 = 0b10 & u2_4.5 = 0b10 & op0 = 0 {
    return [a0];
}

# The manual suggests that RET is equivalent to JX A0, yet RET has bit 5 unset, JX doesn’t.
:ret is op2 = 0 & op1 = 0 & ar = 0 & as = 0 & u2_6.7 = 0b10 & u2_4.5 = 0b00 & op0 = 0 {
    return [a0];
}

# JX - Uncoditional Jump Register, pg. 368.
:jx as is op2 = 0 & op1 = 0 & ar = 0 & as & u2_6.7 = 0b10 & u2_4.5 = 0b10 & op0 = 0 {
    goto [as];
}

# L8UI - Load 8-bit Unsigned, pg. 369.
:l8ui at, as, u8_16.23 is u8_16.23 & ar = 0 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u8_16.23:1);
    at = zext(*:1 addr);
}

# L16SI - Load 16-bit Signed, pg. 370.
:l16si at, as, u9_16.23_sb1 is u9_16.23_sb1 & ar = 0b1001 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u9_16.23_sb1);
    at = sext(*:2 addr);
}

# L16UI - Load 16-bit Unsigned, pg. 372.
:l16ui at, as, u9_16.23_sb1 is u9_16.23_sb1 & ar = 0b001 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u9_16.23_sb1);
    at = zext(*:2 addr);
}

# L32AI - Load 32-bit Acquire, pg. 374.
:l32ai at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1011 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u10_16.23_sb2);
    at = *:4 addr;
    acquire(addr);
}

# L32I - Load 32-bit, pg. 378.
:l32i at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0010 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u10_16.23_sb2);
    at = *:4 addr;
}

# L32I.N - Narrow Load 32-bit, pg. 380.
:l32i.n n_at, n_as, n_u6_12.15_sb2 is n_u6_12.15_sb2 & n_as & n_at & n_op0 = 0b1000 {
    local addr:4 = n_as + zext(n_u6_12.15_sb2);
    n_at = *:4 addr;
}

# L32R - Load 32-bit PC-relative, pg. 382.
:l32r at, srel_8.23_oex_sb2 is srel_8.23_oex_sb2 & at & op0 = 0b0001 {
    at = srel_8.23_oex_sb2;
}

# LDCT - Load Data Cache Tag, pg. 384.
:ldct at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1000 & as & at & op0 = 0 {
    at = ldct(as);
}

# LICT - Load Instruction Cache Tag, pg. 388.
:lict at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0 & as & at & op0 = 0 {
    at = lict(as);
}

# LICW - Load Instruction Cache Word, pg. 390.
:licw at, as is op2 = 0b1111 & op1 = 0b0010 & ar = 0 & as & at & op0 = 0 {
    at = licw(as);
}

macro loopSetup(as, end, doit) {
    LCOUNT = as - 1;
    LBEG = inst_next;
    #LEND = end;
    if (doit) goto <body>;
    goto end;
    <body>
}

# LOOP - Loop, pg. 392.
:loop as, urel_16.23 is urel_16.23 & ar=0b1000 & as & at=0b0111 & op0=0b0110
[loopEnd=1; globalset(urel_16.23, loopEnd);] {
    loopSetup(as, urel_16.23, 1:1);
}

# LOOPGTZ - Loop if Greater Than Zero, pg. 394.
:loopgtz as, urel_16.23 is urel_16.23 & ar=0b1010 & as & at=0b0111 & op0=0b0110
[loopEnd=1; globalset(urel_16.23, loopEnd);] {
    loopSetup(as, urel_16.23, as s> 0);
}

# LOOPNEZ - Loop if Not Equal Zero, pg. 396.
:loopnez as, urel_16.23 is urel_16.23 & ar=0b1001 & as & at=0b0111 & op0=0b0110
[loopEnd=1; globalset(urel_16.23, loopEnd);] {
    loopSetup(as, urel_16.23, as != 0);
}

# LSI - Load Single Immediate, pg. 398.
:lsi ft, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0 & as & ft & op0 = 0b0011 {
    local addr:4 = as + zext(u10_16.23_sb2);
    ft = *:4 addr;
}

# LSIU - Load Single Immediate with Update, pg. 400.
:lsiu ft, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1000 & as & ft & op0 = 0b0011 {
    local addr:4 = as + zext(u10_16.23_sb2);
    ft = *:4 addr;
    as = addr;
}

# LSX - Load Single Indexed, pg. 402.
:lsx fr, as, at is op2 = 0 & op1 = 0b1000 & fr & as & at & op0 = 0 {
    local addr:4 = as+at;
    fr = *:4 addr;
}

# LSXU - Load Single Indexed with Update, pg. 404.
:lsxu fr, as, at is op2 = 0b0001 & op1 = 0b1000 & fr & as & at & op0 = 0 {
    local addr:4 = as+at;
    fr = *:4 addr;
    as = addr;
}

# MADD.S - Multiply and Add Single, pg. 406.
:madd.s fr, fs, ft is op2 = 0b0100 & op1 = 0b1010 & fr & fs & ft & op0 = 0 {
    fr = fr f+ (fs f* ft);
}

# MAX - Maximum Value, pg. 407.
:max ar, as, at is op2 = 0b0101 & op1 = 0b0011 & ar & as & at & op0 = 0 {
    if (as s> at)
        goto <s_larger>;
    ar = at;
    goto inst_next;
<s_larger>
    ar = as;
}

# MAXU - Maximum Value Unsigned, pg. 408.
:maxu ar, as, at is op2 = 0b0111 & op1 = 0b0011 & ar & as & at & op0 = 0 {
    if (as > at)
        goto <s_larger>;
    ar = at;
    goto inst_next;
<s_larger>
    ar = as;
}

# MEMW - Memory Wait, pg. 409.
:memw is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1100 & op0 = 0 {
    memw();
}

# MIN - Minimum Value, pg. 410.
:min ar, as, at is op2 = 0b0100 & op1 = 0b0011 & ar & as & at & op0 = 0 {
    if (as s< at)
        goto <s_smaller>;
    ar = at;
    goto inst_next;
<s_smaller>
    ar = as;
}

# MINU - Minimum Value Unsigned, pg. 411.
:minu ar, as, at is op2 = 0b0110 & op1 = 0b0011 & ar & as & at & op0 = 0 {
    if (as < at)
        goto <s_smaller>;
    ar = at;
    goto inst_next;
<s_smaller>
    ar = as;
}

# MOV.N - Narrow Move, pg. 413.
:mov.n n_at, n_as is n_ar = 0 & n_as & n_at & n_op0 = 0b1101 {
    n_at = n_as;
}

# MOV.S - Move Single, pg. 414.
:mov.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0 & op0 = 0 {
    fr = fs;
}

# MOVEQZ - Move if Equal to Zero, pg. 415.
:moveqz ar, as, at is op2 = 0b1000 & op1 = 0b0011 & ar & as & at & op0 = 0 {
    if (at != 0)
        goto inst_next;
    ar = as;
}

# MOVEQZ.S - Move Single if Equal to Zero, pg. 416.
:moveqz.s fr, fs, at is op2 = 0b1000 & op1 = 0b1011 & fr & fs & at & op0 = 0 {
    if (at != 0)
        goto inst_next;
    fr = fs;
}

# MOVF - Move if False, pg. 417.
:movf ar, as, bt is op2 = 0b1100 & op1 = 0b0011 & ar & as & bt & op0 = 0 {
    if (bt)
        goto inst_next;
    ar = as;
}

# MOVF.S - Move Single if False, pg. 418.
:movf.s fr, fs, bt is op2 = 0b1100 & op1 = 0b1011 & fr & fs & bt & op0 = 0 {
    if (bt)
        goto inst_next;
    fr = fs;
}

# MOVGEZ - Move if Greater Than or Equal to Zero, pg. 419.
:movgez ar, as, at is op2 = 0b1011 & op1 = 0b0011 & ar & as & at & op0 = 0 {
    if (at s< 0)
        goto inst_next;
    ar = as;
}

# MOVGEZ.S - Move Single if Greater Than or Equal to Zero, pg. 420.
:movgez.s fr, fs, at is op2 = 0b1011 & op1 = 0b1011 & fr & fs & at & op0 = 0 {
    if (at s< 0)
        goto inst_next;
    fr = fs;
}

# MOVI - Move Immediate, pg. 421.
:movi at, s16_16.23_8.11 is s16_16.23_8.11 & ar = 0b1010 & at & op0 = 0b0010 {
    local val:4 = sext(s16_16.23_8.11);
    at = val;
}


# MOVI.N - Narrow Move Immediate, pg. 422.
:movi.n n_as, n_s8_12.15_4.6_asymm is n_s8_12.15_4.6_asymm & n_as & n_u1_7 = 0 & n_op0 = 0b1100 {
    local val:4 = sext(n_s8_12.15_4.6_asymm);
    n_as = val;
}

# MOVLTZ - Move if Less Than Zero, pg. 423.
:movltz ar, as, at is op2 = 0b1010 & op1 = 0b0011 & ar & as & at & op0 = 0 {
    if (at s>= 0)
        goto inst_next;
    ar = as;
}

# MOVLTZ.S - Move Single if Less Than Zero, pg. 424.
:movltz.s fr, fs, at is op2 = 0b1010 & op1 = 0b1011 & fr & fs & at & op0 = 0 {
    if (at s>= 0)
        goto inst_next;
    fr = fs;
}

# MOVNEZ - Move if Not Equal to Zero, pg. 425.
:movnez ar, as, at is op2 = 0b1001 & op1 = 0b0011 & ar & as & at & op0 = 0 {
    if (at == 0)
        goto inst_next;
    ar = as;
}

# MOVNEZ.S - Move Single if Not Equal to Zero, pg. 426.
:movnez.s fr, fs, at is op2 = 0b1001 & op1 = 0b1011 & fr & fs & at & op0 = 0 {
    if (at == 0)
        goto inst_next;
    fr = fs;
}

# MOVT - Move if True, pg. 428.
:movt ar, as, bt is op2 = 0b1101 & op1 = 0b0011 & ar & as & bt & op0 = 0 {
    if (!bt)
        goto inst_next;
    ar = as;
}

# MOVT.S - Move Single if True, pg. 429.
:movt.s fr, fs, bt is op2 = 0b1101 & op1 = 0b1011 & fr & fs & bt & op0 = 0 {
    if (!bt)
        goto inst_next;
    fr = fs;
}

# MSUB.S - Multiply and Subtract Single, pg. 430.
:msub.s fr, fs, ft is op2 = 0b0101 & op1 = 0b1010 & fr & fs & ft & op0 = 0 {
    fr = fr f- (fs f* ft);
}

# MUL.S - Multiply Single, pg. 435.
:mul.s fr, fs, ft is op2 = 0b0010 & op1 = 0b1010 & fr & fs & ft & op0 = 0 {
    fr = fs f* ft;
}

# MUL16S - Multiply 16-bit Signed, pg. 436.
:mul16s ar, as, at is op2 = 0b1101 & op1 = 0b0001 & ar & as & at & op0 = 0 {
    ar = sext(as:2) * sext(at:2);
}

# MUL16U - Multiply 16-bit Unsigned, pg. 437.
:mul16u ar, as, at is op2 = 0b1100 & op1 = 0b0001 & ar & as & at & op0 = 0 {
    ar = zext(as:2) * zext(at:2);
}

# MULL - Multiply Low, pg. 450.
:mull ar, as, at is op2 = 0b1000 & op1 = 0b0010 & ar & as & at & op0 = 0 {
    ar = as * at;
}

# MULSH - Multiply Signed High, pg. 455.
:mulsh ar, as, at is op2 = 0b1011 & op1 = 0b0010 & ar & as & at & op0 = 0 {
    local s64:8 = sext(as);
    local t64:8 = sext(at);
    local p:8 = (s64 * t64);
    ar = p(4);
}

# MULUH - Multiply Unsigned High, pg. 456.
:muluh ar, as, at is op2 = 0b1010 & op1 = 0b0010 & ar & as & at & op0 = 0 {
    local s64:8 = zext(as);
    local t64:8 = zext(at);
    local p:8 = (s64 * t64);
    ar = p(4);
}

# NEG - Negate, pg. 457.
:neg ar, at is op2 = 0b0110 & op1 = 0 & ar & as = 0 & at & op0 = 0 {
    ar = -at;
}

# NEG.S - Negate Single, pg. 458.
:neg.s fr, fs is op2 = 0b1111 & op1 = 0b1010 & fr & fs & at = 0b0110 & op0 = 0 {
    fr = f- fs;
}

# NOP - No Operation, pg. 459.
:nop is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b1111 & op0 = 0 { }

# NOP.N - Narrow No Operation, pg. 460.
:nop.n is n_ar = 0b1111 & n_as = 0 & n_at = 0b0011 & n_op0 = 0b1101 { }

# NSA - Normalization Shift Amount, pg. 461.
:nsa at, as is op2 = 0b0100 & op1 = 0 & ar = 0b1110 & as & at & op0 = 0 {
    # https://stackoverflow.com/questions/54772520/normalizing-a-two-complement-number
    at = nsa(as);
}

# NSAU - Normalization Shift Amount Unsigned, pg. 462. (Count leading zeros)
:nsau at, as is op2 = 0b0100 & op1 = 0 & ar = 0b1111 & as & at & op0 = 0 {
    local z4 = as[16,16] == 0;

    local t3 = zext(z4)*as[0,16] + zext(!z4)*as[16,16];
    local z3 = t3[8,8] == 0;

    local t2 = (z3)*t3[0,8] + (!z3)*t3[8,8];
    local z2 = t2[4,4] == 0;

    local t1 = (z2)*t2[0,4] + (!z2)*t2[4,4];
    local z1 = t1[2,2] == 0;

    local z0 = (z1)*(t1[1,1] == 0) + (!z1)*(t1[3,1] == 0);
    local all0 = as == 0;

    at = zext((all0)*32 + (!all0)*(z4<<4 | z3<<3 | z2<<2 | z1<<1 | z0));
}

# OEQ.S - Compare Single Equal, pg. 463.
:oeq.s br, fs, ft is op2 = 0b0010 & op1 = 0b1011 & br & fs & ft & op0 = 0 {
    br = !nan(fs) && !nan(ft) && fs f== ft;
}

# OLE.S - Compare Single Ordered and Less Than or Equal, pg. 464
:ole.s br, fs, ft is op2 = 0b0110 & op1 = 0b1011 & br & fs & ft & op0 = 0 {
    br = !nan(fs) && !nan(ft) && fs f<= ft;
}

# OLT.S - Compare Single Ordered and Less Than, pg. 465.
:olt.s br, fs, ft is op2 = 0b0100 & op1 = 0b1011 & br & fs & ft & op0 = 0 {
    br = !nan(fs) && !nan(ft) && fs f< ft;
}

# MOV - Move, pg. 412. Special case of OR as, at, at.
:mov ar, as is op2 = 0b0010 & op1 = 0 & ar & as & as = at & op0 = 0 {
    ar = as;
}

# OR - Bitwise Logical Or, pg. 466.
:or ar, as, at is op2 = 0b0010 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = as | at;
}

# ORB - Boolean Or, pg. 467.
:orb br, bs, bt is op2 = 0b0010 & op1 = 0b0010 & br & bs & bt & op0 = 0 {
    br = bs || bt;
}

# ORBC - Boolean Or with Complement, pg. 468.
:orbc br, bs, bt is op2 = 0b0011 & op1 = 0b0010 & br & bs & bt & op0 = 0 {
    br = bs || !bt;
}

# PDTLB - Probe Data TLB, pg. 469.
:pdtlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1101 & as & at & op0 = 0 {
    at = pdtlb(as);
}

# PITLB - Probe Instruction TLB, pg. 470.
:pitlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0101 & as & at & op0 = 0 {
    at = pitlb(as);
}

# QUOS - Quotient Signed, pg. 471.
:quos ar, as, at is op2 = 0b1101 & op1 = 0b0010 & ar & as & at & op0 = 0 {
    ar = as s/ at;
}

# QUOU - Quotient Unsigned, pg. 472.
:quou ar, as, at is op2 = 0b1100 & op1 = 0b0010 & ar & as & at & op0 = 0 {
    ar = as / at;
}

# RDTLB0 - Read Data TLB Virtual Entry, pg. 473.
:rdtlb0 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1011 & as & at & op0 = 0 {
    at = rdtlb0(as);
}

# RDTLB1 - Read Data TLB Entry Translation, pg. 474.
:rdtlb1 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1111 & as & at & op0 = 0 {
    at = rdtlb1(as);
}

# REMS - Remainder Signed, pg. 475.
:rems ar, as, at, is op2 = 0b1111 & op1 = 0b0010 & ar & as & at & op0 = 0 {
    ar = as s% at;
}

# REMU - Remainder Unsigned, pg. 476.
:remu ar, as, at, is op2 = 0b1110 & op1 = 0b0010 & ar & as & at & op0 = 0 {
    ar = as % at;
}

# RER - Read External Register, pg. 477.
:rer as, at is op2 = 0b0100 & op1 = 0 & ar = 0b0110 & as & at & op0 = 0 {
    as = rer(at);
}

# RET.N - Narrow Non-Windowed Return, pg. 479.
:ret.n is n_ar = 0b1111 & n_as = 0 & n_at = 0 & n_op0 = 0b1101 {
    return [a0];
    o2=a2;
}

# RFDD - Return from Debug and Dispatch, pg. 484.
:rfdd is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1110 & (as = 0b0000 | as = 0b0001) & at = 0b0001 & op0 = 0 {
    rfdd();
}

# RFDE _ Return From Double Exception, pg. 485.
:rfde is op2 = 0 & op1 = 0 & ar = 0b0011 & as =0b0010 & at = 0 & op0 = 0 {
    rfde();
}

# RFDO - Return from Debug Operation, pg. 486.
:rfdo is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1110 & as = 0 & at = 0 & op0 = 0 {
    rfdo();
}

# RFE - Return From Exception, pg. 487.
:rfe is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0 & at = 0 & op0 = 0 {
    rfe();
}

# RFI - Return from High-Priority Interrupt, pg. 488.
:rfi u4_8.11 is op2 = 0 & op1 = 0 & ar = 0b0011 & u4_8.11 & at = 0b0001 & op0 = 0 {
    rfi(u4_8.11:1);
}

# RFME - Return from Memory Error, pg. 489.
:rfme is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0 & at = 0b0010 & op0 = 0 {
    rfme();
}

# RFR - Move FR to AR, pg. 490.
:rfr ar, fs is op2 = 0b1111 & op1 = 0b1010 & ar & fs & at = 0b0100 & op0 = 0 {
    ar = fs;
}

# RFUE - Return from User-Mode Exception, pg. 491.
:rfue is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0001 & at = 0 & op0 = 0 {
    rfue();
}

# RFWO - Return from Window Overflow, pg. 492.
:rfwo is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0100 & at = 0 & op0 = 0 {
    rfwo();
}

# RFWU - Return from Window Underflow, pg. 493.
:rfwu is op2 = 0 & op1 = 0 & ar = 0b0011 & as = 0b0101 & at = 0 & op0 = 0 {
    rfwu();
}

# RITLB0 - Read Instruction TLB Virtual Entry, pg. 494.
:ritlb0 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0011 & as & at & op0 = 0 {
    at = ritlb0(as);
}

# RITLB1 - Read Instruction TLB Entry Translation, pg. 495.
:ritlb1 at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0111 & as & at & op0 = 0 {
    at = ritlb1(as);
}

# ROUND.S - Round Single to Fixed, pg. 497.
:round.s ar, fs, u4_4.7 is op2 = 0b1000 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 {
    local scale:4 = int2float(1:2 << u4_4.7:2);
    ar = round(fs f* scale);
}

# RSIL - Read and Set Interrupt Level, pg. 498.
:rsil at, u4_8.11 is op2 = 0 & op1 = 0 & ar = 0b0110 & u4_8.11 & at & op0 = 0 {
    at = rsil(u4_8.11:1);
}

# RSR - Read Special Register, pg. 500.
:rsr at, sr is op0 = 0 & op1 = 0b0011 & sr & at & op0 = 0 {
    local src:4 =  zext(sr);
    at = *[register]:4 src;
}

# RSYNC - Register Read Synchronize, pg. 502.
:rsync is op2 = 0 & op1 = 0 & ar = 0b0010 & as = 0 & at = 0b0001 & op0 = 0 {
    rsync();
}

# RUR - Read User Register, pg. 503.
:rur ar, u8_4.11 is op2 = 0b1110 & op1 = 0b0011 & ar & u8_4.11 & op0 = 0 {
    ar = rur(u8_4.11:1);
}

# S8I - Store 8-bit, pg. 504.
:s8i at, as, u8_16.23 is u8_16.23 & ar = 0b0100 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u8_16.23:1);
    *:1 addr = at:1;
}

# S16I - Store 16-bit, pg. 505.
:s16i at, as, u9_16.23_sb1 is u9_16.23_sb1 & ar = 0b0101 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u9_16.23_sb1);
    *:2 addr = at:2;
}

# S32C1I - Store 32-bit Compare Conditional, pg. 506
:s32c1i at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1110 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u10_16.23_sb2);
    at = s32c1i(addr);
}

# S32I - Store 32-bit, pg. 510.
:s32i at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0110 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u10_16.23_sb2);
    *:4 addr = at;
}

# S32I.N - Narrow Store 32-bit, pg. 512.
:s32i.n n_at, n_as, n_u6_12.15_sb2 is n_u6_12.15_sb2 & n_as & n_at & n_op0 = 0b1001 {
    local addr:4 = n_as + zext(n_u6_12.15_sb2);
    *:4 addr = n_at;
}

# S32RI - Store 32-bit Release, pg. 514.
:s32ri at, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1111 & as & at & op0 = 0b0010 {
    local addr:4 = as + zext(u10_16.23_sb2);
    *:4 addr = at;
    release(addr);
}

# SDCT - Store Data Cache Tag, pg. 516.
:sdct at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b1001 & as & at & op0 = 0 {
    sdct(as, at);
}

# SEXT - Sign Extend, pg. 518.
:sext ar, as, u5_4.7_plus7 is op2 = 0b0010 & op1 = 0b0011 & ar & as & u5_4.7_plus7 & op0 = 0 {
    local shift:1 = 31:1 - u5_4.7_plus7;
    local tmp:4 = as << shift;
    ar = tmp s>> shift;
}

# SICT - Store Instruction Cache Tag, pg. 519.
:sict at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b0001 & as & at & op0 = 0 {
    sict(as, at);
}

# SICW - Store Instruction Cache word, pg. 521.
:sicw at, as is op2 = 0b1111 & op1 = 0b0001 & ar = 0b0011 & as & at & op0 = 0 {
    sicw(as, at);
}

# SIMCALL - Simulator Call, pg. 523.
:simcall is op2 = 0 & op1 = 0 & ar = 0b0101 & as = 0b0001 & at = 0 & op0 = 0 {
    simcall();
}

# SLL - Shift Left Logical, pg. 524.
:sll ar, as is op2 = 0b1010 & op1 = 0b0001 & ar & as & at = 0 & op0 = 0 {
    local sa = 32 - SAR;
    ar = as << sa;
}

# SLLI - Shift Left Logical Immediate, pg. 525.
:slli ar, as, u5_4.7_20_slli is u3_21.23 = 0 & u5_4.7_20_slli & op1 = 0b0001 & ar & as & op0 = 0 {
    ar = as << u5_4.7_20_slli;
}


# SRA - Shift Right Arithmetic, pg. 526.
:sra ar, at is op2 = 0b1011 & op1 = 0b0001 & ar & as = 0 & at & op0 = 0 {
    ar = at s>> SAR;
}

# SRAI - Shift Right Arithmetic Immediate, pg. 527.
:srai ar, at, u5_8.11_20 is u3_21.23 = 0b001 & u5_8.11_20 & op1 = 0b0001 & ar & at & op0 = 0 {
    ar = at s>> u5_8.11_20;
}

# SRC - Shift Right Combined, pg. 528.
:src ar, as, at is op2 = 0b1000 & op1 = 0b0001 & ar & as & at & op0 = 0 {
    local s64:8 = zext(as);
    local t64:8 = zext(at);
    local combined:8 = (s64 << 32) | t64;
    local shifted:8 = combined >> SAR;
    ar = shifted:4;
}

# SRL - Shift Right Logical, pg. 529.
:srl ar, at is op2 = 0b1001 & op1 = 0b0001 & ar & as = 0 & at & op0 = 0 {
    ar = at >> SAR;
}

# SRLI - Shift Right Logical Immediate, pg. 530.
:srli ar, at, u4_8.11 is op2 = 0b0100 & op1 = 0b0001 & ar & u4_8.11 & at & op0 = 0 {
    ar = at >> u4_8.11;
}

# SSA8B - Set Shift Amount for BE Byte Shift, pg. 531.
:ssa8b as is op2 = 0b0100 & op1 = 0 & ar = 0b0011 & as & at = 0 & op0 = 0 {
    local lsa:4 = (as&3)*8;
    SAR = 32 - lsa;
}

# SSA8L - Set Shift Amount for LE Byte Shift, pg. 532.
:ssa8l as is op2 = 0b0100 & op1 = 0 & ar = 0b0010 & as & at = 0 & op0 = 0 {
    SAR = (as&3)*8;
}

# SSAI - Set Shift Amount Immediate, pg. 533.
:ssai u5_8.11_4 is op2 = 0b0100 & op1 = 0 & ar = 0b0100 & u5_8.11_4 & u3_5.7 = 0 & op0 = 0 {
    SAR = zext(u5_8.11_4);
}

# SSI - Store Single Immediate, pg. 534.
:ssi ft, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b0100 & as & ft & op0 = 0b0011 {
    local addr:4 = as + zext(u10_16.23_sb2);
    *:4 addr = ft;
}

# SSIU - Store Single Immediate with Update, pg. 536.
:ssiu ft, as, u10_16.23_sb2 is u10_16.23_sb2 & ar = 0b1100 & as & ft & op0 = 0b0011 {
    local addr:4 = as + zext(u10_16.23_sb2);
    *:4 addr = ft;
    as = addr;
}

# SSL - Set Shift Amount for Left Shift, pg. 538.
:ssl as is op2 = 0b0100 & op1 = 0 & ar = 0b0001 & as & at = 0 & op0 = 0 {
    SAR = 32 - (as & 0x1f);
}

# SSR - Set Shift Amount for Right Shift, pg. 539.
:ssr as is op2 = 0b0100 & op1 = 0 & ar = 0 & as & at = 0 & op0 = 0 {
    SAR = (as & 0x1f);
}

# SSX - Store Singe Indexed, pg. 540.
:ssx fr, as, at is op2 = 0b0100 & op1 = 0b1000 & fr & as & at & op0 = 0 {
    local addr:4 = as+at;
    *:4 addr = fr;
}

# SSXU - Store Singe Indexed with Update, pg. 541.
:ssxu fr, as, at is op2 = 0b0101 & op1 = 0b1000 & fr & as & at & op0 = 0 {
    local addr:4 = as+at;
    *:4 addr = fr;
    as = addr;
}

# SUB - Subtract, pg. 542.
:sub ar, as, at is op2 = 0b1100 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = as - at;
}

# SUB.S - Subtract Single, pg. 543.
:sub.s fr, fs, ft is op2 = 0b0001 & op1 = 0b1010 & fr & fs & ft & op0 = 0 {
    fr = fs f- ft;
}

# SUBX2 - Subtract with Shift by 1, pg. 544.
:subx2 ar, as, at is op2 = 0b1101 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = (as << 1) - at;
}

# SUBX4 - Subtract with Shift by 2, pg. 545.
:subx4 ar, as, at is op2 = 0b1110 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = (as << 2) - at;
}

# SUBX8 - Subtract with Shift by 3, pg. 546.
:subx8 ar, as, at is op2 = 0b1111 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = (as << 3) - at;
}

# SYSCALL - System Call, pg. 547.
:syscall is op2 = 0 & op1 = 0 & ar = 0b0101 & as = 0 & at = 0 & op0 = 0 {
    syscall();
}

# TRUNC.S - Truncate Single to Fixed, pg. 548
:trunc.s ar, fs, u4_4.7 is op2 = 0b1001 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 {
    local scale:4 = int2float(1:2 << u4_4.7:2);
    ar = trunc(fs f* scale);
}

# UEQ.S - Compare Single Unordered or Equal, pg. 549.
:ueq.s br, fs, ft is op2 = 0b0011 & op1 = 0b1011 & br & fs & ft & op0 = 0 {
    br = nan(fs) || nan(ft) || fs f== ft;
}

# UFLOAT.S - Convert Unsigned Fixed to Single, pg. 550.
:ufloat.s fr, as, u4_4.7 is op2 = 0b1101 & op1 = 0b1010 & fr & as & u4_4.7 & op0 = 0 {
    local tmp:8 = zext(as);
    local f = int2float(tmp);
    local d = int2float(1:2 << u4_4.7:2);
    fr = d f/ f;
}

# ULE.S - Compare Single Unordered or Less Than or Equal, pg. 551.
:ule.s br, fs, ft is op2 = 0b0111 & op1 = 0b1011 & br & fs & ft & op0 = 0 {
    br = nan(fs) || nan(ft) || fs f<= ft;
}

# ULT.S - Compare Single Unordered or Less Than, pg. 552.
:ult.s br, fs, ft is op2 = 0b0101 & op1 = 0b1011 & br & fs & ft & op0 = 0 {
    br = nan(fs) || nan(ft) || fs f< ft;
}

# FIXME: UMUL.AA*

# UN.S - Compare Single Unordered, pg. 554.
:un.s br, fs, ft is op2 = 0b0001 & op1 = 0b1011 & br & fs & ft & op0 = 0 {
    br = nan(fs) || nan(ft);
}

# UTRUNC.S - Truncate Single to Fixed Unsigned, pg. 555.
:utrunc.s ar, fs, u4_4.7 is op2 = 0b1110 & op1 = 0b1010 & ar & fs & u4_4.7 & op0 = 0 {
    local scale:4 = int2float(1:2 << u4_4.7:2);
    local tmp:8 = trunc(fs f* scale);
    local posof = nan(fs) || (tmp >> 16) != 0;
    local negof = tmp s< 0;
    local noof  = !posof && !negof;
    ar = zext(posof)*0xffffffff + zext(negof)*0x80000000 + zext(noof)*tmp:4;
}

# WAITI - Wait Interrupt, pg. 556.
:waiti u4_8.11 is op2 = 0 & op1 = 0 & ar = 0b0111 & u4_8.11 & at = 0 & op0 = 0 {
    waiti(u4_8.11:4);
}

# WDTLB - Write Data TLB Entry, pg. 557.
:wdtlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b1110 & as & at & op0 = 0 {
    wdtlb(as, at);
}

# WER - Write External Register, pg. 558.
:wer as, at is op2 = 0b0100 & op1 = 0 & ar = 0b0111 & as & at & op0 = 0 {
    wer(as, at);
}

# WFR - Move AR to FR, pg. 559.
:wfr fr, as is op2 = 0b1111 & op1 = 0b1010 & fr & as & at = 0b0101 & op0 = 0 {
    fr = as;
}

# WITLB - Write Instruction TLB Entry, pg. 560.
:witlb at, as is op2 = 0b0101 & op1 = 0 & ar = 0b0110 & as & at & op0 = 0 {
    witlb(as, at);
}

# WSR - Write Special Register, pg. 561.
:wsr at, sr is op2 = 0b0001 & op1 = 0b0011 & sr & at & op0 = 0 {
    local dst:4 =  zext(sr);
    *[register]:4 dst = at;
}
#:WSR.^sr at is op2=0x1 & op1=0x3 & sr & at & op0=0x0
#{
#	*[register]:4 sr = at;
#}

# WUR - Write User Register, pg. 563.
:wur at, u8_8.15 is op2 = 0b1111 & op1 = 0b0011 & u8_8.15 & at & op0 = 0 {
    wur(u8_8.15:1, at);
}

# XOR - Bitwise Exclusive Or, pg. 564.
:xor ar, as, at is op2 = 0b0011 & op1 = 0 & ar & as & at & op0 = 0 {
    ar = as ^ at;
}

# XORB - Boolean Exclusive Or, pg. 565.
:xorb br, bs, bt is op2 = 0b0100 & op1 = 0b0010 & br & bs & bt & op0 = 0 {
    br = bs ^^ bt;
}

# XSR - Exchange Special Register, pg. 566.
:xsr at, u8_8.15 is op2 = 0b0110 & op1 = 0b0001 & u8_8.15 & at & op0 = 0 {
    at = xsr(u8_8.15:1, at);
}

# PAD, dummy
#:pad is op0_16=0x0 {
#}

# PAD, dummy
#:pad is op0_8=0x0 {
#}


