2020-08-06 01:40:23 +00:00
|
|
|
package vue;
|
|
|
|
|
2020-08-08 02:24:09 +00:00
|
|
|
// Java imports
|
|
|
|
import java.util.*;
|
|
|
|
|
2020-08-06 01:40:23 +00:00
|
|
|
// CPU state
|
|
|
|
class CPU {
|
|
|
|
|
|
|
|
// Private fields
|
2020-10-03 19:20:56 +00:00
|
|
|
private JavaVue vue; // Emulation state
|
2020-08-06 01:40:23 +00:00
|
|
|
|
|
|
|
// Package fields
|
2020-08-11 01:24:00 +00:00
|
|
|
Access access; // Access state
|
|
|
|
int cycles; // Cycles until next stage
|
2020-12-20 01:51:42 +00:00
|
|
|
int exception; // Exception code
|
2020-08-11 01:24:00 +00:00
|
|
|
int fetch; // Fetch unit index
|
|
|
|
Instruction inst; // Instruction state
|
|
|
|
int irq; // Interrupt lines
|
|
|
|
int[] jumpFrom; // Source PCs of most recent jumps
|
|
|
|
int[] jumpTo; // Destination PCs of most recent jumps
|
|
|
|
int stage; // Current processing stage
|
2020-08-06 01:40:23 +00:00
|
|
|
|
|
|
|
// Program registers
|
|
|
|
int[] program;
|
|
|
|
|
|
|
|
// System registers
|
|
|
|
int adtre; // Address Trap Register for Execution
|
|
|
|
int eipc; // Exception/interrupt PC
|
|
|
|
int eipsw; // Exception/interrupt PSW
|
|
|
|
int fepc; // Duplexed exception PC
|
|
|
|
int fepsw; // Duplexed exception PSW
|
|
|
|
int pc; // Program Counter
|
|
|
|
int sr29; // System register 29
|
|
|
|
int sr31; // System register 31
|
|
|
|
|
|
|
|
// Program Status Word
|
|
|
|
int psw_ae; // Address Trap Enable
|
|
|
|
int psw_ep; // Exception Pending
|
|
|
|
int psw_id; // Interrupt Disable
|
|
|
|
int psw_cy; // Carry
|
|
|
|
int psw_fiv; // Floating Reserved Operand
|
|
|
|
int psw_fov; // Floating Overflow
|
|
|
|
int psw_fpr; // Floating Precision
|
|
|
|
int psw_fro; // Floating Reserved Operand
|
|
|
|
int psw_fud; // Floating Underflow
|
|
|
|
int psw_fzd; // Floating Zero Divide
|
|
|
|
int psw_i; // Interrupt Level
|
|
|
|
int psw_np; // NMI Pending
|
|
|
|
int psw_ov; // Overflow
|
|
|
|
int psw_s; // Sign
|
|
|
|
int psw_z; // Zero
|
|
|
|
|
|
|
|
// Cache Control Word
|
|
|
|
int chcw_cec; // Clear Entry Count
|
|
|
|
int chcw_cen; // Clear Entry Number
|
|
|
|
int chcw_icc; // Instruction Cache Clear
|
|
|
|
int chcw_icd; // Instruction Cache Dump
|
|
|
|
int chcw_ice; // Instruction Cache Enable
|
|
|
|
int chcw_icr; // Instruction Cache Restore
|
|
|
|
int chcw_sa; // Spill-Out Base Address
|
|
|
|
|
|
|
|
// Exception Cause Register
|
|
|
|
int ecr_eicc; // Exception/Interrupt Cause Code
|
|
|
|
int ecr_fecc; // Fatal Error Cause Code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constants //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Stages
|
2020-08-11 01:24:00 +00:00
|
|
|
static final int FATAL = -1;
|
|
|
|
static final int FETCH = 0;
|
|
|
|
static final int EXECUTE = 1;
|
|
|
|
static final int EXCEPTION = 2;
|
|
|
|
static final int HALT = 3;
|
|
|
|
static final int CLEAR = 4;
|
|
|
|
static final int DUMP = 5;
|
|
|
|
static final int RESTORE = 6;
|
|
|
|
|
|
|
|
// Instruction cycle counts
|
|
|
|
private static final byte[] CYCLES = {
|
|
|
|
1, 1, 28, 1, 1, 1, 1, 1, 1, 26, 12, 1, 1, 10, 14, 16,
|
|
|
|
38, 44, 36, 1, 5, 5, 5, 3, 3, 3, 5, 5, 5, 8, 1, 1,
|
|
|
|
1, 1, 1, 9, 13, 30, 13, 1, 1, 1, 1, 1, 1, 4, 4, 4,
|
|
|
|
10, 22, 1, 1, 1, 1, 1, 1, 12, 1, 1, 1, 1, 1, 4, 4,
|
|
|
|
4, 8, 1, 28, 15, 14, 6, 1, 1, 1, 1, 1
|
|
|
|
};
|
2020-08-06 01:40:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructors //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Default constructor
|
2020-10-03 19:20:56 +00:00
|
|
|
CPU(JavaVue vue) {
|
2020-08-11 18:38:31 +00:00
|
|
|
access = new Access();
|
|
|
|
inst = new Instruction();
|
|
|
|
jumpFrom = new int[3];
|
|
|
|
jumpTo = new int[3];
|
|
|
|
program = new int[32];
|
|
|
|
this.vue = vue;
|
2020-08-06 01:40:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Package Methods //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2020-08-11 01:24:00 +00:00
|
|
|
// Process the simulation
|
|
|
|
void emulate(int cycles) {
|
|
|
|
|
2020-12-20 01:51:42 +00:00
|
|
|
// The CPU is in fatal halt status
|
|
|
|
if (stage == FATAL)
|
2020-08-11 01:24:00 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Process for the given number of cycles
|
2020-08-11 18:38:31 +00:00
|
|
|
for (;;) {
|
2020-08-11 01:24:00 +00:00
|
|
|
|
2020-12-20 01:51:42 +00:00
|
|
|
// The next stage occurs after the given number of cycles
|
2020-08-11 01:24:00 +00:00
|
|
|
if (this.cycles > cycles) {
|
|
|
|
this.cycles -= cycles;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Processing by stage
|
2020-12-20 01:51:42 +00:00
|
|
|
cycles -= this.cycles;
|
2020-12-17 21:40:37 +00:00
|
|
|
this.cycles = 0;
|
2020-08-11 01:24:00 +00:00
|
|
|
switch (stage) {
|
2020-12-20 01:51:42 +00:00
|
|
|
case EXCEPTION: if (exception()) return; break;
|
|
|
|
case EXECUTE : if (execute ()) return; break;
|
|
|
|
case FETCH : if (fetch ()) return; break;
|
|
|
|
case HALT : testException(); return;
|
2020-08-11 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
2020-08-11 18:38:31 +00:00
|
|
|
}
|
|
|
|
|
2020-08-11 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
2020-08-06 01:40:23 +00:00
|
|
|
// Read a system register
|
|
|
|
int getSystemRegister(int index) {
|
|
|
|
switch (index) {
|
2020-10-03 19:20:56 +00:00
|
|
|
case Vue.ADTRE: return adtre;
|
|
|
|
case Vue.EIPC : return eipc;
|
|
|
|
case Vue.EIPSW: return eipsw;
|
|
|
|
case Vue.FEPC : return fepc;
|
|
|
|
case Vue.FEPSW: return fepsw;
|
|
|
|
case Vue.ECR : return ecr_fecc << 16 | ecr_eicc;
|
|
|
|
case Vue.PIR : return 0x00005346;
|
|
|
|
case Vue.TKCW : return 0x000000E0;
|
|
|
|
case Vue.CHCW : return chcw_ice << 1;
|
2020-08-06 01:40:23 +00:00
|
|
|
case 29 : return sr29;
|
|
|
|
case 30 : return 0x00000004;
|
|
|
|
case 31 : return sr31;
|
2020-10-03 19:20:56 +00:00
|
|
|
case Vue.PSW : return
|
2020-08-06 01:40:23 +00:00
|
|
|
psw_i << 16 | psw_fro << 9 | psw_fpr << 4 |
|
|
|
|
psw_np << 15 | psw_fiv << 8 | psw_cy << 3 |
|
|
|
|
psw_ep << 14 | psw_fzd << 7 | psw_ov << 2 |
|
|
|
|
psw_ae << 13 | psw_fov << 6 | psw_s << 1 |
|
|
|
|
psw_id << 12 | psw_fud << 5 | psw_z
|
|
|
|
;
|
|
|
|
|
|
|
|
// Remaining cases to encourage tableswitch
|
|
|
|
case 8: case 9: case 10: case 11: case 12: case 13: case 14:
|
2020-08-08 02:24:09 +00:00
|
|
|
case 15: case 16: case 17: case 18: case 19: case 20: case 21:
|
2020-08-06 01:40:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1; // Unreachable
|
|
|
|
}
|
|
|
|
|
|
|
|
// System reset
|
|
|
|
void reset() {
|
|
|
|
|
|
|
|
// Configure instance fields
|
2020-12-20 01:51:42 +00:00
|
|
|
cycles = 0;
|
|
|
|
exception = 0;
|
|
|
|
fetch = -1;
|
|
|
|
irq = 0;
|
|
|
|
stage = FETCH;
|
2020-08-06 01:40:23 +00:00
|
|
|
|
|
|
|
// Clear all registers (hardware only sets ECR, PC and PSW)
|
|
|
|
for (int x = 0; x < 32; x++) {
|
|
|
|
program[x] = 0;
|
|
|
|
setSystemRegister(x, 0, true);
|
|
|
|
}
|
|
|
|
|
2020-08-08 02:24:09 +00:00
|
|
|
// Configure jump histories
|
|
|
|
Arrays.fill(jumpFrom, 0xFFFFFFF0);
|
|
|
|
Arrays.fill(jumpTo , 0xFFFFFFF0);
|
|
|
|
|
2020-08-06 21:37:05 +00:00
|
|
|
// Configure registers
|
|
|
|
ecr_eicc = 0xFFF0;
|
|
|
|
pc = 0xFFFFFFF0;
|
|
|
|
psw_np = 1;
|
2020-08-06 01:40:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write a system register
|
|
|
|
int setSystemRegister(int index, int value, boolean debug) {
|
|
|
|
switch (index) {
|
2020-10-03 19:20:56 +00:00
|
|
|
case Vue.ADTRE: return adtre = value & 0xFFFFFFFE;
|
|
|
|
case Vue.EIPC : return eipc = value & 0xFFFFFFFE;
|
|
|
|
case Vue.EIPSW: return eipsw = value & 0x000FF3FF;
|
|
|
|
case Vue.FEPC : return fepc = value & 0xFFFFFFFE;
|
|
|
|
case Vue.FEPSW: return fepsw = value & 0x000FF3FF;
|
2020-08-06 01:40:23 +00:00
|
|
|
case 29 : return sr29 = value;
|
|
|
|
case 31 : return sr31 = debug || value >= 0 ? value : -value;
|
|
|
|
|
2020-10-03 19:20:56 +00:00
|
|
|
case Vue.ECR:
|
2020-08-06 21:37:05 +00:00
|
|
|
if (debug) {
|
|
|
|
ecr_fecc = value >> 16 & 0xFFFF;
|
|
|
|
ecr_eicc = value & 0xFFFF;
|
|
|
|
}
|
|
|
|
return ecr_fecc << 16 | ecr_eicc;
|
|
|
|
|
2020-10-03 19:20:56 +00:00
|
|
|
case Vue.CHCW :
|
2020-08-06 01:40:23 +00:00
|
|
|
chcw_cen = value >> 20 & 0x00000FFF;
|
|
|
|
chcw_cec = value >> 8 & 0x00000FFF;
|
|
|
|
chcw_sa = value >> 8 & 0x00FFFFFF;
|
|
|
|
chcw_icr = value >> 5 & 1;
|
|
|
|
chcw_icd = value >> 4 & 1;
|
|
|
|
chcw_ice = value >> 1 & 1;
|
|
|
|
chcw_icc = value & 1;
|
|
|
|
|
|
|
|
// Only one of ICC, ICD or ICR is set
|
|
|
|
value &= 0x00000031;
|
|
|
|
if ((value & value - 1) == 0) {
|
|
|
|
// Clear
|
|
|
|
// Dump
|
|
|
|
// Restore
|
|
|
|
}
|
|
|
|
|
|
|
|
return chcw_ice << 1;
|
|
|
|
|
2020-10-03 19:20:56 +00:00
|
|
|
case Vue.PSW :
|
2020-08-06 01:40:23 +00:00
|
|
|
psw_i = value >> 16 & 15; psw_fov = value >> 6 & 1;
|
|
|
|
psw_np = value >> 15 & 1; psw_fud = value >> 5 & 1;
|
|
|
|
psw_ep = value >> 14 & 1; psw_fpr = value >> 4 & 1;
|
|
|
|
psw_ae = value >> 13 & 1; psw_cy = value >> 3 & 1;
|
|
|
|
psw_id = value >> 12 & 1; psw_ov = value >> 2 & 1;
|
|
|
|
psw_fro = value >> 9 & 1; psw_s = value >> 1 & 1;
|
|
|
|
psw_fiv = value >> 8 & 1; psw_z = value & 1;
|
|
|
|
psw_fzd = value >> 7 & 1;
|
|
|
|
return value & 0x000FF3FF;
|
|
|
|
|
|
|
|
// Remaining cases to encourage tableswitch
|
2020-08-06 21:37:05 +00:00
|
|
|
case 6: case 7: case 8: case 9: case 10: case 11: case 12:
|
|
|
|
case 13: case 14: case 15: case 16: case 17: case 18: case 19:
|
|
|
|
case 20: case 21: case 22: case 23: case 26: case 27: case 28:
|
|
|
|
case 30:
|
2020-08-06 01:40:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1; // Unreachable
|
|
|
|
}
|
|
|
|
|
2020-12-20 01:51:42 +00:00
|
|
|
// Determine the number of CPU cycles until a breakpoint could trigger
|
2020-08-11 01:24:00 +00:00
|
|
|
int until(int cycles) {
|
2020-12-20 01:51:42 +00:00
|
|
|
return stage == FATAL || stage == HALT ?
|
|
|
|
cycles : Math.min(cycles, this.cycles);
|
2020-08-11 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Private Methods //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Operations for exception stage
|
|
|
|
private boolean exception() {
|
|
|
|
|
2020-12-20 01:51:42 +00:00
|
|
|
// Check for breakpoints
|
|
|
|
if (vue.onBreakpoint(Breakpoint.EXCEPTION))
|
2020-10-05 13:10:14 +00:00
|
|
|
return true;
|
2020-08-11 01:24:00 +00:00
|
|
|
|
2020-08-11 18:38:31 +00:00
|
|
|
// Configure working variables
|
2020-12-20 01:51:42 +00:00
|
|
|
exception &= 0xFFFF;
|
|
|
|
boolean isIRQ = (exception & 0xFF00) == 0xFE00;
|
|
|
|
int psw = getSystemRegister(Vue.PSW);
|
2020-08-11 01:24:00 +00:00
|
|
|
|
|
|
|
// Fatal exception
|
|
|
|
if (psw_np != 0) {
|
2020-12-20 01:51:42 +00:00
|
|
|
vue.write(0x00000000, Vue.S32, 0xFFFF0000 | exception);
|
2020-10-03 19:20:56 +00:00
|
|
|
vue.write(0x00000004, Vue.S32, psw);
|
|
|
|
vue.write(0x00000008, Vue.S32, pc);
|
2020-08-11 18:38:31 +00:00
|
|
|
stage = FATAL;
|
|
|
|
return true;
|
2020-08-11 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Duplexed exception
|
|
|
|
if (psw_ep != 0) {
|
2020-12-20 01:51:42 +00:00
|
|
|
ecr_fecc = exception;
|
2020-08-11 01:24:00 +00:00
|
|
|
fepc = pc;
|
|
|
|
fepsw = psw;
|
2020-08-11 18:38:31 +00:00
|
|
|
psw_np = 1;
|
2020-08-11 01:24:00 +00:00
|
|
|
pc = 0xFFFFFFD0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Regular exception
|
|
|
|
else {
|
2020-12-20 01:51:42 +00:00
|
|
|
ecr_eicc = exception;
|
2020-08-11 01:24:00 +00:00
|
|
|
eipc = pc;
|
|
|
|
eipsw = psw;
|
2020-08-11 18:38:31 +00:00
|
|
|
psw_ep = 1;
|
2020-12-20 01:51:42 +00:00
|
|
|
pc = 0xFFFF0000 | exception & 0xFFF0;
|
2020-08-11 01:24:00 +00:00
|
|
|
if (pc == 0xFFFFFF70) // FIV
|
|
|
|
pc = 0xFFFFFF60;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interrupt
|
2020-08-12 01:51:16 +00:00
|
|
|
if (isIRQ) {
|
2020-12-20 01:51:42 +00:00
|
|
|
psw_i = Math.min(15, exception >> 4 & 15);
|
2020-08-12 01:51:16 +00:00
|
|
|
if (stage == HALT)
|
|
|
|
pc += 2;
|
|
|
|
}
|
2020-08-11 01:24:00 +00:00
|
|
|
|
|
|
|
// Common processing
|
2020-12-20 01:51:42 +00:00
|
|
|
cycles = 0; // TODO: Determine the actual number
|
|
|
|
exception = 0;
|
|
|
|
psw_ae = 0;
|
|
|
|
psw_id = 1;
|
|
|
|
stage = FETCH;
|
2020-08-11 01:24:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Operations for execute stage
|
|
|
|
private boolean execute() {
|
|
|
|
|
2020-12-20 01:51:42 +00:00
|
|
|
// Check for breakpoints
|
|
|
|
if (vue.onBreakpoint(Breakpoint.EXECUTE))
|
2020-10-05 13:10:14 +00:00
|
|
|
return true;
|
2020-08-11 01:24:00 +00:00
|
|
|
|
|
|
|
// Processing by instruction ID
|
|
|
|
switch (inst.id) {
|
2020-10-03 19:20:56 +00:00
|
|
|
case Vue.ADD_IMM: ADD_IMM(); break;
|
|
|
|
case Vue.ADD_REG: ADD_REG(); break;
|
|
|
|
case Vue.ADDF_S : ADDF_S (); break;
|
|
|
|
case Vue.ADDI : ADDI (); break;
|
|
|
|
case Vue.AND : AND (); break;
|
|
|
|
//case Vue.ANDBSU : ANDBSU (); break;
|
|
|
|
case Vue.ANDI : ANDI (); break;
|
|
|
|
//case Vue.ANDNBSU: ANDNBSU(); break;
|
|
|
|
case Vue.BCOND : BCOND (); break;
|
|
|
|
case Vue.CAXI : CAXI (); break;
|
|
|
|
case Vue.CLI : CLI (); break;
|
|
|
|
case Vue.CMP_IMM: CMP_IMM(); break;
|
|
|
|
case Vue.CMP_REG: CMP_REG(); break;
|
|
|
|
case Vue.CMPF_S : CMPF_S (); break;
|
|
|
|
case Vue.CVT_SW : CVT_SW (); break;
|
|
|
|
case Vue.CVT_WS : CVT_WS (); break;
|
|
|
|
case Vue.DIV : DIV (); break;
|
|
|
|
case Vue.DIVF_S : DIVF_S (); break;
|
|
|
|
case Vue.DIVU : DIVU (); break;
|
|
|
|
case Vue.HALT : HALT (); break;
|
|
|
|
case Vue.IN_B : IN_B (); break;
|
|
|
|
case Vue.IN_H : IN_H (); break;
|
|
|
|
case Vue.IN_W : IN_W (); break;
|
|
|
|
case Vue.JAL : JAL (); break;
|
|
|
|
case Vue.JMP : JMP (); break;
|
|
|
|
case Vue.JR : JR (); break;
|
|
|
|
case Vue.LD_B : LD_B (); break;
|
|
|
|
case Vue.LD_H : LD_H (); break;
|
|
|
|
case Vue.LD_W : LD_W (); break;
|
|
|
|
case Vue.LDSR : LDSR (); break;
|
|
|
|
case Vue.MOV_IMM: MOV_IMM(); break;
|
|
|
|
case Vue.MOV_REG: MOV_REG(); break;
|
|
|
|
//case Vue.MOVBSU : MOVBSU (); break;
|
|
|
|
case Vue.MOVEA : MOVEA (); break;
|
|
|
|
case Vue.MOVHI : MOVHI (); break;
|
|
|
|
case Vue.MPYHW : MPYHW (); break;
|
|
|
|
case Vue.MUL : MUL (); break;
|
|
|
|
case Vue.MULF_S : MULF_S (); break;
|
|
|
|
case Vue.MULU : MULU (); break;
|
|
|
|
case Vue.NOT : NOT (); break;
|
|
|
|
//case Vue.NOTBSU : NOTBSU (); break;
|
|
|
|
case Vue.OR : OR (); break;
|
|
|
|
//case Vue.ORBSU : ORBSU (); break;
|
|
|
|
case Vue.ORI : ORI (); break;
|
|
|
|
//case Vue.ORNBSU : ORNBSU (); break;
|
|
|
|
case Vue.OUT_B : OUT_B (); break;
|
|
|
|
case Vue.OUT_H : OUT_H (); break;
|
|
|
|
case Vue.OUT_W : OUT_W (); break;
|
|
|
|
case Vue.RETI : RETI (); break;
|
|
|
|
case Vue.REV : REV (); break;
|
|
|
|
case Vue.SAR_IMM: SAR_IMM(); break;
|
|
|
|
case Vue.SAR_REG: SAR_REG(); break;
|
|
|
|
//case Vue.SCH0BSD: SCH0BSD(); break;
|
|
|
|
//case Vue.SCH0BSU: SCH0BSU(); break;
|
|
|
|
//case Vue.SCH1BSD: SCH1BSD(); break;
|
|
|
|
//case Vue.SCH1BSU: SCH1BSU(); break;
|
|
|
|
case Vue.SEI : SEI (); break;
|
|
|
|
case Vue.SETF : SETF (); break;
|
|
|
|
case Vue.SHL_IMM: SHL_IMM(); break;
|
|
|
|
case Vue.SHL_REG: SHL_REG(); break;
|
|
|
|
case Vue.SHR_IMM: SHR_IMM(); break;
|
|
|
|
case Vue.SHR_REG: SHR_REG(); break;
|
|
|
|
case Vue.ST_B : ST_B (); break;
|
|
|
|
case Vue.ST_H : ST_H (); break;
|
|
|
|
case Vue.ST_W : ST_W (); break;
|
|
|
|
case Vue.STSR : STSR (); break;
|
|
|
|
case Vue.SUB : SUB (); break;
|
|
|
|
case Vue.SUBF_S : SUBF_S (); break;
|
|
|
|
case Vue.TRAP : TRAP (); break;
|
|
|
|
case Vue.TRNC_SW: TRNC_SW(); break;
|
|
|
|
case Vue.XB : XB (); break;
|
|
|
|
case Vue.XH : XH (); break;
|
|
|
|
case Vue.XOR : XOR (); break;
|
|
|
|
//case Vue.XORBSU : XORBSU (); break;
|
|
|
|
case Vue.XORI : XORI (); break;
|
|
|
|
//case Vue.XORNBSU: XORNBSU(); break;
|
2020-08-11 18:38:31 +00:00
|
|
|
default: // Invalid instruction
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = 0xFF90;
|
2020-08-11 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// An application break was requested
|
|
|
|
if (vue.breakCode != 0)
|
|
|
|
return true;
|
|
|
|
|
2020-08-11 01:24:00 +00:00
|
|
|
// Common processing
|
2020-12-20 01:51:42 +00:00
|
|
|
if (exception == 0) {
|
2020-08-12 01:51:16 +00:00
|
|
|
cycles += CYCLES[inst.id];
|
|
|
|
pc += inst.size;
|
|
|
|
}
|
2020-08-11 01:24:00 +00:00
|
|
|
program[0] = 0;
|
|
|
|
testException();
|
2020-08-11 18:38:31 +00:00
|
|
|
if (stage == EXECUTE)
|
|
|
|
stage = FETCH;
|
2020-08-11 01:24:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Operations for fetch stage
|
|
|
|
private boolean fetch() {
|
|
|
|
|
2020-12-20 01:51:42 +00:00
|
|
|
// Entering the fetch stage
|
|
|
|
if (fetch == -1)
|
|
|
|
fetch = 0;
|
|
|
|
|
2020-08-11 01:24:00 +00:00
|
|
|
// Read the bits from the bus
|
2020-10-03 19:20:56 +00:00
|
|
|
if (read(pc + (fetch << 1), Vue.U16, fetch))
|
2020-08-12 01:51:16 +00:00
|
|
|
return true;
|
2020-12-20 01:51:42 +00:00
|
|
|
// TODO: Determine how many cycles this takes
|
2020-08-11 01:24:00 +00:00
|
|
|
|
|
|
|
// First unit
|
|
|
|
if (fetch == 0) {
|
2020-12-23 18:26:02 +00:00
|
|
|
inst.bits = access.value;
|
|
|
|
if (Instruction.size(access.value >> 10) == 4) {
|
2020-08-11 01:24:00 +00:00
|
|
|
fetch = 1;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Second unit
|
|
|
|
else {
|
2020-12-22 02:42:28 +00:00
|
|
|
inst.bits |= access.value << 16;
|
2020-12-20 01:51:42 +00:00
|
|
|
fetch = -1;
|
2020-08-11 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Decode the instruction and advance to execute stage
|
|
|
|
inst.decode(inst.bits);
|
|
|
|
stage = EXECUTE;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Perform a bus read
|
|
|
|
private boolean read(int address, int type, int fetch) {
|
|
|
|
|
|
|
|
// Perform the operation
|
|
|
|
access.address = address;
|
|
|
|
access.fetch = fetch;
|
|
|
|
access.type = type;
|
|
|
|
access.value = vue.read(address, type);
|
|
|
|
|
2020-12-20 01:51:42 +00:00
|
|
|
// Check for breakpoints
|
|
|
|
return vue.onBreakpoint(Breakpoint.READ);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test a condition
|
|
|
|
private int testCondition(int condition) {
|
|
|
|
switch (condition) {
|
|
|
|
case 0: return psw_ov;
|
|
|
|
case 1: return psw_cy;
|
|
|
|
case 2: return psw_z;
|
|
|
|
case 3: return psw_cy | psw_z;
|
|
|
|
case 4: return psw_s;
|
|
|
|
case 5: return 1;
|
2020-12-17 21:40:37 +00:00
|
|
|
case 6: return psw_ov ^ psw_s;
|
2020-08-12 01:51:16 +00:00
|
|
|
case 7: return psw_ov ^ psw_s | psw_z;
|
|
|
|
}
|
|
|
|
return testCondition(condition & 7) ^ 1;
|
|
|
|
}
|
|
|
|
|
2020-08-11 01:24:00 +00:00
|
|
|
// Check for an exception or interrupt
|
2020-08-11 18:38:31 +00:00
|
|
|
private boolean testException() {
|
2020-08-11 01:24:00 +00:00
|
|
|
|
|
|
|
// Check for an interrupt
|
2020-12-20 01:51:42 +00:00
|
|
|
if (irq != 0 && (exception | psw_id | psw_ep | psw_np) == 0) {
|
2020-08-11 01:24:00 +00:00
|
|
|
int level;
|
|
|
|
for (level = 4; level >= 0; level--)
|
|
|
|
if ((irq >> level & 1) != 0)
|
|
|
|
break;
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = 0xFE00 | level << 4;
|
2020-08-11 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
2020-08-11 18:38:31 +00:00
|
|
|
// There is no exception
|
2020-12-20 01:51:42 +00:00
|
|
|
if (exception == 0)
|
2020-08-11 18:38:31 +00:00
|
|
|
return stage == HALT && cycles == 0; // No further processing
|
|
|
|
|
|
|
|
// An exception has occurred
|
|
|
|
cycles = 0;
|
|
|
|
stage = EXCEPTION;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Perform a bus write
|
|
|
|
private boolean write(int address, int type, int value) {
|
|
|
|
|
|
|
|
// Prepare the operation
|
|
|
|
access.address = address;
|
|
|
|
access.fetch = -1;
|
|
|
|
access.type = type;
|
|
|
|
access.value = value;
|
|
|
|
|
2020-12-20 01:51:42 +00:00
|
|
|
// Check for breakpoints
|
|
|
|
if (vue.onBreakpoint(Breakpoint.WRITE))
|
2020-10-05 13:10:14 +00:00
|
|
|
return true;
|
2020-08-12 01:51:16 +00:00
|
|
|
|
|
|
|
// Perform the operation
|
2020-12-20 01:51:42 +00:00
|
|
|
if (access.type != Vue.CANCEL)
|
|
|
|
vue.write(access.address, access.type, access.value);
|
2020-08-12 01:51:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Instruction Helpers //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Integer addition
|
|
|
|
private int add(int left, int right) {
|
|
|
|
int result = left + right;
|
|
|
|
psw_cy = Integer.compareUnsigned(result, left) < 0 ? 1 : 0;
|
|
|
|
psw_s = result >>> 31;
|
|
|
|
psw_ov = (~(left ^ right) & (left ^ result)) >>> 31;
|
|
|
|
psw_z = result == 0 ? 1 : 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bitwise operation
|
|
|
|
private void bitwise(int result) {
|
|
|
|
program[inst.reg2] = result;
|
|
|
|
psw_ov = 0;
|
|
|
|
psw_s = result >>> 31;
|
|
|
|
psw_z = result == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Convert a floating short to word
|
|
|
|
private void floatConvert(boolean round) {
|
|
|
|
|
|
|
|
// Reserved operand
|
|
|
|
if (floatReserved(false))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Determine the value to convert
|
|
|
|
float value = Float.intBitsToFloat(program[inst.reg1]);
|
|
|
|
value = (float) (round ? Math.round(value) :
|
|
|
|
value < 0 ? Math.ceil(value) : Math.floor(value));
|
|
|
|
|
|
|
|
// Invalid operation
|
|
|
|
if (value > 0x7FFFFFFF || value < 0x80000000) {
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = 0xFF70;
|
2020-08-12 16:49:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Common processing
|
|
|
|
int result = (int) value;
|
|
|
|
if (result != value) // Precision degradation
|
|
|
|
psw_fpr = 1;
|
|
|
|
program[inst.reg2] = result;
|
|
|
|
psw_ov = 0;
|
|
|
|
psw_s = result >>> 31;
|
|
|
|
psw_z = result == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Determine whether the floating-point operands are reserved values
|
2020-08-12 16:49:32 +00:00
|
|
|
private boolean floatReserved(boolean left) {
|
|
|
|
for (int x = left ? 0 : 1; x < 2; x++) {
|
2020-08-12 01:51:16 +00:00
|
|
|
int operand = program[x == 0 ? inst.reg2 : inst.reg1];
|
|
|
|
int exponent = operand & 0x7F800000;
|
|
|
|
|
|
|
|
// Check for a reserved operand
|
|
|
|
if (!(
|
|
|
|
exponent == 0x7F800000 || // Indefinite
|
|
|
|
exponent == 0 && (operand & 0x007FFFFF) != 0 // Denormal
|
|
|
|
)) continue;
|
|
|
|
|
|
|
|
// The value is a reserved operand
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = 0xFF60;
|
|
|
|
psw_fro = 1;
|
2020-08-12 01:51:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Floating-point result
|
2020-08-12 16:49:32 +00:00
|
|
|
private void floatResult(boolean compare, double full) {
|
2020-08-12 01:51:16 +00:00
|
|
|
|
|
|
|
// Overflow
|
|
|
|
if (full > Float.MAX_VALUE || full < -Float.MAX_VALUE) {
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = 0xFF64;
|
|
|
|
psw_fov = 1;
|
2020-08-12 01:51:16 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process the result
|
|
|
|
float result = (float) full;
|
|
|
|
int bits = Float.floatToRawIntBits(result);
|
|
|
|
|
|
|
|
// Underflow
|
|
|
|
if ((bits & 0x7F800000) == 0 && (bits & 0x007FFFFF) != 0) {
|
|
|
|
bits = 0;
|
|
|
|
result = 0;
|
|
|
|
psw_fud = 1;
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Operations other than compare
|
|
|
|
if (!compare) {
|
|
|
|
program[inst.reg2] = bits;
|
|
|
|
if (result != full) // Precision degradation
|
|
|
|
psw_fpr = 1;
|
|
|
|
}
|
2020-08-12 01:51:16 +00:00
|
|
|
|
|
|
|
// Common processing
|
|
|
|
psw_cy = psw_s = bits >>> 31;
|
|
|
|
psw_ov = 0;
|
|
|
|
psw_z = bits == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Proxy for IN and LD
|
|
|
|
private void IN_LD(int type) {
|
|
|
|
if (!read(program[inst.reg1] + inst.disp, type, -1))
|
|
|
|
program[inst.reg2] = access.value;
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Transfer program to another address
|
|
|
|
private void jump(int address) {
|
2020-12-25 23:59:08 +00:00
|
|
|
if (address != pc) {
|
|
|
|
int level = psw_np != 0 ? 2 : psw_ep;
|
|
|
|
jumpFrom[level] = pc;
|
|
|
|
jumpTo [level] = address;
|
|
|
|
}
|
2020-08-12 16:49:32 +00:00
|
|
|
pc = address - inst.size;
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Proxy for OUT and ST
|
|
|
|
private void OUT_ST(int type) {
|
|
|
|
write(program[inst.reg1] + inst.disp, type, program[inst.reg2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arithmetic shift right
|
|
|
|
private void shiftArithmetic(int value, int bits) {
|
|
|
|
bits &= 31;
|
|
|
|
psw_cy = bits == 0 ? 0 : value >> bits - 1 & 1;
|
|
|
|
bitwise(value >> bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Logical shift left
|
|
|
|
private void shiftLeft(int value, int bits) {
|
|
|
|
bits &= 31;
|
|
|
|
psw_cy = bits == 0 ? 0 : value >> 32 - bits & 1;
|
|
|
|
bitwise(value << bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Logical shift right
|
|
|
|
private void shiftRight(int value, int bits) {
|
|
|
|
bits &= 31;
|
|
|
|
psw_cy = bits == 0 ? 0 : value >> bits - 1 & 1;
|
|
|
|
bitwise(value >>> bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Integer subtraction
|
|
|
|
private int subtract(int left, int right) {
|
|
|
|
int result = left - right;
|
|
|
|
psw_cy = Integer.compareUnsigned(result, left) > 0 ? 1 : 0;
|
|
|
|
psw_s = result >>> 31;
|
|
|
|
psw_ov = ((left ^ right) & (left ^ result)) >>> 31;
|
|
|
|
psw_z = result == 0 ? 1 : 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-08-11 18:38:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Instruction Methods //
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Add Immediate
|
|
|
|
private void ADD_IMM() {
|
|
|
|
program[inst.reg2] = add(program[inst.reg2], inst.imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add Register
|
|
|
|
private void ADD_REG() {
|
|
|
|
program[inst.reg2] = add(program[inst.reg2], program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add Floating Short
|
|
|
|
private void ADDF_S() {
|
2020-08-12 16:49:32 +00:00
|
|
|
if (!floatReserved(true)) floatResult(false,
|
2020-08-12 01:51:16 +00:00
|
|
|
(double) Float.intBitsToFloat(program[inst.reg2]) +
|
|
|
|
(double) Float.intBitsToFloat(program[inst.reg1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add Immediate
|
|
|
|
private void ADDI() {
|
2020-12-25 23:59:08 +00:00
|
|
|
program[inst.reg2] = add(program[inst.reg1], inst.imm);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// And
|
|
|
|
private void AND() {
|
|
|
|
bitwise(program[inst.reg2] & program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// And Immediate
|
|
|
|
private void ANDI() {
|
2020-12-25 23:59:08 +00:00
|
|
|
bitwise(program[inst.reg1] & inst.imm);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Branch on Condition
|
|
|
|
private void BCOND() {
|
|
|
|
if (testCondition(inst.cond) == 0)
|
|
|
|
return;
|
|
|
|
cycles = 2;
|
2020-08-12 16:49:32 +00:00
|
|
|
jump(pc + inst.disp);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compare and Exchange Interlocked
|
|
|
|
private void CAXI() {
|
|
|
|
int address = program[inst.reg1] + inst.disp;
|
|
|
|
int left = program[inst.reg2];
|
|
|
|
|
|
|
|
// Retrieve the lock word
|
2020-10-03 19:20:56 +00:00
|
|
|
if (read(address, Vue.S32, -1))
|
2020-08-12 16:49:32 +00:00
|
|
|
return;
|
|
|
|
int lock = access.value;
|
|
|
|
|
|
|
|
// Compare and exchange
|
|
|
|
if (lock == left)
|
|
|
|
access.value = program[30];
|
2020-10-03 19:20:56 +00:00
|
|
|
if (write(address, Vue.S32, access.value))
|
2020-08-12 16:49:32 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Update CPU state
|
|
|
|
subtract(left, lock);
|
|
|
|
program[inst.reg2] = lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear Interrupt Disable Flag
|
|
|
|
private void CLI() {
|
|
|
|
psw_id = 0;
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compare Immediate
|
|
|
|
private void CMP_IMM() {
|
|
|
|
subtract(program[inst.reg2], inst.imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compare Register
|
|
|
|
private void CMP_REG() {
|
|
|
|
subtract(program[inst.reg2], program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Compare Floating Short
|
|
|
|
private void CMPF_S() {
|
|
|
|
if (!floatReserved(true)) floatResult(true,
|
|
|
|
(double) Float.intBitsToFloat(program[inst.reg2]) -
|
|
|
|
(double) Float.intBitsToFloat(program[inst.reg1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert Short Floating to Word
|
|
|
|
private void CVT_SW() {
|
|
|
|
floatConvert(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert Word Integer to Short
|
|
|
|
private void CVT_WS() {
|
|
|
|
int bits = program[inst.reg1];
|
|
|
|
float result = (float) bits;
|
|
|
|
program[inst.reg2] = Float.floatToRawIntBits(result);
|
|
|
|
if (result != bits) // Precision degradation
|
|
|
|
psw_fpr = 1;
|
|
|
|
psw_cy = psw_s = bits >>> 31;
|
|
|
|
psw_ov = 0;
|
|
|
|
psw_z = bits == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Divide
|
|
|
|
private void DIV() {
|
|
|
|
int left = program[inst.reg2];
|
|
|
|
int right = program[inst.reg1];
|
|
|
|
|
|
|
|
// Zero division
|
|
|
|
if (right == 0) {
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = 0xFF80;
|
2020-08-12 01:51:16 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special case
|
|
|
|
if (left == 0x80000000 && right == 0xFFFFFFFF) {
|
|
|
|
program[30] = 0;
|
|
|
|
program[inst.reg2] = 0x80000000;
|
|
|
|
psw_ov = 1;
|
|
|
|
psw_s = 1;
|
|
|
|
psw_z = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Regular case
|
|
|
|
int result = left / right;
|
|
|
|
program[30] = left % right;
|
|
|
|
program[inst.reg2] = result;
|
|
|
|
psw_ov = 0;
|
|
|
|
psw_s = result >>> 31;
|
|
|
|
psw_z = result == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Divide Floating Short
|
|
|
|
private void DIVF_S() {
|
|
|
|
int left = program[inst.reg2];
|
|
|
|
int right = program[inst.reg1];
|
|
|
|
|
|
|
|
// Reserved operand
|
|
|
|
if (floatReserved(true))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// An exception has occurred
|
|
|
|
if (right == 0) {
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = left == 0 ? 0xFF70 : 0xFF68;
|
2020-08-12 16:49:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform the operation
|
|
|
|
floatResult(false,
|
|
|
|
(double) Float.intBitsToFloat(left) /
|
|
|
|
(double) Float.intBitsToFloat(right));
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Divide Unsigned
|
|
|
|
private void DIVU() {
|
|
|
|
long left = program[inst.reg2] & 0xFFFFFFFFL;
|
|
|
|
long right = program[inst.reg1] & 0xFFFFFFFFL;
|
|
|
|
|
|
|
|
// Zero division
|
|
|
|
if (right == 0) {
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = 0xFF80;
|
2020-08-12 01:51:16 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Regular case
|
|
|
|
int result = (int) (left / right);
|
|
|
|
program[30] = (int) (left % right);
|
|
|
|
program[inst.reg2] = result;
|
|
|
|
psw_ov = 0;
|
|
|
|
psw_s = result >>> 31;
|
|
|
|
psw_z = result == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Halt
|
|
|
|
private void HALT() {
|
|
|
|
stage = HALT;
|
|
|
|
inst.size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Input Byte from Port
|
|
|
|
private void IN_B() {
|
2020-10-03 19:20:56 +00:00
|
|
|
IN_LD(Vue.U8);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Input Halfword from Port
|
|
|
|
private void IN_H() {
|
2020-10-03 19:20:56 +00:00
|
|
|
IN_LD(Vue.U16);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Input Word from Port
|
|
|
|
private void IN_W() {
|
2020-10-03 19:20:56 +00:00
|
|
|
IN_LD(Vue.S32);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Jump and Link
|
|
|
|
private void JAL() {
|
|
|
|
program[31] = pc + 4;
|
2020-08-12 16:49:32 +00:00
|
|
|
jump(pc + inst.disp);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Jump Register
|
2020-08-11 18:38:31 +00:00
|
|
|
private void JMP() {
|
2020-08-12 16:49:32 +00:00
|
|
|
jump(program[inst.reg1]);
|
2020-08-11 18:38:31 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Jump Relative
|
|
|
|
private void JR() {
|
2020-08-12 16:49:32 +00:00
|
|
|
jump(pc + inst.disp);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load Byte
|
|
|
|
private void LD_B() {
|
2020-10-03 19:20:56 +00:00
|
|
|
IN_LD(Vue.S8);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load Halfword
|
|
|
|
private void LD_H() {
|
2020-10-03 19:20:56 +00:00
|
|
|
IN_LD(Vue.S16);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load Word
|
|
|
|
private void LD_W() {
|
2020-10-03 19:20:56 +00:00
|
|
|
IN_LD(Vue.S32);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load to System Register
|
|
|
|
private void LDSR() {
|
|
|
|
setSystemRegister(inst.imm & 31, program[inst.reg2], false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move Immediate
|
|
|
|
private void MOV_IMM() {
|
|
|
|
program[inst.reg2] = inst.imm;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move Register
|
|
|
|
private void MOV_REG() {
|
|
|
|
program[inst.reg2] = program[inst.reg1];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add
|
2020-08-11 18:38:31 +00:00
|
|
|
private void MOVEA() {
|
|
|
|
program[inst.reg2] = program[inst.reg1] + inst.imm;
|
|
|
|
}
|
2020-08-11 01:24:00 +00:00
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Add
|
2020-08-11 18:38:31 +00:00
|
|
|
private void MOVHI() {
|
|
|
|
program[inst.reg2] = program[inst.reg1] + (inst.imm << 16);
|
2020-08-11 01:24:00 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Multiply Halfword
|
|
|
|
private void MPYHW() {
|
|
|
|
program[inst.reg2] *= program[inst.reg1] << 15 >> 15;
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Multiply
|
|
|
|
private void MUL() {
|
|
|
|
long full = (long) program[inst.reg2] * (long) program[inst.reg1];
|
|
|
|
int result = (int) full;
|
|
|
|
program[30] = (int) (full >> 32);
|
|
|
|
program[inst.reg2] = result;
|
|
|
|
psw_ov = (long) result != full ? 1 : 0;
|
|
|
|
psw_s = result >>> 31;
|
|
|
|
psw_z = result == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Multiply Floating Short
|
|
|
|
private void MULF_S() {
|
|
|
|
if (!floatReserved(true)) floatResult(false,
|
|
|
|
(double) Float.intBitsToFloat(program[inst.reg2]) *
|
|
|
|
(double) Float.intBitsToFloat(program[inst.reg1]));
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Multiply Unsigned
|
|
|
|
private void MULU() {
|
|
|
|
long full = (program[inst.reg2] & 0xFFFFFFFFL) *
|
|
|
|
(program[inst.reg1] & 0xFFFFFFFFL);
|
|
|
|
int result = (int) full;
|
|
|
|
program[30] = (int) (full >> 32);
|
|
|
|
program[inst.reg2] = result;
|
|
|
|
psw_ov = full > 0xFFFFFFFFL ? 1 : 0;
|
|
|
|
psw_s = result >>> 31;
|
|
|
|
psw_z = result == 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not
|
|
|
|
private void NOT() {
|
|
|
|
bitwise(~program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Or
|
|
|
|
private void OR() {
|
|
|
|
bitwise(program[inst.reg2] | program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Or Immediate
|
|
|
|
private void ORI() {
|
2020-12-25 23:59:08 +00:00
|
|
|
bitwise(program[inst.reg1] | inst.imm);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Output Byte to Port
|
|
|
|
private void OUT_B() {
|
2020-10-03 19:20:56 +00:00
|
|
|
OUT_ST(Vue.U8);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Output Halfword to Port
|
|
|
|
private void OUT_H() {
|
2020-10-03 19:20:56 +00:00
|
|
|
OUT_ST(Vue.U16);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Output Word to Port
|
|
|
|
private void OUT_W() {
|
2020-10-03 19:20:56 +00:00
|
|
|
OUT_ST(Vue.S32);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return from Trap or Interrupt
|
|
|
|
private void RETI() {
|
|
|
|
if (psw_np == 1) {
|
|
|
|
pc = fepc;
|
2020-10-03 19:20:56 +00:00
|
|
|
setSystemRegister(Vue.PSW, fepsw, false);
|
2020-08-12 01:51:16 +00:00
|
|
|
} else {
|
|
|
|
pc = eipc;
|
2020-10-03 19:20:56 +00:00
|
|
|
setSystemRegister(Vue.PSW, eipsw, false);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Reverse Bits in Word
|
|
|
|
private void REV() {
|
|
|
|
int value = program[inst.reg1];
|
|
|
|
value = value >> 16 & 0x0000FFFF | value << 16;
|
|
|
|
value = value >> 8 & 0x00FF00FF | value << 8 & 0xFF00FF00;
|
|
|
|
value = value >> 4 & 0x0F0F0F0F | value << 4 & 0xF0F0F0F0;
|
|
|
|
value = value >> 2 & 0x33333333 | value << 2 & 0xCCCCCCCC;
|
|
|
|
value = value >> 1 & 0x55555555 | value << 1 & 0xAAAAAAAA;
|
|
|
|
program[inst.reg2] = value;
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Shift Arithmetic Right by Immediate
|
|
|
|
private void SAR_IMM() {
|
|
|
|
shiftArithmetic(program[inst.reg2], inst.imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shift Arithmetic Right by Register
|
|
|
|
private void SAR_REG() {
|
|
|
|
shiftArithmetic(program[inst.reg2], program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Set Interrupt Disable Flag
|
|
|
|
private void SEI() {
|
|
|
|
psw_id = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set Flag Condition
|
|
|
|
private void SETF() {
|
|
|
|
program[inst.reg2] = testCondition(inst.imm & 15);
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Shift Logical Left by Immediate
|
|
|
|
private void SHL_IMM() {
|
|
|
|
shiftLeft(program[inst.reg2], inst.imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shift Logical Left by Register
|
|
|
|
private void SHL_REG() {
|
|
|
|
shiftLeft(program[inst.reg2], program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shift Logical Right by Immediate
|
|
|
|
private void SHR_IMM() {
|
|
|
|
shiftRight(program[inst.reg2], inst.imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shift Logical Right by Register
|
|
|
|
private void SHR_REG() {
|
|
|
|
shiftRight(program[inst.reg2], program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store Byte
|
|
|
|
private void ST_B() {
|
2020-10-03 19:20:56 +00:00
|
|
|
OUT_ST(Vue.S8);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Store Halfword
|
|
|
|
private void ST_H() {
|
2020-10-03 19:20:56 +00:00
|
|
|
OUT_ST(Vue.S16);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Store Word
|
|
|
|
private void ST_W() {
|
2020-10-03 19:20:56 +00:00
|
|
|
OUT_ST(Vue.S32);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Store Contents of System Register
|
|
|
|
private void STSR() {
|
|
|
|
program[inst.reg2] = getSystemRegister(inst.imm & 31);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Subtract
|
|
|
|
private void SUB() {
|
|
|
|
program[inst.reg2] = subtract(program[inst.reg2], program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Subtract Floating Short
|
|
|
|
private void SUBF_S() {
|
|
|
|
if (!floatReserved(true)) floatResult(false,
|
|
|
|
(double) Float.intBitsToFloat(program[inst.reg2]) -
|
|
|
|
(double) Float.intBitsToFloat(program[inst.reg1]));
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Trap
|
|
|
|
private void TRAP() {
|
2020-12-20 01:51:42 +00:00
|
|
|
exception = 0xFFA0 | inst.imm & 31;
|
2020-08-12 01:51:16 +00:00
|
|
|
pc += 2;
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:49:32 +00:00
|
|
|
// Truncate Short Floating to Word
|
|
|
|
private void TRNC_SW() {
|
|
|
|
floatConvert(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exchange Byte
|
|
|
|
private void XB() {
|
|
|
|
int value = program[inst.reg2];
|
|
|
|
program[inst.reg2] = value & 0xFFFF0000 |
|
|
|
|
value >> 8 & 0xFF | (value & 0xFF) << 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exchange Halfword
|
|
|
|
private void XH() {
|
|
|
|
int value = program[inst.reg2];
|
|
|
|
program[inst.reg2] = value >> 16 & 0xFFFF | value << 16;
|
|
|
|
}
|
|
|
|
|
2020-08-12 01:51:16 +00:00
|
|
|
// Exclusive Or
|
|
|
|
private void XOR() {
|
|
|
|
bitwise(program[inst.reg2] ^ program[inst.reg1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exclusive Or Immediate
|
|
|
|
private void XORI() {
|
2020-12-25 23:59:08 +00:00
|
|
|
bitwise(program[inst.reg1] ^ inst.imm);
|
2020-08-12 01:51:16 +00:00
|
|
|
}
|
|
|
|
|
2020-08-06 01:40:23 +00:00
|
|
|
}
|