OpenCores
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.