| /* Copyright 2016-2024 Free Software Foundation, Inc. |
| Contributed by Dimitar Dimitrov <dimitar@dinux.eu> |
| |
| This file is part of the PRU simulator. |
| |
| This library is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, see <http://www.gnu.org/licenses/>. */ |
| |
| /* |
| PRU Instruction Set Architecture |
| |
| INSTRUCTION (NAME, |
| SEMANTICS) |
| */ |
| |
| INSTRUCTION (add, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 + OP2; |
| CARRY = (((uint64_t) RS1 + (uint64_t) OP2) >> RD_WIDTH) & 1; |
| PC++) |
| |
| INSTRUCTION (adc, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 + OP2 + CARRY; |
| CARRY = (((uint64_t) RS1 + (uint64_t) OP2 + (uint64_t) CARRY) |
| >> RD_WIDTH) & 1; |
| PC++) |
| |
| INSTRUCTION (sub, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 - OP2; |
| CARRY = (((uint64_t) RS1 - (uint64_t) OP2) >> RD_WIDTH) & 1; |
| CARRY = !CARRY; |
| PC++) |
| |
| INSTRUCTION (suc, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 - OP2 - !CARRY; |
| CARRY = (((uint64_t) RS1 - (uint64_t) OP2 - (uint64_t) !CARRY) |
| >> RD_WIDTH) & 1; |
| CARRY = !CARRY; |
| PC++) |
| |
| INSTRUCTION (rsb, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = OP2 - RS1; |
| CARRY = (((uint64_t) OP2 - (uint64_t) RS1) >> RD_WIDTH) & 1; |
| CARRY = !CARRY; |
| PC++) |
| |
| INSTRUCTION (rsc, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = OP2 - RS1 - !CARRY; |
| CARRY = (((uint64_t) OP2 - (uint64_t) RS1 - (uint64_t) !CARRY) |
| >> RD_WIDTH) & 1; |
| CARRY = !CARRY; |
| PC++) |
| |
| INSTRUCTION (lsl, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 << (OP2 & 0x1f); |
| PC++) |
| |
| INSTRUCTION (lsr, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 >> (OP2 & 0x1f); |
| PC++) |
| |
| INSTRUCTION (and, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 & OP2; |
| PC++) |
| |
| INSTRUCTION (or, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 | OP2; |
| PC++) |
| |
| INSTRUCTION (xor, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 ^ OP2; |
| PC++) |
| |
| INSTRUCTION (not, |
| RD = ~RS1; |
| PC++) |
| |
| INSTRUCTION (min, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 < OP2 ? RS1 : OP2; |
| PC++) |
| |
| INSTRUCTION (max, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 > OP2 ? RS1 : OP2; |
| PC++) |
| |
| INSTRUCTION (clr, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 & ~(1u << (OP2 & 0x1f)); |
| PC++) |
| |
| INSTRUCTION (set, |
| OP2 = (IO ? IMM8 : RS2); |
| RD = RS1 | (1u << (OP2 & 0x1f)); |
| PC++) |
| |
| INSTRUCTION (jmp, |
| OP2 = (IO ? IMM16 : RS2); |
| PC = OP2) |
| |
| INSTRUCTION (jal, |
| OP2 = (IO ? IMM16 : RS2); |
| RD = PC + 1; |
| PC = OP2) |
| |
| INSTRUCTION (ldi, |
| RD = IMM16; |
| PC++) |
| |
| INSTRUCTION (halt, |
| pru_sim_syscall (sd, cpu); |
| PC++) |
| |
| INSTRUCTION (slp, |
| if (!WAKEONSTATUS) |
| { |
| RAISE_SIGINT (sd); |
| } |
| else |
| { |
| PC++; |
| }) |
| |
| INSTRUCTION (qbgt, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = (OP2 > RS1) ? (PC + BROFF) : (PC + 1)) |
| |
| INSTRUCTION (qbge, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = (OP2 >= RS1) ? (PC + BROFF) : (PC + 1)) |
| |
| INSTRUCTION (qblt, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = (OP2 < RS1) ? (PC + BROFF) : (PC + 1)) |
| |
| INSTRUCTION (qble, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = (OP2 <= RS1) ? (PC + BROFF) : (PC + 1)) |
| |
| INSTRUCTION (qbeq, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = (OP2 == RS1) ? (PC + BROFF) : (PC + 1)) |
| |
| INSTRUCTION (qbne, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = (OP2 != RS1) ? (PC + BROFF) : (PC + 1)) |
| |
| INSTRUCTION (qba, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = PC + BROFF) |
| |
| INSTRUCTION (qbbs, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = (RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1)) |
| |
| INSTRUCTION (qbbc, |
| OP2 = (IO ? IMM8 : RS2); |
| PC = !(RS1 & (1u << (OP2 & 0x1f))) ? (PC + BROFF) : (PC + 1)) |
| |
| INSTRUCTION (lbbo, |
| pru_dmem2reg (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2), |
| BURSTLEN, RD_REGN, RDB); |
| PC++) |
| |
| INSTRUCTION (sbbo, |
| pru_reg2dmem (cpu, XBBO_BASEREG + (IO ? IMM8 : RS2), |
| BURSTLEN, RD_REGN, RDB); |
| PC++) |
| |
| INSTRUCTION (lbco, |
| pru_dmem2reg (cpu, CTABLE[CB] + (IO ? IMM8 : RS2), |
| BURSTLEN, RD_REGN, RDB); |
| PC++) |
| |
| INSTRUCTION (sbco, |
| pru_reg2dmem (cpu, CTABLE[CB] + (IO ? IMM8 : RS2), |
| BURSTLEN, RD_REGN, RDB); |
| PC++) |
| |
| INSTRUCTION (xin, |
| DO_XIN (XFR_WBA, RD_REGN, RDB, XFR_LENGTH); |
| PC++) |
| |
| INSTRUCTION (xout, |
| DO_XOUT (XFR_WBA, RD_REGN, RDB, XFR_LENGTH); |
| PC++) |
| |
| INSTRUCTION (xchg, |
| DO_XCHG (XFR_WBA, RD_REGN, RDB, XFR_LENGTH); |
| PC++) |
| |
| INSTRUCTION (sxin, |
| sim_io_eprintf (sd, "SXIN instruction not supported by sim\n"); |
| RAISE_SIGILL (sd)) |
| |
| INSTRUCTION (sxout, |
| sim_io_eprintf (sd, "SXOUT instruction not supported by sim\n"); |
| RAISE_SIGILL (sd)) |
| |
| INSTRUCTION (sxchg, |
| sim_io_eprintf (sd, "SXCHG instruction not supported by sim\n"); |
| RAISE_SIGILL (sd)) |
| |
| INSTRUCTION (loop, |
| OP2 = (IO ? IMM8 + 1 : RS2_w0); |
| if (OP2 == 0) |
| { |
| PC = PC + LOOP_JMPOFFS; |
| } |
| else |
| { |
| LOOPTOP = PC + 1; |
| LOOPEND = PC + LOOP_JMPOFFS; |
| LOOPCNT = OP2; |
| LOOP_IN_PROGRESS = 1; |
| PC++; |
| }) |
| |
| INSTRUCTION (iloop, |
| OP2 = (IO ? IMM8 + 1 : RS2_w0); |
| if (OP2 == 0) |
| { |
| PC = PC + LOOP_JMPOFFS; |
| } |
| else |
| { |
| LOOPTOP = PC + 1; |
| LOOPEND = PC + LOOP_JMPOFFS; |
| LOOPCNT = OP2; |
| LOOP_IN_PROGRESS = 1; |
| PC++; |
| }) |
| |
| INSTRUCTION (lmbd, |
| { |
| int lmbd_i; |
| |
| OP2 = (IO ? IMM8 : RS2); |
| |
| for (lmbd_i = RS1_WIDTH - 1; lmbd_i >= 0; lmbd_i--) |
| { |
| if (!(((RS1 >> lmbd_i) ^ OP2) & 1)) |
| break; |
| } |
| RD = (lmbd_i < 0) ? 32 : lmbd_i; |
| PC++; |
| }) |