URL
https://opencores.org/ocsvn/altor32/altor32/trunk
Subversion Repositories altor32
Compare Revisions
- This comparison shows the changes necessary to convert path
/altor32/trunk
- from Rev 5 to Rev 6
- ↔ Reverse comparison
Rev 5 → Rev 6
/or32-sim/getopt_win32.c
147,72 → 147,72
// |
/////////////////////////////////////////////////////////////////////////////// |
|
TCHAR *optarg; // global argument pointer |
int optind = 0; // global argv index |
TCHAR *optarg; // global argument pointer |
int optind = 0; // global argv index |
|
int getopt(int argc, TCHAR *argv[], TCHAR *optstring) |
{ |
static TCHAR *next = NULL; |
TCHAR c; |
TCHAR *cp; |
static TCHAR *next = NULL; |
TCHAR c; |
TCHAR *cp; |
|
if (optind == 0) |
next = NULL; |
if (optind == 0) |
next = NULL; |
|
optarg = NULL; |
optarg = NULL; |
|
if (next == NULL || *next == _T('\0')) |
{ |
if (optind == 0) |
optind++; |
if (next == NULL || *next == _T('\0')) |
{ |
if (optind == 0) |
optind++; |
|
if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0')) |
{ |
optarg = NULL; |
if (optind < argc) |
optarg = argv[optind]; |
return EOF; |
} |
if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0')) |
{ |
optarg = NULL; |
if (optind < argc) |
optarg = argv[optind]; |
return EOF; |
} |
|
if (_tcscmp(argv[optind], _T("--")) == 0) |
{ |
optind++; |
optarg = NULL; |
if (optind < argc) |
optarg = argv[optind]; |
return EOF; |
} |
if (_tcscmp(argv[optind], _T("--")) == 0) |
{ |
optind++; |
optarg = NULL; |
if (optind < argc) |
optarg = argv[optind]; |
return EOF; |
} |
|
next = argv[optind]; |
next++; // skip past - |
optind++; |
} |
next = argv[optind]; |
next++; // skip past - |
optind++; |
} |
|
c = *next++; |
cp = _tcschr(optstring, c); |
c = *next++; |
cp = _tcschr(optstring, c); |
|
if (cp == NULL || c == _T(':')) |
return _T('?'); |
if (cp == NULL || c == _T(':')) |
return _T('?'); |
|
cp++; |
if (*cp == _T(':')) |
{ |
if (*next != _T('\0')) |
{ |
optarg = next; |
next = NULL; |
} |
else if (optind < argc) |
{ |
optarg = argv[optind]; |
optind++; |
} |
else |
{ |
return _T('?'); |
} |
} |
cp++; |
if (*cp == _T(':')) |
{ |
if (*next != _T('\0')) |
{ |
optarg = next; |
next = NULL; |
} |
else if (optind < argc) |
{ |
optarg = argv[optind]; |
optind++; |
} |
else |
{ |
return _T('?'); |
} |
} |
|
return c; |
return c; |
} |
#endif |
/or32-sim/main.cpp
1,181 → 1,186
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
// AltOR32 OpenRisc Simulator |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 OpenRisc Simulator. |
// |
// AltOR32 OpenRisc Simulator 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 2 of the License, or |
// (at your option) any later version. |
// |
// AltOR32 OpenRisc Simulator 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 AltOR32 OpenRisc Simulator; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <assert.h> |
|
#include "or32.h" |
|
#ifdef WIN32 |
#include "getopt_win32.h" |
#else |
#include <unistd.h> |
#endif |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
#define DEFAULT_MEM_BASE 0x00000000 |
#define DEFAULT_MEM_SIZE (10 << 20) |
#define DEFAULT_LOAD_ADDR 0x00000000 |
#define DEFAULT_FILENAME NULL |
|
//----------------------------------------------------------------- |
// Locals |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// main |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int c; |
unsigned int loadAddr = DEFAULT_LOAD_ADDR; |
unsigned int memBase = DEFAULT_MEM_BASE; |
unsigned int memSize = DEFAULT_MEM_SIZE; |
int max_cycles = -1; |
char *filename = DEFAULT_FILENAME; |
int help = 0; |
int trace = 0; |
unsigned int trace_mask = 1; |
int exitcode = 0; |
OR32 *sim = NULL; |
|
while ((c = getopt (argc, argv, "tv:l:b:s:f:c:")) != -1) |
{ |
switch(c) |
{ |
case 't': |
trace = 1; |
break; |
case 'v': |
trace_mask = strtoul(optarg, NULL, 0); |
break; |
case 'l': |
loadAddr = strtoul(optarg, NULL, 0); |
break; |
case 'b': |
memBase = strtoul(optarg, NULL, 0); |
break; |
case 's': |
memSize = strtoul(optarg, NULL, 0); |
break; |
case 'f': |
filename = optarg; |
break; |
case 'c': |
max_cycles = (int)strtoul(optarg, NULL, 0); |
break; |
case '?': |
default: |
help = 1; |
break; |
} |
} |
|
if (help || filename == NULL) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-f filename.bin = Executable to load (binary)\n"); |
fprintf (stderr,"-t = Enable program trace\n"); |
fprintf (stderr,"-v 0xX = Trace Mask\n"); |
fprintf (stderr,"-b 0xnnnn = Memory base address\n"); |
fprintf (stderr,"-s 0xnnnn = Memory size\n"); |
fprintf (stderr,"-l 0xnnnn = Executable load address\n"); |
fprintf (stderr,"-c nnnn = Max instructions to execute\n"); |
|
exit(-1); |
} |
|
sim = new OR32(memBase, memSize); |
sim->Reset(loadAddr + VECTOR_RESET); |
|
if (trace) |
sim->EnableTrace(trace_mask); |
|
FILE *f = fopen(filename, "rb"); |
if (f) |
{ |
long size; |
char *buf; |
|
// Get size |
fseek(f, 0, SEEK_END); |
size = ftell(f); |
rewind(f); |
|
buf = (char*)malloc(size+1); |
if (buf) |
{ |
int wait_for_input = 0; |
|
// Read file data in |
int len = fread(buf, 1, size, f); |
buf[len] = 0; |
|
if (sim->Load(loadAddr, (unsigned char *)buf, len)) |
{ |
int cycles = 0; |
|
while (!sim->GetBreak() && !sim->GetFault()) |
{ |
sim->Step(); |
cycles++; |
|
if (max_cycles != -1 && max_cycles == cycles) |
break; |
} |
} |
else |
fprintf (stderr,"Error: Could not load image to memory\n"); |
|
free(buf); |
fclose(f); |
} |
// Show execution stats |
sim->DumpStats(); |
|
if (sim->GetBreak()) |
{ |
printf("Exit code = %d\n", 0); |
} |
} |
else |
fprintf (stderr,"Error: Could not open %s\n", filename); |
|
delete sim; |
|
return exitcode; |
} |
|
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
// AltOR32 OpenRisc Simulator |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 OpenRisc Simulator. |
// |
// AltOR32 OpenRisc Simulator 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 2 of the License, or |
// (at your option) any later version. |
// |
// AltOR32 OpenRisc Simulator 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 AltOR32 OpenRisc Simulator; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <assert.h> |
|
#include "or32.h" |
|
#ifdef WIN32 |
#include "getopt_win32.h" |
#else |
#include <unistd.h> |
#endif |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
#define DEFAULT_MEM_BASE 0x00000000 |
#define DEFAULT_MEM_SIZE (10 << 20) |
#define DEFAULT_LOAD_ADDR 0x00000000 |
#define DEFAULT_FILENAME NULL |
|
//----------------------------------------------------------------- |
// Locals |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// main |
//----------------------------------------------------------------- |
int main(int argc, char *argv[]) |
{ |
int c; |
unsigned int loadAddr = DEFAULT_LOAD_ADDR; |
unsigned int memBase = DEFAULT_MEM_BASE; |
unsigned int memSize = DEFAULT_MEM_SIZE; |
unsigned int startAddr = VECTOR_RESET; |
int max_cycles = -1; |
char *filename = DEFAULT_FILENAME; |
int help = 0; |
int trace = 0; |
unsigned int trace_mask = 1; |
int exitcode = 0; |
OR32 *sim = NULL; |
|
while ((c = getopt (argc, argv, "tv:l:b:s:f:c:x:")) != -1) |
{ |
switch(c) |
{ |
case 't': |
trace = 1; |
break; |
case 'v': |
trace_mask = strtoul(optarg, NULL, 0); |
break; |
case 'l': |
loadAddr = strtoul(optarg, NULL, 0); |
break; |
case 'b': |
memBase = strtoul(optarg, NULL, 0); |
break; |
case 's': |
memSize = strtoul(optarg, NULL, 0); |
break; |
case 'x': |
startAddr = strtoul(optarg, NULL, 0); |
break; |
case 'f': |
filename = optarg; |
break; |
case 'c': |
max_cycles = (int)strtoul(optarg, NULL, 0); |
break; |
case '?': |
default: |
help = 1; |
break; |
} |
} |
|
if (help || filename == NULL) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-f filename.bin = Executable to load (binary)\n"); |
fprintf (stderr,"-t = Enable program trace\n"); |
fprintf (stderr,"-v 0xX = Trace Mask\n"); |
fprintf (stderr,"-b 0xnnnn = Memory base address\n"); |
fprintf (stderr,"-s 0xnnnn = Memory size\n"); |
fprintf (stderr,"-l 0xnnnn = Executable load address\n"); |
fprintf (stderr,"-x 0xnnnn = Executable boot address\n"); |
fprintf (stderr,"-c nnnn = Max instructions to execute\n"); |
|
exit(-1); |
} |
|
sim = new OR32(memBase, memSize); |
sim->Reset(startAddr); |
|
if (trace) |
sim->EnableTrace(trace_mask); |
|
FILE *f = fopen(filename, "rb"); |
if (f) |
{ |
long size; |
char *buf; |
|
// Get size |
fseek(f, 0, SEEK_END); |
size = ftell(f); |
rewind(f); |
|
buf = (char*)malloc(size+1); |
if (buf) |
{ |
int wait_for_input = 0; |
|
// Read file data in |
int len = fread(buf, 1, size, f); |
buf[len] = 0; |
|
if (sim->Load(loadAddr, (unsigned char *)buf, len)) |
{ |
int cycles = 0; |
|
while (!sim->GetBreak() && !sim->GetFault()) |
{ |
sim->Step(); |
cycles++; |
|
if (max_cycles != -1 && max_cycles == cycles) |
break; |
} |
} |
else |
fprintf (stderr,"Error: Could not load image to memory\n"); |
|
free(buf); |
fclose(f); |
} |
// Show execution stats |
sim->DumpStats(); |
|
if (sim->GetBreak()) |
{ |
printf("Exit code = %d\n", 0); |
} |
} |
else |
fprintf (stderr,"Error: Could not open %s\n", filename); |
|
delete sim; |
|
return exitcode; |
} |
|
/or32-sim/or32.cpp
1,1096 → 1,1100
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
// AltOR32 OpenRisc Simulator |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 OpenRisc Simulator. |
// |
// AltOR32 OpenRisc Simulator 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 2 of the License, or |
// (at your option) any later version. |
// |
// AltOR32 OpenRisc Simulator 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 AltOR32 OpenRisc Simulator; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <assert.h> |
#include "or32.h" |
#include "or32_inst_dump.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
// AltOR32 OpenRisc Simulator |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 OpenRisc Simulator. |
// |
// AltOR32 OpenRisc Simulator 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 2 of the License, or |
// (at your option) any later version. |
// |
// AltOR32 OpenRisc Simulator 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 AltOR32 OpenRisc Simulator; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <assert.h> |
#include "or32.h" |
#include "or32_inst_dump.h" |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define DPRINTF(l,a) do { if (Trace & l) printf a; } while (0) |
#define TRACE_ENABLED(l) (Trace & l) |
|
//----------------------------------------------------------------- |
// Constructor |
//----------------------------------------------------------------- |
OR32::OR32(unsigned int baseAddr, unsigned int len) |
{ |
MemBase = baseAddr; |
MemSize = len; |
Mem = new TMemory[len/4]; |
Trace = 0; |
|
assert(Mem); |
|
Reset(); |
} |
//----------------------------------------------------------------- |
// Deconstructor |
//----------------------------------------------------------------- |
OR32::~OR32() |
{ |
if (Mem) |
delete Mem; |
Mem = NULL; |
} |
//----------------------------------------------------------------- |
// Reset: Reset CPU state |
//----------------------------------------------------------------- |
void OR32::Reset(TRegister start_addr /*= VECTOR_RESET*/) |
{ |
int i; |
|
r_pc = start_addr; |
r_pc_next = start_addr; |
r_pc_last = start_addr; |
r_sr = 0; |
r_epc = 0; |
r_esr = 0; |
|
for (i=0;i<REGISTERS;i++) |
r_gpr[i] = 0; |
|
r_reg_ra = 0; |
r_reg_rb = 0; |
r_reg_result = 0; |
r_rd_wb = 0; |
r_ra = 0; |
r_rb = 0; |
|
mem_addr = 0; |
mem_offset = 0; |
mem_wr = 0; |
mem_rd = 0; |
|
Fault = 0; |
Break = 0; |
BreakValue = 0; |
Trace = 0; |
Cycle = 2; |
|
// Clear stats |
StatsMem = 0; |
StatsInstructions = 0; |
StatsNop = 0; |
StatsBranches = 0; |
StatsExceptions = 0; |
|
PeripheralReset(); |
} |
//----------------------------------------------------------------- |
// Load: Load program code into startAddr offset |
//----------------------------------------------------------------- |
bool OR32::Load(unsigned int startAddr, unsigned char *data, int len) |
{ |
int i; |
|
// Program fits in memory? |
if ((startAddr >= MemBase) && (startAddr + len) <= (MemBase + MemSize)) |
{ |
// Zero memory first |
memset(Mem, 0, sizeof(Mem)); |
|
// Make relative to start of memory |
startAddr -= MemBase; |
|
// Convert to word address |
startAddr /= 4; |
|
for (i=0;i<len / (int)sizeof(Mem[0]); i++) |
{ |
Mem[startAddr+i] = *data++; |
Mem[startAddr+i] <<= 8; |
Mem[startAddr+i]|= *data++; |
Mem[startAddr+i] <<= 8; |
Mem[startAddr+i]|= *data++; |
Mem[startAddr+i] <<= 8; |
Mem[startAddr+i]|= *data++; |
} |
|
return true; |
} |
else |
return false; |
} |
//----------------------------------------------------------------- |
// WriteMem: Write a block of memory |
//----------------------------------------------------------------- |
bool OR32::WriteMem(TAddress addr, unsigned char *data, int len) |
{ |
int i; |
TAddress word; |
|
if (addr >= MemBase && addr < (MemBase + MemSize)) |
{ |
word = (addr - MemBase) / 4; |
for (i=0;i<len / (int)sizeof(Mem[0]); i++) |
{ |
Mem[word + i] = *data++; |
Mem[word + i] <<= 8; |
Mem[word + i]|= *data++; |
Mem[word + i] <<= 8; |
Mem[word + i]|= *data++; |
Mem[word + i] <<= 8; |
Mem[word + i]|= *data++; |
} |
|
return true; |
} |
else |
return false; |
} |
//----------------------------------------------------------------- |
// ReadMem: Read a block of memory |
//----------------------------------------------------------------- |
bool OR32::ReadMem(TAddress addr, unsigned char *data, int len) |
{ |
int i; |
TAddress word; |
|
if (addr >= MemBase && addr < (MemBase + MemSize)) |
{ |
word = (addr - MemBase) / 4; |
for (i=0;i<len / (int)sizeof(Mem[0]); i++) |
{ |
*data++ = Mem[word + i] >> 24; |
*data++ = Mem[word + i] >> 16; |
*data++ = Mem[word + i] >> 8; |
*data++ = Mem[word + i] >> 0; |
} |
|
return true; |
} |
else |
return false; |
} |
//----------------------------------------------------------------- |
// Decode: Instruction decode stage |
//----------------------------------------------------------------- |
void OR32::Decode(void) |
{ |
// Instruction opcode read complete |
mem_wr = 0; |
mem_rd = 0; |
|
// Fetch instruction from 'memory bus' |
r_opcode = mem_data_in; |
mem_data_in = 0; |
|
// Decode opcode in-order to perform register reads |
r_ra = (r_opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; |
r_rb = (r_opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; |
r_rd = (r_opcode >> OR32_REG_D_SHIFT) & OR32_REG_D_MASK; |
} |
//----------------------------------------------------------------- |
// Execute: Instruction execution stage |
//----------------------------------------------------------------- |
void OR32::Execute(void) |
{ |
TRegister v_ra = 0; |
TRegister v_rb = 0; |
TRegister v_rd = 0; |
TRegister v_inst = 0; |
TRegister v_op = 0; |
TRegister v_target = 0; |
TRegister v_pc = 0; |
TRegister v_pc_next = 0; |
TRegister v_imm = 0; |
TRegister v_imm_uint32 = 0; |
TRegister v_imm_int32 = 0; |
TRegister v_offset = 0; |
TRegister v_reg_ra = 0; |
TRegister v_reg_rb = 0; |
TRegister v_reg_result = 0; |
TRegister v_store_imm = 0; |
int v_branch = 0; |
int v_jmp = 0; |
int v_exception = 0; |
TRegister v_vector = 0; |
int v_write_rd = 0; |
|
TRegister v_alu_op = 0; |
TRegister v_shift_op = 0; |
TRegister v_sfxx_op = 0; |
|
// Notify observers of instruction execution |
MonInstructionExecute(r_pc, r_opcode); |
|
StatsInstructions++; |
|
DPRINTF(LOG_INST, ("%08x: %08x\n", r_pc, r_opcode)); |
|
// Decode opcode fields |
v_inst = (r_opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; |
v_rd = (r_opcode >> OR32_REG_D_SHIFT) & OR32_REG_D_MASK; |
v_ra = (r_opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; |
v_rb = (r_opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; |
v_imm = (r_opcode >> OR32_IMM16_SHIFT) & OR32_IMM16_MASK; |
v_target = (r_opcode >> OR32_ADDR_SHIFT) & OR32_ADDR_MASK; |
v_sfxx_op = (r_opcode >> OR32_SFXXX_OP_SHIFT) & OR32_SFXXX_OP_MASK; |
v_alu_op = (r_opcode >> OR32_ALU_OP_L_SHIFT) & OR32_ALU_OP_L_MASK; |
v_alu_op |= (r_opcode >> OR32_ALU_OP_H_SHIFT) & OR32_ALU_OP_H_MASK; |
v_shift_op = (r_opcode >> OR32_SHIFT_OP_SHIFT) & OR32_SHIFT_OP_MASK; |
v_store_imm = (r_opcode >> OR32_STORE_IMM_L_SHIFT) & OR32_STORE_IMM_L_MASK; |
v_store_imm|= (r_opcode >> OR32_STORE_IMM_H_SHIFT) & OR32_STORE_IMM_H_MASK; |
|
// Sign extend store immediate |
v_store_imm = (unsigned int)(signed short)v_store_imm; |
|
// Sign extend target immediate |
if (v_target & (1 << OR32_ADDR_SIGN_SHIFT)) |
v_target |= ~OR32_ADDR_MASK; |
|
// Signed & unsigned imm -> 32-bits |
v_imm_int32 = (unsigned int)(signed short)v_imm; |
v_imm_uint32 = v_imm; |
|
// Load register[ra] |
v_reg_ra = r_reg_ra; |
|
// Load register[rb] |
v_reg_rb = r_reg_rb; |
|
// Zero result |
v_reg_result = 0; |
|
// Update PC to next value |
v_pc = r_pc_next; |
|
// Increment next PC value (might be overriden by branch) |
v_pc_next = r_pc_next + 4; |
|
// Default target is r_rd |
r_rd_wb = r_rd; |
|
// Execute instruction |
switch(v_inst) |
{ |
case INST_OR32_ALU: |
switch (v_alu_op) |
{ |
case INST_OR32_ADD: // l.add |
v_reg_result = v_reg_ra + v_reg_rb; |
v_write_rd = 1; |
break; |
case INST_OR32_AND: // l.and |
v_reg_result = v_reg_ra & v_reg_rb; |
v_write_rd = 1; |
break; |
case INST_OR32_OR: // l.or |
v_reg_result = v_reg_ra | v_reg_rb; |
v_write_rd = 1; |
break; |
case INST_OR32_SLL: // l.sll |
v_reg_result = v_reg_ra << (v_reg_rb & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SRA: // l.sra |
v_reg_result = (int)v_reg_ra >> (v_reg_rb & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SRL: // l.srl |
v_reg_result = v_reg_ra >> (v_reg_rb & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SUB: // l.sub |
v_reg_result = v_reg_ra + ~v_reg_rb + 1; |
v_write_rd = 1; |
break; |
case INST_OR32_XOR: // l.xor |
v_reg_result = v_reg_ra ^ v_reg_rb; |
v_write_rd = 1; |
break; |
default: |
fprintf (stderr,"Bad ALU instruction @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_ADDI: // l.addi |
v_reg_result = v_reg_ra + v_imm_int32; |
v_write_rd = 1; |
break; |
|
case INST_OR32_ANDI: // l.andi |
v_reg_result = v_reg_ra & v_imm_uint32; |
v_write_rd = 1; |
break; |
|
case INST_OR32_BF: // l.bf |
if (r_sr & OR32_SR_F_BIT) |
v_branch = 1; |
break; |
|
case INST_OR32_BNF: // l.bnf |
if (!(r_sr & OR32_SR_F_BIT)) |
v_branch = 1; |
break; |
|
case INST_OR32_J: // l.j |
v_branch = 1; |
break; |
|
case INST_OR32_JAL: // l.jal |
// Write next instruction address to LR |
v_reg_result = v_pc_next; |
r_rd_wb = REG_9_LR; |
v_write_rd = 1; |
|
v_branch = 1; |
break; |
|
case INST_OR32_JALR: // l.jalr |
// Write next instruction address to LR |
v_reg_result = v_pc_next; |
r_rd_wb = REG_9_LR; |
v_write_rd = 1; |
|
v_pc_next = v_reg_rb; |
v_jmp = 1; |
break; |
|
case INST_OR32_JR: // l.jr |
v_pc_next = v_reg_rb; |
v_jmp = 1; |
break; |
|
case INST_OR32_LBS: // l.lbs |
case INST_OR32_LHS: // l.lhs |
case INST_OR32_LWS: // l.lws |
case INST_OR32_LBZ: // l.lbz |
case INST_OR32_LHZ: // l.lhz |
case INST_OR32_LWZ: // l.lwz |
mem_addr = v_reg_ra + (int)v_imm_int32; |
mem_offset = mem_addr & 0x3; |
mem_wr = 0; |
mem_rd = 1; |
mem_data_out = 0; |
v_write_rd = 1; |
StatsMem++; |
break; |
|
case INST_OR32_MFSPR: // l.mfspr |
// Move from SPR register |
switch ((v_reg_ra | (v_imm_uint32 & OR32_MFSPR_IMM_MASK))) |
{ |
// VR - Version register |
case SPR_REG_VR: |
v_reg_result = SPR_VERSION_CURRENT; |
v_write_rd = 1; |
break; |
// SR - Supervision register |
case SPR_REG_SR: |
v_reg_result = r_sr; |
v_write_rd = 1; |
break; |
// EPCR - EPC Exception saved PC |
case SPR_REG_EPCR: |
v_reg_result = r_epc; |
v_write_rd = 1; |
break; |
// ESR - Exception saved SR |
case SPR_REG_ESR: |
v_reg_result = r_esr; |
v_write_rd = 1; |
break; |
default: |
fprintf (stderr,"Unsupported SPR register (0x%x) access @ PC %x\n", (v_reg_ra | v_imm_uint32), r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_MTSPR: // l.mtspr |
// Move to SPR register |
switch ((v_reg_ra | (v_imm_uint32 & OR32_MTSPR_IMM_MASK))) |
{ |
// SR - Supervision register |
case SPR_REG_SR: |
r_sr = v_reg_rb; |
break; |
// EPCR - EPC Exception saved PC |
case SPR_REG_EPCR: |
r_epc = v_reg_rb; |
break; |
// ESR - Exception saved SR |
case SPR_REG_ESR: |
r_esr = v_reg_rb; |
break; |
default: |
fprintf (stderr,"Unsupported SPR register (0x%x) access @ PC %x\n", (v_reg_ra | v_imm_uint32), r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_MOVHI: // l.movhi |
v_reg_result = v_imm_uint32 << 16; |
v_write_rd = 1; |
break; |
|
case INST_OR32_NOP: // l.nop |
StatsNop++; |
|
// NOP with simulator instruction? |
if (v_imm != NOP_NOP) |
MonNop(v_imm); |
break; |
|
case INST_OR32_ORI: // l.ori |
v_reg_result = v_reg_ra | v_imm_uint32; |
v_write_rd = 1; |
break; |
|
case INST_OR32_RFE: // l.rfe |
// Restore PC & SR from EPC & ESR |
v_pc_next = r_epc; |
r_sr = r_esr; |
v_jmp = 1; |
|
// TODO: Handle branch delay & next instruction flush |
break; |
|
case INST_OR32_SHIFTI: |
switch (v_shift_op) |
{ |
case INST_OR32_SLLI: // l.slli |
v_reg_result = v_reg_ra << (r_opcode & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SRAI: // l.srai |
v_reg_result = (int)v_reg_ra >> (r_opcode & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SRLI: // l.srli |
v_reg_result = v_reg_ra >> (r_opcode & 0x3F); |
v_write_rd = 1; |
break; |
default: |
fprintf (stderr,"Bad shift instruction @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_SB: // l.sb |
mem_addr = v_reg_ra + (int)v_store_imm; |
mem_offset = mem_addr & 0x3; |
mem_rd = 0; |
switch (mem_offset) |
{ |
case 0x0: |
mem_data_out = (v_reg_rb & 0xFF) << 24; |
mem_wr = 8; |
break; |
case 0x1: |
mem_data_out = (v_reg_rb & 0xFF) << 16; |
mem_wr = 4; |
break; |
case 0x2: |
mem_data_out = (v_reg_rb & 0xFF) << 8; |
mem_wr = 2; |
break; |
case 0x3: |
mem_data_out = (v_reg_rb & 0xFF) << 0; |
mem_wr = 1; |
break; |
} |
StatsMem++; |
break; |
|
case INST_OR32_SFXX: |
case INST_OR32_SFXXI: |
switch (v_sfxx_op) |
{ |
case INST_OR32_SFEQ: // l.sfeq |
if (v_reg_ra == v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFEQI: // l.sfeqi |
if (v_reg_ra == v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGES: // l.sfges |
if ((int)v_reg_ra >= (int)v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGESI: // l.sfgesi |
if ((int)v_reg_ra >= (int)v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGEU: // l.sfgeu |
if (v_reg_ra >= v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGEUI: // l.sfgeui |
if (v_reg_ra >= v_imm_uint32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGTS: // l.sfgts |
if ((int)v_reg_ra > (int)v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGTSI: // l.sfgtsi |
if ((int)v_reg_ra > (int)v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGTU: // l.sfgtu |
if (v_reg_ra > v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGTUI: // l.sfgtui |
if (v_reg_ra > v_imm_uint32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLES: // l.sfles |
if ((int)v_reg_ra <= (int)v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLESI: // l.sflesi |
if ((int)v_reg_ra <= (int)v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLEU: // l.sfleu |
if (v_reg_ra <= v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLEUI: // l.sfleui |
if (v_reg_ra <= v_imm_uint32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLTS: // l.sflts |
if ((int)v_reg_ra < (int)v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLTSI: // l.sfltsi |
if ((int)v_reg_ra < (int)v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLTU: // l.sfltu |
if (v_reg_ra < v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLTUI: // l.sfltui |
if (v_reg_ra < v_imm_uint32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFNE: // l.sfne |
if (v_reg_ra != v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFNEI: // l.sfnei |
if (v_reg_ra != v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
default: |
fprintf (stderr,"Bad SFxx instruction @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_SH: // l.sh |
mem_addr = v_reg_ra + (int)v_store_imm; |
mem_offset = mem_addr & 0x3; |
mem_rd = 0; |
switch (mem_offset) |
{ |
case 0x0: |
mem_data_out = (v_reg_rb & 0xFFFF) << 16; |
mem_wr = 0xC; |
break; |
case 0x2: |
mem_data_out = (v_reg_rb & 0xFFFF) << 0; |
mem_wr = 0x3; |
break; |
default: |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
mem_wr = 0; |
break; |
} |
StatsMem++; |
break; |
|
case INST_OR32_SW: // l.sw |
mem_addr = v_reg_ra + (int)v_store_imm; |
mem_offset = mem_addr & 0x3; |
mem_rd = 0; |
mem_wr = 0xF; |
mem_data_out = v_reg_rb; |
if (mem_offset != 0) |
{ |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
mem_wr = 0; |
} |
StatsMem++; |
break; |
|
case INST_OR32_MISC: |
switch (r_opcode >> 24) |
{ |
case INST_OR32_SYS: // l.sys |
v_exception = 1; |
v_vector = VECTOR_SYSCALL; |
break; |
|
case INST_OR32_TRAP: // l.trap |
Break = 1; |
BreakValue = v_imm_uint32; |
v_exception = 1; |
v_vector = VECTOR_TRAP; |
break; |
} |
break; |
|
case INST_OR32_XORI: // l.xori |
v_reg_result = v_reg_ra ^ v_imm_int32; |
v_write_rd = 1; |
break; |
|
default: |
fprintf (stderr,"Fault @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
|
// Notify observer of fault |
if (Fault) |
MonFault(r_pc, r_opcode); |
|
// Handle branches (jumps relative to current PC) |
if (v_branch == 1) |
{ |
v_offset = v_target << 2; |
v_pc_next = r_pc + v_offset; |
StatsBranches++; |
} |
// If not branching, handle interrupts / exceptions |
else if (v_jmp == 0) |
{ |
// External interrupt (and not handling an exception)? |
if (PeripheralInt() == 1 && (r_sr & (1 << OR32_SR_IEE)) && v_exception == 0) |
{ |
v_exception = 1; |
v_vector = VECTOR_EXTINT; |
} |
|
// Interrupt / Exception |
if (v_exception == 1) |
{ |
// Save PC & SR |
r_epc = v_pc; |
r_esr = r_sr; |
|
v_pc = v_vector; |
v_pc_next = v_pc + 4; |
|
// Disable further interrupts |
r_sr = 0; |
|
StatsExceptions++; |
StatsBranches++; |
} |
} |
else |
StatsBranches++; |
|
// Update registers with variable values |
r_pc_last = r_pc; |
r_pc = v_pc; |
r_pc_next = v_pc_next; |
r_reg_result = v_reg_result; |
|
// No writeback required? |
if (v_write_rd == 0) |
{ |
// Target register is $0 which is read-only |
r_rd_wb = 0; |
} |
} |
//----------------------------------------------------------------- |
// WriteBack: Register write back stage |
//----------------------------------------------------------------- |
void OR32::WriteBack(void) |
{ |
TRegister v_inst; |
TRegister v_reg_result; |
|
mem_wr = 0; |
mem_rd = 0; |
|
v_inst = (r_opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; |
|
// Writeback read result |
switch(v_inst) |
{ |
case INST_OR32_LBS: // l.lbs |
switch (mem_offset) |
{ |
case 0x0: |
v_reg_result = (int)((signed char)(mem_data_in >> 24)); |
break; |
case 0x1: |
v_reg_result = (int)((signed char)(mem_data_in >> 16)); |
break; |
case 0x2: |
v_reg_result = (int)((signed char)(mem_data_in >> 8)); |
break; |
case 0x3: |
v_reg_result = (int)((signed char)(mem_data_in >> 0)); |
break; |
} |
break; |
|
case INST_OR32_LBZ: // l.lbz |
switch (mem_offset) |
{ |
case 0x0: |
v_reg_result = ((unsigned char)(mem_data_in >> 24)); |
break; |
case 0x1: |
v_reg_result = ((unsigned char)(mem_data_in >> 16)); |
break; |
case 0x2: |
v_reg_result = ((unsigned char)(mem_data_in >> 8)); |
break; |
case 0x3: |
v_reg_result = ((unsigned char)(mem_data_in >> 0)); |
break; |
} |
break; |
|
case INST_OR32_LHS: // l.lhs |
switch (mem_offset) |
{ |
case 0x0: |
v_reg_result = (int)((signed short)(mem_data_in >> 16)); |
break; |
case 0x2: |
v_reg_result = (int)((signed short)(mem_data_in >> 0)); |
break; |
default: |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
break; |
} |
break; |
|
case INST_OR32_LHZ: // l.lhz |
switch (mem_offset) |
{ |
case 0x0: |
v_reg_result = ((unsigned short)(mem_data_in >> 16)); |
break; |
case 0x2: |
v_reg_result = ((unsigned short)(mem_data_in >> 0)); |
break; |
default: |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
break; |
} |
break; |
|
case INST_OR32_LWZ: // l.lwz |
case INST_OR32_LWS: // l.lws |
v_reg_result = mem_data_in; |
if (mem_offset != 0) |
{ |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
} |
break; |
|
default: |
v_reg_result = r_reg_result; |
break; |
} |
|
// Decode instruction to full text? |
if (TRACE_ENABLED(LOG_OR1K)) |
or32_instruction_dump(r_pc_last, r_opcode, r_gpr, r_rd_wb, v_reg_result, r_sr); |
|
// Register writeback required? |
r_reg_rd_out = v_reg_result; |
if (r_rd_wb != 0) |
r_writeback = 1; |
|
// Fetch next instruction |
mem_addr = r_pc; |
mem_data_out = 0; |
mem_rd = 1; |
} |
//----------------------------------------------------------------- |
// Clock: Execute a single instruction (including load / store) |
//----------------------------------------------------------------- |
bool OR32::Clock(void) |
{ |
bool writeback = false; |
|
switch (Cycle) |
{ |
// Instruction decode |
case 0: |
Cycle++; |
Decode(); |
break; |
|
// Execute |
case 1: |
Cycle++; |
Execute(); |
break; |
|
// Writeback & fetch next |
case 2: |
Cycle = 0; |
WriteBack(); |
writeback = true; |
break; |
} |
|
// Notify observers if memory write will occur |
if (mem_wr) |
{ |
DPRINTF(LOG_MEM, ("MEM: Write Addr %x Value %x Mask %x\n", mem_addr, mem_data_out, mem_wr)); |
MonDataStore(mem_addr, mem_wr, mem_data_out); |
} |
|
// Internal Memory? |
if (mem_addr >= MemBase && mem_addr < (MemBase + MemSize)) |
{ |
TAddress wordAddress = (mem_addr - MemBase) / 4; |
|
// Write |
switch (mem_wr) |
{ |
case 0xF: |
Mem[wordAddress] = mem_data_out; |
break; |
case 0x3: |
mem_data_out &= 0x0000FFFF; |
Mem[wordAddress] &=~ 0x0000FFFF; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0xC: |
mem_data_out &= 0xFFFF0000; |
Mem[wordAddress] &=~ 0xFFFF0000; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0x1: |
mem_data_out &= 0x000000FF; |
Mem[wordAddress] &=~ 0x000000FF; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0x2: |
mem_data_out &= 0x0000FF00; |
Mem[wordAddress] &=~ 0x0000FF00; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0x4: |
mem_data_out &= 0x00FF0000; |
Mem[wordAddress] &=~ 0x00FF0000; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0x8: |
mem_data_out &= 0xFF000000; |
Mem[wordAddress] &=~ 0xFF000000; |
Mem[wordAddress] |= mem_data_out; |
break; |
} |
|
// Read |
mem_data_in = Mem[wordAddress]; |
} |
// External / Peripheral memory |
else |
{ |
mem_data_in = PeripheralAccess(mem_addr, mem_data_out, mem_wr, mem_rd); |
} |
|
// Notify observers if memory read has occurred |
if (mem_rd) |
{ |
DPRINTF(LOG_MEM, ("MEM: Read Addr %x Value %x\n", mem_addr, mem_data_in)); |
MonDataLoad(mem_addr, 0xF, mem_data_in); |
} |
|
// Clock peripherals |
PeripheralClock(); |
|
// Writeback (if target is not R0) |
if (r_writeback && r_rd_wb != REG_0_ZERO) |
{ |
r_gpr[r_rd_wb] = r_reg_rd_out; |
r_writeback = 0; |
} |
|
// If write-back stage just completed, show register state... |
if (writeback && TRACE_ENABLED(LOG_REGISTERS)) |
{ |
// Register trace |
int i; |
for (i=0;i<REGISTERS;i+=4) |
{ |
printf(" %d: ", i); |
printf(" %08x %08x %08x %08x\n", r_gpr[i+0], r_gpr[i+1], r_gpr[i+2], r_gpr[i+3]); |
} |
|
printf(" SR = 0x%08x, EPC = 0x%08x, ESR = 0x%08x, SR_F=%d\n\n", r_sr, r_epc, r_esr, (r_sr & OR32_SR_F_BIT) ? 1 : 0); |
} |
|
// Reload register contents |
r_reg_ra = r_gpr[r_ra]; |
r_reg_rb = r_gpr[r_rb]; |
|
return writeback; |
} |
//----------------------------------------------------------------- |
// Step: Step through one instruction |
//----------------------------------------------------------------- |
bool OR32::Step(void) |
{ |
while (!Clock()) |
; |
return true; |
} |
//----------------------------------------------------------------- |
// MonNop: Default NOP functions |
//----------------------------------------------------------------- |
void OR32::MonNop(TRegister imm) |
{ |
switch (imm) |
{ |
// Exit |
case NOP_EXIT: |
exit(r_gpr[NOP_DATA_REG]); |
break; |
// Report value |
case NOP_REPORT: |
if (Trace) |
fprintf(stderr, "report(0x%x)\n", r_gpr[NOP_DATA_REG]); |
else |
printf("report(0x%x)\n", r_gpr[NOP_DATA_REG]); |
break; |
// putc() |
case NOP_PUTC: |
if (Trace) |
fprintf(stderr, "%c", r_gpr[NOP_DATA_REG]); |
else |
printf("%c", r_gpr[NOP_DATA_REG]); |
break; |
// Trace Control |
case NOP_TRACE_ON: |
Trace = r_gpr[NOP_DATA_REG]; |
break; |
case NOP_TRACE_OFF: |
Trace = 0; |
break; |
} |
} |
//----------------------------------------------------------------- |
// DumpStats: Show execution stats |
//----------------------------------------------------------------- |
void OR32::DumpStats(void) |
{ |
printf("Runtime Stats:\n"); |
printf("- Total Instructions %d\n", StatsInstructions); |
printf("- Memory Operations %d (%d%%)\n", StatsMem, (StatsMem * 100) / StatsInstructions); |
printf("- NOPS %d (%d%%)\n", StatsNop, (StatsNop * 100) / StatsInstructions); |
printf("- Branches Operations %d (%d%%)\n", StatsBranches, (StatsBranches * 100) / StatsInstructions); |
printf("- Exceptions %d (%d%%)\n", StatsExceptions, (StatsExceptions * 100) / StatsInstructions); |
|
StatsMem = 0; |
StatsInstructions = 0; |
StatsNop = 0; |
StatsBranches = 0; |
StatsExceptions = 0; |
} |
#define TRACE_ENABLED(l) (Trace & l) |
|
//----------------------------------------------------------------- |
// Constructor |
//----------------------------------------------------------------- |
OR32::OR32(unsigned int baseAddr, unsigned int len) |
{ |
MemBase = baseAddr; |
MemSize = len; |
Mem = new TMemory[len/4]; |
Trace = 0; |
|
assert(Mem); |
|
Reset(); |
} |
//----------------------------------------------------------------- |
// Deconstructor |
//----------------------------------------------------------------- |
OR32::~OR32() |
{ |
if (Mem) |
delete Mem; |
Mem = NULL; |
} |
//----------------------------------------------------------------- |
// Reset: Reset CPU state |
//----------------------------------------------------------------- |
void OR32::Reset(TRegister start_addr /*= VECTOR_RESET*/) |
{ |
int i; |
|
r_pc = start_addr; |
r_pc_next = start_addr; |
r_pc_last = start_addr; |
r_sr = 0; |
r_epc = 0; |
r_esr = 0; |
|
for (i=0;i<REGISTERS;i++) |
r_gpr[i] = 0; |
|
r_reg_ra = 0; |
r_reg_rb = 0; |
r_reg_result = 0; |
r_rd_wb = 0; |
r_ra = 0; |
r_rb = 0; |
|
mem_addr = 0; |
mem_offset = 0; |
mem_wr = 0; |
mem_rd = 0; |
|
Fault = 0; |
Break = 0; |
BreakValue = 0; |
Trace = 0; |
Cycle = 2; |
|
// Clear stats |
StatsMem = 0; |
StatsInstructions = 0; |
StatsNop = 0; |
StatsBranches = 0; |
StatsExceptions = 0; |
|
PeripheralReset(); |
} |
//----------------------------------------------------------------- |
// Load: Load program code into startAddr offset |
//----------------------------------------------------------------- |
bool OR32::Load(unsigned int startAddr, unsigned char *data, int len) |
{ |
int i; |
|
// Program fits in memory? |
if ((startAddr >= MemBase) && (startAddr + len) <= (MemBase + MemSize)) |
{ |
// Zero memory first |
memset(Mem, 0, sizeof(Mem)); |
|
// Make relative to start of memory |
startAddr -= MemBase; |
|
// Convert to word address |
startAddr /= 4; |
|
for (i=0;i<len / (int)sizeof(Mem[0]); i++) |
{ |
Mem[startAddr+i] = *data++; |
Mem[startAddr+i] <<= 8; |
Mem[startAddr+i]|= *data++; |
Mem[startAddr+i] <<= 8; |
Mem[startAddr+i]|= *data++; |
Mem[startAddr+i] <<= 8; |
Mem[startAddr+i]|= *data++; |
} |
|
return true; |
} |
else |
return false; |
} |
//----------------------------------------------------------------- |
// WriteMem: Write a block of memory |
//----------------------------------------------------------------- |
bool OR32::WriteMem(TAddress addr, unsigned char *data, int len) |
{ |
int i; |
TAddress word; |
|
if (addr >= MemBase && addr < (MemBase + MemSize)) |
{ |
word = (addr - MemBase) / 4; |
for (i=0;i<len / (int)sizeof(Mem[0]); i++) |
{ |
Mem[word + i] = *data++; |
Mem[word + i] <<= 8; |
Mem[word + i]|= *data++; |
Mem[word + i] <<= 8; |
Mem[word + i]|= *data++; |
Mem[word + i] <<= 8; |
Mem[word + i]|= *data++; |
} |
|
return true; |
} |
else |
return false; |
} |
//----------------------------------------------------------------- |
// ReadMem: Read a block of memory |
//----------------------------------------------------------------- |
bool OR32::ReadMem(TAddress addr, unsigned char *data, int len) |
{ |
int i; |
TAddress word; |
|
if (addr >= MemBase && addr < (MemBase + MemSize)) |
{ |
word = (addr - MemBase) / 4; |
for (i=0;i<len / (int)sizeof(Mem[0]); i++) |
{ |
*data++ = Mem[word + i] >> 24; |
*data++ = Mem[word + i] >> 16; |
*data++ = Mem[word + i] >> 8; |
*data++ = Mem[word + i] >> 0; |
} |
|
return true; |
} |
else |
return false; |
} |
//----------------------------------------------------------------- |
// Decode: Instruction decode stage |
//----------------------------------------------------------------- |
void OR32::Decode(void) |
{ |
// Instruction opcode read complete |
mem_wr = 0; |
mem_rd = 0; |
|
// Fetch instruction from 'memory bus' |
r_opcode = mem_data_in; |
mem_data_in = 0; |
|
// Decode opcode in-order to perform register reads |
r_ra = (r_opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; |
r_rb = (r_opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; |
r_rd = (r_opcode >> OR32_REG_D_SHIFT) & OR32_REG_D_MASK; |
} |
//----------------------------------------------------------------- |
// Execute: Instruction execution stage |
//----------------------------------------------------------------- |
void OR32::Execute(void) |
{ |
TRegister v_ra = 0; |
TRegister v_rb = 0; |
TRegister v_rd = 0; |
TRegister v_inst = 0; |
TRegister v_op = 0; |
TRegister v_target = 0; |
TRegister v_pc = 0; |
TRegister v_pc_next = 0; |
TRegister v_imm = 0; |
TRegister v_imm_uint32 = 0; |
TRegister v_imm_int32 = 0; |
TRegister v_offset = 0; |
TRegister v_reg_ra = 0; |
TRegister v_reg_rb = 0; |
TRegister v_reg_result = 0; |
TRegister v_store_imm = 0; |
int v_branch = 0; |
int v_jmp = 0; |
int v_exception = 0; |
TRegister v_vector = 0; |
int v_write_rd = 0; |
|
TRegister v_alu_op = 0; |
TRegister v_shift_op = 0; |
TRegister v_sfxx_op = 0; |
|
// Notify observers of instruction execution |
MonInstructionExecute(r_pc, r_opcode); |
|
StatsInstructions++; |
|
DPRINTF(LOG_INST, ("%08x: %08x\n", r_pc, r_opcode)); |
|
// Decode opcode fields |
v_inst = (r_opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; |
v_rd = (r_opcode >> OR32_REG_D_SHIFT) & OR32_REG_D_MASK; |
v_ra = (r_opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; |
v_rb = (r_opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; |
v_imm = (r_opcode >> OR32_IMM16_SHIFT) & OR32_IMM16_MASK; |
v_target = (r_opcode >> OR32_ADDR_SHIFT) & OR32_ADDR_MASK; |
v_sfxx_op = (r_opcode >> OR32_SFXXX_OP_SHIFT) & OR32_SFXXX_OP_MASK; |
v_alu_op = (r_opcode >> OR32_ALU_OP_L_SHIFT) & OR32_ALU_OP_L_MASK; |
v_alu_op |= (r_opcode >> OR32_ALU_OP_H_SHIFT) & OR32_ALU_OP_H_MASK; |
v_shift_op = (r_opcode >> OR32_SHIFT_OP_SHIFT) & OR32_SHIFT_OP_MASK; |
v_store_imm = (r_opcode >> OR32_STORE_IMM_L_SHIFT) & OR32_STORE_IMM_L_MASK; |
v_store_imm|= (r_opcode >> OR32_STORE_IMM_H_SHIFT) & OR32_STORE_IMM_H_MASK; |
|
// Sign extend store immediate |
v_store_imm = (unsigned int)(signed short)v_store_imm; |
|
// Sign extend target immediate |
if (v_target & (1 << OR32_ADDR_SIGN_SHIFT)) |
v_target |= ~OR32_ADDR_MASK; |
|
// Signed & unsigned imm -> 32-bits |
v_imm_int32 = (unsigned int)(signed short)v_imm; |
v_imm_uint32 = v_imm; |
|
// Load register[ra] |
v_reg_ra = r_reg_ra; |
|
// Load register[rb] |
v_reg_rb = r_reg_rb; |
|
// Zero result |
v_reg_result = 0; |
|
// Update PC to next value |
v_pc = r_pc_next; |
|
// Increment next PC value (might be overriden by branch) |
v_pc_next = r_pc_next + 4; |
|
// Default target is r_rd |
r_rd_wb = r_rd; |
|
// Execute instruction |
switch(v_inst) |
{ |
case INST_OR32_ALU: |
switch (v_alu_op) |
{ |
case INST_OR32_ADD: // l.add |
v_reg_result = v_reg_ra + v_reg_rb; |
v_write_rd = 1; |
break; |
case INST_OR32_AND: // l.and |
v_reg_result = v_reg_ra & v_reg_rb; |
v_write_rd = 1; |
break; |
case INST_OR32_OR: // l.or |
v_reg_result = v_reg_ra | v_reg_rb; |
v_write_rd = 1; |
break; |
case INST_OR32_SLL: // l.sll |
v_reg_result = v_reg_ra << (v_reg_rb & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SRA: // l.sra |
v_reg_result = (int)v_reg_ra >> (v_reg_rb & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SRL: // l.srl |
v_reg_result = v_reg_ra >> (v_reg_rb & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SUB: // l.sub |
v_reg_result = v_reg_ra + ~v_reg_rb + 1; |
v_write_rd = 1; |
break; |
case INST_OR32_XOR: // l.xor |
v_reg_result = v_reg_ra ^ v_reg_rb; |
v_write_rd = 1; |
break; |
default: |
fprintf (stderr,"Bad ALU instruction @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_ADDI: // l.addi |
v_reg_result = v_reg_ra + v_imm_int32; |
v_write_rd = 1; |
break; |
|
case INST_OR32_ANDI: // l.andi |
v_reg_result = v_reg_ra & v_imm_uint32; |
v_write_rd = 1; |
break; |
|
case INST_OR32_BF: // l.bf |
if (r_sr & OR32_SR_F_BIT) |
v_branch = 1; |
break; |
|
case INST_OR32_BNF: // l.bnf |
if (!(r_sr & OR32_SR_F_BIT)) |
v_branch = 1; |
break; |
|
case INST_OR32_J: // l.j |
v_branch = 1; |
break; |
|
case INST_OR32_JAL: // l.jal |
// Write next instruction address to LR |
v_reg_result = v_pc_next; |
r_rd_wb = REG_9_LR; |
v_write_rd = 1; |
|
v_branch = 1; |
break; |
|
case INST_OR32_JALR: // l.jalr |
// Write next instruction address to LR |
v_reg_result = v_pc_next; |
r_rd_wb = REG_9_LR; |
v_write_rd = 1; |
|
v_pc_next = v_reg_rb; |
v_jmp = 1; |
break; |
|
case INST_OR32_JR: // l.jr |
v_pc_next = v_reg_rb; |
v_jmp = 1; |
break; |
|
case INST_OR32_LBS: // l.lbs |
case INST_OR32_LHS: // l.lhs |
case INST_OR32_LWS: // l.lws |
case INST_OR32_LBZ: // l.lbz |
case INST_OR32_LHZ: // l.lhz |
case INST_OR32_LWZ: // l.lwz |
mem_addr = v_reg_ra + (int)v_imm_int32; |
mem_offset = mem_addr & 0x3; |
mem_wr = 0; |
mem_rd = 1; |
mem_data_out = 0; |
v_write_rd = 1; |
StatsMem++; |
break; |
|
case INST_OR32_MFSPR: // l.mfspr |
// Move from SPR register |
switch ((v_reg_ra | (v_imm_uint32 & OR32_MFSPR_IMM_MASK))) |
{ |
// VR - Version register |
case SPR_REG_VR: |
v_reg_result = SPR_VERSION_CURRENT; |
v_write_rd = 1; |
break; |
// SR - Supervision register |
case SPR_REG_SR: |
v_reg_result = r_sr; |
v_write_rd = 1; |
break; |
// EPCR - EPC Exception saved PC |
case SPR_REG_EPCR: |
v_reg_result = r_epc; |
v_write_rd = 1; |
break; |
// ESR - Exception saved SR |
case SPR_REG_ESR: |
v_reg_result = r_esr; |
v_write_rd = 1; |
break; |
default: |
fprintf (stderr,"Unsupported SPR register (0x%x) access @ PC %x\n", (v_reg_ra | v_imm_uint32), r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_MTSPR: // l.mtspr |
// Move to SPR register |
switch ((v_reg_ra | (v_imm_uint32 & OR32_MTSPR_IMM_MASK))) |
{ |
// SR - Supervision register |
case SPR_REG_SR: |
r_sr = v_reg_rb; |
break; |
// EPCR - EPC Exception saved PC |
case SPR_REG_EPCR: |
r_epc = v_reg_rb; |
break; |
// ESR - Exception saved SR |
case SPR_REG_ESR: |
r_esr = v_reg_rb; |
break; |
default: |
fprintf (stderr,"Unsupported SPR register (0x%x) access @ PC %x\n", (v_reg_ra | v_imm_uint32), r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_MOVHI: // l.movhi |
v_reg_result = v_imm_uint32 << 16; |
v_write_rd = 1; |
break; |
|
case INST_OR32_NOP: // l.nop |
StatsNop++; |
|
// NOP with simulator instruction? |
if (v_imm != NOP_NOP) |
MonNop(v_imm); |
break; |
|
case INST_OR32_ORI: // l.ori |
v_reg_result = v_reg_ra | v_imm_uint32; |
v_write_rd = 1; |
break; |
|
case INST_OR32_RFE: // l.rfe |
// Restore PC & SR from EPC & ESR |
v_pc_next = r_epc; |
r_sr = r_esr; |
v_jmp = 1; |
|
// TODO: Handle branch delay & next instruction flush |
break; |
|
case INST_OR32_SHIFTI: |
switch (v_shift_op) |
{ |
case INST_OR32_SLLI: // l.slli |
v_reg_result = v_reg_ra << (r_opcode & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SRAI: // l.srai |
v_reg_result = (int)v_reg_ra >> (r_opcode & 0x3F); |
v_write_rd = 1; |
break; |
case INST_OR32_SRLI: // l.srli |
v_reg_result = v_reg_ra >> (r_opcode & 0x3F); |
v_write_rd = 1; |
break; |
default: |
fprintf (stderr,"Bad shift instruction @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_SB: // l.sb |
mem_addr = v_reg_ra + (int)v_store_imm; |
mem_offset = mem_addr & 0x3; |
mem_rd = 0; |
switch (mem_offset) |
{ |
case 0x0: |
mem_data_out = (v_reg_rb & 0xFF) << 24; |
mem_wr = 8; |
break; |
case 0x1: |
mem_data_out = (v_reg_rb & 0xFF) << 16; |
mem_wr = 4; |
break; |
case 0x2: |
mem_data_out = (v_reg_rb & 0xFF) << 8; |
mem_wr = 2; |
break; |
case 0x3: |
mem_data_out = (v_reg_rb & 0xFF) << 0; |
mem_wr = 1; |
break; |
} |
StatsMem++; |
break; |
|
case INST_OR32_SFXX: |
case INST_OR32_SFXXI: |
switch (v_sfxx_op) |
{ |
case INST_OR32_SFEQ: // l.sfeq |
if (v_reg_ra == v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFEQI: // l.sfeqi |
if (v_reg_ra == v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGES: // l.sfges |
if ((int)v_reg_ra >= (int)v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGESI: // l.sfgesi |
if ((int)v_reg_ra >= (int)v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGEU: // l.sfgeu |
if (v_reg_ra >= v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGEUI: // l.sfgeui |
if (v_reg_ra >= v_imm_uint32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGTS: // l.sfgts |
if ((int)v_reg_ra > (int)v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGTSI: // l.sfgtsi |
if ((int)v_reg_ra > (int)v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGTU: // l.sfgtu |
if (v_reg_ra > v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFGTUI: // l.sfgtui |
if (v_reg_ra > v_imm_uint32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLES: // l.sfles |
if ((int)v_reg_ra <= (int)v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLESI: // l.sflesi |
if ((int)v_reg_ra <= (int)v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLEU: // l.sfleu |
if (v_reg_ra <= v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLEUI: // l.sfleui |
if (v_reg_ra <= v_imm_uint32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLTS: // l.sflts |
if ((int)v_reg_ra < (int)v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLTSI: // l.sfltsi |
if ((int)v_reg_ra < (int)v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLTU: // l.sfltu |
if (v_reg_ra < v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFLTUI: // l.sfltui |
if (v_reg_ra < v_imm_uint32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFNE: // l.sfne |
if (v_reg_ra != v_reg_rb) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
case INST_OR32_SFNEI: // l.sfnei |
if (v_reg_ra != v_imm_int32) |
r_sr |= OR32_SR_F_BIT; |
else |
r_sr &=~OR32_SR_F_BIT; |
break; |
default: |
fprintf (stderr,"Bad SFxx instruction @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_SH: // l.sh |
mem_addr = v_reg_ra + (int)v_store_imm; |
mem_offset = mem_addr & 0x3; |
mem_rd = 0; |
switch (mem_offset) |
{ |
case 0x0: |
mem_data_out = (v_reg_rb & 0xFFFF) << 16; |
mem_wr = 0xC; |
break; |
case 0x2: |
mem_data_out = (v_reg_rb & 0xFFFF) << 0; |
mem_wr = 0x3; |
break; |
default: |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
mem_wr = 0; |
break; |
} |
StatsMem++; |
break; |
|
case INST_OR32_SW: // l.sw |
mem_addr = v_reg_ra + (int)v_store_imm; |
mem_offset = mem_addr & 0x3; |
mem_rd = 0; |
mem_wr = 0xF; |
mem_data_out = v_reg_rb; |
if (mem_offset != 0) |
{ |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
mem_wr = 0; |
} |
StatsMem++; |
break; |
|
case INST_OR32_MISC: |
switch (r_opcode >> 24) |
{ |
case INST_OR32_SYS: // l.sys |
v_exception = 1; |
v_vector = VECTOR_SYSCALL; |
break; |
|
case INST_OR32_TRAP: // l.trap |
Break = 1; |
BreakValue = v_imm_uint32; |
v_exception = 1; |
v_vector = VECTOR_TRAP; |
break; |
} |
break; |
|
case INST_OR32_XORI: // l.xori |
v_reg_result = v_reg_ra ^ v_imm_int32; |
v_write_rd = 1; |
break; |
|
default: |
fprintf (stderr,"Fault @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = VECTOR_ILLEGAL_INST; |
break; |
} |
|
// Notify observer of fault |
if (Fault) |
MonFault(r_pc, r_opcode); |
|
// Handle branches (jumps relative to current PC) |
if (v_branch == 1) |
{ |
v_offset = v_target << 2; |
v_pc_next = r_pc + v_offset; |
StatsBranches++; |
} |
// If not branching, handle interrupts / exceptions |
else if (v_jmp == 0) |
{ |
// Check for external interrupt |
if ((v_exception == 0) && (r_sr & (1 << OR32_SR_IEE))) |
{ |
// External interrupt (and not handling an exception)? |
if (PeripheralInterrupt()) |
{ |
v_exception = 1; |
v_vector = VECTOR_EXTINT; |
} |
} |
|
// Interrupt / Exception |
if (v_exception == 1) |
{ |
// Save PC & SR |
r_epc = v_pc; |
r_esr = r_sr; |
|
v_pc = v_vector; |
v_pc_next = v_pc + 4; |
|
// Disable further interrupts |
r_sr = 0; |
|
StatsExceptions++; |
StatsBranches++; |
} |
} |
else |
StatsBranches++; |
|
// Update registers with variable values |
r_pc_last = r_pc; |
r_pc = v_pc; |
r_pc_next = v_pc_next; |
r_reg_result = v_reg_result; |
|
// No writeback required? |
if (v_write_rd == 0) |
{ |
// Target register is $0 which is read-only |
r_rd_wb = 0; |
} |
} |
//----------------------------------------------------------------- |
// WriteBack: Register write back stage |
//----------------------------------------------------------------- |
void OR32::WriteBack(void) |
{ |
TRegister v_inst; |
TRegister v_reg_result; |
|
mem_wr = 0; |
mem_rd = 0; |
|
v_inst = (r_opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; |
|
// Writeback read result |
switch(v_inst) |
{ |
case INST_OR32_LBS: // l.lbs |
switch (mem_offset) |
{ |
case 0x0: |
v_reg_result = (int)((signed char)(mem_data_in >> 24)); |
break; |
case 0x1: |
v_reg_result = (int)((signed char)(mem_data_in >> 16)); |
break; |
case 0x2: |
v_reg_result = (int)((signed char)(mem_data_in >> 8)); |
break; |
case 0x3: |
v_reg_result = (int)((signed char)(mem_data_in >> 0)); |
break; |
} |
break; |
|
case INST_OR32_LBZ: // l.lbz |
switch (mem_offset) |
{ |
case 0x0: |
v_reg_result = ((unsigned char)(mem_data_in >> 24)); |
break; |
case 0x1: |
v_reg_result = ((unsigned char)(mem_data_in >> 16)); |
break; |
case 0x2: |
v_reg_result = ((unsigned char)(mem_data_in >> 8)); |
break; |
case 0x3: |
v_reg_result = ((unsigned char)(mem_data_in >> 0)); |
break; |
} |
break; |
|
case INST_OR32_LHS: // l.lhs |
switch (mem_offset) |
{ |
case 0x0: |
v_reg_result = (int)((signed short)(mem_data_in >> 16)); |
break; |
case 0x2: |
v_reg_result = (int)((signed short)(mem_data_in >> 0)); |
break; |
default: |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
break; |
} |
break; |
|
case INST_OR32_LHZ: // l.lhz |
switch (mem_offset) |
{ |
case 0x0: |
v_reg_result = ((unsigned short)(mem_data_in >> 16)); |
break; |
case 0x2: |
v_reg_result = ((unsigned short)(mem_data_in >> 0)); |
break; |
default: |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
break; |
} |
break; |
|
case INST_OR32_LWZ: // l.lwz |
case INST_OR32_LWS: // l.lws |
v_reg_result = mem_data_in; |
if (mem_offset != 0) |
{ |
fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); |
Fault = 1; |
} |
break; |
|
default: |
v_reg_result = r_reg_result; |
break; |
} |
|
// Decode instruction to full text? |
if (TRACE_ENABLED(LOG_OR1K)) |
or32_instruction_dump(r_pc_last, r_opcode, r_gpr, r_rd_wb, v_reg_result, r_sr); |
|
// Register writeback required? |
r_reg_rd_out = v_reg_result; |
if (r_rd_wb != 0) |
r_writeback = 1; |
|
// Fetch next instruction |
mem_addr = r_pc; |
mem_data_out = 0; |
mem_rd = 1; |
} |
//----------------------------------------------------------------- |
// Clock: Execute a single instruction (including load / store) |
//----------------------------------------------------------------- |
bool OR32::Clock(void) |
{ |
bool writeback = false; |
|
switch (Cycle) |
{ |
// Instruction decode |
case 0: |
Cycle++; |
Decode(); |
break; |
|
// Execute |
case 1: |
Cycle++; |
Execute(); |
break; |
|
// Writeback & fetch next |
case 2: |
Cycle = 0; |
WriteBack(); |
writeback = true; |
break; |
} |
|
// Notify observers if memory write will occur |
if (mem_wr) |
{ |
DPRINTF(LOG_MEM, ("MEM: Write Addr %x Value %x Mask %x\n", mem_addr, mem_data_out, mem_wr)); |
MonDataStore(mem_addr, mem_wr, mem_data_out); |
} |
|
// Internal Memory? |
if (mem_addr >= MemBase && mem_addr < (MemBase + MemSize)) |
{ |
TAddress wordAddress = (mem_addr - MemBase) / 4; |
|
// Write |
switch (mem_wr) |
{ |
case 0xF: |
Mem[wordAddress] = mem_data_out; |
break; |
case 0x3: |
mem_data_out &= 0x0000FFFF; |
Mem[wordAddress] &=~ 0x0000FFFF; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0xC: |
mem_data_out &= 0xFFFF0000; |
Mem[wordAddress] &=~ 0xFFFF0000; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0x1: |
mem_data_out &= 0x000000FF; |
Mem[wordAddress] &=~ 0x000000FF; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0x2: |
mem_data_out &= 0x0000FF00; |
Mem[wordAddress] &=~ 0x0000FF00; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0x4: |
mem_data_out &= 0x00FF0000; |
Mem[wordAddress] &=~ 0x00FF0000; |
Mem[wordAddress] |= mem_data_out; |
break; |
case 0x8: |
mem_data_out &= 0xFF000000; |
Mem[wordAddress] &=~ 0xFF000000; |
Mem[wordAddress] |= mem_data_out; |
break; |
} |
|
// Read |
mem_data_in = Mem[wordAddress]; |
} |
// External / Peripheral memory |
else |
{ |
mem_data_in = PeripheralAccess(mem_addr, mem_data_out, mem_wr, mem_rd); |
} |
|
// Notify observers if memory read has occurred |
if (mem_rd) |
{ |
DPRINTF(LOG_MEM, ("MEM: Read Addr %x Value %x\n", mem_addr, mem_data_in)); |
MonDataLoad(mem_addr, 0xF, mem_data_in); |
} |
|
// Clock peripherals |
PeripheralClock(); |
|
// Writeback (if target is not R0) |
if (r_writeback && r_rd_wb != REG_0_ZERO) |
{ |
r_gpr[r_rd_wb] = r_reg_rd_out; |
r_writeback = 0; |
} |
|
// If write-back stage just completed, show register state... |
if (writeback && TRACE_ENABLED(LOG_REGISTERS)) |
{ |
// Register trace |
int i; |
for (i=0;i<REGISTERS;i+=4) |
{ |
printf(" %d: ", i); |
printf(" %08x %08x %08x %08x\n", r_gpr[i+0], r_gpr[i+1], r_gpr[i+2], r_gpr[i+3]); |
} |
|
printf(" SR = 0x%08x, EPC = 0x%08x, ESR = 0x%08x, SR_F=%d\n\n", r_sr, r_epc, r_esr, (r_sr & OR32_SR_F_BIT) ? 1 : 0); |
} |
|
// Reload register contents |
r_reg_ra = r_gpr[r_ra]; |
r_reg_rb = r_gpr[r_rb]; |
|
return writeback; |
} |
//----------------------------------------------------------------- |
// Step: Step through one instruction |
//----------------------------------------------------------------- |
bool OR32::Step(void) |
{ |
while (!Clock()) |
; |
return true; |
} |
//----------------------------------------------------------------- |
// MonNop: Default NOP functions |
//----------------------------------------------------------------- |
void OR32::MonNop(TRegister imm) |
{ |
switch (imm) |
{ |
// Exit |
case NOP_EXIT: |
exit(r_gpr[NOP_DATA_REG]); |
break; |
// Report value |
case NOP_REPORT: |
if (Trace) |
fprintf(stderr, "report(0x%x)\n", r_gpr[NOP_DATA_REG]); |
else |
printf("report(0x%x)\n", r_gpr[NOP_DATA_REG]); |
break; |
// putc() |
case NOP_PUTC: |
if (Trace) |
fprintf(stderr, "%c", r_gpr[NOP_DATA_REG]); |
else |
printf("%c", r_gpr[NOP_DATA_REG]); |
break; |
// Trace Control |
case NOP_TRACE_ON: |
Trace = r_gpr[NOP_DATA_REG]; |
break; |
case NOP_TRACE_OFF: |
Trace = 0; |
break; |
} |
} |
//----------------------------------------------------------------- |
// DumpStats: Show execution stats |
//----------------------------------------------------------------- |
void OR32::DumpStats(void) |
{ |
printf("Runtime Stats:\n"); |
printf("- Total Instructions %d\n", StatsInstructions); |
printf("- Memory Operations %d (%d%%)\n", StatsMem, (StatsMem * 100) / StatsInstructions); |
printf("- NOPS %d (%d%%)\n", StatsNop, (StatsNop * 100) / StatsInstructions); |
printf("- Branches Operations %d (%d%%)\n", StatsBranches, (StatsBranches * 100) / StatsInstructions); |
printf("- Exceptions %d (%d%%)\n", StatsExceptions, (StatsExceptions * 100) / StatsInstructions); |
|
StatsMem = 0; |
StatsInstructions = 0; |
StatsNop = 0; |
StatsBranches = 0; |
StatsExceptions = 0; |
} |
/or32-sim/or32_isa.h
197,22 → 197,23
// OR32 NOP Control Codes |
//-------------------------------------------------------------------- |
#define NOP_DATA_REG REG_3 |
#define NOP_NOP 0x0000 |
#define NOP_EXIT 0x0001 |
#define NOP_REPORT 0x0002 |
#define NOP_PUTC 0x0004 |
#define NOP_TRACE_ON 0x0008 |
#define NOP_TRACE_OFF 0x0009 |
#define NOP_NOP 0x0000 |
#define NOP_EXIT 0x0001 |
#define NOP_REPORT 0x0002 |
#define NOP_PUTC 0x0004 |
#define NOP_TRACE_ON 0x0008 |
#define NOP_TRACE_OFF 0x0009 |
|
//-------------------------------------------------------------------- |
// OR32 Vectors |
// NOTE: These differ from the real OR32 vectors for space reasons |
//-------------------------------------------------------------------- |
#define VECTOR_RESET 0x100 |
#define VECTOR_TICK_TIMER 0x500 |
#define VECTOR_ILLEGAL_INST 0x700 |
#define VECTOR_EXTINT 0x800 |
#define VECTOR_SYSCALL 0xC00 |
#define VECTOR_TRAP 0xE00 |
#define VECTOR_ILLEGAL_INST 0x200 |
#define VECTOR_EXTINT 0x300 |
#define VECTOR_SYSCALL 0x400 |
#define VECTOR_BUS_ERROR 0x500 |
#define VECTOR_TRAP 0x600 |
|
#endif |
|
/or32-sim/or32_inst_dump.cpp
1,406 → 1,406
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
// AltOR32 OpenRisc Simulator |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 OpenRisc Simulator. |
// |
// AltOR32 OpenRisc Simulator 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 2 of the License, or |
// (at your option) any later version. |
// |
// AltOR32 OpenRisc Simulator 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 AltOR32 OpenRisc Simulator; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <assert.h> |
#include "or32_isa.h" |
#include "or32_inst_dump.h" |
|
//----------------------------------------------------------------- |
// or32_instruction_to_string: Decode instruction to string |
//----------------------------------------------------------------- |
int or32_instruction_to_string(TRegister opcode, char *output, int max_len) |
{ |
TRegister v_ra = 0; |
TRegister v_rb = 0; |
TRegister v_rd = 0; |
TRegister v_inst = 0; |
TRegister v_op = 0; |
TRegister v_target = 0; |
TRegister v_pc = 0; |
TRegister v_pc_next = 0; |
TRegister v_imm = 0; |
TRegister v_imm_uint32 = 0; |
TRegister v_imm_int32 = 0; |
TRegister v_offset = 0; |
TRegister v_store_imm = 0; |
int v_branch = 0; |
int v_jmp = 0; |
|
TRegister v_alu_op = 0; |
TRegister v_shift_op = 0; |
TRegister v_sfxx_op = 0; |
|
// Decode opcode |
v_inst = (opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; |
v_rd = (opcode >> OR32_REG_D_SHIFT) & OR32_REG_D_MASK; |
v_ra = (opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; |
v_rb = (opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; |
v_imm = (opcode >> OR32_IMM16_SHIFT) & OR32_IMM16_MASK; |
v_target = (opcode >> OR32_ADDR_SHIFT) & OR32_ADDR_MASK; |
v_sfxx_op = (opcode >> OR32_SFXXX_OP_SHIFT) & OR32_SFXXX_OP_MASK; |
v_alu_op = (opcode >> OR32_ALU_OP_L_SHIFT) & OR32_ALU_OP_L_MASK; |
v_alu_op |= (opcode >> OR32_ALU_OP_H_SHIFT) & OR32_ALU_OP_H_MASK; |
v_shift_op = (opcode >> OR32_SHIFT_OP_SHIFT) & OR32_SHIFT_OP_MASK; |
v_store_imm = (opcode >> OR32_STORE_IMM_L_SHIFT) & OR32_STORE_IMM_L_MASK; |
v_store_imm|= (opcode >> OR32_STORE_IMM_H_SHIFT) & OR32_STORE_IMM_H_MASK; |
|
// Sign extend store immediate |
v_store_imm = (unsigned int)(signed short)v_store_imm; |
|
// Sign extend target immediate |
if (v_target & (1 << 25)) |
v_target |= ~OR32_ADDR_MASK; |
|
// Signed & unsigned imm -> 32-bits |
v_imm_int32 = (unsigned int)(signed short)v_imm; |
v_imm_uint32 = v_imm; |
|
output[0] = 0; |
|
// Execute instruction |
switch(v_inst) |
{ |
case INST_OR32_ALU: |
switch (v_alu_op) |
{ |
case INST_OR32_ADD: // l.add |
sprintf(output, "l.add r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_ADDC: // l.addc |
sprintf(output, "l.addc r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_AND: // l.and |
sprintf(output, "l.and r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_OR: // l.or |
sprintf(output, "l.or r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_SLL: // l.sll |
sprintf(output, "l.sll r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_SRA: // l.sra |
sprintf(output, "l.sra r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_SRL: // l.srl |
sprintf(output, "l.srl r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_SUB: // l.sub |
sprintf(output, "l.sub r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_XOR: // l.xor |
sprintf(output, "l.xor r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
} |
break; |
|
case INST_OR32_ADDI: // l.addi |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.addi r%d,r%d,%d", v_rd, v_ra, v_imm_int32); |
else |
sprintf(output, "l.addi r%d,r%d,0x%x", v_rd, v_ra, v_imm_int32); |
break; |
|
case INST_OR32_ANDI: // l.andi |
sprintf(output, "l.andi r%d,r%d,0x%x", v_rd, v_ra, v_imm_uint32); |
break; |
|
case INST_OR32_BF: // l.bf |
if ((int)v_target <= 0) |
sprintf(output, "l.bf %d", (int)v_target); |
else |
sprintf(output, "l.bf 0x%x", (int)v_target); |
break; |
|
case INST_OR32_BNF: // l.bnf |
if ((int)v_target <= 0) |
sprintf(output, "l.bnf %d", (int)v_target); |
else |
sprintf(output, "l.bnf 0x%x", (int)v_target); |
break; |
|
case INST_OR32_J: // l.j |
if ((int)v_target <= 0) |
sprintf(output, "l.j %d", (int)v_target); |
else |
sprintf(output, "l.j 0x%x", (int)v_target); |
break; |
|
case INST_OR32_JAL: // l.jal |
if ((int)v_target <= 0) |
sprintf(output, "l.jal %d", (int)v_target); |
else |
sprintf(output, "l.jal 0x%x", (int)v_target); |
break; |
|
case INST_OR32_JALR: // l.jalr |
sprintf(output, "l.jalr r%d", v_rb); |
break; |
|
case INST_OR32_JR: // l.jr |
sprintf(output, "l.jr r%d", v_rb); |
break; |
|
case INST_OR32_LBS: // l.lbs |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lbs r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lbs r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LHS: // l.lhs |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lhs r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lhs r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LWS: // l.lws |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lws r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lws r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LBZ: // l.lbz |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lbz r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lbz r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LHZ: // l.lhz |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lhz r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lhz r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LWZ: // l.lwz |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lwz r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lwz r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_MFSPR: // l.mfspr |
break; |
|
case INST_OR32_MOVHI: // l.movhi |
if (v_imm_uint32 == 0) |
sprintf(output, "l.movhi r%d,%d", v_rd, v_imm_uint32); |
else |
sprintf(output, "l.movhi r%d,0x%x", v_rd, v_imm_uint32); |
break; |
|
case INST_OR32_MTSPR: // l.mtspr |
break; |
|
case INST_OR32_NOP: // l.nop |
if (v_imm != 0) |
sprintf(output, "l.nop 0x%x", v_imm); |
else |
sprintf(output, "l.nop 0"); |
break; |
|
case INST_OR32_ORI: // l.ori |
if (v_imm_uint32 == 0) |
sprintf(output, "l.ori r%d,r%d,%d", v_rd, v_ra, v_imm_uint32); |
else |
sprintf(output, "l.ori r%d,r%d,0x%x", v_rd, v_ra, v_imm_uint32); |
break; |
|
case INST_OR32_RFE: // l.rfe |
sprintf(output, "l.rfe"); |
break; |
|
case INST_OR32_SHIFTI: |
switch (v_shift_op) |
{ |
case INST_OR32_SLLI: // l.slli |
sprintf(output, "l.slli r%d,r%d,0x%x", v_rd, v_ra, (opcode & 0x3F)); |
break; |
case INST_OR32_SRAI: // l.srai |
sprintf(output, "l.srai r%d,r%d,0x%x", v_rd, v_ra, (opcode & 0x3F)); |
break; |
case INST_OR32_SRLI: // l.srli |
sprintf(output, "l.srli r%d,r%d,0x%x", v_rd, v_ra, (opcode & 0x3F)); |
break; |
} |
break; |
|
case INST_OR32_SB: // l.sb |
if ((int)v_store_imm < 0) |
sprintf(output, "l.sb %d(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
else |
sprintf(output, "l.sb 0x%x(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
break; |
|
case INST_OR32_SFXX: |
case INST_OR32_SFXXI: |
switch (v_sfxx_op) |
{ |
case INST_OR32_SFEQ: // l.sfeq |
sprintf(output, "l.sfeq r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFEQI: // l.sfeqi |
sprintf(output, "l.sfeqi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFGES: // l.sfges |
sprintf(output, "l.sfges r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFGESI: // l.sfgesi |
sprintf(output, "l.sfgesi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFGEU: // l.sfgeu |
sprintf(output, "l.sfgeu r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFGEUI: // l.sfgeui |
sprintf(output, "l.sfgeui r%d,0x%x", v_ra, v_imm_uint32); |
break; |
case INST_OR32_SFGTS: // l.sfgts |
sprintf(output, "l.sfgts r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFGTSI: // l.sfgtsi |
sprintf(output, "l.sfgtsi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFGTU: // l.sfgtu |
sprintf(output, "l.sfgtu r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFGTUI: // l.sfgtui |
sprintf(output, "l.sfgtui r%d,0x%x", v_ra, v_imm_uint32); |
break; |
case INST_OR32_SFLES: // l.sfles |
sprintf(output, "l.sfles r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFLESI: // l.sflesi |
sprintf(output, "l.sflesi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFLEU: // l.sfleu |
sprintf(output, "l.sfleu r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFLEUI: // l.sfleui |
sprintf(output, "l.sfleui r%d,0x%x", v_ra, v_imm_uint32); |
break; |
case INST_OR32_SFLTS: // l.sflts |
sprintf(output, "l.sflts r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFLTSI: // l.sfltsi |
sprintf(output, "l.sfltsi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFLTU: // l.sfltu |
sprintf(output, "l.sfltu r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFLTUI: // l.sfltui |
sprintf(output, "l.sfltui r%d,0x%x", v_ra, v_imm_uint32); |
break; |
case INST_OR32_SFNE: // l.sfne |
sprintf(output, "l.sfne r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFNEI: // l.sfnei |
sprintf(output, "l.sfnei r%d,0x%x", v_ra, v_imm_uint32); |
break; |
} |
break; |
|
case INST_OR32_SH: // l.sh |
if ((int)v_store_imm < 0) |
sprintf(output, "l.sh %d(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
else |
sprintf(output, "l.sh 0x%x(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
break; |
|
case INST_OR32_SW: // l.sw |
if ((int)v_store_imm < 0) |
sprintf(output, "l.sw %d(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
else |
sprintf(output, "l.sw 0x%x(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
break; |
|
case INST_OR32_MISC: |
switch (opcode >> 24) |
{ |
case INST_OR32_SYS: // l.sys |
sprintf(output, "l.sys"); |
break; |
|
case INST_OR32_TRAP: // l.trap |
sprintf(output, "l.trap"); |
break; |
} |
break; |
|
case INST_OR32_XORI: // l.xori |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.xori r%d,r%d,%d", v_rd, v_ra, v_imm_int32); |
else |
sprintf(output, "l.xori r%d,r%d,0x%x", v_rd, v_ra, v_imm_int32); |
break; |
} |
|
return (output[0] != 0); |
} |
//----------------------------------------------------------------- |
// or32_instruction_to_string: Decode instruction to string |
//----------------------------------------------------------------- |
void or32_instruction_dump(TRegister pc, TRegister opcode, TRegister gpr[REGISTERS], TRegister rd, TRegister result, TRegister sr) |
{ |
char output[1024]; |
|
// Decode opcode in-order to perform register reads |
TRegister ra = (opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; |
TRegister rb = (opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; |
TRegister v_inst = (opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; |
|
TRegister v_store_imm = (opcode >> OR32_STORE_IMM_L_SHIFT) & OR32_STORE_IMM_L_MASK; |
v_store_imm|= (opcode >> OR32_STORE_IMM_H_SHIFT) & OR32_STORE_IMM_H_MASK; |
v_store_imm = (unsigned int)(signed short)v_store_imm; |
|
// Decode instruction in or1ksim trace format |
or32_instruction_to_string(opcode, output, sizeof(output)-1); |
|
if (rd != 0 && v_inst != INST_OR32_JAL && v_inst != INST_OR32_JALR) |
printf("S %08x: %08x %-23s r%d = %08x flag: %d\n", pc, opcode, output, rd, result, sr & OR32_SR_F_BIT ? 1: 0); |
else if (v_inst == INST_OR32_SB || v_inst == INST_OR32_SH || v_inst == INST_OR32_SW) |
{ |
if (v_inst == INST_OR32_SB) |
printf("S %08x: %08x %-23s [%08x] = %02x flag: %d\n", pc, opcode, output, gpr[ra] + (int)v_store_imm, gpr[rb], sr & OR32_SR_F_BIT ? 1: 0); |
else if (v_inst == INST_OR32_SH) |
printf("S %08x: %08x %-23s [%08x] = %04x flag: %d\n", pc, opcode, output, gpr[ra] + (int)v_store_imm, gpr[rb], sr & OR32_SR_F_BIT ? 1: 0); |
else |
printf("S %08x: %08x %-23s [%08x] = %08x flag: %d\n", pc, opcode, output, gpr[ra] + (int)v_store_imm, gpr[rb], sr & OR32_SR_F_BIT ? 1: 0); |
} |
else |
printf("S %08x: %08x %-45s flag: %d\n", pc, opcode, output, sr & OR32_SR_F_BIT ? 1: 0); |
} |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
// AltOR32 OpenRisc Simulator |
// V0.1 |
// Ultra-Embedded.com |
// Copyright 2011 - 2012 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: GPL |
// Please contact the above address if you would like a version of this |
// software with a more permissive license for use in closed source commercial |
// applications. |
//----------------------------------------------------------------------------- |
// |
// This file is part of AltOR32 OpenRisc Simulator. |
// |
// AltOR32 OpenRisc Simulator 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 2 of the License, or |
// (at your option) any later version. |
// |
// AltOR32 OpenRisc Simulator 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 AltOR32 OpenRisc Simulator; if not, write to the Free Software |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
//----------------------------------------------------------------------------- |
//----------------------------------------------------------------------------- |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <assert.h> |
#include "or32_isa.h" |
#include "or32_inst_dump.h" |
|
//----------------------------------------------------------------- |
// or32_instruction_to_string: Decode instruction to string |
//----------------------------------------------------------------- |
int or32_instruction_to_string(TRegister opcode, char *output, int max_len) |
{ |
TRegister v_ra = 0; |
TRegister v_rb = 0; |
TRegister v_rd = 0; |
TRegister v_inst = 0; |
TRegister v_op = 0; |
TRegister v_target = 0; |
TRegister v_pc = 0; |
TRegister v_pc_next = 0; |
TRegister v_imm = 0; |
TRegister v_imm_uint32 = 0; |
TRegister v_imm_int32 = 0; |
TRegister v_offset = 0; |
TRegister v_store_imm = 0; |
int v_branch = 0; |
int v_jmp = 0; |
|
TRegister v_alu_op = 0; |
TRegister v_shift_op = 0; |
TRegister v_sfxx_op = 0; |
|
// Decode opcode |
v_inst = (opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; |
v_rd = (opcode >> OR32_REG_D_SHIFT) & OR32_REG_D_MASK; |
v_ra = (opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; |
v_rb = (opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; |
v_imm = (opcode >> OR32_IMM16_SHIFT) & OR32_IMM16_MASK; |
v_target = (opcode >> OR32_ADDR_SHIFT) & OR32_ADDR_MASK; |
v_sfxx_op = (opcode >> OR32_SFXXX_OP_SHIFT) & OR32_SFXXX_OP_MASK; |
v_alu_op = (opcode >> OR32_ALU_OP_L_SHIFT) & OR32_ALU_OP_L_MASK; |
v_alu_op |= (opcode >> OR32_ALU_OP_H_SHIFT) & OR32_ALU_OP_H_MASK; |
v_shift_op = (opcode >> OR32_SHIFT_OP_SHIFT) & OR32_SHIFT_OP_MASK; |
v_store_imm = (opcode >> OR32_STORE_IMM_L_SHIFT) & OR32_STORE_IMM_L_MASK; |
v_store_imm|= (opcode >> OR32_STORE_IMM_H_SHIFT) & OR32_STORE_IMM_H_MASK; |
|
// Sign extend store immediate |
v_store_imm = (unsigned int)(signed short)v_store_imm; |
|
// Sign extend target immediate |
if (v_target & (1 << 25)) |
v_target |= ~OR32_ADDR_MASK; |
|
// Signed & unsigned imm -> 32-bits |
v_imm_int32 = (unsigned int)(signed short)v_imm; |
v_imm_uint32 = v_imm; |
|
output[0] = 0; |
|
// Execute instruction |
switch(v_inst) |
{ |
case INST_OR32_ALU: |
switch (v_alu_op) |
{ |
case INST_OR32_ADD: // l.add |
sprintf(output, "l.add r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_ADDC: // l.addc |
sprintf(output, "l.addc r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_AND: // l.and |
sprintf(output, "l.and r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_OR: // l.or |
sprintf(output, "l.or r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_SLL: // l.sll |
sprintf(output, "l.sll r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_SRA: // l.sra |
sprintf(output, "l.sra r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_SRL: // l.srl |
sprintf(output, "l.srl r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_SUB: // l.sub |
sprintf(output, "l.sub r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_XOR: // l.xor |
sprintf(output, "l.xor r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
} |
break; |
|
case INST_OR32_ADDI: // l.addi |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.addi r%d,r%d,%d", v_rd, v_ra, v_imm_int32); |
else |
sprintf(output, "l.addi r%d,r%d,0x%x", v_rd, v_ra, v_imm_int32); |
break; |
|
case INST_OR32_ANDI: // l.andi |
sprintf(output, "l.andi r%d,r%d,0x%x", v_rd, v_ra, v_imm_uint32); |
break; |
|
case INST_OR32_BF: // l.bf |
if ((int)v_target <= 0) |
sprintf(output, "l.bf %d", (int)v_target); |
else |
sprintf(output, "l.bf 0x%x", (int)v_target); |
break; |
|
case INST_OR32_BNF: // l.bnf |
if ((int)v_target <= 0) |
sprintf(output, "l.bnf %d", (int)v_target); |
else |
sprintf(output, "l.bnf 0x%x", (int)v_target); |
break; |
|
case INST_OR32_J: // l.j |
if ((int)v_target <= 0) |
sprintf(output, "l.j %d", (int)v_target); |
else |
sprintf(output, "l.j 0x%x", (int)v_target); |
break; |
|
case INST_OR32_JAL: // l.jal |
if ((int)v_target <= 0) |
sprintf(output, "l.jal %d", (int)v_target); |
else |
sprintf(output, "l.jal 0x%x", (int)v_target); |
break; |
|
case INST_OR32_JALR: // l.jalr |
sprintf(output, "l.jalr r%d", v_rb); |
break; |
|
case INST_OR32_JR: // l.jr |
sprintf(output, "l.jr r%d", v_rb); |
break; |
|
case INST_OR32_LBS: // l.lbs |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lbs r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lbs r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LHS: // l.lhs |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lhs r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lhs r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LWS: // l.lws |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lws r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lws r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LBZ: // l.lbz |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lbz r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lbz r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LHZ: // l.lhz |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lhz r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lhz r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_LWZ: // l.lwz |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.lwz r%d,%d(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
else |
sprintf(output, "l.lwz r%d,0x%x(r%d)", v_rd, (int)v_imm_int32, v_ra, v_rd); |
break; |
|
case INST_OR32_MFSPR: // l.mfspr |
break; |
|
case INST_OR32_MOVHI: // l.movhi |
if (v_imm_uint32 == 0) |
sprintf(output, "l.movhi r%d,%d", v_rd, v_imm_uint32); |
else |
sprintf(output, "l.movhi r%d,0x%x", v_rd, v_imm_uint32); |
break; |
|
case INST_OR32_MTSPR: // l.mtspr |
break; |
|
case INST_OR32_NOP: // l.nop |
if (v_imm != 0) |
sprintf(output, "l.nop 0x%x", v_imm); |
else |
sprintf(output, "l.nop 0"); |
break; |
|
case INST_OR32_ORI: // l.ori |
if (v_imm_uint32 == 0) |
sprintf(output, "l.ori r%d,r%d,%d", v_rd, v_ra, v_imm_uint32); |
else |
sprintf(output, "l.ori r%d,r%d,0x%x", v_rd, v_ra, v_imm_uint32); |
break; |
|
case INST_OR32_RFE: // l.rfe |
sprintf(output, "l.rfe"); |
break; |
|
case INST_OR32_SHIFTI: |
switch (v_shift_op) |
{ |
case INST_OR32_SLLI: // l.slli |
sprintf(output, "l.slli r%d,r%d,0x%x", v_rd, v_ra, (opcode & 0x3F)); |
break; |
case INST_OR32_SRAI: // l.srai |
sprintf(output, "l.srai r%d,r%d,0x%x", v_rd, v_ra, (opcode & 0x3F)); |
break; |
case INST_OR32_SRLI: // l.srli |
sprintf(output, "l.srli r%d,r%d,0x%x", v_rd, v_ra, (opcode & 0x3F)); |
break; |
} |
break; |
|
case INST_OR32_SB: // l.sb |
if ((int)v_store_imm < 0) |
sprintf(output, "l.sb %d(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
else |
sprintf(output, "l.sb 0x%x(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
break; |
|
case INST_OR32_SFXX: |
case INST_OR32_SFXXI: |
switch (v_sfxx_op) |
{ |
case INST_OR32_SFEQ: // l.sfeq |
sprintf(output, "l.sfeq r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFEQI: // l.sfeqi |
sprintf(output, "l.sfeqi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFGES: // l.sfges |
sprintf(output, "l.sfges r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFGESI: // l.sfgesi |
sprintf(output, "l.sfgesi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFGEU: // l.sfgeu |
sprintf(output, "l.sfgeu r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFGEUI: // l.sfgeui |
sprintf(output, "l.sfgeui r%d,0x%x", v_ra, v_imm_uint32); |
break; |
case INST_OR32_SFGTS: // l.sfgts |
sprintf(output, "l.sfgts r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFGTSI: // l.sfgtsi |
sprintf(output, "l.sfgtsi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFGTU: // l.sfgtu |
sprintf(output, "l.sfgtu r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFGTUI: // l.sfgtui |
sprintf(output, "l.sfgtui r%d,0x%x", v_ra, v_imm_uint32); |
break; |
case INST_OR32_SFLES: // l.sfles |
sprintf(output, "l.sfles r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFLESI: // l.sflesi |
sprintf(output, "l.sflesi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFLEU: // l.sfleu |
sprintf(output, "l.sfleu r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFLEUI: // l.sfleui |
sprintf(output, "l.sfleui r%d,0x%x", v_ra, v_imm_uint32); |
break; |
case INST_OR32_SFLTS: // l.sflts |
sprintf(output, "l.sflts r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFLTSI: // l.sfltsi |
sprintf(output, "l.sfltsi r%d,0x%x", v_ra, (int)v_imm_int32); |
break; |
case INST_OR32_SFLTU: // l.sfltu |
sprintf(output, "l.sfltu r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFLTUI: // l.sfltui |
sprintf(output, "l.sfltui r%d,0x%x", v_ra, v_imm_uint32); |
break; |
case INST_OR32_SFNE: // l.sfne |
sprintf(output, "l.sfne r%d,r%d", v_ra, v_rb); |
break; |
case INST_OR32_SFNEI: // l.sfnei |
sprintf(output, "l.sfnei r%d,0x%x", v_ra, v_imm_uint32); |
break; |
} |
break; |
|
case INST_OR32_SH: // l.sh |
if ((int)v_store_imm < 0) |
sprintf(output, "l.sh %d(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
else |
sprintf(output, "l.sh 0x%x(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
break; |
|
case INST_OR32_SW: // l.sw |
if ((int)v_store_imm < 0) |
sprintf(output, "l.sw %d(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
else |
sprintf(output, "l.sw 0x%x(r%d),r%d", (int)v_store_imm, v_ra, v_rb); |
break; |
|
case INST_OR32_MISC: |
switch (opcode >> 24) |
{ |
case INST_OR32_SYS: // l.sys |
sprintf(output, "l.sys"); |
break; |
|
case INST_OR32_TRAP: // l.trap |
sprintf(output, "l.trap"); |
break; |
} |
break; |
|
case INST_OR32_XORI: // l.xori |
if ((int)v_imm_int32 < 0) |
sprintf(output, "l.xori r%d,r%d,%d", v_rd, v_ra, v_imm_int32); |
else |
sprintf(output, "l.xori r%d,r%d,0x%x", v_rd, v_ra, v_imm_int32); |
break; |
} |
|
return (output[0] != 0); |
} |
//----------------------------------------------------------------- |
// or32_instruction_to_string: Decode instruction to string |
//----------------------------------------------------------------- |
void or32_instruction_dump(TRegister pc, TRegister opcode, TRegister gpr[REGISTERS], TRegister rd, TRegister result, TRegister sr) |
{ |
char output[1024]; |
|
// Decode opcode in-order to perform register reads |
TRegister ra = (opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; |
TRegister rb = (opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; |
TRegister v_inst = (opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; |
|
TRegister v_store_imm = (opcode >> OR32_STORE_IMM_L_SHIFT) & OR32_STORE_IMM_L_MASK; |
v_store_imm|= (opcode >> OR32_STORE_IMM_H_SHIFT) & OR32_STORE_IMM_H_MASK; |
v_store_imm = (unsigned int)(signed short)v_store_imm; |
|
// Decode instruction in or1ksim trace format |
or32_instruction_to_string(opcode, output, sizeof(output)-1); |
|
if (rd != 0 && v_inst != INST_OR32_JAL && v_inst != INST_OR32_JALR) |
printf("S %08x: %08x %-23s r%d = %08x flag: %d\n", pc, opcode, output, rd, result, sr & OR32_SR_F_BIT ? 1: 0); |
else if (v_inst == INST_OR32_SB || v_inst == INST_OR32_SH || v_inst == INST_OR32_SW) |
{ |
if (v_inst == INST_OR32_SB) |
printf("S %08x: %08x %-23s [%08x] = %02x flag: %d\n", pc, opcode, output, gpr[ra] + (int)v_store_imm, gpr[rb], sr & OR32_SR_F_BIT ? 1: 0); |
else if (v_inst == INST_OR32_SH) |
printf("S %08x: %08x %-23s [%08x] = %04x flag: %d\n", pc, opcode, output, gpr[ra] + (int)v_store_imm, gpr[rb], sr & OR32_SR_F_BIT ? 1: 0); |
else |
printf("S %08x: %08x %-23s [%08x] = %08x flag: %d\n", pc, opcode, output, gpr[ra] + (int)v_store_imm, gpr[rb], sr & OR32_SR_F_BIT ? 1: 0); |
} |
else |
printf("S %08x: %08x %-45s flag: %d\n", pc, opcode, output, sr & OR32_SR_F_BIT ? 1: 0); |
} |
/or32-sim/or32.h
46,7 → 46,7
virtual void PeripheralReset(void) { } |
virtual void PeripheralClock(void) { } |
virtual TRegister PeripheralAccess(TAddress addr, TRegister data_in, TRegister wr, TRegister rd) { return 0; } |
virtual bool PeripheralInt(void) { return false; } |
virtual bool PeripheralInterrupt(void) { return false; } |
|
protected: |
// Execution monitoring |