Restructure
This commit is contained in:
804
emulator/instruction.cpp
Normal file
804
emulator/instruction.cpp
Normal file
@@ -0,0 +1,804 @@
|
||||
/*******************************************************************************
|
||||
HARPtools by Chad D. Kersey, Summer 2011
|
||||
*******************************************************************************/
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "include/instruction.h"
|
||||
#include "include/obj.h"
|
||||
#include "include/core.h"
|
||||
#include "include/harpfloat.h"
|
||||
#include "include/debug.h"
|
||||
|
||||
#ifdef EMU_INSTRUMENTATION
|
||||
#include "include/qsim-harp.h"
|
||||
#endif
|
||||
|
||||
using namespace Harp;
|
||||
using namespace std;
|
||||
|
||||
/* It is important that this stays consistent with the Harp::Instruction::Opcode
|
||||
enum. */
|
||||
|
||||
ostream &Harp::operator<<(ostream& os, Instruction &inst) {
|
||||
os << dec;
|
||||
|
||||
// if (inst.predicated) {
|
||||
// os << "@p" << dec << inst.pred << " ? ";
|
||||
// }
|
||||
|
||||
// os << inst.instTable[inst.op].opString << ' ';
|
||||
// if (inst.rdestPresent) os << "%r" << dec << inst.rdest << ' ';
|
||||
// if (inst.pdestPresent) os << "@p" << inst.pdest << ' ';
|
||||
// for (int i = 0; i < inst.nRsrc; i++) {
|
||||
// os << "%r" << dec << inst.rsrc[i] << ' ';
|
||||
// }
|
||||
// for (int i = 0; i < inst.nPsrc; i++) {
|
||||
// os << "@p" << dec << inst.psrc[i] << ' ';
|
||||
// }
|
||||
// if (inst.immsrcPresent) {
|
||||
// if (inst.refLiteral) os << inst.refLiteral->name;
|
||||
// else os << "#0x" << hex << inst.immsrc;
|
||||
// }
|
||||
|
||||
os << instTable[inst.op].opString;
|
||||
|
||||
os << ';';
|
||||
return os;
|
||||
}
|
||||
|
||||
bool checkUnanimous(unsigned p, const std::vector<std::vector<Reg<Word> > >& m,
|
||||
const std::vector<bool> &tm) {
|
||||
bool same;
|
||||
unsigned i;
|
||||
for (i = 0; i < m.size(); ++i) {
|
||||
if (tm[i]) {
|
||||
same = m[i][p];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == m.size()) throw DivergentBranchException();
|
||||
|
||||
//std::cout << "same: " << same << " with -> ";
|
||||
for (; i < m.size(); ++i) {
|
||||
if (tm[i]) {
|
||||
//std::cout << " " << (bool(m[i][p]));
|
||||
if (same != (bool(m[i][p]))) {
|
||||
//std::cout << " FALSE\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//std::cout << " TRUE\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
Word signExt(Word w, Size bit, Word mask) {
|
||||
if (w>>(bit-1)) w |= ~mask;
|
||||
return w;
|
||||
}
|
||||
|
||||
void Instruction::executeOn(Warp &c) {
|
||||
D(3, "Begin instruction execute.");
|
||||
|
||||
/* If I try to execute a privileged instruction in user mode, throw an
|
||||
exception 3. */
|
||||
if (instTable[op].privileged && !c.supervisorMode) {
|
||||
std::cout << "INTERRUPT SUPERVISOR\n";
|
||||
c.interrupt(3);
|
||||
return;
|
||||
}
|
||||
|
||||
// /* Also throw exceptions on non-masked divergent branches. */
|
||||
// if (instTable[op].controlFlow) {
|
||||
// Size t, count, active;
|
||||
// for (t = 0, count = 0, active = 0; t < c.activeThreads; ++t) {
|
||||
// if ((!predicated || c.pred[t][pred]) && c.tmask[t]) ++count;
|
||||
// if (c.tmask[t]) ++active;
|
||||
// }
|
||||
|
||||
// if (count != 0 && count != active)
|
||||
// throw DivergentBranchException();
|
||||
// }
|
||||
|
||||
Size nextActiveThreads = c.activeThreads;
|
||||
Size wordSz = c.core->a.getWordSize();
|
||||
Word nextPc = c.pc;
|
||||
|
||||
c.memAccesses.clear();
|
||||
|
||||
// If we have a load, overwriting a register's contents, we have to make sure
|
||||
// ahead of time it will not fault. Otherwise we may perform an indirect load
|
||||
// by mistake.
|
||||
// if (op == L_INST && rdest == rsrc[0]) {
|
||||
// for (Size t = 0; t < c.activeThreads; t++) {
|
||||
// if ((!predicated || c.pred[t][pred]) && c.tmask[t]) {
|
||||
// Word memAddr = c.reg[t][rsrc[0]] + immsrc;
|
||||
// c.core->mem.read(memAddr, c.supervisorMode);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
bool sjOnce(true), // Has not yet split or joined once.
|
||||
pcSet(false); // PC has already been set
|
||||
for (Size t = 0; t < c.activeThreads; t++) {
|
||||
vector<Reg<Word> > ®(c.reg[t]);
|
||||
vector<Reg<bool> > &pReg(c.pred[t]);
|
||||
stack<DomStackEntry> &domStack(c.domStack);
|
||||
|
||||
//std::cout << std::hex << "opcode: " << op << " func3: " << func3 << "\n";
|
||||
//if (op == GPGPU) //std::cout << "OPCODE MATCHED GPGPU\n";
|
||||
|
||||
// If this thread is masked out, don't execute the instruction, unless it's
|
||||
// a split or join.
|
||||
// if (((predicated && !pReg[pred]) || !c.tmask[t]) &&
|
||||
// op != SPLIT && op != JOIN) continue;
|
||||
|
||||
bool split = (op == GPGPU) && (func3 == 2);
|
||||
bool join = (op == GPGPU) && (func3 == 3);
|
||||
|
||||
|
||||
predicated = (op == GPGPU) && ((func3 == 7) || (func3 == 2));
|
||||
|
||||
|
||||
// printf("Predicated: %d, split: %d, join: %d\n",predicated, split, join );
|
||||
// printf("%d && ((%d) || (%d))\n",(op == GPGPU), (func3 == 7), (func3 == 2) );
|
||||
|
||||
// cout << "before " << op << " = " << GPGPU << "\n";
|
||||
if (((predicated && !reg[pred]) || !c.tmask[t]) && !split && !join)
|
||||
{
|
||||
// cout << "about to continue\n";
|
||||
continue;
|
||||
}
|
||||
// cout << "after\n";
|
||||
|
||||
++c.insts;
|
||||
|
||||
Word memAddr;
|
||||
Word shift_by;
|
||||
Word shamt;
|
||||
Word temp;
|
||||
Word data_read;
|
||||
int op1, op2;
|
||||
bool m_exten;
|
||||
// std::cout << "op = " << op << "\n";
|
||||
// std::cout << "R_INST: " << R_INST << "\n";
|
||||
switch (op) {
|
||||
|
||||
case NOP:
|
||||
//std::cout << "NOP_INST\n";
|
||||
break;
|
||||
case R_INST:
|
||||
// std::cout << "R_INST\n";
|
||||
m_exten = func7 & 0x1;
|
||||
|
||||
if (m_exten)
|
||||
{
|
||||
// std::cout << "FOUND A MUL/DIV\n";
|
||||
|
||||
switch (func3)
|
||||
{
|
||||
case 0:
|
||||
// MUL
|
||||
// cout << "MUL\n";
|
||||
reg[rdest] = ((int) reg[rsrc[0]]) * ((int) reg[rsrc[1]]);
|
||||
break;
|
||||
case 1:
|
||||
// MULH
|
||||
{
|
||||
int64_t first = (int64_t) reg[rsrc[0]];
|
||||
if (reg[rsrc[0]] & 0x80000000)
|
||||
{
|
||||
first = first | 0xFFFFFFFF00000000;
|
||||
}
|
||||
int64_t second = (int64_t) reg[rsrc[1]];
|
||||
if (reg[rsrc[1]] & 0x80000000)
|
||||
{
|
||||
second = second | 0xFFFFFFFF00000000;
|
||||
}
|
||||
// cout << "mulh: " << std::dec << first << " * " << second;
|
||||
uint64_t result = first * second;
|
||||
reg[rdest] = ( result >> 32) & 0xFFFFFFFF;
|
||||
// cout << " = " << result << " or " << reg[rdest] << "\n";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// MULHSU
|
||||
{
|
||||
int64_t first = (int64_t) reg[rsrc[0]];
|
||||
if (reg[rsrc[0]] & 0x80000000)
|
||||
{
|
||||
first = first | 0xFFFFFFFF00000000;
|
||||
}
|
||||
int64_t second = (int64_t) reg[rsrc[1]];
|
||||
reg[rdest] = (( first * second ) >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// MULHU
|
||||
{
|
||||
uint64_t first = (uint64_t) reg[rsrc[0]];
|
||||
uint64_t second = (uint64_t) reg[rsrc[1]];
|
||||
// cout << "MULHU\n";
|
||||
reg[rdest] = (( first * second) >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// DIV
|
||||
if (reg[rsrc[1]] == 0)
|
||||
{
|
||||
reg[rdest] = -1;
|
||||
break;
|
||||
}
|
||||
// cout << "dividing: " << dec << ((int) reg[rsrc[0]]) << " / " << ((int) reg[rsrc[1]]);
|
||||
reg[rdest] = ( (int) reg[rsrc[0]]) / ( (int) reg[rsrc[1]]);
|
||||
// cout << " = " << ((int) reg[rdest]) << "\n";
|
||||
break;
|
||||
case 5:
|
||||
// DIVU
|
||||
if (reg[rsrc[1]] == 0)
|
||||
{
|
||||
reg[rdest] = -1;
|
||||
break;
|
||||
}
|
||||
reg[rdest] = ((uint32_t) reg[rsrc[0]]) / ((uint32_t) reg[rsrc[1]]);
|
||||
break;
|
||||
case 6:
|
||||
// REM
|
||||
if (reg[rsrc[1]] == 0)
|
||||
{
|
||||
reg[rdest] = reg[rsrc[0]];
|
||||
break;
|
||||
}
|
||||
reg[rdest] = ((int) reg[rsrc[0]]) % ((int) reg[rsrc[1]]);
|
||||
break;
|
||||
case 7:
|
||||
// REMU
|
||||
if (reg[rsrc[1]] == 0)
|
||||
{
|
||||
reg[rdest] = reg[rsrc[0]];
|
||||
break;
|
||||
}
|
||||
reg[rdest] = ((uint32_t) reg[rsrc[0]]) % ((uint32_t) reg[rsrc[1]]);
|
||||
break;
|
||||
default:
|
||||
cout << "unsupported MUL/DIV instr\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "NORMAL R-TYPE\n";
|
||||
switch (func3)
|
||||
{
|
||||
case 0:
|
||||
if (func7)
|
||||
{
|
||||
reg[rdest] = reg[rsrc[0]] - reg[rsrc[1]];
|
||||
reg[rdest].trunc(wordSz);
|
||||
}
|
||||
else
|
||||
{
|
||||
reg[rdest] = reg[rsrc[0]] + reg[rsrc[1]];
|
||||
reg[rdest].trunc(wordSz);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
reg[rdest] = reg[rsrc[0]] << reg[rsrc[1]];
|
||||
reg[rdest].trunc(wordSz);
|
||||
break;
|
||||
case 2:
|
||||
if ( int(reg[rsrc[0]]) < int(reg[rsrc[1]]))
|
||||
{
|
||||
reg[rdest] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reg[rdest] = 0;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if ( Word_u(reg[rsrc[0]]) < Word_u(reg[rsrc[1]]))
|
||||
{
|
||||
reg[rdest] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reg[rdest] = 0;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
reg[rdest] = reg[rsrc[0]] ^ reg[rsrc[1]];
|
||||
break;
|
||||
case 5:
|
||||
if (func7)
|
||||
{
|
||||
reg[rdest] = int(reg[rsrc[0]]) >> int(reg[rsrc[1]]);
|
||||
reg[rdest].trunc(wordSz);
|
||||
}
|
||||
else
|
||||
{
|
||||
reg[rdest] = Word_u(reg[rsrc[0]]) >> Word_u(reg[rsrc[1]]);
|
||||
reg[rdest].trunc(wordSz);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
reg[rdest] = reg[rsrc[0]] | reg[rsrc[1]];
|
||||
break;
|
||||
case 7:
|
||||
reg[rdest] = reg[rsrc[0]] & reg[rsrc[1]];
|
||||
break;
|
||||
default:
|
||||
cout << "ERROR: UNSUPPORTED R INST\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case L_INST:
|
||||
//std::cout << "L_INST\n";
|
||||
memAddr = ((reg[rsrc[0]] + immsrc) & 0xFFFFFFFC);
|
||||
shift_by = ((reg[rsrc[0]] + immsrc) & 0x00000003) * 8;
|
||||
data_read = c.core->mem.read(memAddr, c.supervisorMode);
|
||||
// //std::cout <<std::hex<< "EXECUTE: " << reg[rsrc[0]] << " + " << immsrc << " = " << memAddr << " -> data_read: " << data_read << "\n";
|
||||
#ifdef EMU_INSTRUMENTATION
|
||||
Harp::OSDomain::osDomain->
|
||||
do_mem(0, memAddr, c.core->mem.virtToPhys(memAddr), 8, true);
|
||||
#endif
|
||||
switch (func3)
|
||||
{
|
||||
|
||||
case 0:
|
||||
// LB
|
||||
reg[rdest] = signExt((data_read >> shift_by) & 0xFF, 8, 0xFF);
|
||||
break;
|
||||
case 1:
|
||||
// LH
|
||||
// //std::cout << "shifting by: " << shift_by << " final data: " << ((data_read >> shift_by) & 0xFFFF, 16, 0xFFFF) << "\n";
|
||||
reg[rdest] = signExt((data_read >> shift_by) & 0xFFFF, 16, 0xFFFF);
|
||||
break;
|
||||
case 2:
|
||||
reg[rdest] = int(data_read & 0xFFFFFFFF);
|
||||
break;
|
||||
case 4:
|
||||
// LBU
|
||||
reg[rdest] = unsigned((data_read >> shift_by) & 0xFF);
|
||||
break;
|
||||
case 5:
|
||||
reg[rdest] = unsigned((data_read >> shift_by) & 0xFFFF);
|
||||
break;
|
||||
default:
|
||||
cout << "ERROR: UNSUPPORTED L INST\n";
|
||||
exit(1);
|
||||
c.memAccesses.push_back(Warp::MemAccess(false, memAddr));
|
||||
}
|
||||
break;
|
||||
case I_INST:
|
||||
//std::cout << "I_INST\n";
|
||||
switch (func3)
|
||||
{
|
||||
|
||||
case 0:
|
||||
// ADDI
|
||||
reg[rdest] = reg[rsrc[0]] + immsrc;
|
||||
reg[rdest].trunc(wordSz);
|
||||
break;
|
||||
case 2:
|
||||
// SLTI
|
||||
if ( int(reg[rsrc[0]]) < int(immsrc))
|
||||
{
|
||||
reg[rdest] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reg[rdest] = 0;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// SLTIU
|
||||
op1 = (unsigned) reg[rsrc[0]];
|
||||
if ( unsigned(reg[rsrc[0]]) < unsigned(immsrc))
|
||||
{
|
||||
reg[rdest] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reg[rdest] = 0;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// XORI
|
||||
reg[rdest] = reg[rsrc[0]] ^ immsrc;
|
||||
break;
|
||||
case 6:
|
||||
// ORI;
|
||||
reg[rdest] = reg[rsrc[0]] | immsrc;
|
||||
break;
|
||||
case 7:
|
||||
// ANDI
|
||||
reg[rdest] = reg[rsrc[0]] & immsrc;
|
||||
break;
|
||||
case 1:
|
||||
// SLLI
|
||||
reg[rdest] = reg[rsrc[0]] << immsrc;
|
||||
reg[rdest].trunc(wordSz);
|
||||
break;
|
||||
case 5:
|
||||
if ((func7 == 0))
|
||||
{
|
||||
// SRLI
|
||||
// //std::cout << "WTF\n";
|
||||
bool isNeg = ((0x80000000 & reg[rsrc[0]])) > 0;
|
||||
Word result = Word_u(reg[rsrc[0]]) >> Word_u(immsrc);
|
||||
// if (isNeg)
|
||||
// {
|
||||
// Word mask = 0x80000000;
|
||||
// for (int i = 32; i < Word_u(immsrc); i++)
|
||||
// {
|
||||
// result |= mask;
|
||||
// mask = mask >> 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
reg[rdest] = result;
|
||||
|
||||
reg[rdest].trunc(wordSz);
|
||||
}
|
||||
else
|
||||
{
|
||||
// SRAI
|
||||
// //std::cout << "WOHOOOOO\n";
|
||||
op1 = reg[rsrc[0]];
|
||||
op2 = immsrc;
|
||||
reg[rdest] = op1 >> op2;
|
||||
reg[rdest].trunc(wordSz);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cout << "ERROR: UNSUPPORTED L INST\n";
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case S_INST:
|
||||
//std::cout << "S_INST\n";
|
||||
++c.stores;
|
||||
memAddr = reg[rsrc[0]] + immsrc;
|
||||
// //std::cout << "STORE MEM ADDRESS: " << std::hex << reg[rsrc[0]] << " + " << immsrc << "\n";
|
||||
// //std::cout << "FUNC3: " << func3 << "\n";
|
||||
if (memAddr == 0x00010000)
|
||||
{
|
||||
std::cout << (char) reg[rsrc[1]];
|
||||
break;
|
||||
}
|
||||
switch (func3)
|
||||
{
|
||||
case 0:
|
||||
// //std::cout << "SB\n";
|
||||
c.core->mem.write(memAddr, reg[rsrc[1]] & 0x000000FF, c.supervisorMode, 1);
|
||||
break;
|
||||
case 1:
|
||||
// //std::cout << "SH\n";
|
||||
c.core->mem.write(memAddr, reg[rsrc[1]], c.supervisorMode, 2);
|
||||
break;
|
||||
case 2:
|
||||
// //std::cout << std::hex << "SW: about to write: " << reg[rsrc[1]] << " to " << memAddr << "\n";
|
||||
c.core->mem.write(memAddr, reg[rsrc[1]], c.supervisorMode, 4);
|
||||
break;
|
||||
default:
|
||||
cout << "ERROR: UNSUPPORTED S INST\n";
|
||||
exit(1);
|
||||
}
|
||||
c.memAccesses.push_back(Warp::MemAccess(true, memAddr));
|
||||
#ifdef EMU_INSTRUMENTATION
|
||||
Harp::OSDomain::osDomain->
|
||||
do_mem(0, memAddr, c.core->mem.virtToPhys(memAddr), 8, true);
|
||||
#endif
|
||||
break;
|
||||
case B_INST:
|
||||
//std::cout << "B_INST\n";
|
||||
switch (func3)
|
||||
{
|
||||
case 0:
|
||||
// BEQ
|
||||
if (int(reg[rsrc[0]]) == int(reg[rsrc[1]]))
|
||||
{
|
||||
if (!pcSet) nextPc = (c.pc - 4) + immsrc;
|
||||
pcSet = true;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// BNE
|
||||
if (int(reg[rsrc[0]]) != int(reg[rsrc[1]]))
|
||||
{
|
||||
if (!pcSet) nextPc = (c.pc - 4) + immsrc;
|
||||
pcSet = true;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// BLT
|
||||
if (int(reg[rsrc[0]]) < int(reg[rsrc[1]]))
|
||||
{
|
||||
if (!pcSet) nextPc = (c.pc - 4) + immsrc;
|
||||
pcSet = true;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
// BGE
|
||||
if (int(reg[rsrc[0]]) >= int(reg[rsrc[1]]))
|
||||
{
|
||||
if (!pcSet) nextPc = (c.pc - 4) + immsrc;
|
||||
pcSet = true;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
// BLTU
|
||||
if (Word_u(reg[rsrc[0]]) < Word_u(reg[rsrc[1]]))
|
||||
{
|
||||
if (!pcSet) nextPc = (c.pc - 4) + immsrc;
|
||||
pcSet = true;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
// BGEU
|
||||
if (Word_u(reg[rsrc[0]]) >= Word_u(reg[rsrc[1]]))
|
||||
{
|
||||
if (!pcSet) nextPc = (c.pc - 4) + immsrc;
|
||||
pcSet = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LUI_INST:
|
||||
//std::cout << "LUI_INST\n";
|
||||
reg[rdest] = (immsrc << 12) & 0xfffff000;
|
||||
break;
|
||||
case AUIPC_INST:
|
||||
//std::cout << "AUIPC_INST\n";
|
||||
reg[rdest] = ((immsrc << 12) & 0xfffff000) + (c.pc - 4);
|
||||
break;
|
||||
case JAL_INST:
|
||||
//std::cout << "JAL_INST\n";
|
||||
if (!pcSet) nextPc = (c.pc - 4) + immsrc;
|
||||
if (!pcSet) //std::cout << "JAL... SETTING PC: " << nextPc << "\n";
|
||||
if (rdest != 0)
|
||||
{
|
||||
reg[rdest] = c.pc;
|
||||
}
|
||||
pcSet = true;
|
||||
break;
|
||||
case JALR_INST:
|
||||
//std::cout << "JALR_INST\n";
|
||||
if (!pcSet) nextPc = reg[rsrc[0]] + immsrc;
|
||||
if (!pcSet) //std::cout << "JALR... SETTING PC: " << nextPc << "\n";
|
||||
if (rdest != 0)
|
||||
{
|
||||
reg[rdest] = c.pc;
|
||||
}
|
||||
pcSet = true;
|
||||
break;
|
||||
case SYS_INST:
|
||||
//std::cout << "SYS_INST\n";
|
||||
temp = reg[rsrc[0]];
|
||||
switch (func3)
|
||||
{
|
||||
case 1:
|
||||
// printf("Case 1\n");
|
||||
if (rdest != 0)
|
||||
{
|
||||
reg[rdest] = c.csr[immsrc & 0x00000FFF];
|
||||
}
|
||||
c.csr[immsrc & 0x00000FFF] = temp;
|
||||
|
||||
break;
|
||||
case 2:
|
||||
// printf("Case 2\n");
|
||||
if (rdest != 0)
|
||||
{
|
||||
// printf("Reading from CSR: %d = %d\n", (immsrc & 0x00000FFF), c.csr[immsrc & 0x00000FFF]);
|
||||
reg[rdest] = c.csr[immsrc & 0x00000FFF];
|
||||
}
|
||||
// printf("Writing to CSR --> %d = %d\n", immsrc, (temp | c.csr[immsrc & 0x00000FFF]));
|
||||
c.csr[immsrc & 0x00000FFF] = temp | c.csr[immsrc & 0x00000FFF];
|
||||
|
||||
break;
|
||||
case 3:
|
||||
// printf("Case 3\n");
|
||||
if (rdest != 0)
|
||||
{
|
||||
reg[rdest] = c.csr[immsrc & 0x00000FFF];
|
||||
}
|
||||
c.csr[immsrc & 0x00000FFF] = temp & (~c.csr[immsrc & 0x00000FFF]);
|
||||
|
||||
break;
|
||||
case 5:
|
||||
// printf("Case 5\n");
|
||||
if (rdest != 0)
|
||||
{
|
||||
reg[rdest] = c.csr[immsrc & 0x00000FFF];
|
||||
}
|
||||
c.csr[immsrc & 0x00000FFF] = rsrc[0];
|
||||
|
||||
break;
|
||||
case 6:
|
||||
// printf("Case 6\n");
|
||||
if (rdest != 0)
|
||||
{
|
||||
reg[rdest] = c.csr[immsrc & 0x00000FFF];
|
||||
}
|
||||
c.csr[immsrc & 0x00000FFF] = rsrc[0] | c.csr[immsrc & 0x00000FFF];
|
||||
|
||||
break;
|
||||
case 7:
|
||||
// printf("Case 7\n");
|
||||
if (rdest != 0)
|
||||
{
|
||||
reg[rdest] = c.csr[immsrc & 0x00000FFF];
|
||||
}
|
||||
c.csr[immsrc & 0x00000FFF] = rsrc[0] & (~c.csr[immsrc & 0x00000FFF]);
|
||||
|
||||
break;
|
||||
case 0:
|
||||
if (immsrc < 2)
|
||||
{
|
||||
//std::cout << "INTERRUPT ECALL/EBREAK\n";
|
||||
nextActiveThreads = 0;
|
||||
c.spawned = false;
|
||||
// c.interrupt(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TRAP:
|
||||
//std::cout << "INTERRUPT TRAP\n";
|
||||
nextActiveThreads = 0;
|
||||
c.interrupt(0);
|
||||
break;
|
||||
case FENCE:
|
||||
//std::cout << "FENCE_INST\n";
|
||||
break;
|
||||
case PJ_INST:
|
||||
// pred jump reg
|
||||
//std::cout << "pred jump... src: " << rsrc[0] << std::hex << " val: " << reg[rsrc[0]] << " dest: " << reg[rsrc[1]] << "\n";
|
||||
if (reg[rsrc[0]])
|
||||
{
|
||||
if (!pcSet) nextPc = reg[rsrc[1]];
|
||||
pcSet = true;
|
||||
}
|
||||
break;
|
||||
case GPGPU:
|
||||
//std::cout << "GPGPU\n";
|
||||
switch(func3)
|
||||
{
|
||||
case 0:
|
||||
// WSPAWN
|
||||
//std::cout << "WSPAWN\n";
|
||||
if (sjOnce)
|
||||
{
|
||||
sjOnce = false;
|
||||
D(0, "Spawning a new warp.");
|
||||
// //std::cout << "SIZE: " << c.core->w.size() << "\n";
|
||||
for (unsigned i = 0; i < c.core->w.size(); ++i)
|
||||
{
|
||||
// std::cout << "SPAWNING WARP\n";
|
||||
Warp &newWarp(c.core->w[i]);
|
||||
// //std::cout << "STARTING\n";
|
||||
if (newWarp.spawned == false) {
|
||||
// //std::cout << "ABOUT TO START\n";
|
||||
newWarp.pc = reg[rsrc[0]];
|
||||
newWarp.reg[0] = reg;
|
||||
newWarp.csr = c.csr;
|
||||
newWarp.activeThreads = 1;
|
||||
newWarp.supervisorMode = false;
|
||||
newWarp.spawned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
// SPLIT
|
||||
//std::cout << "SPLIT\n";
|
||||
if (sjOnce)
|
||||
{
|
||||
sjOnce = false;
|
||||
if (checkUnanimous(pred, c.reg, c.tmask)) {
|
||||
//std::cout << "Unanimous pred: " << pred << " val: " << reg[pred] << "\n";
|
||||
DomStackEntry e(c.tmask);
|
||||
e.uni = true;
|
||||
c.domStack.push(e);
|
||||
break;
|
||||
}
|
||||
DomStackEntry e(pred, c.reg, c.tmask, c.pc);
|
||||
c.domStack.push(c.tmask);
|
||||
c.domStack.push(e);
|
||||
for (unsigned i = 0; i < e.tmask.size(); ++i)
|
||||
{
|
||||
c.tmask[i] = !e.tmask[i] && c.tmask[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// JOIN
|
||||
//std::cout << "JOIN\n";
|
||||
if (sjOnce)
|
||||
{
|
||||
sjOnce = false;
|
||||
if (!c.domStack.empty() && c.domStack.top().uni) {
|
||||
D(2, "Uni branch at join");
|
||||
c.tmask = c.domStack.top().tmask;
|
||||
c.domStack.pop();
|
||||
break;
|
||||
}
|
||||
if (!c.domStack.top().fallThrough) {
|
||||
if (!pcSet) nextPc = c.domStack.top().pc;
|
||||
pcSet = true;
|
||||
}
|
||||
c.tmask = c.domStack.top().tmask;
|
||||
c.domStack.pop();
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// JMPRT
|
||||
//std::cout << "JMPRT\n";
|
||||
nextActiveThreads = 1;
|
||||
if (!pcSet) nextPc = reg[rsrc[0]];
|
||||
pcSet = true;
|
||||
break;
|
||||
case 5:
|
||||
// CLONE
|
||||
//std::cout << "CLONE\n";
|
||||
// //std::cout << "CLONING REG: " << rsrc[0] << " lane: " << reg[rsrc[0]] << "\n";
|
||||
c.reg[reg[rsrc[0]]] = reg;
|
||||
break;
|
||||
case 6:
|
||||
// JALRS
|
||||
//std::cout << "JALRS\n";
|
||||
nextActiveThreads = reg[rsrc[1]];
|
||||
reg[rdest] = c.pc;
|
||||
if (!pcSet) nextPc = reg[rsrc[0]];
|
||||
pcSet = true;
|
||||
// //std::cout << "ACTIVE_THREDS: " << rsrc[1] << " val: " << reg[rsrc[1]] << "\n";
|
||||
// //std::cout << "nextPC: " << rsrc[0] << " val: " << std::hex << reg[rsrc[0]] << "\n";
|
||||
break;
|
||||
default:
|
||||
cout << "ERROR: UNSUPPORTED GPGPU INSTRUCTION " << *this << "\n";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cout << "pc: " << hex << (c.pc) << "\n";
|
||||
cout << "aERROR: Unsupported instruction: " << *this << "\n" << flush;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
D(3, "End instruction execute.");
|
||||
|
||||
c.activeThreads = nextActiveThreads;
|
||||
|
||||
// if (nextActiveThreads != 0)
|
||||
// {
|
||||
// for (int i = 7; i >= c.activeThreads; i--)
|
||||
// {
|
||||
// c.tmask[i] = c.tmask[i] && false;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// //std::cout << "new thread mask: ";
|
||||
// for (int i = 0; i < c.tmask.size(); ++i) //std::cout << " " << c.tmask[i];
|
||||
// //std::cout << "\n";
|
||||
|
||||
// This way, if pc was set by a side effect (such as interrupt), it will
|
||||
// retain its new value.
|
||||
if (pcSet) c.pc = nextPc;
|
||||
|
||||
if (nextActiveThreads > c.reg.size()) {
|
||||
cerr << "Error: attempt to spawn " << nextActiveThreads << " threads. "
|
||||
<< c.reg.size() << " available.\n";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user