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 27 to Rev 28
- ↔ Reverse comparison
Rev 27 → Rev 28
/or1k-sim/peripheral.h
0,0 → 1,69
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#ifndef __PERIPHERAL_H__ |
#define __PERIPHERAL_H__ |
|
//-------------------------------------------------------------------- |
// Class |
//-------------------------------------------------------------------- |
class Peripheral |
{ |
public: |
// Peripheral access |
virtual void Reset(void) = 0; |
virtual void Clock(void) = 0; |
virtual TRegister Access(TAddress addr, TRegister data_in, TRegister wr, TRegister rd) = 0; |
virtual bool Interrupt(void) = 0; |
virtual TAddress GetStartAddress() = 0; |
virtual TAddress GetStopAddress() = 0; |
}; |
|
//-------------------------------------------------------------------- |
// Class |
//-------------------------------------------------------------------- |
class PeripheralInstance |
{ |
public: |
PeripheralInstance() { instance = NULL; start_address = end_address = 0; } |
|
public: |
Peripheral * instance; |
TRegister start_address; |
TRegister end_address; |
}; |
|
#endif |
/or1k-sim/getopt_win32.c
0,0 → 1,218
// XGetopt.c Version 1.2 |
// |
// Author: Hans Dietrich |
// hdietrich2@hotmail.com |
// |
// Description: |
// XGetopt.cpp implements getopt(), a function to parse command lines. |
// |
// History |
// Version 1.2 - 2003 May 17 |
// - Added Unicode support |
// |
// Version 1.1 - 2002 March 10 |
// - Added example to XGetopt.cpp module header |
// |
// This software is released into the public domain. |
// You are free to use it in any way you like. |
// |
// This software is provided "as is" with no expressed |
// or implied warranty. I accept no liability for any |
// damage or loss of business that this software may cause. |
// |
/////////////////////////////////////////////////////////////////////////////// |
|
#ifdef WIN32 |
|
/////////////////////////////////////////////////////////////////////////////// |
// if you are not using precompiled headers then include these lines: |
#include <windows.h> |
#include <stdio.h> |
#include <tchar.h> |
/////////////////////////////////////////////////////////////////////////////// |
|
|
#include "getopt_win32.h" |
|
|
/////////////////////////////////////////////////////////////////////////////// |
// |
// X G e t o p t . c |
// |
// |
// NAME |
// getopt -- parse command line options |
// |
// SYNOPSIS |
// int getopt(int argc, TCHAR *argv[], TCHAR *optstring) |
// |
// extern TCHAR *optarg; |
// extern int optind; |
// |
// DESCRIPTION |
// The getopt() function parses the command line arguments. Its |
// arguments argc and argv are the argument count and array as |
// passed into the application on program invocation. In the case |
// of Visual C++ programs, argc and argv are available via the |
// variables __argc and __argv (double underscores), respectively. |
// getopt returns the next option letter in argv that matches a |
// letter in optstring. (Note: Unicode programs should use |
// __targv instead of __argv. Also, all character and string |
// literals should be enclosed in _T( ) ). |
// |
// optstring is a string of recognized option letters; if a letter |
// is followed by a colon, the option is expected to have an argument |
// that may or may not be separated from it by white space. optarg |
// is set to point to the start of the option argument on return from |
// getopt. |
// |
// Option letters may be combined, e.g., "-ab" is equivalent to |
// "-a -b". Option letters are case sensitive. |
// |
// getopt places in the external variable optind the argv index |
// of the next argument to be processed. optind is initialized |
// to 0 before the first call to getopt. |
// |
// When all options have been processed (i.e., up to the first |
// non-option argument), getopt returns EOF, optarg will point |
// to the argument, and optind will be set to the argv index of |
// the argument. If there are no non-option arguments, optarg |
// will be set to NULL. |
// |
// The special option "--" may be used to delimit the end of the |
// options; EOF will be returned, and "--" (and everything after it) |
// will be skipped. |
// |
// RETURN VALUE |
// For option letters contained in the string optstring, getopt |
// will return the option letter. getopt returns a question mark (?) |
// when it encounters an option letter not included in optstring. |
// EOF is returned when processing is finished. |
// |
// BUGS |
// 1) Long options are not supported. |
// 2) The GNU double-colon extension is not supported. |
// 3) The environment variable POSIXLY_CORRECT is not supported. |
// 4) The + syntax is not supported. |
// 5) The automatic permutation of arguments is not supported. |
// 6) This implementation of getopt() returns EOF if an error is |
// encountered, instead of -1 as the latest standard requires. |
// |
// EXAMPLE |
// BOOL CMyApp::ProcessCommandLine(int argc, TCHAR *argv[]) |
// { |
// int c; |
// |
// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF) |
// { |
// switch (c) |
// { |
// case _T('a'): |
// TRACE(_T("option a\n")); |
// // |
// // set some flag here |
// // |
// break; |
// |
// case _T('B'): |
// TRACE( _T("option B\n")); |
// // |
// // set some other flag here |
// // |
// break; |
// |
// case _T('n'): |
// TRACE(_T("option n: value=%d\n"), atoi(optarg)); |
// // |
// // do something with value here |
// // |
// break; |
// |
// case _T('?'): |
// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]); |
// return FALSE; |
// break; |
// |
// default: |
// TRACE(_T("WARNING: no handler for option %c\n"), c); |
// return FALSE; |
// break; |
// } |
// } |
// // |
// // check for non-option args here |
// // |
// return TRUE; |
// } |
// |
/////////////////////////////////////////////////////////////////////////////// |
|
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; |
|
if (optind == 0) |
next = NULL; |
|
optarg = NULL; |
|
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 (_tcscmp(argv[optind], _T("--")) == 0) |
{ |
optind++; |
optarg = NULL; |
if (optind < argc) |
optarg = argv[optind]; |
return EOF; |
} |
|
next = argv[optind]; |
next++; // skip past - |
optind++; |
} |
|
c = *next++; |
cp = _tcschr(optstring, c); |
|
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('?'); |
} |
} |
|
return c; |
} |
#endif |
/or1k-sim/main.cpp
0,0 → 1,368
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; 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 "periph_timer.h" |
|
#ifdef WIN32 |
#include "getopt_win32.h" |
#else |
#include <unistd.h> |
#endif |
|
#ifdef INCLUDE_ELF_SUPPORT |
#include <libelf.h> |
#include <fcntl.h> |
#include <gelf.h> |
#endif |
|
//----------------------------------------------------------------- |
// Defines |
//----------------------------------------------------------------- |
#define DEFAULT_MEM_BASE 0x10000000 |
#define DEFAULT_MEM_SIZE (10 << 20) |
#define DEFAULT_LOAD_ADDR 0x10000000 |
#define DEFAULT_FILENAME NULL |
|
//----------------------------------------------------------------- |
// Locals |
//----------------------------------------------------------------- |
|
//----------------------------------------------------------------- |
// elf_load |
//----------------------------------------------------------------- |
#ifdef INCLUDE_ELF_SUPPORT |
static int elf_load(OR32 *sim, const char *filename, unsigned int *startAddr) |
{ |
int fd; |
Elf * e; |
Elf_Kind ek; |
Elf_Scn *scn; |
Elf_Data *data; |
Elf32_Shdr *shdr; |
size_t shstrndx; |
|
if (elf_version ( EV_CURRENT ) == EV_NONE) |
return 0; |
|
if ((fd = open ( filename , O_RDONLY , 0)) < 0) |
return 0; |
|
if ((e = elf_begin ( fd , ELF_C_READ, NULL )) == NULL) |
return 0; |
|
ek = elf_kind ( e ); |
if (ek != ELF_K_ELF) |
return 0; |
|
// Get section name header index |
if (elf_getshdrstrndx(e, &shstrndx)!=0) |
return 0; |
|
int section_idx = 0; |
while ((scn = elf_getscn(e, section_idx)) != NULL) |
{ |
shdr = elf32_getshdr(scn); |
|
// Section which need loading (.text, .bss, .data, etc) |
if ((shdr->sh_type == SHT_PROGBITS || shdr->sh_type == SHT_NOBITS) && |
(shdr->sh_flags & SHF_EXECINSTR || shdr->sh_flags & SHF_ALLOC) |
) |
{ |
data = elf_getdata(scn, NULL); |
|
// .text section? |
if (elf_strptr(e, shstrndx, shdr->sh_name) && startAddr && |
strcmp(elf_strptr(e, shstrndx, shdr->sh_name), ".text") == 0) |
{ |
*startAddr = shdr->sh_addr; |
} |
|
// Create some memory for this section |
if (!sim->CreateMemory(shdr->sh_addr, shdr->sh_size)) |
return 0; |
|
printf("Memory: 0x%x - 0x%x (Size=%dKB) [%s]\n", shdr->sh_addr, shdr->sh_addr + shdr->sh_size - 1, shdr->sh_size / 1024, elf_strptr(e, shstrndx, shdr->sh_name)); |
|
if (shdr->sh_type == SHT_PROGBITS) |
{ |
if (!sim->Load(shdr->sh_addr, (unsigned char*)data->d_buf, data->d_size)) |
return 0; |
} |
} |
|
section_idx++; |
} |
|
elf_end ( e ); |
close ( fd ); |
|
return 1; |
} |
#endif |
//----------------------------------------------------------------- |
// 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 = DEFAULT_MEM_BASE + VECTOR_RESET; |
int max_cycles = -1; |
char *filename = DEFAULT_FILENAME; |
char *elf_file = NULL; |
int help = 0; |
int trace = 0; |
unsigned int trace_mask = 1; |
int exitcode = -1; |
int mem_trace = 0; |
unsigned int trace_enable_pc = 0xFFFFFFFF; |
unsigned int stop_pc = 0xFFFFFFFF; |
OR32 *sim = NULL; |
|
while ((c = getopt (argc, argv, "tv:l:b:s:f:c:x:nme:d:z:k:r:")) != -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 'k': |
trace_enable_pc = strtoul(optarg, NULL, 0); |
break; |
case 'r': |
stop_pc = strtoul(optarg, NULL, 0); |
break; |
case 'f': |
filename = optarg; |
break; |
#ifdef INCLUDE_ELF_SUPPORT |
case 'e': |
elf_file = optarg; |
break; |
#endif |
case 'c': |
max_cycles = (int)strtoul(optarg, NULL, 0); |
break; |
case 'm': |
mem_trace = 1; |
break; |
case '?': |
default: |
help = 1; |
break; |
} |
} |
|
if (help || (filename == NULL && elf_file == NULL)) |
{ |
fprintf (stderr,"Usage:\n"); |
fprintf (stderr,"-f filename.bin = Executable to load (binary)\n"); |
#ifdef INCLUDE_ELF_SUPPORT |
fprintf (stderr,"-e filename.elf = Executable to load (ELF)\n"); |
#endif |
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"); |
fprintf (stderr,"-k 0xnnnn = Trace enable PC\n"); |
|
exit(-1); |
} |
|
|
if (elf_file) |
{ |
#ifdef INCLUDE_ELF_SUPPORT |
sim = new OR32(false); |
sim->AttachPeripheral(new TimerPeripheral()); |
|
if (elf_load(sim, elf_file, &memBase)) |
{ |
int cycles = 0; |
|
sim->Reset(memBase + VECTOR_RESET); |
|
if (trace & trace_enable_pc == 0xFFFFFFFF) |
sim->EnableTrace(trace_mask); |
|
if (mem_trace) |
{ |
printf("Memory trace enabled\n"); |
sim->EnableMemoryTrace(); |
} |
|
printf("Execute from 0x%x\n", memBase + VECTOR_RESET); |
while (!sim->GetBreak() && !sim->GetFault() && sim->GetPC() != stop_pc) |
{ |
sim->Step(); |
cycles++; |
|
if (max_cycles != -1 && max_cycles == cycles) |
break; |
|
if (trace) |
{ |
if (sim->GetPC() == trace_enable_pc) |
sim->EnableTrace(trace_mask); |
} |
} |
|
// Show execution stats |
sim->DumpStats(); |
|
// Fault occurred? |
if (sim->GetFault()) |
exitcode = 1; |
else |
exitcode = 0; |
} |
else |
fprintf (stderr,"Error: Could not open ELF file %s\n", elf_file); |
|
delete sim; |
|
return exitcode; |
#else |
fprintf (stderr,"Error: ELF files not supported\n"); |
return -1; |
#endif |
} |
else |
{ |
sim = new OR32(memBase, memSize, false); |
sim->AttachPeripheral(new TimerPeripheral()); |
|
sim->Reset(startAddr); |
|
if (trace) |
sim->EnableTrace(trace_mask); |
|
if (mem_trace) |
{ |
printf("Memory trace enabled\n"); |
sim->EnableMemoryTrace(); |
} |
|
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->GetPC() != stop_pc) |
{ |
sim->Step(); |
cycles++; |
|
if (max_cycles != -1 && max_cycles == cycles) |
break; |
|
if (trace) |
{ |
if (sim->GetPC() == trace_enable_pc) |
sim->EnableTrace(trace_mask); |
} |
} |
} |
else |
fprintf (stderr,"Error: Could not load image to memory\n"); |
|
free(buf); |
fclose(f); |
} |
// Show execution stats |
sim->DumpStats(); |
|
// Fault occurred? |
if (sim->GetFault()) |
exitcode = 1; |
else |
exitcode = 0; |
} |
else |
fprintf (stderr,"Error: Could not open %s\n", filename); |
|
delete sim; |
} |
|
return exitcode; |
} |
|
/or1k-sim/or32.cpp
0,0 → 1,1424
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; 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 INCLUDE_INST_DUMP |
#include "or32_inst_dump.h" |
#endif |
|
//----------------------------------------------------------------- |
// Defines: |
//----------------------------------------------------------------- |
#define DPRINTF(l,a) do { if (Trace & l) printf a; } while (0) |
#define TRACE_ENABLED(l) (Trace & l) |
|
#define MEMTRACE_WRITES "mem_writes.txt" |
#define MEMTRACE_READS "mem_reads.txt" |
#define MEMTRACE_INST "mem_inst.txt" |
#define MEMTRACE_MIN 100 |
|
#define ADD_CARRY_OUT(a,b) ((((unsigned long long)(a) + (unsigned long long)(b)) & ((unsigned long long)1 << 32)) != 0) |
|
#define HTONL(n) (((((unsigned int)(n) & 0xFF)) << 24) | \ |
((((unsigned int)(n) & 0xFF00)) << 8) | \ |
((((unsigned int)(n) & 0xFF0000)) >> 8) | \ |
((((unsigned int)(n) & 0xFF000000)) >> 24)) |
|
//----------------------------------------------------------------- |
// Constructor |
//----------------------------------------------------------------- |
OR32::OR32(bool delay_slot) |
{ |
MemRegions = 0; |
|
int m; |
for (m=0;m<MAX_MEM_REGIONS;m++) |
{ |
MemInstHits[m] = NULL; |
MemReadHits[m] = NULL; |
MemWriteHits[m] = NULL; |
} |
|
MemVectorBase = 0; |
|
Trace = 0; |
DelaySlotEnabled = delay_slot; |
EnablePutc = true; |
|
Reset(); |
} |
//----------------------------------------------------------------- |
// Constructor |
//----------------------------------------------------------------- |
OR32::OR32(unsigned int baseAddr, unsigned int len, bool delay_slot) |
{ |
int m; |
|
MemBase[0] = baseAddr; |
MemSize[0] = len; |
|
Mem[0] = new TMemory[(len + 3)/4]; |
assert(Mem[0]); |
memset(Mem[0], 0, (len + 3)/4); |
|
MemRegions = 1; |
|
for (m=0;m<MAX_MEM_REGIONS;m++) |
{ |
MemInstHits[m] = NULL; |
MemReadHits[m] = NULL; |
MemWriteHits[m] = NULL; |
} |
|
MemVectorBase = baseAddr; |
|
Trace = 0; |
DelaySlotEnabled = delay_slot; |
EnablePutc = true; |
|
Reset(); |
} |
//----------------------------------------------------------------- |
// Deconstructor |
//----------------------------------------------------------------- |
OR32::~OR32() |
{ |
int m; |
|
for (m=0;m<MemRegions;m++) |
{ |
if (Mem[m]) |
delete Mem[m]; |
Mem[m] = NULL; |
} |
} |
//----------------------------------------------------------------- |
// CreateMemory: |
//----------------------------------------------------------------- |
bool OR32::CreateMemory(unsigned int baseAddr, unsigned int len) |
{ |
if (MemRegions < MAX_MEM_REGIONS) |
{ |
MemBase[MemRegions] = baseAddr; |
MemSize[MemRegions] = len; |
|
Mem[MemRegions] = new TMemory[(len + 3)/4]; |
if (!Mem[MemRegions]) |
return false; |
|
memset(Mem[MemRegions], 0, (len + 3)/4); |
|
MemRegions++; |
|
return true; |
} |
|
return false; |
} |
//----------------------------------------------------------------- |
// EnableMemoryTrace: |
//----------------------------------------------------------------- |
void OR32::EnableMemoryTrace(void) |
{ |
int m; |
|
for (m=0;m<MemRegions;m++) |
{ |
MemInstHits[m] = new TRegister[MemSize[m]/4]; |
MemReadHits[m] = new TRegister[MemSize[m]/4]; |
MemWriteHits[m] = new TRegister[MemSize[m]/4]; |
assert(MemInstHits[m]); |
assert(MemReadHits[m]); |
assert(MemWriteHits[m]); |
|
memset(MemInstHits[m], 0, MemSize[m]); |
memset(MemReadHits[m], 0, MemSize[m]); |
memset(MemWriteHits[m], 0, MemSize[m]); |
} |
} |
//----------------------------------------------------------------- |
// 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; |
mem_ifetch = 0; |
|
Fault = 0; |
Break = 0; |
BreakValue = 0; |
Trace = 0; |
Cycle = 2; |
|
MemVectorBase = start_addr - VECTOR_RESET; |
|
ResetStats(); |
PeripheralReset(); |
} |
//----------------------------------------------------------------- |
// ResetStats: Reset runtime stats |
//----------------------------------------------------------------- |
void OR32::ResetStats(void) |
{ |
int m; |
|
// Clear stats |
StatsMem = 0; |
StatsMarkers = 0; |
StatsMemWrites = 0; |
StatsInstructions = 0; |
StatsNop = 0; |
StatsBranches = 0; |
StatsExceptions = 0; |
StatsMulu = 0; |
StatsMul = 0; |
|
for (m=0;m<MemRegions;m++) |
{ |
if (MemReadHits[m]) |
memset(MemReadHits[m], 0, MemSize[m]); |
if (MemWriteHits[m]) |
memset(MemWriteHits[m], 0, MemSize[m]); |
if (MemInstHits[m]) |
memset(MemInstHits[m], 0, MemSize[m]); |
} |
} |
//----------------------------------------------------------------- |
// Load: Load program code into startAddr offset |
//----------------------------------------------------------------- |
bool OR32::Load(unsigned int startAddr, unsigned char *data, int len) |
{ |
int i; |
int j; |
|
for (j=0;j<MemRegions;j++) |
{ |
// Program fits in memory? |
if ((startAddr >= MemBase[j]) && (startAddr + len) <= (MemBase[j] + MemSize[j])) |
{ |
// Make relative to start of memory |
startAddr -= MemBase[j]; |
|
// Convert to word address |
startAddr /= 4; |
|
for (i=0;i<len / 4; i++) |
{ |
Mem[j][startAddr+i] = *data++; |
Mem[j][startAddr+i] <<= 8; |
Mem[j][startAddr+i]|= *data++; |
Mem[j][startAddr+i] <<= 8; |
Mem[j][startAddr+i]|= *data++; |
Mem[j][startAddr+i] <<= 8; |
Mem[j][startAddr+i]|= *data++; |
|
Mem[j][startAddr+i] = HTONL(Mem[j][startAddr+i]); |
} |
|
return true; |
} |
} |
return false; |
} |
//----------------------------------------------------------------- |
// WriteMem: Write a block of memory |
//----------------------------------------------------------------- |
bool OR32::WriteMem(TAddress addr, unsigned char *data, int len) |
{ |
int i; |
int j; |
|
for (j=0;j<MemRegions;j++) |
{ |
if (addr >= MemBase[j] && addr < (MemBase[j] + MemSize[j])) |
{ |
unsigned char *ptr = (unsigned char *)Mem[j]; |
ptr += (addr - MemBase[j]); |
|
for (i=0;i<len; i++) |
ptr[i] = data[i]; |
|
return true; |
} |
} |
|
return false; |
} |
//----------------------------------------------------------------- |
// ReadMem: Read a block of memory |
//----------------------------------------------------------------- |
bool OR32::ReadMem(TAddress addr, unsigned char *data, int len) |
{ |
int i; |
int j; |
|
for (j=0;j<MemRegions;j++) |
{ |
if (addr >= MemBase[j] && addr < (MemBase[j] + MemSize[j])) |
{ |
unsigned char *ptr = (unsigned char *)Mem[j]; |
ptr += (addr - MemBase[j]); |
|
for (i=0;i<len; i++) |
data[i] = ptr[i]; |
|
return true; |
} |
} |
|
return false; |
} |
//----------------------------------------------------------------- |
// GetOpcode: Get instruction from address |
//----------------------------------------------------------------- |
TRegister OR32::GetOpcode(TRegister address) |
{ |
int m; |
for (m=0;m<MemRegions;m++) |
{ |
if (address >= MemBase[m] && address < (MemBase[m] + MemSize[m])) |
{ |
TAddress wordAddress = (address - MemBase[m]) / 4; |
TRegister mem_word = Mem[m][wordAddress]; |
return HTONL(mem_word); |
} |
} |
|
return 0; |
} |
//----------------------------------------------------------------- |
// Decode: Instruction decode stage |
//----------------------------------------------------------------- |
void OR32::Decode(void) |
{ |
// Instruction opcode read complete |
mem_wr = 0; |
mem_rd = 0; |
mem_ifetch = 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: Execute 0x%08x\n", r_pc, r_opcode)); |
DPRINTF(LOG_INST, (" rA[%2d] = 0x%08x\n", r_ra, r_reg_ra)); |
DPRINTF(LOG_INST, (" rB[%2d] = 0x%08x\n", r_rb, r_reg_rb)); |
|
// 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; |
|
// Default target is r_rd |
r_rd_wb = r_rd; |
|
if (DelaySlotEnabled) |
{ |
// 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; |
} |
else |
{ |
v_pc = r_pc + 4; // Current PC + 4 |
v_pc_next = r_pc + 8; // Current PC + 8 (used in branches) |
} |
|
// 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; |
|
// Carry out |
r_sr = (r_sr & ~OR32_SR_CY_BIT) | (ADD_CARRY_OUT(v_reg_ra, v_reg_rb) ? OR32_SR_CY_BIT : 0); |
break; |
case INST_OR32_ADDC: // l.addc |
v_reg_result = v_reg_ra + v_reg_rb + ((r_sr & OR32_SR_CY_BIT) ? 1 : 0); |
v_write_rd = 1; |
|
// Carry out |
r_sr = (r_sr & ~OR32_SR_CY_BIT) | (ADD_CARRY_OUT(v_reg_ra, v_reg_rb) ? OR32_SR_CY_BIT : 0); |
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; |
case INST_OR32_MUL: // l.mul |
{ |
long long res = ((long long) (int)v_reg_ra) * ((long long)(int)v_reg_rb); |
v_reg_result = (int)(res >> 0); |
v_write_rd = 1; |
StatsMul++; |
} |
break; |
case INST_OR32_MULU: // l.mulu |
{ |
// This implementation differs from other cores - l.mulu returns upper |
// 32-bits of multiplication result... |
long long res = ((long long) (int)v_reg_ra) * ((long long)(int)v_reg_rb); |
v_reg_result = (int)(res >> 32); |
v_write_rd = 1; |
StatsMulu++; |
} |
break; |
default: |
fprintf (stderr,"Bad ALU instruction @ PC %x\n", r_pc); |
Fault = 1; |
v_exception = 1; |
v_vector = MemVectorBase + VECTOR_ILLEGAL_INST; |
break; |
} |
break; |
|
case INST_OR32_ADDI: // l.addi |
v_reg_result = v_reg_ra + v_imm_int32; |
v_write_rd = 1; |
|
// Carry out |
r_sr = (r_sr & ~OR32_SR_CY_BIT) | (ADD_CARRY_OUT(v_reg_ra, v_reg_rb) ? OR32_SR_CY_BIT : 0); |
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 |
if (DelaySlotEnabled) |
v_reg_result = v_pc_next; |
else |
v_reg_result = v_pc; |
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 |
if (DelaySlotEnabled) |
v_reg_result = v_pc_next; |
else |
v_reg_result = v_pc; |
r_rd_wb = REG_9_LR; |
v_write_rd = 1; |
|
if (DelaySlotEnabled) |
v_pc_next = v_reg_rb; |
else |
v_pc = v_reg_rb; |
v_jmp = 1; |
break; |
|
case INST_OR32_JR: // l.jr |
if (DelaySlotEnabled) |
v_pc_next = v_reg_rb; |
else |
v_pc = 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 = MemVectorBase + 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 |
if (DelaySlotEnabled) |
v_pc_next = r_epc; |
else |
v_pc = 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 = MemVectorBase + 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++; |
StatsMemWrites++; |
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_int32) |
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_int32) |
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_int32) |
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_int32) |
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 = MemVectorBase + 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++; |
StatsMemWrites++; |
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++; |
StatsMemWrites++; |
break; |
|
case INST_OR32_MISC: |
switch (r_opcode >> 24) |
{ |
case INST_OR32_SYS: // l.sys |
v_exception = 1; |
v_vector = MemVectorBase + VECTOR_SYSCALL; |
break; |
|
case INST_OR32_TRAP: // l.trap |
Break = 1; |
BreakValue = v_imm_uint32; |
v_exception = 1; |
v_vector = MemVectorBase + 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 = MemVectorBase + 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; |
if (DelaySlotEnabled) |
v_pc_next = r_pc + v_offset; |
else |
v_pc = 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 = MemVectorBase + 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 |
if (DelaySlotEnabled) |
{ |
r_pc_last = r_pc; |
r_pc = v_pc; |
r_pc_next = v_pc_next; |
} |
else |
{ |
r_pc_last = r_pc; |
r_pc = v_pc; |
} |
|
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; |
mem_ifetch = 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? |
#ifdef INCLUDE_INST_DUMP |
if (TRACE_ENABLED(LOG_OR1K)) |
or32_instruction_dump(r_pc_last, r_opcode, r_gpr, r_rd_wb, v_reg_result, r_sr); |
#endif |
|
// 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; |
mem_ifetch = 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? |
int m; |
for (m=0;m<MemRegions;m++) |
{ |
if (mem_addr >= MemBase[m] && mem_addr < (MemBase[m] + MemSize[m])) |
{ |
TAddress wordAddress = (mem_addr - MemBase[m]) / 4; |
TRegister mem_word = Mem[m][wordAddress]; |
mem_word = HTONL(mem_word); |
|
// Write |
switch (mem_wr) |
{ |
case 0xF: |
mem_word = mem_data_out; |
break; |
case 0x3: |
mem_data_out &= 0x0000FFFF; |
mem_word &=~ 0x0000FFFF; |
mem_word |= mem_data_out; |
break; |
case 0xC: |
mem_data_out &= 0xFFFF0000; |
mem_word &=~ 0xFFFF0000; |
mem_word |= mem_data_out; |
break; |
case 0x1: |
mem_data_out &= 0x000000FF; |
mem_word &=~ 0x000000FF; |
mem_word |= mem_data_out; |
break; |
case 0x2: |
mem_data_out &= 0x0000FF00; |
mem_word &=~ 0x0000FF00; |
mem_word |= mem_data_out; |
break; |
case 0x4: |
mem_data_out &= 0x00FF0000; |
mem_word &=~ 0x00FF0000; |
mem_word |= mem_data_out; |
break; |
case 0x8: |
mem_data_out &= 0xFF000000; |
mem_word &=~ 0xFF000000; |
mem_word |= mem_data_out; |
break; |
} |
|
Mem[m][wordAddress] = HTONL(mem_word); |
|
// Read |
mem_data_in = mem_word; |
|
if (!mem_ifetch) |
{ |
if (mem_wr && MemWriteHits[m]) |
MemWriteHits[m][wordAddress]++; |
else if (mem_rd && MemReadHits[m]) |
MemReadHits[m][wordAddress]++; |
} |
else if (MemInstHits[m]) |
MemInstHits[m][wordAddress]++; |
|
break; |
} |
} |
|
// External / Peripheral memory |
if (m == MemRegions) |
{ |
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 (EnablePutc) |
{ |
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; |
case NOP_STATS_RESET: |
ResetStats(); |
break; |
case NOP_STATS_MARKER: |
StatsMarkers++; |
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(" - Reads %d (%d%%)\n", (StatsMem - StatsMemWrites), ((StatsMem - StatsMemWrites) * 100) / StatsMem); |
printf(" - Writes %d (%d%%)\n", StatsMemWrites, (StatsMemWrites * 100) / StatsMem); |
printf("- MUL %d (%d%%)\n", StatsMul, (StatsMul * 100) / StatsInstructions); |
printf("- MULU %d (%d%%)\n", StatsMulu, (StatsMulu * 100) / StatsInstructions); |
printf("- NOPS %d (%d%%)\n", StatsNop, (StatsNop * 100) / StatsInstructions); |
printf("- Markers %d (%d%%)\n", StatsMarkers, (StatsMarkers * 100) / StatsInstructions); |
printf("- Branches Operations %d (%d%%)\n", StatsBranches, (StatsBranches * 100) / StatsInstructions); |
printf("- Exceptions %d (%d%%)\n", StatsExceptions, (StatsExceptions * 100) / StatsInstructions); |
|
FILE *f; |
int i; |
int m; |
|
for (m=0;m<MemRegions;m++) |
{ |
if (MemReadHits[m]) |
{ |
printf("Saving %s\n", MEMTRACE_READS); |
f = fopen(MEMTRACE_READS, "w"); |
if (f) |
{ |
for (i=0;i<MemSize[m]/4;i++) |
{ |
unsigned int addr = MemBase[m] + (i * 4); |
if (MemReadHits[m][i] > MEMTRACE_MIN) |
{ |
fprintf(f, "%08x %d\n", addr, MemReadHits[m][i]); |
} |
} |
fclose(f); |
} |
else |
fprintf (stderr,"Could not open file for writing\n"); |
} |
|
if (MemWriteHits[m]) |
{ |
printf("Saving %s\n", MEMTRACE_WRITES); |
f = fopen(MEMTRACE_WRITES, "w"); |
if (f) |
{ |
for (i=0;i<MemSize[m]/4;i++) |
{ |
unsigned int addr = MemBase[m] + (i * 4); |
if (MemWriteHits[m][i] > MEMTRACE_MIN) |
{ |
fprintf(f, "%08x %d\n", addr, MemWriteHits[m][i]); |
} |
} |
fclose(f); |
} |
else |
fprintf (stderr,"Could not open file for writing\n"); |
} |
|
if (MemInstHits[m]) |
{ |
printf("Saving %s\n", MEMTRACE_INST); |
f = fopen(MEMTRACE_INST, "w"); |
if (f) |
{ |
for (i=0;i<MemSize[m]/4;i++) |
{ |
unsigned int addr = MemBase[m] + (i * 4); |
if (MemInstHits[m][i] > MEMTRACE_MIN) |
{ |
fprintf(f, "%08x %d\n", addr, MemInstHits[m][i]); |
} |
} |
fclose(f); |
} |
else |
fprintf (stderr,"Could not open file for writing\n"); |
} |
} |
|
ResetStats(); |
} |
/or1k-sim/or32_isa.h
0,0 → 1,262
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#ifndef __OR32_ISA_H__ |
#define __OR32_ISA_H__ |
|
//----------------------------------------------------------------- |
// General: |
//----------------------------------------------------------------- |
typedef unsigned int TInstruction; |
typedef unsigned int TRegister; |
typedef unsigned int TAddress; |
typedef unsigned int TMemory; |
|
enum ERegisters |
{ |
REG_0_ZERO, |
REG_1_SP, |
REG_2_FP, |
REG_3, |
REG_4, |
REG_5, |
REG_6, |
REG_7, |
REG_8, |
REG_9_LR, |
REG_10, |
REG_11, |
REG_12, |
REG_13, |
REG_14, |
REG_15, |
REG_16, |
REG_17, |
REG_18, |
REG_19, |
REG_20, |
REG_21, |
REG_22, |
REG_23, |
REG_24, |
REG_25, |
REG_26, |
REG_27, |
REG_28, |
REG_29, |
REG_30, |
REG_31, |
REGISTERS |
}; |
|
//-------------------------------------------------------------------- |
// Instruction Encoding |
//-------------------------------------------------------------------- |
#define OR32_OPCODE_SHIFT 26 |
#define OR32_OPCODE_MASK 0x3F |
#define OR32_REG_D_SHIFT 21 |
#define OR32_REG_D_MASK 0x1F |
#define OR32_REG_A_SHIFT 16 |
#define OR32_REG_A_MASK 0x1F |
#define OR32_REG_B_SHIFT 11 |
#define OR32_REG_B_MASK 0x1F |
#define OR32_IMM16_SHIFT 0 |
#define OR32_IMM16_MASK 0xFFFF |
#define OR32_ADDR_SHIFT 0 |
#define OR32_ADDR_MASK 0x3FFFFFF |
#define OR32_ADDR_SIGN_SHIFT 25 |
#define OR32_SHIFT_OP_SHIFT 6 |
#define OR32_SHIFT_OP_MASK 0x3 |
#define OR32_SFXXX_OP_SHIFT 21 |
#define OR32_SFXXX_OP_MASK 0x7FF |
#define OR32_ALU_OP_L_SHIFT 0 |
#define OR32_ALU_OP_L_MASK 0xF |
#define OR32_ALU_OP_H_SHIFT 2 |
#define OR32_ALU_OP_H_MASK 0xF0 |
#define OR32_STORE_IMM_L_SHIFT 0 |
#define OR32_STORE_IMM_L_MASK 0x7FF |
#define OR32_STORE_IMM_H_SHIFT 10 |
#define OR32_STORE_IMM_H_MASK 0xF800 |
#define OR32_MFSPR_IMM_MASK 0xFFFF |
#define OR32_MTSPR_IMM_MASK 0x7FF |
|
//-------------------------------------------------------------------- |
// Instructions |
//-------------------------------------------------------------------- |
|
// ALU Instructions |
#define INST_OR32_ALU 0x38 |
#define INST_OR32_ADD 0x0000 |
#define INST_OR32_ADDC 0x0001 |
#define INST_OR32_AND 0x0003 |
#define INST_OR32_OR 0x0004 |
#define INST_OR32_SLL 0x0008 |
#define INST_OR32_SRA 0x0028 |
#define INST_OR32_SRL 0x0018 |
#define INST_OR32_SUB 0x0002 |
#define INST_OR32_XOR 0x0005 |
#define INST_OR32_MUL 0x00c6 |
#define INST_OR32_MULU 0x00cb |
|
// INST_OR32_SHIFTI Instructions |
#define INST_OR32_SHIFTI 0x2e |
#define INST_OR32_SLLI 0x0000 |
#define INST_OR32_SRAI 0x0002 |
#define INST_OR32_SRLI 0x0001 |
|
// General Instructions |
#define INST_OR32_ADDI 0x0027 |
#define INST_OR32_ANDI 0x0029 |
#define INST_OR32_BF 0x0004 |
#define INST_OR32_BNF 0x0003 |
#define INST_OR32_J 0x0000 |
#define INST_OR32_JAL 0x0001 |
#define INST_OR32_JALR 0x0012 |
#define INST_OR32_JR 0x0011 |
#define INST_OR32_LBS 0x0024 |
#define INST_OR32_LHS 0x0026 |
#define INST_OR32_LWS 0x0022 |
#define INST_OR32_LBZ 0x0023 |
#define INST_OR32_LHZ 0x0025 |
#define INST_OR32_LWZ 0x0021 |
#define INST_OR32_MFSPR 0x002d |
#define INST_OR32_MOVHI 0x0006 |
#define INST_OR32_MTSPR 0x0030 |
#define INST_OR32_NOP 0x0005 |
#define INST_OR32_ORI 0x002a |
#define INST_OR32_RFE 0x0009 |
#define INST_OR32_SB 0x0036 |
#define INST_OR32_SH 0x0037 |
#define INST_OR32_SW 0x0035 |
#define INST_OR32_XORI 0x002b |
#define INST_OR32_LBS 0x0024 |
#define INST_OR32_LBZ 0x0023 |
#define INST_OR32_LHS 0x0026 |
#define INST_OR32_LHZ 0x0025 |
#define INST_OR32_LWZ 0x0021 |
#define INST_OR32_LWS 0x0022 |
|
// Set Flag Instructions |
#define INST_OR32_SFXX 0x2f |
#define INST_OR32_SFXXI 0x39 |
#define INST_OR32_SFEQ 0x0720 |
#define INST_OR32_SFEQI 0x05e0 |
#define INST_OR32_SFGES 0x072b |
#define INST_OR32_SFGESI 0x05eb |
#define INST_OR32_SFGEU 0x0723 |
#define INST_OR32_SFGEUI 0x05e3 |
#define INST_OR32_SFGTS 0x072a |
#define INST_OR32_SFGTSI 0x05ea |
#define INST_OR32_SFGTU 0x0722 |
#define INST_OR32_SFGTUI 0x05e2 |
#define INST_OR32_SFLES 0x072d |
#define INST_OR32_SFLESI 0x05ed |
#define INST_OR32_SFLEU 0x0725 |
#define INST_OR32_SFLEUI 0x05e5 |
#define INST_OR32_SFLTS 0x072c |
#define INST_OR32_SFLTSI 0x05ec |
#define INST_OR32_SFLTU 0x0724 |
#define INST_OR32_SFLTUI 0x05e4 |
#define INST_OR32_SFNE 0x0721 |
#define INST_OR32_SFNEI 0x05e1 |
|
// Misc Instructions |
#define INST_OR32_MISC 0x08 |
#define INST_OR32_SYS 0x0020 |
#define INST_OR32_TRAP 0x0021 |
|
//-------------------------------------------------------------------- |
// SPR Register Map |
//-------------------------------------------------------------------- |
#define SPR_REG_VR 0 |
#define SPR_VERSION_CURRENT 0x00000000 |
#define SPR_REG_SR 17 |
#define SPR_REG_EPCR 32 |
#define SPR_REG_ESR 64 |
|
//-------------------------------------------------------------------- |
// SR Register bits |
//-------------------------------------------------------------------- |
#define OR32_SR_SM 0 |
#define OR32_SR_TEE 1 |
#define OR32_SR_IEE 2 |
#define OR32_SR_DCE 3 |
#define OR32_SR_ICE 4 |
#define OR32_SR_DME 5 |
#define OR32_SR_IME 6 |
#define OR32_SR_LEE 7 |
#define OR32_SR_CE 8 |
#define OR32_SR_F 9 |
#define OR32_SR_F_BIT (1 << OR32_SR_F) |
#define OR32_SR_CY 10 |
#define OR32_SR_CY_BIT (1 << OR32_SR_CY) |
#define OR32_SR_OV 11 |
#define OR32_SR_OV_BIT (1 << OR32_SR_OV) |
#define OR32_SR_OVE 12 |
#define OR32_SR_DSX 13 |
#define OR32_SR_EPH 14 |
#define OR32_SR_FO 15 |
#define OR32_SR_TED 16 |
|
//-------------------------------------------------------------------- |
// 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_STATS_RESET 0x000A |
#define NOP_PROFILE_ON 0x000B |
#define NOP_PROFILE_OFF 0x000C |
#define NOP_STATS_MARKER 0x000D |
|
//-------------------------------------------------------------------- |
// OR32 Vectors |
// NOTE: These differ from the real OR32 vectors for space reasons |
//-------------------------------------------------------------------- |
#define VECTOR_RESET 0x100 |
#define VECTOR_ILLEGAL_INST 0x200 |
#define VECTOR_EXTINT 0x300 |
#define VECTOR_SYSCALL 0x400 |
#define VECTOR_TRAP 0x600 |
#define VECTOR_NMI 0x700 |
#define VECTOR_BUS_ERROR 0x800 |
|
#endif |
|
/or1k-sim/or32_inst_dump.cpp
0,0 → 1,416
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; 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; |
case INST_OR32_MUL: // l.mul |
sprintf(output, "l.mul r%d,r%d,r%d", v_rd, v_ra, v_rb); |
break; |
case INST_OR32_MULU: // l.mulu |
sprintf(output, "l.mulu 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); |
} |
/or1k-sim/getopt_win32.h
0,0 → 1,37
// XGetopt.h Version 1.2 |
// |
// Author: Hans Dietrich |
// hdietrich2@hotmail.com |
// |
// This software is released into the public domain. |
// You are free to use it in any way you like. |
// |
// This software is provided "as is" with no expressed |
// or implied warranty. I accept no liability for any |
// damage or loss of business that this software may cause. |
// |
/////////////////////////////////////////////////////////////////////////////// |
|
#ifndef XGETOPT_H |
#define XGETOPT_H |
|
#ifdef __cplusplus |
extern "C" { |
#endif |
|
#ifdef WIN32 |
|
#include <windows.h> |
|
extern int optind, opterr; |
extern TCHAR *optarg; |
|
int getopt(int argc, TCHAR *argv[], TCHAR *optstring); |
|
#endif |
|
#ifdef __cplusplus |
} |
#endif |
|
#endif //XGETOPT_H |
/or1k-sim/README.txt
0,0 → 1,49
AltOR32 OpenRisc Simulator |
-------------------------- |
|
Details |
------- |
|
- Simple simulator for OpenRisc instructions, where only the essentials have been implemented. |
- Compiles under Linux (make) or Windows (VS2003+). |
- Able to execute OpenRisc 1000 (ORBIS32) code compiled with the following options: |
-msoft-div -msoft-float -msoft-mul -mno-ror -mno-cmov -mno-sext |
|
Usage |
----- |
|
-f filename.bin = Executable to load (binary) [Required] |
-t = Enable program trace [Optional] |
-v 0xX = Trace Mask [Optional] |
-b 0xnnnn = Memory base address [Optional] |
-s 0xnnnn = Memory size [Optional] |
-l 0xnnnn = Executable load address [Optional] |
-c nnnn = Max instructions to execute [Optional] |
|
Console Output |
-------------- |
|
This simulator implements some of the basic l.nop extensions such as NOP_PUTC(4). |
|
Example: |
|
void putc(int c) |
{ |
register char t1 asm ("r3") = c; |
asm volatile ("\tl.nop\t%0" : : "K" (4), "r" (t1)); |
} |
|
Implementing Peripherals |
------------------------ |
|
Peripherals can be implemented by creating a new class which inherits from 'Peripheral' and overrides the following functions to provide memory mapped I/O extensions; |
|
// Peripheral access |
virtual void Reset(void) |
virtual void Clock(void) |
virtual TRegister Access(TAddress addr, TRegister data_in, TRegister wr, TRegister rd) |
virtual bool Interrupt(void) |
virtual TAddress GetStartAddress() |
virtual TAddress GetStopAddress() |
|
The new peripheral can then be attached to the simulator (using AttachPeripheral). |
/or1k-sim/or32.h
0,0 → 1,227
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#ifndef __OR32_H__ |
#define __OR32_H__ |
|
#include "or32_isa.h" |
#include "peripheral.h" |
|
//-------------------------------------------------------------------- |
// Defines: |
//-------------------------------------------------------------------- |
#define LOG_OR1K (1 << 0) |
#define LOG_INST (1 << 1) |
#define LOG_REGISTERS (1 << 2) |
#define LOG_MEM (1 << 3) |
|
#define MAX_MEM_REGIONS 4 |
|
#define MAX_PERIPHERALS 10 |
|
//-------------------------------------------------------------------- |
// Class |
//-------------------------------------------------------------------- |
class OR32 |
{ |
public: |
OR32(bool delay_slot = true); |
OR32(unsigned int baseAddr, unsigned int len, bool delay_slot = true); |
virtual ~OR32(); |
|
bool CreateMemory(unsigned int baseAddr, unsigned int len); |
|
bool Load(unsigned int startAddr, unsigned char *data, int len); |
bool WriteMem(TAddress addr, unsigned char *data, int len); |
bool ReadMem(TAddress addr, unsigned char *data, int len); |
|
void Reset(TRegister start_addr = VECTOR_RESET); |
bool Clock(void); |
bool Step(void); |
|
int GetFault(void) { return Fault; } |
int GetBreak(void) { return Break; } |
TRegister GetRegister(int r) { return (r < REGISTERS) ? r_gpr[r] : 0; } |
TRegister GetPC(void) { return !DelaySlotEnabled ? r_pc : r_pc_next; } |
TRegister GetOpcode(TRegister address); |
|
void EnableTrace(unsigned mask) { Trace = mask; } |
void EnableOutput(bool en) { EnablePutc = en; } |
void EnableMemoryTrace(void); |
|
void ResetStats(void); |
void DumpStats(void); |
|
protected: |
void Decode(void); |
void Execute(void); |
void WriteBack(void); |
|
protected: |
|
// Peripheral access |
void PeripheralReset(void) |
{ |
int i; |
for (i=0;i<MAX_PERIPHERALS;i++) |
if (periperhals[i].instance) |
periperhals[i].instance->Reset(); |
} |
|
void PeripheralClock(void) |
{ |
int i; |
for (i=0;i<MAX_PERIPHERALS;i++) |
if (periperhals[i].instance) |
periperhals[i].instance->Clock(); |
} |
|
TRegister PeripheralAccess(TAddress addr, TRegister data_in, TRegister wr, TRegister rd) |
{ |
int i; |
for (i=0;i<MAX_PERIPHERALS;i++) |
if (periperhals[i].instance) |
if (addr >= periperhals[i].start_address && addr <= periperhals[i].end_address) |
return periperhals[i].instance->Access(addr, data_in, wr, rd); |
|
return 0; |
} |
|
bool PeripheralInterrupt(void) |
{ |
int i; |
bool interrupt = false; |
|
for (i=0;i<MAX_PERIPHERALS;i++) |
if (periperhals[i].instance) |
interrupt |= periperhals[i].instance->Interrupt(); |
|
return interrupt; |
} |
|
public: |
|
void AttachPeripheral(Peripheral *instance) |
{ |
int i; |
for (i=0;i<MAX_PERIPHERALS;i++) |
if (!periperhals[i].instance) |
{ |
periperhals[i].instance = instance; |
periperhals[i].start_address = instance->GetStartAddress(); |
periperhals[i].end_address = instance->GetStopAddress(); |
|
break; |
} |
} |
|
protected: |
// Execution monitoring |
virtual void MonInstructionExecute(TAddress addr, TRegister instr) { } |
virtual void MonDataLoad(TAddress addr, TRegister mask, TAddress value) { } |
virtual void MonDataStore(TAddress addr, TRegister mask, TAddress value) { } |
virtual void MonFault(TAddress addr, TRegister instr) { } |
virtual void MonExit(void) { } |
virtual void MonNop(TRegister imm); |
|
private: |
|
// CPU Registers |
TRegister r_gpr[REGISTERS]; |
TRegister r_pc; |
TRegister r_pc_next; |
TRegister r_pc_last; |
TRegister r_sr; |
TRegister r_epc; |
TRegister r_esr; |
|
// Register file access |
TRegister r_ra; |
TRegister r_rd; |
TRegister r_rd_wb; |
TRegister r_rb; |
TRegister r_reg_ra; |
TRegister r_reg_rb; |
TRegister r_reg_result; |
TRegister r_reg_rd_out; |
int r_writeback; |
TInstruction r_opcode; |
|
// Memory |
TMemory *Mem[MAX_MEM_REGIONS]; |
TAddress MemBase[MAX_MEM_REGIONS]; |
unsigned int MemSize[MAX_MEM_REGIONS]; |
int MemRegions; |
TAddress MemVectorBase; |
TRegister *MemInstHits[MAX_MEM_REGIONS]; |
TRegister *MemReadHits[MAX_MEM_REGIONS]; |
TRegister *MemWriteHits[MAX_MEM_REGIONS]; |
|
// Peripherals |
PeripheralInstance periperhals[MAX_PERIPHERALS]; |
|
// Memory access |
TAddress mem_addr; |
TRegister mem_data_out; |
TRegister mem_data_in; |
TRegister mem_offset; |
TRegister mem_wr; |
TRegister mem_rd; |
TRegister mem_ifetch; |
|
// Status |
int Fault; |
int Break; |
TRegister BreakValue; |
unsigned Trace; |
int Cycle; |
bool DelaySlotEnabled; |
bool TraceMemory; |
bool EnablePutc; |
|
// Stats |
int StatsMem; |
int StatsMemWrites; |
int StatsMulu; |
int StatsMul; |
int StatsMarkers; |
int StatsInstructions; |
int StatsNop; |
int StatsBranches; |
int StatsExceptions; |
}; |
|
#endif |
/or1k-sim/makefile
0,0 → 1,35
############################################################################### |
## Simulator Makefile |
############################################################################### |
|
# Target |
TARGET = or1knd-sim |
|
# Options |
CFLAGS = -DINCLUDE_INST_DUMP |
LDFLAGS = |
|
# Optional (you need libelf-dev) |
#CFLAGS += -DINCLUDE_ELF_SUPPORT |
#LIBS += -lelf |
|
# Source Files |
OBJ = main.o or32.o or32_inst_dump.o |
|
############################################################################### |
# Rules |
############################################################################### |
all: $(TARGET) |
|
clean: |
-rm *.o $(TARGET) |
|
%.o : %.c |
gcc -c $(CFLAGS) $< -o $@ |
|
%.o : %.cpp |
g++ -c $(CFLAGS) $< -o $@ |
|
$(TARGET): $(OBJ) makefile |
g++ $(LDFLAGS) $(OBJ) $(LIBS) -o $@ |
|
/or1k-sim/or32_inst_dump.h
0,0 → 1,49
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#ifndef _OR32_INST_DUMP_H_ |
#define _OR32_INST_DUMP_H_ |
|
#include "or32_isa.h" |
|
//----------------------------------------------------------------- |
// Prototypes: |
//----------------------------------------------------------------- |
int or32_instruction_to_string(TRegister opcode, char *output, int max_len); |
void or32_instruction_dump(TRegister pc, TRegister opcode, TRegister gpr[REGISTERS], TRegister rd, TRegister result, TRegister sr); |
|
#endif |
|
/or1k-sim/periph_timer.h
0,0 → 1,92
//----------------------------------------------------------------- |
// AltOR32 |
// Alternative Lightweight OpenRisc |
// V2.0 |
// Ultra-Embedded.com |
// Copyright 2011 - 2013 |
// |
// Email: admin@ultra-embedded.com |
// |
// License: LGPL |
//----------------------------------------------------------------- |
// |
// Copyright (C) 2011 - 2013 Ultra-Embedded.com |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source 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 Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, write to the |
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
// Boston, MA 02111-1307 USA |
//----------------------------------------------------------------- |
#ifndef __PERIPH_TIMER_H__ |
#define __PERIPH_TIMER_H__ |
|
#include "peripheral.h" |
|
//-------------------------------------------------------------------- |
// Defines: |
//-------------------------------------------------------------------- |
#define TIMER_BASE 0x12000100 |
|
//-------------------------------------------------------------------- |
// Class |
//-------------------------------------------------------------------- |
class TimerPeripheral: public Peripheral |
{ |
virtual void Reset(void) |
{ |
tick_count = 0; |
} |
|
virtual void Clock(void) |
{ |
static int ticks = 0; |
|
// 1ms tick, 1MHz clock rate... |
if (++ticks == 1000) |
{ |
tick_count++; |
ticks = 0; |
} |
} |
|
virtual TRegister Access(TAddress addr, TRegister data_in, TRegister wr, TRegister rd) |
{ |
switch (addr) |
{ |
case TIMER_BASE: |
return tick_count; |
} |
|
return 0; |
} |
|
virtual bool Interrupt(void) |
{ |
return false; |
} |
|
virtual TAddress GetStartAddress() { return TIMER_BASE; } |
virtual TAddress GetStopAddress() { return TIMER_BASE; } |
private: |
|
TRegister tick_count; |
}; |
|
#endif |