OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/tags/nog_patch_50/or1ksim/cpu/or32
    from Rev 1425 to Rev 1765
    Reverse comparison

Rev 1425 → Rev 1765

/execute.c
0,0 → 1,810
/* execute.c -- OR1K architecture dependent simulation
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
 
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
/* Most of the OR1K simulation is done in here.
 
When SIMPLE_EXECUTION is defined below a file insnset.c is included!
*/
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
 
#include "config.h"
 
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
 
#include "port.h"
#include "arch.h"
#include "branch_predict.h"
#include "abstract.h"
#include "labels.h"
#include "parse.h"
#include "execute.h"
#include "except.h"
#include "sprs.h"
#include "sim-config.h"
#include "debug_unit.h"
#include "opcode/or32.h"
#include "immu.h"
#include "dmmu.h"
#include "debug.h"
#include "stats.h"
 
/* General purpose registers. */
uorreg_t reg[MAX_GPRS];
 
/* Instruction queue */
struct iqueue_entry iqueue[20];
 
/* Is current insn in execution a delay insn? */
int delay_insn;
 
/* Benchmark multi issue execution */
int multissue[20];
int issued_per_cycle = 4;
 
/* Completition queue */
struct iqueue_entry icomplet[20];
 
/* Program counter (and translated PC) */
oraddr_t pc;
 
/* Previous program counter */
oraddr_t pcprev = 0;
 
/* Temporary program counter */
oraddr_t pcnext;
 
/* Delay instruction effective address register */
oraddr_t pcdelay;
 
/* CCR */
int flag;
 
/* Store buffer analysis - stores are accumulated and commited when IO is idle */
static int sbuf_head = 0, sbuf_tail = 0, sbuf_count = 0;
static int sbuf_buf[MAX_SBUF_LEN] = {0};
static int sbuf_prev_cycles = 0;
 
/* Num cycles waiting for stores to complete */
int sbuf_wait_cyc = 0;
 
/* Number of total store cycles */
int sbuf_total_cyc = 0;
 
/* Whether we are doing statistical analysis */
int do_stats = 0;
 
/* Local data needed for execution. */
static int next_delay_insn;
static int breakpoint;
 
/* Effective address of instructions that have an effective address. This is
* only used to get dump_exe_log correct */
static oraddr_t insn_ea;
 
/* History of execution */
struct hist_exec *hist_exec_tail = NULL;
 
/* Implementation specific.
Get an actual value of a specific register. */
 
uorreg_t evalsim_reg(unsigned int regno)
{
if (regno < MAX_GPRS) {
return reg[regno];
} else {
PRINTF("\nABORT: read out of registers\n");
runtime.sim.cont_run = 0;
return 0;
}
}
 
/* Implementation specific.
Set a specific register with value. */
 
void setsim_reg(unsigned int regno, uorreg_t value)
{
if (regno == 0) /* gpr0 is always zero */
value = 0;
if (regno < MAX_GPRS) {
reg[regno] = value;
} else {
PRINTF("\nABORT: write out of registers\n");
runtime.sim.cont_run = 0;
}
}
 
/* Implementation specific.
Set a specific register with value. */
 
inline static void set_reg(int regno, uorreg_t value)
{
#if 0
if (strcmp(regstr, FRAME_REG) == 0) {
PRINTF("FP (%s) modified by insn at %x. ", FRAME_REG, pc);
PRINTF("Old:%.8lx New:%.8lx\n", eval_reg(regno), value);
}
if (strcmp(regstr, STACK_REG) == 0) {
PRINTF("SP (%s) modified by insn at %x. ", STACK_REG, pc);
PRINTF("Old:%.8lx New:%.8lx\n", eval_reg(regno), value);
}
#endif
 
if (regno < MAX_GPRS) {
reg[regno] = value;
#if RAW_RANGE_STATS
raw_stats.reg[regno] = runtime.sim.cycles;
#endif /* RAW_RANGE */
} else {
PRINTF("\nABORT: write out of registers\n");
runtime.sim.cont_run = 0;
}
}
 
/* Implementation specific.
Evaluates source operand opd. */
 
static uorreg_t eval_operand_val(uint32_t insn, struct insn_op_struct *opd)
{
unsigned long operand = 0;
unsigned long sbit;
unsigned int nbits = 0;
 
while(1) {
operand |= ((insn >> (opd->type & OPTYPE_SHR)) & ((1 << opd->data) - 1)) << nbits;
nbits += opd->data;
 
if(opd->type & OPTYPE_OP)
break;
opd++;
}
 
if(opd->type & OPTYPE_SIG) {
sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
if(operand & (1 << sbit)) operand |= ~REG_C(0) << sbit;
}
 
return operand;
}
 
/* Does source operand depend on computation of dstoperand? Return
non-zero if yes.
 
Cycle t Cycle t+1
dst: irrelevant src: immediate always 0
dst: reg1 direct src: reg2 direct 0 if reg1 != reg2
dst: reg1 disp src: reg2 direct always 0
dst: reg1 direct src: reg2 disp 0 if reg1 != reg2
dst: reg1 disp src: reg2 disp always 1 (store must
finish before load)
dst: flag src: flag always 1
*/
 
int depend_operands(prev, next)
struct iqueue_entry *prev;
struct iqueue_entry *next;
{
/* Find destination type. */
unsigned long type = 0;
int prev_dis, next_dis;
orreg_t prev_reg_val = 0;
struct insn_op_struct *opd;
 
if (or32_opcodes[prev->insn_index].flags & OR32_W_FLAG
&& or32_opcodes[next->insn_index].flags & OR32_R_FLAG)
return 1;
 
opd = op_start[prev->insn_index];
prev_dis = 0;
 
while (1) {
if (opd->type & OPTYPE_DIS)
prev_dis = 1;
 
if (opd->type & OPTYPE_DST) {
type = opd->type;
if (prev_dis)
type |= OPTYPE_DIS;
/* Destination is always a register */
prev_reg_val = eval_operand_val (prev->insn, opd);
break;
}
if (opd->type & OPTYPE_LAST)
return 0; /* Doesn't have a destination operand */
if (opd->type & OPTYPE_OP)
prev_dis = 0;
opd++;
}
 
/* We search all source operands - if we find confict => return 1 */
opd = op_start[next->insn_index];
next_dis = 0;
 
while (1) {
if (opd->type & OPTYPE_DIS)
next_dis = 1;
/* This instruction sequence also depends on order of execution:
* l.lw r1, k(r1)
* l.sw k(r1), r4
* Here r1 is a destination in l.sw */
/* FIXME: This situation is not handeld here when r1 == r2:
* l.sw k(r1), r4
* l.lw r3, k(r2)
*/
if (!(opd->type & OPTYPE_DST) || (next_dis && (opd->type & OPTYPE_DST))) {
if (opd->type & OPTYPE_REG)
if (eval_operand_val (next->insn, opd) == prev_reg_val)
return 1;
}
if (opd->type & OPTYPE_LAST)
break;
opd++;
}
 
return 0;
}
 
/* Sets a new SPR_SR_OV value, based on next register value */
 
#if SET_OV_FLAG
#define set_ov_flag(value) if((value) & 0x80000000) setsprbits (SPR_SR, SPR_SR_OV, 1); else setsprbits (SPR_SR, SPR_SR_OV, 0)
#else
#define set_ov_flag(value)
#endif
 
/* Modified by CZ 26/05/01 for new mode execution */
/* Fetch returns nonzero if instruction should NOT be executed. */
static inline int fetch()
{
static int break_just_hit = 0;
 
if (CHECK_BREAKPOINTS) {
/* MM: Check for breakpoint. This has to be done in fetch cycle,
because of peripheria.
MM1709: if we cannot access the memory entry, we could not set the
breakpoint earlier, so just check the breakpoint list. */
if (has_breakpoint (peek_into_itlb (pc)) && !break_just_hit) {
break_just_hit = 1;
return 1; /* Breakpoint set. */
}
break_just_hit = 0;
}
 
breakpoint = 0;
/* Fetch instruction. */
iqueue[0].insn_addr = pc;
iqueue[0].insn = eval_insn (pc, &breakpoint);
 
if (!except_pending)
runtime.cpu.instructions++;
 
/* update_pc will be called after execution */
 
return 0;
}
 
/* This code actually updates the PC value. */
static inline void update_pc ()
{
delay_insn = next_delay_insn;
pcprev = pc; /* Store value for later */
pc = pcnext;
pcnext = delay_insn ? pcdelay : pcnext + 4;
}
 
#if SIMPLE_EXECUTION
static inline
#endif
void analysis (struct iqueue_entry *current)
{
if (config.cpu.dependstats) {
/* Dynamic, dependency stats. */
adddstats(icomplet[0].insn_index, current->insn_index, 1, check_depend());
 
/* Dynamic, functional units stats. */
addfstats(or32_opcodes[icomplet[0].insn_index].func_unit,
or32_opcodes[current->insn_index].func_unit, 1, check_depend());
 
/* Dynamic, single stats. */
addsstats(current->insn_index, 1);
}
 
if (config.cpu.superscalar) {
if ((or32_opcodes[current->insn_index].func_unit == it_branch) ||
(or32_opcodes[current->insn_index].func_unit == it_jump))
runtime.sim.storecycles += 0;
if (or32_opcodes[current->insn_index].func_unit == it_store)
runtime.sim.storecycles += 1;
if (or32_opcodes[current->insn_index].func_unit == it_load)
runtime.sim.loadcycles += 1;
#if 0
if ((icomplet[0].func_unit == it_load) && check_depend())
runtime.sim.loadcycles++;
#endif
/* Pseudo multiple issue benchmark */
if ((multissue[or32_opcodes[current->insn_index].func_unit] < 1) ||
(check_depend()) || (issued_per_cycle < 1)) {
int i;
for (i = 0; i < 20; i++)
multissue[i] = 2;
issued_per_cycle = 2;
runtime.cpu.supercycles++;
if (check_depend())
runtime.cpu.hazardwait++;
multissue[it_unknown] = 2;
multissue[it_shift] = 2;
multissue[it_compare] = 1;
multissue[it_branch] = 1;
multissue[it_jump] = 1;
multissue[it_extend] = 2;
multissue[it_nop] = 2;
multissue[it_move] = 2;
multissue[it_movimm] = 2;
multissue[it_arith] = 2;
multissue[it_store] = 2;
multissue[it_load] = 2;
}
multissue[or32_opcodes[current->insn_index].func_unit]--;
issued_per_cycle--;
}
if (config.cpu.dependstats)
/* Instruction waits in completition buffer until retired. */
memcpy (&icomplet[0], current, sizeof (struct iqueue_entry));
 
if (config.sim.history) {
/* History of execution */
hist_exec_tail = hist_exec_tail->next;
hist_exec_tail->addr = icomplet[0].insn_addr;
}
 
if (config.sim.exe_log) dump_exe_log();
}
 
/* Store buffer analysis - stores are accumulated and commited when IO is idle */
static inline void sbuf_store (int cyc) {
int delta = runtime.sim.cycles - sbuf_prev_cycles;
sbuf_total_cyc += cyc;
sbuf_prev_cycles = runtime.sim.cycles;
//PRINTF (">STORE %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]);
//PRINTF ("|%i,%i\n", sbuf_total_cyc, sbuf_wait_cyc);
/* Take stores from buffer, that occured meanwhile */
while (sbuf_count && delta >= sbuf_buf[sbuf_tail]) {
delta -= sbuf_buf[sbuf_tail];
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN;
sbuf_count--;
}
if (sbuf_count)
sbuf_buf[sbuf_tail] -= delta;
 
/* Store buffer is full, take one out */
if (sbuf_count >= config.cpu.sbuf_len) {
sbuf_wait_cyc += sbuf_buf[sbuf_tail];
runtime.sim.mem_cycles += sbuf_buf[sbuf_tail];
sbuf_prev_cycles += sbuf_buf[sbuf_tail];
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN;
sbuf_count--;
}
/* Put newest store in the buffer */
sbuf_buf[sbuf_head] = cyc;
sbuf_head = (sbuf_head + 1) % MAX_SBUF_LEN;
sbuf_count++;
//PRINTF ("|STORE %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]);
}
 
/* Store buffer analysis - previous stores should commit, before any load */
static inline void sbuf_load () {
int delta = runtime.sim.cycles - sbuf_prev_cycles;
sbuf_prev_cycles = runtime.sim.cycles;
//PRINTF (">LOAD %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]);
//PRINTF ("|%i,%i\n", sbuf_total_cyc, sbuf_wait_cyc);
/* Take stores from buffer, that occured meanwhile */
while (sbuf_count && delta >= sbuf_buf[sbuf_tail]) {
delta -= sbuf_buf[sbuf_tail];
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN;
sbuf_count--;
}
if (sbuf_count)
sbuf_buf[sbuf_tail] -= delta;
 
/* Wait for all stores to complete */
while (sbuf_count > 0) {
sbuf_wait_cyc += sbuf_buf[sbuf_tail];
runtime.sim.mem_cycles += sbuf_buf[sbuf_tail];
sbuf_prev_cycles += sbuf_buf[sbuf_tail];
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN;
sbuf_count--;
}
//PRINTF ("|LOAD %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]);
}
 
/* Outputs dissasembled instruction */
void dump_exe_log ()
{
oraddr_t insn_addr = iqueue[0].insn_addr;
unsigned int i, j;
uorreg_t operand;
 
if (insn_addr == 0xffffffff) return;
if ((config.sim.exe_log_start <= runtime.cpu.instructions) &&
((config.sim.exe_log_end <= 0) ||
(runtime.cpu.instructions <= config.sim.exe_log_end))) {
if (config.sim.exe_log_marker &&
!(runtime.cpu.instructions % config.sim.exe_log_marker)) {
fprintf (runtime.sim.fexe_log, "--------------------- %8lli instruction ---------------------\n", runtime.cpu.instructions);
}
switch (config.sim.exe_log_type) {
case EXE_LOG_HARDWARE:
fprintf (runtime.sim.fexe_log, "\nEXECUTED(%11llu): %"PRIxADDR": ",
runtime.cpu.instructions, insn_addr);
fprintf (runtime.sim.fexe_log, "%.2x%.2x", evalsim_mem8_void(insn_addr),
evalsim_mem8_void(insn_addr + 1));
fprintf (runtime.sim.fexe_log, "%.2x%.2x",
evalsim_mem8_void(insn_addr + 2),
evalsim_mem8_void(insn_addr + 3));
for(i = 0; i < MAX_GPRS; i++) {
if (i % 4 == 0)
fprintf(runtime.sim.fexe_log, "\n");
fprintf (runtime.sim.fexe_log, "GPR%2u: %"PRIxREG" ", i, reg[i]);
}
fprintf (runtime.sim.fexe_log, "\n");
fprintf (runtime.sim.fexe_log, "SR : %.8lx ", mfspr(SPR_SR));
fprintf (runtime.sim.fexe_log, "EPCR0: %.8lx ", mfspr(SPR_EPCR_BASE));
fprintf (runtime.sim.fexe_log, "EEAR0: %.8lx ", mfspr(SPR_EEAR_BASE));
fprintf (runtime.sim.fexe_log, "ESR0 : %.8lx\n", mfspr(SPR_ESR_BASE));
break;
case EXE_LOG_SIMPLE:
case EXE_LOG_SOFTWARE:
{
extern char *disassembled;
disassemble_index (iqueue[0].insn, iqueue[0].insn_index);
{
struct label_entry *entry;
entry = get_label(insn_addr);
if (entry)
fprintf (runtime.sim.fexe_log, "%s:\n", entry->name);
}
 
if (config.sim.exe_log_type == EXE_LOG_SOFTWARE) {
struct insn_op_struct *opd = op_start[iqueue[0].insn_index];
j = 0;
while (1) {
operand = eval_operand_val (iqueue[0].insn, opd);
while (!(opd->type & OPTYPE_OP))
opd++;
if (opd->type & OPTYPE_DIS) {
fprintf (runtime.sim.fexe_log, "EA =%"PRIxADDR" PA =%"PRIxADDR" ",
insn_ea, peek_into_dtlb(insn_ea,0,0));
opd++; /* Skip of register operand */
j++;
} else if ((opd->type & OPTYPE_REG) && operand) {
fprintf (runtime.sim.fexe_log, "r%-2i=%"PRIxREG" ",
(int)operand, evalsim_reg (operand));
} else
fprintf (runtime.sim.fexe_log, " ");
j++;
if(opd->type & OPTYPE_LAST)
break;
opd++;
}
while(j < 3) {
fprintf (runtime.sim.fexe_log, " ");
j++;
}
}
fprintf (runtime.sim.fexe_log, "%"PRIxADDR" ", insn_addr);
fprintf (runtime.sim.fexe_log, "%s\n", disassembled);
}
}
}
}
 
/* Dump registers - 'r' or 't' command */
void dumpreg()
{
int i;
oraddr_t physical_pc;
 
if ((physical_pc = peek_into_itlb(iqueue[0].insn_addr))) {
/*
* PRINTF("\t\t\tEA: %08x <--> PA: %08x\n", iqueue[0].insn_addr, physical_pc);
*/
dumpmemory(physical_pc, physical_pc + 4, 1, 0);
}
else {
PRINTF("INTERNAL SIMULATOR ERROR:\n");
PRINTF("no translation for currently executed instruction\n");
}
// generate_time_pretty (temp, runtime.sim.cycles * config.sim.clkcycle_ps);
PRINTF(" (executed) [cycle %lld, #%lld]\n", runtime.sim.cycles,
runtime.cpu.instructions);
if (config.cpu.superscalar)
PRINTF ("Superscalar CYCLES: %u", runtime.cpu.supercycles);
if (config.cpu.hazards)
PRINTF (" HAZARDWAIT: %u\n", runtime.cpu.hazardwait);
else
if (config.cpu.superscalar)
PRINTF ("\n");
 
if ((physical_pc = peek_into_itlb(pc))) {
/*
* PRINTF("\t\t\tEA: %08x <--> PA: %08x\n", pc, physical_pc);
*/
dumpmemory(physical_pc, physical_pc + 4, 1, 0);
}
else
PRINTF("%"PRIxADDR": : xxxxxxxx ITLB miss follows", pc);
PRINTF(" (next insn) %s", (delay_insn?"(delay insn)":""));
for(i = 0; i < MAX_GPRS; i++) {
if (i % 4 == 0)
PRINTF("\n");
PRINTF("GPR%.2u: %"PRIxREG" ", i, evalsim_reg(i));
}
PRINTF("flag: %u\n", flag);
}
 
/* Generated/built in decoding/executing function */
static inline void decode_execute (struct iqueue_entry *current);
 
/* Wrapper around real decode_execute function -- some statistics here only */
static inline void decode_execute_wrapper (struct iqueue_entry *current)
{
breakpoint = 0;
 
#ifndef HAS_EXECUTION
#error HAS_EXECUTION has to be defined in order to execute programs.
#endif
decode_execute (current);
#if SET_OV_FLAG
/* Check for range exception */
if (testsprbits (SPR_SR, SPR_SR_OVE) && testsprbits (SPR_SR, SPR_SR_OV))
except_handle (EXCEPT_RANGE, mfspr(SPR_EEAR_BASE));
#endif
 
if(breakpoint)
except_handle(EXCEPT_TRAP, mfspr(SPR_EEAR_BASE));
}
 
/* Reset the CPU */
void cpu_reset()
{
int i;
struct hist_exec *hist_exec_head = NULL;
struct hist_exec *hist_exec_new;
 
runtime.sim.cycles = 0;
runtime.sim.loadcycles = 0;
runtime.sim.storecycles = 0;
runtime.cpu.instructions = 0;
runtime.cpu.supercycles = 0;
runtime.cpu.hazardwait = 0;
for (i = 0; i < MAX_GPRS; i++)
set_reg (i, 0);
memset(iqueue, 0, sizeof(iqueue));
memset(icomplet, 0, sizeof(icomplet));
sbuf_head = 0;
sbuf_tail = 0;
sbuf_count = 0;
sbuf_prev_cycles = 0;
 
/* Initialise execution history circular buffer */
for (i = 0; i < HISTEXEC_LEN; i++) {
hist_exec_new = malloc(sizeof(struct hist_exec));
if(!hist_exec_new) {
fprintf(stderr, "Out-of-memory\n");
exit(1);
}
if(!hist_exec_head)
hist_exec_head = hist_exec_new;
else
hist_exec_tail->next = hist_exec_new;
 
hist_exec_new->prev = hist_exec_tail;
hist_exec_tail = hist_exec_new;
}
/* Make hist_exec_tail->next point to hist_exec_head */
hist_exec_tail->next = hist_exec_head;
hist_exec_head->prev = hist_exec_tail;
 
/* Cpu configuration */
mtspr(SPR_UPR, config.cpu.upr);
setsprbits(SPR_VR, SPR_VR_VER, config.cpu.ver);
setsprbits(SPR_VR, SPR_VR_REV, config.cpu.rev);
mtspr(SPR_SR, config.cpu.sr);
 
pcnext = 0x0; /* MM1409: All programs should start at reset vector entry! */
if (config.sim.verbose) PRINTF ("Starting at 0x%"PRIxADDR"\n", pcnext);
pc = pcnext;
pcnext += 4;
debug(1, "reset ...\n");
/* MM1409: All programs should set their stack pointer! */
except_handle(EXCEPT_RESET, 0);
update_pc();
except_pending = 0;
}
 
/* Simulates one CPU clock cycle */
inline int cpu_clock ()
{
except_pending = 0;
next_delay_insn = 0;
if(fetch()) {
PRINTF ("Breakpoint hit.\n");
runtime.sim.cont_run = 0; /* memory breakpoint encountered */
return 1;
}
 
if(except_pending) {
update_pc();
except_pending = 0;
return 0;
}
 
if(breakpoint) {
except_handle(EXCEPT_TRAP, mfspr(SPR_EEAR_BASE));
update_pc();
except_pending = 0;
return 0;
}
 
decode_execute_wrapper (&iqueue[0]);
update_pc();
return 0;
}
 
/* If decoding cannot be found, call this function */
#if SIMPLE_EXECUTION
void l_invalid (struct iqueue_entry *current) {
#else
void l_invalid () {
#endif
except_handle(EXCEPT_ILLEGAL, iqueue[0].insn_addr);
}
 
#if !SIMPLE_EXECUTION
 
/* Include decode_execute function */
#include "execgen.c"
 
#else /* SIMPLE_EXECUTION */
 
 
#define INSTRUCTION(name) void name (struct iqueue_entry *current)
 
/* Implementation specific.
Get an actual value of a specific register. */
 
static uorreg_t eval_reg(unsigned int regno)
{
if (regno < MAX_GPRS) {
#if RAW_RANGE_STATS
int delta = (runtime.sim.cycles - raw_stats.reg[regno]);
if ((unsigned long)delta < (unsigned long)MAX_RAW_RANGE)
raw_stats.range[delta]++;
#endif /* RAW_RANGE */
return reg[regno];
} else {
PRINTF("\nABORT: read out of registers\n");
runtime.sim.cont_run = 0;
return 0;
}
}
 
/* Implementation specific.
Evaluates source operand op_no. */
 
static uorreg_t eval_operand (int op_no, unsigned long insn_index, uint32_t insn)
{
struct insn_op_struct *opd = op_start[insn_index];
uorreg_t ret;
 
while (op_no) {
if(opd->type & OPTYPE_LAST) {
fprintf (stderr, "Instruction requested more operands than it has\n");
exit (1);
}
if((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS))
op_no--;
opd++;
}
 
if (opd->type & OPTYPE_DIS) {
ret = eval_operand_val (insn, opd);
while (!(opd->type & OPTYPE_OP))
opd++;
opd++;
ret += eval_reg (eval_operand_val (insn, opd));
insn_ea = ret;
return ret;
}
if (opd->type & OPTYPE_REG)
return eval_reg (eval_operand_val (insn, opd));
 
return eval_operand_val (insn, opd);
}
 
/* Implementation specific.
Set destination operand (reister direct) with value. */
inline static void set_operand(int op_no, orreg_t value,
unsigned long insn_index, uint32_t insn)
{
struct insn_op_struct *opd = op_start[insn_index];
 
while (op_no) {
if(opd->type & OPTYPE_LAST) {
fprintf (stderr, "Instruction requested more operands than it has\n");
exit (1);
}
if((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS))
op_no--;
opd++;
}
 
if (!(opd->type & OPTYPE_REG)) {
fprintf (stderr, "Trying to set a non-register operand\n");
exit (1);
}
set_reg (eval_operand_val (insn, opd), value);
}
 
/* Simple and rather slow decoding function based on built automata. */
static inline void decode_execute (struct iqueue_entry *current)
{
int insn_index;
current->insn_index = insn_index = insn_decode(current->insn);
 
if (insn_index < 0)
l_invalid(current);
else {
or32_opcodes[insn_index].exec(current);
}
if (do_stats) analysis(&iqueue[0]);
}
 
#define SET_PARAM0(val) set_operand(0, val, current->insn_index, current->insn)
 
#define PARAM0 eval_operand(0, current->insn_index, current->insn)
#define PARAM1 eval_operand(1, current->insn_index, current->insn)
#define PARAM2 eval_operand(2, current->insn_index, current->insn)
 
#include "insnset.c"
 
#endif /* !SIMPLE_EXECUTION */
/insnset.c
0,0 → 1,565
/* execute.c -- Instruction specific functions.
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
2000-2002 Marko Mlinar, markom@opencores.org
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
INSTRUCTION (l_add) {
orreg_t temp1, temp2, temp3;
int8_t temp4;
temp2 = (orreg_t)PARAM2;
temp3 = (orreg_t)PARAM1;
temp1 = temp2 + temp3;
SET_PARAM0(temp1);
set_ov_flag (temp1);
if (ARITH_SET_FLAG) {
flag = temp1 == 0;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
if ((uorreg_t) temp1 < (uorreg_t) temp2)
setsprbits(SPR_SR, SPR_SR_CY, 1);
else
setsprbits(SPR_SR, SPR_SR_CY, 0);
 
temp4 = temp1;
if (temp4 == temp1)
or1k_mstats.byteadd++;
}
INSTRUCTION (l_addc) {
orreg_t temp1, temp2, temp3;
int8_t temp4;
temp2 = (orreg_t)PARAM2;
temp3 = (orreg_t)PARAM1;
temp1 = temp2 + temp3 + getsprbits(SPR_SR, SPR_SR_CY);
SET_PARAM0(temp1);
set_ov_flag (temp1);
if (ARITH_SET_FLAG) {
flag = temp1 == 0;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
if ((uorreg_t) temp1 < (uorreg_t) temp2)
setsprbits(SPR_SR, SPR_SR_CY, 1);
else
setsprbits(SPR_SR, SPR_SR_CY, 0);
 
temp4 = temp1;
if (temp4 == temp1)
or1k_mstats.byteadd++;
}
INSTRUCTION (l_sw) {
int old_cyc = 0;
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
set_mem32(PARAM0, PARAM1, &breakpoint);
if (config.cpu.sbuf_len) {
int t = runtime.sim.mem_cycles;
runtime.sim.mem_cycles = old_cyc;
sbuf_store (t - old_cyc);
}
}
INSTRUCTION (l_sb) {
int old_cyc = 0;
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
set_mem8(PARAM0, PARAM1, &breakpoint);
if (config.cpu.sbuf_len) {
int t = runtime.sim.mem_cycles;
runtime.sim.mem_cycles = old_cyc;
sbuf_store (t- old_cyc);
}
}
INSTRUCTION (l_sh) {
int old_cyc = 0;
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
set_mem16(PARAM0, PARAM1, &breakpoint);
if (config.cpu.sbuf_len) {
int t = runtime.sim.mem_cycles;
runtime.sim.mem_cycles = old_cyc;
sbuf_store (t - old_cyc);
}
}
INSTRUCTION (l_lwz) {
uint32_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem32(PARAM1, &breakpoint);
/* If eval operand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lbs) {
int8_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem8(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lbz) {
uint8_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem8(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lhs) {
int16_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem16(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lhz) {
uint16_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem16(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_movhi) {
SET_PARAM0(PARAM1 << 16);
}
INSTRUCTION (l_and) {
uorreg_t temp1;
temp1 = PARAM1 & PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
if (ARITH_SET_FLAG) {
flag = temp1 == 0;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
}
INSTRUCTION (l_or) {
uorreg_t temp1;
temp1 = PARAM1 | PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
}
INSTRUCTION (l_xor) {
uorreg_t temp1;
temp1 = PARAM1 ^ PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
}
INSTRUCTION (l_sub) {
orreg_t temp1;
temp1 = (orreg_t)PARAM1 - (orreg_t)PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
}
/*int mcount = 0;*/
INSTRUCTION (l_mul) {
orreg_t temp1;
temp1 = (orreg_t)PARAM1 * (orreg_t)PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
/*if (!(mcount++ & 1023)) {
PRINTF ("[%i]\n",mcount);
}*/
}
INSTRUCTION (l_div) {
orreg_t temp3, temp2, temp1;
temp3 = PARAM2;
temp2 = PARAM1;
if (temp3)
temp1 = temp2 / temp3;
else {
except_handle(EXCEPT_ILLEGAL, iqueue[0].insn_addr);
return;
}
set_ov_flag (temp1);
SET_PARAM0(temp1);
}
INSTRUCTION (l_divu) {
uorreg_t temp3, temp2, temp1;
temp3 = PARAM2;
temp2 = PARAM1;
if (temp3)
temp1 = temp2 / temp3;
else {
except_handle(EXCEPT_ILLEGAL, iqueue[0].insn_addr);
return;
}
set_ov_flag (temp1);
SET_PARAM0(temp1);
/* runtime.sim.cycles += 16; */
}
INSTRUCTION (l_sll) {
uorreg_t temp1;
 
temp1 = PARAM1 << PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
/* runtime.sim.cycles += 2; */
}
INSTRUCTION (l_sra) {
orreg_t temp1;
temp1 = (orreg_t)PARAM1 >> PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
/* runtime.sim.cycles += 2; */
}
INSTRUCTION (l_srl) {
uorreg_t temp1;
temp1 = PARAM1 >> PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
/* runtime.sim.cycles += 2; */
}
INSTRUCTION (l_bf) {
if (config.bpb.enabled) {
int fwd = (PARAM0 >= pc) ? 1 : 0;
or1k_mstats.bf[flag][fwd]++;
bpb_update(current->insn_addr, flag);
}
if (flag) {
pcdelay = pc + (orreg_t)PARAM0 * 4;
btic_update(pcnext);
next_delay_insn = 1;
} else {
btic_update(pc);
}
}
INSTRUCTION (l_bnf) {
if (config.bpb.enabled) {
int fwd = (PARAM0 >= pc) ? 1 : 0;
or1k_mstats.bnf[!flag][fwd]++;
bpb_update(current->insn_addr, flag == 0);
}
if (flag == 0) {
pcdelay = pc + (orreg_t)PARAM0 * 4;
btic_update(pcnext);
next_delay_insn = 1;
} else {
btic_update(pc);
}
}
INSTRUCTION (l_j) {
pcdelay = pc + (orreg_t)PARAM0 * 4;
next_delay_insn = 1;
}
INSTRUCTION (l_jal) {
pcdelay = pc + (orreg_t)PARAM0 * 4;
set_reg(LINK_REGNO, pc + 8);
next_delay_insn = 1;
if (config.sim.profile) {
struct label_entry *tmp;
if (verify_memoryarea(pcdelay) && (tmp = get_label (pcdelay)))
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" %s\n",
runtime.sim.cycles, pc + 8, pcdelay, tmp->name);
else
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" @%"PRIxADDR"\n",
runtime.sim.cycles, pc + 8, pcdelay, pcdelay);
}
}
INSTRUCTION (l_jalr) {
pcdelay = PARAM0;
set_reg(LINK_REGNO, pc + 8);
next_delay_insn = 1;
}
INSTRUCTION (l_jr) {
pcdelay = PARAM0;
next_delay_insn = 1;
if (config.sim.profile)
fprintf (runtime.sim.fprof, "-%08llX %"PRIxADDR"\n", runtime.sim.cycles,
pcdelay);
}
INSTRUCTION (l_rfe) {
pcnext = mfspr(SPR_EPCR_BASE);
mtspr(SPR_SR, mfspr(SPR_ESR_BASE));
}
INSTRUCTION (l_nop) {
oraddr_t stackaddr;
uint32_t k = PARAM0;
switch (k) {
case NOP_NOP:
break;
case NOP_EXIT:
PRINTF("exit(%"PRIdREG")\n", evalsim_reg (3));
fprintf(stderr, "@reset : cycles %lld, insn #%lld\n",
runtime.sim.reset_cycles, runtime.cpu.reset_instructions);
fprintf(stderr, "@exit : cycles %lld, insn #%lld\n", runtime.sim.cycles,
runtime.cpu.instructions);
fprintf(stderr, " diff : cycles %lld, insn #%lld\n",
runtime.sim.cycles - runtime.sim.reset_cycles,
runtime.cpu.instructions - runtime.cpu.reset_instructions);
if (config.debug.gdb_enabled)
set_stall_state (1);
else
runtime.sim.cont_run = 0;
break;
case NOP_CNT_RESET:
PRINTF("****************** counters reset ******************\n");
PRINTF("cycles %lld, insn #%lld\n", runtime.sim.cycles, runtime.cpu.instructions);
PRINTF("****************** counters reset ******************\n");
runtime.sim.reset_cycles = runtime.sim.cycles;
runtime.cpu.reset_instructions = runtime.cpu.instructions;
break;
case NOP_PRINTF:
stackaddr = evalsim_reg(4);
simprintf(stackaddr, evalsim_reg(3));
debug(5, "simprintf %x\n", stackaddr);
break;
case NOP_REPORT:
PRINTF("report(0x%"PRIdREG");\n", evalsim_reg(3));
default:
if (k >= NOP_REPORT_FIRST && k <= NOP_REPORT_LAST)
PRINTF("report %i (0x%"PRIxREG");\n", k - NOP_REPORT_FIRST,
evalsim_reg(3));
break;
}
}
INSTRUCTION (l_sfeq) {
flag = PARAM0 == PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sfne) {
flag = PARAM0 != PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sfgts) {
flag = (orreg_t)PARAM0 > (orreg_t)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sfges) {
flag = (orreg_t)PARAM0 >= (orreg_t)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sflts) {
flag = (orreg_t)PARAM0 < (orreg_t)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sfles) {
flag = (orreg_t)PARAM0 <= (orreg_t)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sfgtu) {
flag = PARAM0 > PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sfgeu) {
flag = PARAM0 >= PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sfltu) {
flag = PARAM0 < PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_sfleu) {
flag = PARAM0 <= PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (l_extbs) {
int8_t x;
x = PARAM1;
SET_PARAM0((orreg_t)x);
}
INSTRUCTION (l_extbz) {
uint8_t x;
x = PARAM1;
SET_PARAM0((uorreg_t)x);
}
INSTRUCTION (l_exths) {
int16_t x;
x = PARAM1;
SET_PARAM0((orreg_t)x);
}
INSTRUCTION (l_exthz) {
uint16_t x;
x = PARAM1;
SET_PARAM0((uorreg_t)x);
}
INSTRUCTION (l_extws) {
int32_t x;
x = PARAM1;
SET_PARAM0((orreg_t)x);
}
INSTRUCTION (l_extwz) {
uint32_t x;
x = PARAM1;
SET_PARAM0((uorreg_t)x);
}
INSTRUCTION (l_mtspr) {
uint16_t regno = PARAM0 + PARAM2;
uorreg_t value = PARAM1;
 
if (runtime.sim.fspr_log) {
fprintf(runtime.sim.fspr_log, "Write to SPR : [%08"PRIx16"] <- [%08"PRIx32"]\n", regno, value);
}
 
if (mfspr(SPR_SR) & SPR_SR_SM)
mtspr(regno, value);
else {
PRINTF("WARNING: trying to write SPR while SR[SUPV] is cleared.\n");
runtime.sim.cont_run = 0;
}
}
INSTRUCTION (l_mfspr) {
uint16_t regno = PARAM1 + PARAM2;
uorreg_t value = mfspr(regno);
 
if (runtime.sim.fspr_log) {
fprintf(runtime.sim.fspr_log, "Read from SPR : [%08"PRIx16"] -> [%08"PRIx32"]\n", regno, value);
}
 
if (mfspr(SPR_SR) & SPR_SR_SM)
SET_PARAM0(value);
else {
SET_PARAM0(0);
PRINTF("WARNING: trying to read SPR while SR[SUPV] is cleared.\n");
runtime.sim.cont_run = 0;
}
}
INSTRUCTION (l_sys) {
except_handle(EXCEPT_SYSCALL, mfspr(SPR_EEAR_BASE));
}
INSTRUCTION (l_trap) {
/* TODO: some SR related code here! */
except_handle(EXCEPT_TRAP, mfspr(SPR_EEAR_BASE));
}
INSTRUCTION (l_mac) {
sprword lo, hi;
LONGEST l;
orreg_t x, y;
 
lo = mfspr (SPR_MACLO);
hi = mfspr (SPR_MACHI);
x = PARAM0;
y = PARAM1;
PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y);
l = (ULONGEST)lo | ((LONGEST)hi << 32);
l += (LONGEST) x * (LONGEST) y;
 
/* This implementation is very fast - it needs only one cycle for mac. */
lo = ((ULONGEST)l) & 0xFFFFFFFF;
hi = ((LONGEST)l) >> 32;
mtspr (SPR_MACLO, lo);
mtspr (SPR_MACHI, hi);
PRINTF ("(%08lx,%08lx)\n", hi, lo);
}
INSTRUCTION (l_msb) {
sprword lo, hi;
LONGEST l;
orreg_t x, y;
 
lo = mfspr (SPR_MACLO);
hi = mfspr (SPR_MACHI);
x = PARAM0;
y = PARAM1;
 
PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y);
 
l = (ULONGEST)lo | ((LONGEST)hi << 32);
l -= x * y;
 
/* This implementation is very fast - it needs only one cycle for msb. */
lo = ((ULONGEST)l) & 0xFFFFFFFF;
hi = ((LONGEST)l) >> 32;
mtspr (SPR_MACLO, lo);
mtspr (SPR_MACHI, hi);
PRINTF ("(%08lx,%08lx)\n", hi, lo);
}
INSTRUCTION (l_macrc) {
sprword lo, hi;
LONGEST l;
/* No need for synchronization here -- all MAC instructions are 1 cycle long. */
lo = mfspr (SPR_MACLO);
hi = mfspr (SPR_MACHI);
l = (ULONGEST) lo | ((LONGEST)hi << 32);
l >>= 28;
//PRINTF ("<%08x>\n", (unsigned long)l);
SET_PARAM0((orreg_t)l);
mtspr (SPR_MACLO, 0);
mtspr (SPR_MACHI, 0);
}
INSTRUCTION (l_cmov) {
SET_PARAM0(flag ? PARAM1 : PARAM2);
}
INSTRUCTION (l_ff1) {
SET_PARAM0(ffs(PARAM1));
}
/******* Floating point instructions *******/
/* Single precision */
INSTRUCTION (lf_add_s) {
SET_PARAM0((float)PARAM1 + (float)PARAM2);
}
INSTRUCTION (lf_div_s) {
SET_PARAM0((float)PARAM1 / (float)PARAM2);
}
INSTRUCTION (lf_ftoi_s) {
// set_operand32(0, freg[get_operand(1)], &breakpoint);
}
INSTRUCTION (lf_itof_s) {
// freg[get_operand(0)] = eval_operand32(1, &breakpoint);
}
INSTRUCTION (lf_madd_s) {
SET_PARAM0((float)PARAM0 + (float)PARAM1 * (float)PARAM2);
}
INSTRUCTION (lf_mul_s) {
SET_PARAM0((float)PARAM1 * (float)PARAM2);
}
INSTRUCTION (lf_rem_s) {
float temp = (float)PARAM1 / (float)PARAM2;
SET_PARAM0(temp - (uint32_t)temp);
}
INSTRUCTION (lf_sfeq_s) {
flag = (float)PARAM0 == (float)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (lf_sfge_s) {
flag = (float)PARAM0 >= (float)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (lf_sfgt_s) {
flag = (float)PARAM0 > (float)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (lf_sfle_s) {
flag = (float)PARAM0 <= (float)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (lf_sflt_s) {
flag = (float)PARAM0 < (float)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (lf_sfne_s) {
flag = (float)PARAM0 != (float)PARAM1;
setsprbits(SPR_SR, SPR_SR_F, flag);
}
INSTRUCTION (lf_sub_s) {
SET_PARAM0((float)PARAM1 - (float)PARAM2);
}
 
/******* Custom instructions *******/
INSTRUCTION (l_cust1) {
/*int destr = current->insn >> 21;
int src1r = current->insn >> 15;
int src2r = current->insn >> 9;*/
}
INSTRUCTION (l_cust2) {
}
INSTRUCTION (l_cust3) {
}
INSTRUCTION (l_cust4) {
}
insnset.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: or32.c =================================================================== --- or32.c (nonexistent) +++ or32.c (revision 1765) @@ -0,0 +1,1295 @@ +/* Table of opcodes for the OpenRISC 1000 ISA. + Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Contributed by Damjan Lampret (lampret@opencores.org). + +This file is part of gen_or1k_isa, or1ksim, GDB and GAS. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * $Log: not supported by cvs2svn $ + * Revision 1.41 2005/02/09 17:41:03 nogj + * Mark a simulated cpu address as such, by introducing the new oraddr_t type + * + * Revision 1.40 2005/01/27 14:14:13 nogj + * Remove the global op structure + * + * Revision 1.39 2005/01/27 13:35:40 nogj + * * Fix generate.c to produce a execgen.c with less warnings. + * * Fix the --enable-simple configure option. + * + * Revision 1.38 2005/01/27 13:15:50 nogj + * Mark wich operand is the destination operand in the architechture definition + * + * Revision 1.37 2005/01/11 15:41:58 andreje + * l.ff1 instruction added + * + * Revision 1.36 2004/07/22 20:17:23 phoenix + * removed includes + * + * Revision 1.35 2004/07/19 23:07:37 phoenix + * Gyorgy Jeney: extensive cleanup + * + * Revision 1.34 2004/06/27 22:56:48 lampret + * Updated instruction set descriptions. Changed FP instructions encoding. + * + * Revision 1.33 2004/05/09 19:52:31 lampret + * Changed desciption of the l.cust5 insns + * + * Revision 1.31 2003/07/01 19:34:49 csanchez + * Added support for l.addc instruction. + * + * Revision 1.30 2003/01/28 03:49:24 lampret + * Added cvs log keywords + * + */ + +#include +#include +#include +#include + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAS_EXECUTION +# ifdef HAVE_INTTYPES_H +# include /* ...but to get arch.h we need uint{8,16,32}_t... */ +# endif +# include "port.h" +# include "arch.h" /* ...but to get abstract.h, we need oraddr_t... */ +# include "abstract.h" /* To get struct iqueue_entry... */ +#endif +#include "opcode/or32.h" + +/* **INDENT-OFF** */ + +/* We treat all letters the same in encode/decode routines so + we need to assign some characteristics to them like signess etc.*/ +CONST struct or32_letter or32_letters[] = +{ +{ 'A', NUM_UNSIGNED }, +{ 'B', NUM_UNSIGNED }, +{ 'D', NUM_UNSIGNED }, +{ 'I', NUM_SIGNED }, +{ 'K', NUM_UNSIGNED }, +{ 'L', NUM_UNSIGNED }, +{ 'N', NUM_SIGNED }, +{ '0', NUM_UNSIGNED }, +{ '\0', 0 } /* dummy entry */ +}; + +/* Opcode encoding: + machine[31:30]: first two bits of opcode + 00 - neither of source operands is GPR + 01 - second source operand is GPR (rB) + 10 - first source operand is GPR (rA) + 11 - both source operands are GPRs (rA and rB) + machine[29:26]: next four bits of opcode + machine[25:00]: instruction operands (specific to individual instruction) + + Recommendation: irrelevant instruction bits should be set with a value of + bits in same positions of instruction preceding current instruction in the + code (when assembling). +*/ + +#ifdef HAS_EXECUTION +# if SIMPLE_EXECUTION +# define EFN &l_none +# define EF(func) &(func) +# define EFI &l_invalid +# else /* SIMPLE_EXECUTION */ +# define EFN "l_none" +# define EFI "l_invalid" +# ifdef __GNUC__ +# define EF(func) #func +# else +# define EF(func) "func" +# endif +# endif /* SIMPLE_EXECUTION */ +#else /* HAS_EXECUTION */ +# define EFN &l_none +# define EF(func) EFN +# define EFI EFN +#endif /* HAS_EXECUTION */ + +CONST struct or32_opcode or32_opcodes[] = +{ + +{ "l.j", "N", "00 0x0 NNNNN NNNNN NNNN NNNN NNNN NNNN", + EF(l_j), OR32_IF_DELAY, it_jump }, +{ "l.jal", "N", "00 0x1 NNNNN NNNNN NNNN NNNN NNNN NNNN", + EF(l_jal), OR32_IF_DELAY, it_jump }, +{ "l.bnf", "N", "00 0x3 NNNNN NNNNN NNNN NNNN NNNN NNNN", + EF(l_bnf), OR32_IF_DELAY | OR32_R_FLAG, it_branch }, +{ "l.bf", "N", "00 0x4 NNNNN NNNNN NNNN NNNN NNNN NNNN", + EF(l_bf), OR32_IF_DELAY | OR32_R_FLAG, it_branch }, +{ "l.nop", "K", "00 0x5 01--- ----- KKKK KKKK KKKK KKKK", + EF(l_nop), 0, it_nop }, +{ "l.movhi", "rD,K", "00 0x6 DDDDD ----0 KKKK KKKK KKKK KKKK", + EF(l_movhi), 0, it_movimm }, +{ "l.macrc", "rD", "00 0x6 DDDDD ----1 0000 0000 0000 0000", + EF(l_macrc), 0, it_mac }, +{ "l.sys", "K", "00 0x8 00000 00000 KKKK KKKK KKKK KKKK", + EF(l_sys), 0, it_unknown }, +{ "l.trap", "K", "00 0x8 01000 00000 KKKK KKKK KKKK KKKK", + EF(l_trap), 0, it_unknown }, +{ "l.msync", "", "00 0x8 10000 00000 0000 0000 0000 0000", EFN, + 0, it_unknown }, +{ "l.psync", "", "00 0x8 10100 00000 0000 0000 0000 0000", EFN, + 0, it_unknown }, +{ "l.csync", "", "00 0x8 11000 00000 0000 0000 0000 0000", EFN, + 0, it_unknown }, +{ "l.rfe", "", "00 0x9 ----- ----- ---- ---- ---- ----", + EF(l_rfe), OR32_IF_DELAY, it_exception }, +{ "lv.all_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x0", EFI, 0, + it_unknown }, +{ "lv.all_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x1", EFI, 0, + it_unknown }, +{ "lv.all_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x2", EFI, 0, + it_unknown }, +{ "lv.all_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x3", EFI, 0, + it_unknown }, +{ "lv.all_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x4", EFI, 0, + it_unknown }, +{ "lv.all_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x5", EFI, 0, + it_unknown }, +{ "lv.all_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x6", EFI, 0, + it_unknown }, +{ "lv.all_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x7", EFI, 0, + it_unknown }, +{ "lv.all_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x8", EFI, 0, + it_unknown }, +{ "lv.all_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x9", EFI, 0, + it_unknown }, +{ "lv.all_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0xA", EFI, 0, + it_unknown }, +{ "lv.all_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0xB", EFI, 0, + it_unknown }, +{ "lv.any_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x0", EFI, 0, + it_unknown }, +{ "lv.any_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x1", EFI, 0, + it_unknown }, +{ "lv.any_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x2", EFI, 0, + it_unknown }, +{ "lv.any_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x3", EFI, 0, + it_unknown }, +{ "lv.any_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x4", EFI, 0, + it_unknown }, +{ "lv.any_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x5", EFI, 0, + it_unknown }, +{ "lv.any_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x6", EFI, 0, + it_unknown }, +{ "lv.any_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x7", EFI, 0, + it_unknown }, +{ "lv.any_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x8", EFI, 0, + it_unknown }, +{ "lv.any_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x9", EFI, 0, + it_unknown }, +{ "lv.any_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0xA", EFI, 0, + it_unknown }, +{ "lv.any_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0xB", EFI, 0, + it_unknown }, +{ "lv.add.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x0", EFI, 0, + it_unknown }, +{ "lv.add.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x1", EFI, 0, + it_unknown }, +{ "lv.adds.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x2", EFI, 0, + it_unknown }, +{ "lv.adds.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x3", EFI, 0, + it_unknown }, +{ "lv.addu.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x4", EFI, 0, + it_unknown }, +{ "lv.addu.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x5", EFI, 0, + it_unknown }, +{ "lv.addus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x6", EFI, 0, + it_unknown }, +{ "lv.addus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x7", EFI, 0, + it_unknown }, +{ "lv.and", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x8", EFI, 0, + it_unknown }, +{ "lv.avg.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x9", EFI, 0, + it_unknown }, +{ "lv.avg.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0xA", EFI, 0, + it_unknown }, +{ "lv.cmp_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x0", EFI, 0, + it_unknown }, +{ "lv.cmp_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x1", EFI, 0, + it_unknown }, +{ "lv.cmp_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x2", EFI, 0, + it_unknown }, +{ "lv.cmp_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x3", EFI, 0, + it_unknown }, +{ "lv.cmp_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x4", EFI, 0, + it_unknown }, +{ "lv.cmp_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x5", EFI, 0, + it_unknown }, +{ "lv.cmp_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x6", EFI, 0, + it_unknown }, +{ "lv.cmp_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x7", EFI, 0, + it_unknown }, +{ "lv.cmp_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x8", EFI, 0, + it_unknown }, +{ "lv.cmp_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x9", EFI, 0, + it_unknown }, +{ "lv.cmp_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0xA", EFI, 0, + it_unknown }, +{ "lv.cmp_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0xB", EFI, 0, + it_unknown }, +{ "lv.madds.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x4", EFI, 0, + it_unknown }, +{ "lv.max.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x5", EFI, 0, + it_unknown }, +{ "lv.max.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x6", EFI, 0, + it_unknown }, +{ "lv.merge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x7", EFI, 0, + it_unknown }, +{ "lv.merge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x8", EFI, 0, + it_unknown }, +{ "lv.min.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x9", EFI, 0, + it_unknown }, +{ "lv.min.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xA", EFI, 0, + it_unknown }, +{ "lv.msubs.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xB", EFI, 0, + it_unknown }, +{ "lv.muls.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xC", EFI, 0, + it_unknown }, +{ "lv.nand", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xD", EFI, 0, + it_unknown }, +{ "lv.nor", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xE", EFI, 0, + it_unknown }, +{ "lv.or", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xF", EFI, 0, + it_unknown }, +{ "lv.pack.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x0", EFI, 0, + it_unknown }, +{ "lv.pack.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x1", EFI, 0, + it_unknown }, +{ "lv.packs.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x2", EFI, 0, + it_unknown }, +{ "lv.packs.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x3", EFI, 0, + it_unknown }, +{ "lv.packus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x4", EFI, 0, + it_unknown }, +{ "lv.packus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x5", EFI, 0, + it_unknown }, +{ "lv.perm.n", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x6", EFI, 0, + it_unknown }, +{ "lv.rl.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x7", EFI, 0, + it_unknown }, +{ "lv.rl.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x8", EFI, 0, + it_unknown }, +{ "lv.sll.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x9", EFI, 0, + it_unknown }, +{ "lv.sll.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xA", EFI, 0, + it_unknown }, +{ "lv.sll", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xB", EFI, 0, + it_unknown }, +{ "lv.srl.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xC", EFI, 0, + it_unknown }, +{ "lv.srl.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xD", EFI, 0, + it_unknown }, +{ "lv.sra.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xE", EFI, 0, + it_unknown }, +{ "lv.sra.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xF", EFI, 0, + it_unknown }, +{ "lv.srl", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x0", EFI, 0, + it_unknown }, +{ "lv.sub.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x1", EFI, 0, + it_unknown }, +{ "lv.sub.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x2", EFI, 0, + it_unknown }, +{ "lv.subs.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x3", EFI, 0, + it_unknown }, +{ "lv.subs.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x4", EFI, 0, + it_unknown }, +{ "lv.subu.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x5", EFI, 0, + it_unknown }, +{ "lv.subu.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x6", EFI, 0, + it_unknown }, +{ "lv.subus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x7", EFI, 0, + it_unknown }, +{ "lv.subus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x8", EFI, 0, + it_unknown }, +{ "lv.unpack.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x9", EFI, 0, + it_unknown }, +{ "lv.unpack.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0xA", EFI, 0, + it_unknown }, +{ "lv.xor", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0xB", EFI, 0, + it_unknown }, +{ "lv.cust1", "", "00 0xA ----- ----- ---- ---- 0xC ----", EFI, 0, + it_unknown }, +{ "lv.cust2", "", "00 0xA ----- ----- ---- ---- 0xD ----", EFI, 0, + it_unknown }, +{ "lv.cust3", "", "00 0xA ----- ----- ---- ---- 0xE ----", EFI, 0, + it_unknown }, +{ "lv.cust4", "", "00 0xA ----- ----- ---- ---- 0xF ----", EFI, 0, + it_unknown }, + +{ "l.jr", "rB", "01 0x1 ----- ----- BBBB B--- ---- ----", + EF(l_jr), OR32_IF_DELAY, it_jump }, +{ "l.jalr", "rB", "01 0x2 ----- ----- BBBB B--- ---- ----", + EF(l_jalr), OR32_IF_DELAY, it_jump }, +{ "l.maci", "rA,I", "01 0x3 IIIII ----- AAAA AIII IIII IIII", + EF(l_mac), 0, it_mac }, +{ "l.cust1", "", "01 0xC ----- ----- ---- ---- ---- ----", + EF(l_cust1), 0, it_unknown }, +{ "l.cust2", "", "01 0xD ----- ----- ---- ---- ---- ----", + EF(l_cust2), 0, it_unknown }, +{ "l.cust3", "", "01 0xE ----- ----- ---- ---- ---- ----", + EF(l_cust3), 0, it_unknown }, +{ "l.cust4", "", "01 0xF ----- ----- ---- ---- ---- ----", + EF(l_cust4), 0, it_unknown }, + +{ "l.ld", "rD,I(rA)", "10 0x0 DDDDD AAAAA IIII IIII IIII IIII", EFI, + 0, it_load }, +{ "l.lwz", "rD,I(rA)", "10 0x1 DDDDD AAAAA IIII IIII IIII IIII", + EF(l_lwz), 0, it_load }, +{ "l.lws", "rD,I(rA)", "10 0x2 DDDDD AAAAA IIII IIII IIII IIII", EFI, + 0, it_load }, +{ "l.lbz", "rD,I(rA)", "10 0x3 DDDDD AAAAA IIII IIII IIII IIII", + EF(l_lbz), 0, it_load }, +{ "l.lbs", "rD,I(rA)", "10 0x4 DDDDD AAAAA IIII IIII IIII IIII", + EF(l_lbs), 0, it_load }, +{ "l.lhz", "rD,I(rA)", "10 0x5 DDDDD AAAAA IIII IIII IIII IIII", + EF(l_lhz), 0, it_load }, +{ "l.lhs", "rD,I(rA)", "10 0x6 DDDDD AAAAA IIII IIII IIII IIII", + EF(l_lhs), 0, it_load }, + +{ "l.addi", "rD,rA,I", "10 0x7 DDDDD AAAAA IIII IIII IIII IIII", + EF(l_add), OR32_W_FLAG, it_arith }, +{ "l.addic", "rD,rA,I", "10 0x8 DDDDD AAAAA IIII IIII IIII IIII", EFI, + 0, it_arith }, +{ "l.andi", "rD,rA,K", "10 0x9 DDDDD AAAAA KKKK KKKK KKKK KKKK", + EF(l_and), OR32_W_FLAG, it_arith }, +{ "l.ori", "rD,rA,K", "10 0xA DDDDD AAAAA KKKK KKKK KKKK KKKK", + EF(l_or), 0, it_arith }, +{ "l.xori", "rD,rA,I", "10 0xB DDDDD AAAAA IIII IIII IIII IIII", + EF(l_xor), 0, it_arith }, +{ "l.muli", "rD,rA,I", "10 0xC DDDDD AAAAA IIII IIII IIII IIII", + EF(l_mul), 0, it_arith }, +{ "l.mfspr", "rD,rA,K", "10 0xD DDDDD AAAAA KKKK KKKK KKKK KKKK", + EF(l_mfspr), 0, it_move }, +{ "l.slli", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 00LL LLLL", + EF(l_sll), 0, it_shift }, +{ "l.srli", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 01LL LLLL", + EF(l_srl), 0, it_shift }, +{ "l.srai", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 10LL LLLL", + EF(l_sra), 0, it_shift }, +{ "l.rori", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 11LL LLLL", EFI, + 0, it_shift }, + +{ "l.sfeqi", "rA,I", "10 0xF 00000 AAAAA IIII IIII IIII IIII", + EF(l_sfeq), OR32_W_FLAG, it_compare }, +{ "l.sfnei", "rA,I", "10 0xF 00001 AAAAA IIII IIII IIII IIII", + EF(l_sfne), OR32_W_FLAG, it_compare }, +{ "l.sfgtui", "rA,I", "10 0xF 00010 AAAAA IIII IIII IIII IIII", + EF(l_sfgtu), OR32_W_FLAG, it_compare }, +{ "l.sfgeui", "rA,I", "10 0xF 00011 AAAAA IIII IIII IIII IIII", + EF(l_sfgeu), OR32_W_FLAG, it_compare }, +{ "l.sfltui", "rA,I", "10 0xF 00100 AAAAA IIII IIII IIII IIII", + EF(l_sfltu), OR32_W_FLAG, it_compare }, +{ "l.sfleui", "rA,I", "10 0xF 00101 AAAAA IIII IIII IIII IIII", + EF(l_sfleu), OR32_W_FLAG, it_compare }, +{ "l.sfgtsi", "rA,I", "10 0xF 01010 AAAAA IIII IIII IIII IIII", + EF(l_sfgts), OR32_W_FLAG, it_compare }, +{ "l.sfgesi", "rA,I", "10 0xF 01011 AAAAA IIII IIII IIII IIII", + EF(l_sfges), OR32_W_FLAG, it_compare }, +{ "l.sfltsi", "rA,I", "10 0xF 01100 AAAAA IIII IIII IIII IIII", + EF(l_sflts), OR32_W_FLAG, it_compare }, +{ "l.sflesi", "rA,I", "10 0xF 01101 AAAAA IIII IIII IIII IIII", + EF(l_sfles), OR32_W_FLAG, it_compare }, + +{ "l.mtspr", "rA,rB,K", "11 0x0 KKKKK AAAAA BBBB BKKK KKKK KKKK", + EF(l_mtspr), 0, it_move }, +{ "l.mac", "rA,rB", "11 0x1 ----- AAAAA BBBB B--- ---- 0x1", + EF(l_mac), 0, it_mac }, +{ "l.msb", "rA,rB", "11 0x1 ----- AAAAA BBBB B--- ---- 0x2", + EF(l_msb), 0, it_mac }, + +{ "lf.add.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x0", + EF(lf_add_s), 0, it_float }, +{ "lf.sub.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x1", + EF(lf_sub_s), 0, it_float }, +{ "lf.mul.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x2", + EF(lf_mul_s), 0, it_float }, +{ "lf.div.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x3", + EF(lf_div_s), 0, it_float }, +{ "lf.itof.s", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x0 0x4", + EF(lf_itof_s), 0, it_float }, +{ "lf.ftoi.s", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x0 0x5", + EF(lf_ftoi_s), 0, it_float }, +{ "lf.rem.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x6", + EF(lf_rem_s), 0, it_float }, +{ "lf.madd.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x7", + EF(lf_madd_s), 0, it_float }, +{ "lf.sfeq.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0x8", + EF(lf_sfeq_s), 0, it_float }, +{ "lf.sfne.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0x9", + EF(lf_sfne_s), 0, it_float }, +{ "lf.sfgt.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xA", + EF(lf_sfgt_s), 0, it_float }, +{ "lf.sfge.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xB", + EF(lf_sfge_s), 0, it_float }, +{ "lf.sflt.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xC", + EF(lf_sflt_s), 0, it_float }, +{ "lf.sfle.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xD", + EF(lf_sfle_s), 0, it_float }, +{ "lf.cust1.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0xD ----", EFI, + 0, it_float }, + +{ "lf.add.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x0", EFI, 0, + it_float }, +{ "lf.sub.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x1", EFI, 0, + it_float }, +{ "lf.mul.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x2", EFI, 0, + it_float }, +{ "lf.div.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x3", EFI, 0, + it_float }, +{ "lf.itof.d", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x1 0x4", EFI, 0, + it_float }, +{ "lf.ftoi.d", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x1 0x5", EFI, 0, + it_float }, +{ "lf.rem.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x6", EFI, 0, + it_float }, +{ "lf.madd.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x7", EFI, 0, + it_float }, +{ "lf.sfeq.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0x8", EFI, 0, + it_float }, +{ "lf.sfne.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0x9", EFI, 0, + it_float }, +{ "lf.sfgt.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xA", EFI, 0, + it_float }, +{ "lf.sfge.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xB", EFI, 0, + it_float }, +{ "lf.sflt.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xC", EFI, 0, + it_float }, +{ "lf.sfle.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xD", EFI, 0, + it_float }, +{ "lf.cust1.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0xE ----", EFI, 0, + it_float }, + +{ "l.sd", "I(rD),rB", "11 0x4 IIIII DDDDD BBBB BIII IIII IIII", EFI, + 0, it_store }, +{ "l.sw", "I(rD),rB", "11 0x5 IIIII DDDDD BBBB BIII IIII IIII", + EF(l_sw), 0, it_store }, +{ "l.sb", "I(rD),rB", "11 0x6 IIIII DDDDD BBBB BIII IIII IIII", + EF(l_sb), 0, it_store }, +{ "l.sh", "I(rD),rB", "11 0x7 IIIII DDDDD BBBB BIII IIII IIII", + EF(l_sh), 0, it_store }, + +{ "l.add", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x0", + EF(l_add), OR32_W_FLAG, it_arith }, +{ "l.addc", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x1", + EF(l_addc), OR32_W_FLAG, it_arith }, +{ "l.sub", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x2", + EF(l_sub), 0, it_arith }, +{ "l.and", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x3", + EF(l_and), OR32_W_FLAG, it_arith }, +{ "l.or", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x4", + EF(l_or), 0, it_arith }, +{ "l.xor", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x5", + EF(l_xor), 0, it_arith }, +{ "l.mul", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0x6", + EF(l_mul), 0, it_arith }, + +{ "l.sll", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 00-- 0x8", + EF(l_sll), 0, it_shift }, +{ "l.srl", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 01-- 0x8", + EF(l_srl), 0, it_shift }, +{ "l.sra", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 10-- 0x8", + EF(l_sra), 0, it_shift }, +{ "l.ror", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 11-- 0x8", EFI, + 0, it_shift }, +{ "l.div", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0x9", + EF(l_div), 0, it_arith }, +{ "l.divu", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0xA", + EF(l_divu), 0, it_arith }, +{ "l.mulu", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0xB", EFI, + 0, it_arith }, +{ "l.extbs", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 01-- 0xC", + EF(l_extbs), 0, it_move }, +{ "l.exths", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 00-- 0xC", + EF(l_exths), 0, it_move }, +{ "l.extws", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 00-- 0xD", + EF(l_extws), 0, it_move }, +{ "l.extbz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 11-- 0xC", + EF(l_extbz), 0, it_move }, +{ "l.exthz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 10-- 0xC", + EF(l_exthz), 0, it_move }, +{ "l.extwz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 01-- 0xD", + EF(l_extwz), 0, it_move }, +{ "l.cmov", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0xE", + EF(l_cmov), OR32_R_FLAG, it_move }, +{ "l.ff1", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 ---- 0xF", EFI, 0, + it_arith }, + +{ "l.sfeq", "rA,rB", "11 0x9 00000 AAAAA BBBB B--- ---- ----", + EF(l_sfeq), OR32_W_FLAG, it_compare }, +{ "l.sfne", "rA,rB", "11 0x9 00001 AAAAA BBBB B--- ---- ----", + EF(l_sfne), OR32_W_FLAG, it_compare }, +{ "l.sfgtu", "rA,rB", "11 0x9 00010 AAAAA BBBB B--- ---- ----", + EF(l_sfgtu), OR32_W_FLAG, it_compare }, +{ "l.sfgeu", "rA,rB", "11 0x9 00011 AAAAA BBBB B--- ---- ----", + EF(l_sfgeu), OR32_W_FLAG, it_compare }, +{ "l.sfltu", "rA,rB", "11 0x9 00100 AAAAA BBBB B--- ---- ----", + EF(l_sfltu), OR32_W_FLAG, it_compare }, +{ "l.sfleu", "rA,rB", "11 0x9 00101 AAAAA BBBB B--- ---- ----", + EF(l_sfleu), OR32_W_FLAG, it_compare }, +{ "l.sfgts", "rA,rB", "11 0x9 01010 AAAAA BBBB B--- ---- ----", + EF(l_sfgts), OR32_W_FLAG, it_compare }, +{ "l.sfges", "rA,rB", "11 0x9 01011 AAAAA BBBB B--- ---- ----", + EF(l_sfges), OR32_W_FLAG, it_compare }, +{ "l.sflts", "rA,rB", "11 0x9 01100 AAAAA BBBB B--- ---- ----", + EF(l_sflts), OR32_W_FLAG, it_compare }, +{ "l.sfles", "rA,rB", "11 0x9 01101 AAAAA BBBB B--- ---- ----", + EF(l_sfles), OR32_W_FLAG, it_compare }, + +{ "l.cust5", "rD,rA,rB,L,K", "11 0xC DDDDD AAAAA BBBB BLLL LLLK KKKK", EFI, + 0, it_unknown }, +{ "l.cust6", "", "11 0xD ----- ----- ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust7", "", "11 0xE ----- ----- ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust8", "", "11 0xF ----- ----- ---- ---- ---- ----", EFI, + 0, it_unknown }, + +/* This section should not be defined in or1ksim, since it contains duplicates, + which would cause machine builder to complain. */ +#ifdef HAS_CUST +{ "l.cust5_1", "rD", "11 0xC DDDDD ----- ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust5_2", "rD,rA" , "11 0xC DDDDD AAAAA ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust5_3", "rD,rA,rB", "11 0xC DDDDD AAAAA BBBB B--- ---- ----", EFI, + 0, it_unknown }, + +{ "l.cust6_1", "rD", "11 0xD DDDDD ----- ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust6_2", "rD,rA" , "11 0xD DDDDD AAAAA ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust6_3", "rD,rA,rB", "11 0xD DDDDD AAAAA BBBB B--- ---- ----", EFI, + 0, it_unknown }, + +{ "l.cust7_1", "rD", "11 0xE DDDDD ----- ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust7_2", "rD,rA" , "11 0xE DDDDD AAAAA ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust7_3", "rD,rA,rB", "11 0xE DDDDD AAAAA BBBB B--- ---- ----", EFI, + 0, it_unknown }, + +{ "l.cust8_1", "rD", "11 0xF DDDDD ----- ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust8_2", "rD,rA" , "11 0xF DDDDD AAAAA ---- ---- ---- ----", EFI, + 0, it_unknown }, +{ "l.cust8_3", "rD,rA,rB", "11 0xF DDDDD AAAAA BBBB B--- ---- ----", EFI, + 0, it_unknown }, +#endif + +{ "", "", "", EFI, 0, 0 } /* Dummy entry, not included in num_opcodes. This + * lets code examine entry i+1 without checking + * if we've run off the end of the table. */ +}; + +#undef EFI +#undef EFN +#undef EF + +/* **INDENT-ON** */ + +/* Define dummy, if debug is not defined. */ +#ifndef HAS_DEBUG +#define debug(l, fmt...) ; +#endif + +CONST int num_opcodes = ((sizeof(or32_opcodes)) / (sizeof(struct or32_opcode))) - 1; + +/* Calculates instruction length in bytes. Always 4 for OR32. */ +int +insn_len(int insn_index) +{ + insn_index = 0; /* Just to get rid that warning. */ + return 4; +} + +/* Is individual insn's operand signed or unsigned? */ +int +letter_signed(char l) +{ + CONST struct or32_letter *pletter; + + for(pletter = or32_letters; pletter->letter != '\0'; pletter++) + if (pletter->letter == l) + return pletter->sign; + + printf("letter_signed(%c): Unknown letter.\n", l); + return 0; +} + +/* Simple cache for letter ranges */ +static int range_cache[256] = {0}; + +/* Number of letters in the individual lettered operand. */ +int +letter_range(char l) +{ + CONST struct or32_opcode *pinsn; + char *enc; + int range = 0; + + /* Is value cached? */ + if ((range = range_cache[(unsigned char)l])) return range; + + for(pinsn = or32_opcodes; strlen(pinsn->name); pinsn++) + { + if (strchr(pinsn->encoding,l)) + { + for (enc = pinsn->encoding; *enc != '\0'; enc++) + if ((*enc == '0') && (*(enc+1) == 'x')) + enc += 2; + else if (*enc == l) + range++; + return range_cache[(unsigned char)l] = range; + } + } + + printf("\nABORT: letter_range(%c): Never used letter.\n", l); + exit(1); +} + +/* MM: Returns index of given instruction name. */ +int +insn_index (char *insn) +{ + int i, found = -1; + for (i = 0; i < num_opcodes; i++) + if (!strcmp (or32_opcodes[i].name, insn)) + { + found = i; + break; + } + return found; +} + +/* Returns name of the specified instruction index */ +CONST char * +insn_name(int index) +{ + if (index >= 0 && index < num_opcodes) + return or32_opcodes[index].name; + else + return "???"; +} + +#if defined(HAS_EXECUTION) && SIMPLE_EXECUTION +void +l_none(struct iqueue_entry *current) +{ +} +#else +void +l_none() +{ +} +#endif + +/*** Finite automata for instruction decoding building code ***/ + +/* Find symbols in encoding. */ +unsigned long +insn_extract(param_ch, enc_initial) + char param_ch; + char *enc_initial; +{ + char *enc; + unsigned long ret = 0; + unsigned opc_pos = 32; + for (enc = enc_initial; *enc != '\0'; ) + if ((*enc == '0') && (*(enc+1) == 'x')) + { + unsigned long tmp = strtol(enc+2, NULL, 16); + opc_pos -= 4; + if (param_ch == '0' || param_ch == '1') + { + if (param_ch == '0') + tmp = 15 - tmp; + ret |= tmp << opc_pos; + } + enc += 3; + } + else + { + if (*enc == '0' || *enc == '1' || *enc == '-' || isalpha(*enc) ) + { + opc_pos--; + if (param_ch == *enc) + ret |= 1 << opc_pos; + } + enc++; + } + return ret; +} + +#define MAX_AUTOMATA_SIZE (1200) +#define MAX_OP_TABLE_SIZE (1200) +#define MAX_LEN (8) + +#ifndef MIN +# define MIN(x,y) ((x) < (y) ? (x) : (y)) +#endif + +unsigned long *automata; +int nuncovered; +int curpass = 0; + +/* MM: Struct that holds runtime build information about instructions. */ +struct temp_insn_struct *ti; + +struct insn_op_struct *op_data, **op_start; + +/* Recursive utility function used to find best match and to build automata. */ + +static unsigned long * +cover_insn (unsigned long *cur, int pass, unsigned int mask) +{ + int best_first = 0, best_len = 0, i, last_match = -1, ninstr = 0; + unsigned long cur_mask = mask; + unsigned long *next; + + for (i = 0; i < num_opcodes; i++) + if (ti[i].in_pass == pass) + { + cur_mask &= ti[i].insn_mask; + ninstr++; + last_match = i; + } + + debug(8, "%08X %08X\n", mask, cur_mask); + if (ninstr == 0) + return 0; + if (ninstr == 1) + { + /* Leaf holds instruction index. */ + debug(8, "%i>I%i %s\n", cur - automata, last_match, or32_opcodes[last_match].name); + *cur = LEAF_FLAG | last_match; + cur++; + nuncovered--; + } else { + /* Find longest match. */ + for (i = 0; i < 32; i++) + { + int len; + for (len = best_len + 1; len < MIN(MAX_LEN, 33 - i); len++) + { + unsigned long m = (1UL << ((unsigned long)len)) - 1; + debug(9, " (%i(%08X & %08X>>%i = %08X, %08X)",len,m, cur_mask, i, (cur_mask >> (unsigned)i), (cur_mask >> (unsigned)i) & m); + if ((m & (cur_mask >> (unsigned)i)) == m) + { + best_len = len; + best_first = i; + debug(9, "!"); + } + else + break; + } + } + debug(9, "\n"); + if (!best_len) + { + fprintf (stderr, "%i instructions match mask 0x%08X:\n", ninstr, mask); + for (i = 0; i < num_opcodes; i++) + if (ti[i].in_pass == pass) + fprintf (stderr, "%s ", or32_opcodes[i].name); + + fprintf (stderr, "\n"); + exit (1); + } + debug(8, "%i> #### %i << %i (%i) ####\n", cur - automata, best_len, best_first, ninstr); + *cur = best_first; + cur++; + *cur = (1 << best_len) - 1; + cur++; + next = cur; + /* Allocate space for pointers. */ + cur += 1 << best_len; + cur_mask = (1 << (unsigned long)best_len) - 1; + + for (i = 0; i < (1 << (unsigned long)best_len); i++) + { + int j; + unsigned long *c; + curpass++; + for (j = 0; j < num_opcodes; j++) + if (ti[j].in_pass == pass + && ((ti[j].insn >> best_first) & cur_mask) == (unsigned long) i + && ((ti[j].insn_mask >> best_first) & cur_mask) == cur_mask) + ti[j].in_pass = curpass; + + debug(9, "%08X %08X %i\n", mask, cur_mask, best_first); + c = cover_insn (cur, curpass, mask & (~(cur_mask << best_first))); + if (c) + { + debug(8, "%i> #%X -> %u\n", next - automata, i, cur - automata); + *next = cur - automata; + cur = c; + } + else + { + debug(8, "%i> N/A\n", next - automata); + *next = 0; + } + next++; + } + } + return cur; +} + +/* Returns number of nonzero bits. */ +static int +num_ones (unsigned long value) +{ + int c = 0; + while (value) + { + if (value & 1) + c++; + value >>= 1; + } + return c; +} + +/* Utility function, which converts parameters from or32_opcode format to more binary form. + Parameters are stored in ti struct. */ + +static struct insn_op_struct * +parse_params (CONST struct or32_opcode *opcode, struct insn_op_struct *cur) +{ + char *args = opcode->args; + int i, type; + int num_cur_op = 0;; + + i = 0; + type = 0; + /* In case we don't have any parameters, we add dummy read from r0. */ + if (!(*args)) { + cur->type = OPTYPE_REG | OPTYPE_OP | OPTYPE_LAST; + cur->data = 0; + debug(9, "#%08X %08X\n", cur->type, cur->data); + cur++; + return cur; + } + + while (*args != '\0') + { + if (*args == 'r') + { + args++; + type |= OPTYPE_REG; + if(args[1] == 'D') + type |= OPTYPE_DST; + } + else if (isalpha (*args)) + { + unsigned long arg; + arg = insn_extract(*args, opcode->encoding); + debug(9, "%s : %08X ------\n", opcode->name, arg); + if (letter_signed (*args)) + { + type |= OPTYPE_SIG; + type |= ((num_ones (arg) - 1) << OPTYPE_SBIT_SHR) & OPTYPE_SBIT; + } + + num_cur_op = 0; + /* Split argument to sequences of consecutive ones. */ + while (arg) + { + int shr = 0; + unsigned long tmp = arg, mask = 0; + while ((tmp & 1) == 0) + { + shr++; + tmp >>= 1; + } + while (tmp & 1) + { + mask++; + tmp >>= 1; + } + cur->type = type | shr; + cur->data = mask; + arg &= ~(((1 << mask) - 1) << shr); + debug(6, "|%08X %08X\n", cur->type, cur->data); + cur++; + num_cur_op++; + } + args++; + } + else if (*args == '(') + { + /* Next param is displacement. Later we will treat them as one operand. */ + /* Set the OPTYPE_DIS flag on all insn_op_structs that belong to this + * operand */ + while(num_cur_op > 0) { + cur[-num_cur_op].type |= type | OPTYPE_DIS; + num_cur_op--; + } + cur[-1].type |= OPTYPE_OP; + debug(9, ">%08X %08X\n", cur->type, cur->data); + type = 0; + i++; + args++; + } + else if (*args == OPERAND_DELIM) + { + cur--; + cur->type = type | cur->type | OPTYPE_OP; + debug(9, ">%08X %08X\n", cur->type, cur->data); + cur++; + type = 0; + i++; + args++; + } + else if (*args == '0') + { + cur->type = type; + cur->data = 0; + debug(9, ">%08X %08X\n", cur->type, cur->data); + cur++; + type = 0; + i++; + args++; + } + else if (*args == ')') + args++; + else + { + fprintf (stderr, "%s : parse error in args.\n", opcode->name); + exit (1); + } + } + cur--; + cur->type = type | cur->type | OPTYPE_OP | OPTYPE_LAST; + debug(9, "#%08X %08X\n", cur->type, cur->data); + cur++; + return cur; +} + +/* Constructs new automata based on or32_opcodes array. */ + +void +build_automata() +{ + int i; + unsigned long *end; + struct insn_op_struct *cur; + + automata = (unsigned long *) malloc (MAX_AUTOMATA_SIZE * sizeof (unsigned long)); + ti = (struct temp_insn_struct *) malloc (sizeof (struct temp_insn_struct) * num_opcodes); + + nuncovered = num_opcodes; + +#ifdef HAS_EXECUTION + printf("Building automata... "); +#endif + + /* Build temporary information about instructions. */ + for (i = 0; i < num_opcodes; i++) + { + unsigned long ones, zeros; + char *encoding = or32_opcodes[i].encoding; + ones = insn_extract('1', encoding); + zeros = insn_extract('0', encoding); + ti[i].insn_mask = ones | zeros; + ti[i].insn = ones; + ti[i].in_pass = curpass = 0; + /*debug(9, "%s: %s %08X %08X\n", or32_opcodes[i].name, + or32_opcodes[i].encoding, ti[i].insn_mask, ti[i].insn);*/ + } + + /* Until all are covered search for best criteria to separate them. */ + end = cover_insn (automata, curpass, 0xFFFFFFFF); + if (end - automata > MAX_AUTOMATA_SIZE) + { + fprintf (stderr, "Automata too large. Increase MAX_AUTOMATA_SIZE."); + exit (1); + } +#ifdef HAS_EXECUTION + printf("done, num uncovered: %i/%i.\n", nuncovered, num_opcodes); +#endif + +#ifdef HAS_EXECUTION + printf("Parsing operands data... "); +#endif + op_data = (struct insn_op_struct *) malloc (MAX_OP_TABLE_SIZE * sizeof (struct insn_op_struct)); + op_start = (struct insn_op_struct **) malloc (num_opcodes * sizeof (struct insn_op_struct *)); + cur = op_data; + for (i = 0; i < num_opcodes; i++) + { + op_start[i] = cur; + cur = parse_params (&or32_opcodes[i], cur); + if (cur - op_data > MAX_OP_TABLE_SIZE) + { + fprintf (stderr, "Operands table too small, increase MAX_OP_TABLE_SIZE.\n"); + exit (1); + } + } +#ifdef HAS_EXECUTION + printf("done.\n"); +#endif +} + +void destruct_automata () +{ + free (ti); + free (automata); + free (op_data); + free (op_start); +} + +/* Decodes instruction and returns instruction index. */ +int insn_decode (unsigned int insn) +{ + unsigned long *a = automata; + int i; + while (!(*a & LEAF_FLAG)) + { + unsigned int first = *a; + //debug(9, "%i ", a - automata); + a++; + i = (insn >> first) & *a; + a++; + if (!*(a + i)) + { /* Invalid instruction found? */ + //debug(9, "XXX\n", i); + return -1; + } + a = automata + *(a + i); + } + i = *a & ~LEAF_FLAG; + //debug(9, "%i\n", i); + /* Final check - do we have direct match? + (based on or32_opcodes this should be the only possibility, + but in case of invalid/missing instruction we must perform a check) */ + if ((ti[i].insn_mask & insn) == ti[i].insn) + return i; + else + return -1; +} + +static char disassembled_str[50]; +char *disassembled = &disassembled_str[0]; + +/* Automagically does zero- or sign- extension and also finds correct + sign bit position if sign extension is correct extension. Which extension + is proper is figured out from letter description. */ + +unsigned long +extend_imm(unsigned long imm, char l) +{ + unsigned long mask; + int letter_bits; + + /* First truncate all bits above valid range for this letter + in case it is zero extend. */ + letter_bits = letter_range(l); + mask = (1 << letter_bits) - 1; + imm &= mask; + + /* Do sign extend if this is the right one. */ + if (letter_signed(l) && (imm >> (letter_bits - 1))) + imm |= (~mask); + + return imm; +} + +unsigned long +or32_extract(param_ch, enc_initial, insn) + char param_ch; + char *enc_initial; + unsigned long insn; +{ + char *enc; + unsigned long ret = 0; + int opc_pos = 0; + int param_pos = 0; + + for (enc = enc_initial; *enc != '\0'; enc++) + if (*enc == param_ch) + { + if (enc - 2 >= enc_initial && (*(enc - 2) == '0') && (*(enc - 1) == 'x')) + continue; + else + param_pos++; + } + +#if DEBUG + printf("or32_extract: %x ", param_pos); +#endif + opc_pos = 32; + for (enc = enc_initial; *enc != '\0'; ) + if ((*enc == '0') && (*(enc+1) == 'x')) + { + opc_pos -= 4; + if ((param_ch == '0') || (param_ch == '1')) + { + unsigned long tmp = strtol(enc, NULL, 16); +#if DEBUG + printf(" enc=%s, tmp=%x ", enc, tmp); +#endif + if (param_ch == '0') + tmp = 15 - tmp; + ret |= tmp << opc_pos; + } + enc += 3; + } + else if ((*enc == '0') || (*enc == '1')) + { + opc_pos--; + if (param_ch == *enc) + ret |= 1 << opc_pos; + enc++; + } + else if (*enc == param_ch) + { + opc_pos--; + param_pos--; +#if DEBUG + printf("\n ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos); +#endif + if (islower(param_ch)) + ret -= ((insn >> opc_pos) & 0x1) << param_pos; + else + ret += ((insn >> opc_pos) & 0x1) << param_pos; + enc++; + } + else if (isalpha(*enc)) + { + opc_pos--; + enc++; + } + else if (*enc == '-') + { + opc_pos--; + enc++; + } + else + enc++; + +#if DEBUG + printf ("ret=%x\n", ret); +#endif + return ret; +} + +/* Print register. Used only by print_insn. */ + +static char * +or32_print_register (dest, param_ch, encoding, insn) + char *dest; + char param_ch; + char *encoding; + unsigned long insn; +{ + int regnum = or32_extract(param_ch, encoding, insn); + + sprintf (dest, "r%d", regnum); + while (*dest) dest++; + return dest; +} + +/* Print immediate. Used only by print_insn. */ + +static char * +or32_print_immediate (dest, param_ch, encoding, insn) + char *dest; + char param_ch; + char *encoding; + unsigned long insn; +{ + int imm = or32_extract (param_ch, encoding, insn); + + imm = extend_imm(imm, param_ch); + + if (letter_signed(param_ch)) + { + if (imm < 0) + sprintf (dest, "%d", imm); + else + sprintf (dest, "0x%x", imm); + } + else + sprintf (dest, "%#x", imm); + while (*dest) dest++; + return dest; +} + +/* Disassemble one instruction from insn to disassemble. + Return the size of the instruction. */ + +int +disassemble_insn (insn) + unsigned long insn; +{ + return disassemble_index (insn, insn_decode (insn)); +} + +/* Disassemble one instruction from insn index. + Return the size of the instruction. */ + +int +disassemble_index (insn, index) + unsigned long insn; + int index; +{ + char *dest = disassembled; + if (index >= 0) + { + struct or32_opcode const *opcode = &or32_opcodes[index]; + char *s; + + strcpy (dest, opcode->name); + while (*dest) dest++; + *dest++ = ' '; + *dest = 0; + + for (s = opcode->args; *s != '\0'; ++s) + { + switch (*s) + { + case '\0': + return insn_len (insn); + + case 'r': + dest = or32_print_register(dest, *++s, opcode->encoding, insn); + break; + + default: + if (strchr (opcode->encoding, *s)) + dest = or32_print_immediate (dest, *s, opcode->encoding, insn); + else { + *dest++ = *s; + *dest = 0; + } + } + } + } + else + { + /* This used to be %8x for binutils. */ + sprintf(dest, ".word 0x%08lx", insn); + while (*dest) dest++; + } + return insn_len (insn); +} Index: Makefile.in =================================================================== --- Makefile.in (nonexistent) +++ Makefile.in (revision 1765) @@ -0,0 +1,368 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile -- Makefile for OR32 dependent simulation +# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org +# +# This file is part of OpenRISC 1000 Architectural Simulator. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +AWK = @AWK@ +BUILD_DIR = @BUILD_DIR@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPU_ARCH = @CPU_ARCH@ +DEPDIR = @DEPDIR@ +INCLUDES = @INCLUDES@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +LOCAL_DEFS = @LOCAL_DEFS@ +MAKE_SHELL = @MAKE_SHELL@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +SUMVERSION = @SUMVERSION@ +TERMCAP_LIB = @TERMCAP_LIB@ +VERSION = @VERSION@ +am__include = @am__include@ +am__quote = @am__quote@ +host = @host@ +host_cpu = @host_cpu@ +host_os = @host_os@ +install_sh = @install_sh@ + +noinst_LIBRARIES = libarch.a +libarch_a_SOURCES = execute.c or32.c + +@SIMPLE_EXECUTION_TRUE@noinst_PROGRAMS = +@SIMPLE_EXECUTION_FALSE@noinst_PROGRAMS = generate +@SIMPLE_EXECUTION_TRUE@generate_SOURCES = +@SIMPLE_EXECUTION_FALSE@generate_SOURCES = or32.c generate.c +@SIMPLE_EXECUTION_FALSE@BUILT_SOURCES = execgen.c + +# If the simulator was first built without --enable-simple and then with it, +# then also remove these two files +CLEANFILES = execgen.c generate +subdir = cpu/or32 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libarch_a_AR = $(AR) cru +libarch_a_LIBADD = +am_libarch_a_OBJECTS = execute.$(OBJEXT) or32.$(OBJEXT) +libarch_a_OBJECTS = $(am_libarch_a_OBJECTS) +@SIMPLE_EXECUTION_TRUE@noinst_PROGRAMS = +@SIMPLE_EXECUTION_FALSE@noinst_PROGRAMS = generate$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) + +@SIMPLE_EXECUTION_TRUE@am_generate_OBJECTS = +@SIMPLE_EXECUTION_FALSE@am_generate_OBJECTS = or32.$(OBJEXT) \ +@SIMPLE_EXECUTION_FALSE@ generate.$(OBJEXT) +generate_OBJECTS = $(am_generate_OBJECTS) +generate_LDADD = $(LDADD) +generate_DEPENDENCIES = +generate_LDFLAGS = + +DEFS = @DEFS@ +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/execute.Po ./$(DEPDIR)/generate.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/or32.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libarch_a_SOURCES) $(generate_SOURCES) +DIST_COMMON = Makefile.am Makefile.in +SOURCES = $(libarch_a_SOURCES) $(generate_SOURCES) + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu cpu/or32/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libarch.a: $(libarch_a_OBJECTS) $(libarch_a_DEPENDENCIES) + -rm -f libarch.a + $(libarch_a_AR) libarch.a $(libarch_a_OBJECTS) $(libarch_a_LIBADD) + $(RANLIB) libarch.a + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +generate$(EXEEXT): $(generate_OBJECTS) $(generate_DEPENDENCIES) + @rm -f generate$(EXEEXT) + $(LINK) $(generate_LDFLAGS) $(generate_OBJECTS) $(generate_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/execute.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/or32.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) + +installdirs: + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-noinstPROGRAMS distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic tags uninstall \ + uninstall-am uninstall-info-am + + +@SIMPLE_EXECUTION_FALSE@execgen.c: generate $(srcdir)/insnset.c +@SIMPLE_EXECUTION_FALSE@ ./generate $(srcdir)/insnset.c execgen.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Index: generate.c =================================================================== --- generate.c (nonexistent) +++ generate.c (revision 1765) @@ -0,0 +1,391 @@ +/* generate.c -- generates file execgen.c from instruction set + Copyright (C) 1999 Damjan Lampret, lampret@opencores.org + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "opcode/or32.h" + +static char *in_file; +static char *out_file; + +/* Whether this instruction stores something in register */ +static int write_to_reg; + +static int out_lines = 0; + +void debug(int level, const char *format, ...) +{ +#if DEBUG + char *p; + va_list ap; + + if ((p = malloc(1000)) == NULL) + return; + va_start(ap, format); + (void) vsnprintf(p, 1000, format, ap); + va_end(ap); + printf("%s\n", p); + fflush(stdout); + free(p); +#endif +} + +static int shift_fprintf(int level, FILE *f, const char *fmt, ...) +{ + va_list ap; + int i; + + va_start(ap, fmt); + for(i = 0; i < level; i++) + fprintf(f, " "); + + i = vfprintf(f, fmt, ap); + va_end(ap); + + out_lines++; + return i + (level * 2); +} + +/* Generates a execute sequence for one instruction */ +int output_function (FILE *fo, const char *func_name, int level) +{ + FILE *fi; + int olevel; + int line_num = 0; + + if ((fi = fopen (in_file, "rt")) == NULL) { + printf("could not open file\n"); + return 1; + } + + while (!feof (fi)) { + char line[10000], *str = line; + fgets (str, sizeof (line), fi); + line[sizeof (line) - 1] = 0; + line_num++; + if (strncmp (str, "INSTRUCTION (", 13) == 0) { + char *s; + str += 13; + while (isspace (*str)) str++; + s = str; + while (*s && *s != ')') s++; + *s = 0; + while (isspace(*(s - 1))) s--; + *s = 0; + if (strcmp (str, func_name) == 0) { + olevel = 1; + str += strlen (str) + 1; + while (isspace (*str)) str++; + s = str; + while (*s && *s != '\n' && *s != '\r') s++; + *s = 0; + while (isspace(*(s - 1))) s--; + *s = 0; + /*shift_fprintf (level, fo, "#line %i \"%s\"\n", line_num, in_file);*/ + shift_fprintf (level, fo, "%s", str); + shift_fprintf (level, fo, " /* \"%s\" */\n", func_name); + do { + fgets (line, sizeof (line), fi); + line[sizeof(line) - 1] = 0; + for (str = line; *str; str++) { + if (*str == '{') olevel++; + else if (*str == '}') olevel--; + } + shift_fprintf (level, fo, "%s", line); + } while (olevel); + fclose(fi); + /*shift_fprintf (level, fo, "#line %i \"%s\"\n", out_lines, out_file);*/ + return 0; + } + } + } + shift_fprintf (level, fo, "%s ();\n", func_name); + + fclose(fi); + return 0; +} + +/* Parses operands. */ + +static int +gen_eval_operands (FILE *fo, int insn_index, int level) +{ + struct insn_op_struct *opd = op_start[insn_index]; + int i; + int num_ops; + int nbits = 0; + int set_param = 0; + int dis = 0; + int sbit; + int dis_op = -1; + + write_to_reg = 0; + + shift_fprintf (level, fo, "uorreg_t "); + + /* Count number of operands */ + for (i = 0, num_ops = 0;; i++) { + if (!(opd[i].type & OPTYPE_OP)) + continue; + if (opd[i].type & OPTYPE_DIS) + continue; + if (num_ops) + fprintf(fo, ", "); + fprintf(fo, "%c", 'a' + num_ops); + num_ops++; + if (opd[i].type & OPTYPE_LAST) + break; + } + + fprintf (fo, ";\n"); + + shift_fprintf (level, fo, "/* Number of operands: %i */\n", num_ops); + + i = 0; + num_ops = 0; + do { +/* + printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_LAST ? '1' : '0'); printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_OP ? '1' : '0'); + printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_REG ? '1' : '0'); + printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_SIG ? '1' : '0'); + printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_DIS ? '1' : '0'); + printf("opd[%i].type = %i\n", i, opd->type & OPTYPE_SHR); + printf("opd[%i].type = %i\n", i, (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR); + printf("opd[%i].data = %i\n", i, opd->data); +*/ + + if (!nbits) + shift_fprintf (level, fo, "%c = (insn >> %i) & 0x%x;\n", 'a' + num_ops, + opd->type & OPTYPE_SHR, (1 << opd->data) - 1); + else + shift_fprintf (level, fo, "%c |= ((insn >> %i) & 0x%x) << %i;\n", + 'a' + num_ops, opd->type & OPTYPE_SHR, + (1 << opd->data) - 1, nbits); + + nbits += opd->data; + + if ((opd->type & OPTYPE_DIS) && (opd->type & OPTYPE_OP)) { + sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR; + if (opd->type & OPTYPE_SIG) + shift_fprintf (level, fo, "if(%c & 0x%08x) %c |= 0x%x;\n", + 'a' + num_ops, 1 << sbit, 'a' + num_ops, + 0xffffffff << sbit); + opd++; + shift_fprintf (level, fo, "(signed)%c += (signed)reg[(insn >> %i) & 0x%x];\n", + 'a' + num_ops, opd->type & OPTYPE_SHR, + (1 << opd->data) - 1); + dis = 1; + dis_op = num_ops; + } + + if (opd->type & OPTYPE_OP) { + sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR; + if (opd->type & OPTYPE_SIG) + shift_fprintf (level, fo, "if(%c & 0x%08x) %c |= 0x%x;\n", + 'a' + num_ops, 1 << sbit, 'a' + num_ops, + 0xffffffff << sbit); + if ((opd->type & OPTYPE_REG) && !dis) { + if(!i) { + shift_fprintf (level, fo, "#define SET_PARAM0(val) reg[a] = val\n"); + set_param = 1; + } + shift_fprintf (level, fo, "#define PARAM%i reg[%c]\n", num_ops, + 'a' + num_ops); + if(opd->type & OPTYPE_DST) + write_to_reg = 1; + } else { + shift_fprintf (level, fo, "#define PARAM%i %c\n", num_ops, + 'a' + num_ops); + } + num_ops++; + nbits = 0; + dis = 0; + } + + if ((opd->type & OPTYPE_LAST)) + break; + opd++; + i++; + } while (1); + + output_function (fo, or32_opcodes[insn_index].function_name, level); + + if (set_param) + shift_fprintf (level, fo, "#undef SET_PARAM\n"); + + for (i = 0; i < num_ops; i++) + shift_fprintf (level, fo, "#undef PARAM%i\n", i); + + return dis_op; +} + +/* Generates decode and execute for one instruction instance */ +static int output_call (FILE *fo, int index, int level) +{ + int dis_op = -1; + + /*printf ("%i:%s\n", index, insn_name (index));*/ + + shift_fprintf (level++, fo, "{\n"); + + if (index >= 0) + dis_op = gen_eval_operands (fo, index, level); + + if (index < 0) output_function (fo, "l_invalid", level); + + fprintf (fo, "\n"); + + shift_fprintf (level++, fo, "if (do_stats) {\n"); + + if (dis_op >= 0) + shift_fprintf (level, fo, "insn_ea = %c;\n", 'a' + dis_op); + + shift_fprintf (level, fo, "current->insn_index = %i; /* \"%s\" */\n", index, + insn_name (index)); + + shift_fprintf (level, fo, "analysis(current);\n"); + shift_fprintf (--level, fo, "}\n"); + if (write_to_reg) + shift_fprintf (level, fo, "reg[0] = 0; /* Repair in case we changed it */\n"); + shift_fprintf (--level, fo, "}\n"); + return 0; +} + +/* Generates .c file header */ +static int generate_header (FILE *fo) +{ + fprintf (fo, "/* This file was automatically generated by generate (see cpu/or32/generate.c) */\n\n"); + fprintf (fo, "static inline void decode_execute (struct iqueue_entry *current)\n{\n"); + fprintf (fo, " uint32_t insn = current->insn;\n"); + out_lines = 5; + return 0; +} + +/* Generates .c file footer */ +static int generate_footer (FILE *fo) +{ + fprintf (fo, "}\n"); + return 0; +} + +/* Decodes all instructions and generates code for that. This function + is similar to insn_decode, except it decodes all instructions. */ +static int generate_body (FILE *fo, unsigned long *a, unsigned long cur_mask, int level) +{ + unsigned long shift = *a; + unsigned long mask; + int i; + int prev_inv = 0; + + if (!(*a & LEAF_FLAG)) { + shift = *a++; + mask = *a++; + shift_fprintf (level, fo, "switch((insn >> %i) & 0x%x) {\n", shift, + mask); + for (i = 0; i <= mask; i++, a++) { + if (!*a) { + shift_fprintf (level, fo, "case 0x%x:\n", i); + prev_inv = 1; + } else { + if(prev_inv) { + shift_fprintf (++level, fo, "/* Invalid instruction(s) */\n"); + shift_fprintf (level--, fo, "break;\n"); + } + shift_fprintf (level, fo, "case 0x%x:\n", i); + generate_body (fo, automata + *a, cur_mask | (mask << shift), ++level); + shift_fprintf (level--, fo, "break;\n"); + prev_inv = 0; + } + } + if (prev_inv) { + shift_fprintf (++level, fo, "/* Invalid instruction(s) */\n"); + shift_fprintf (level--, fo, "break;\n"); + } + shift_fprintf (level, fo, "}\n"); + } else { + i = *a & ~LEAF_FLAG; + + /* Final check - do we have direct match? + (based on or32_opcodes this should be the only possibility, + but in case of invalid/missing instruction we must perform a check) */ + + if (ti[i].insn_mask != cur_mask) { + shift_fprintf (level, fo, "/* Not unique: real mask %08lx and current mask %08lx differ - do final check */\n", ti[i].insn_mask, cur_mask); + shift_fprintf (level++, fo, "if((insn & 0x%x) == 0x%x) {\n", + ti[i].insn_mask, ti[i].insn); + } + shift_fprintf (level, fo, "/* Instruction: %s */\n", or32_opcodes[i].name); + + output_call (fo, i, level); + + if (ti[i].insn_mask != cur_mask) { + shift_fprintf (--level, fo, "} else {\n"); + shift_fprintf (++level, fo, "/* Invalid insn */\n"); + output_call (fo, -1, level); + shift_fprintf (--level, fo, "}\n"); + } + } + return 0; +} + +/* Main function; it takes two parameters: + input_file(possibly insnset.c) output_file(possibly execgen.c)*/ +int main (int argc, char *argv[]) +{ + FILE *fo; + + if (argc != 3) { + fprintf (stderr, "USAGE: generate input_file(possibly insnset.c) output_file(possibly execgen.c)\n"); + exit (-1); + } + + in_file = argv[1]; + out_file = argv[2]; + if (!(fo = fopen (argv[2], "wt+"))) { + fprintf (stderr, "Cannot create '%s'.\n", argv[2]); + exit (1); + } + + build_automata (); + if (generate_header (fo)) { + fprintf (stderr, "generate_header\n"); + return 1; + } + + if (generate_body (fo, automata, 0, 1)) { + fprintf (stderr, "generate_body\n"); + return 1; + } + + if (generate_footer (fo)) { + fprintf (stderr, "generate_footer\n"); + return 1; + } + + fclose (fo); + destruct_automata (); + return 0; +} +
generate.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: Makefile.am =================================================================== --- Makefile.am (nonexistent) +++ Makefile.am (revision 1765) @@ -0,0 +1,40 @@ +# Makefile -- Makefile for OR32 dependent simulation +# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org +# +# This file is part of OpenRISC 1000 Architectural Simulator. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +noinst_LIBRARIES = libarch.a +libarch_a_SOURCES = execute.c or32.c + +if SIMPLE_EXECUTION +noinst_PROGRAMS = +generate_SOURCES = + +else +noinst_PROGRAMS = generate +generate_SOURCES = or32.c generate.c +BUILT_SOURCES = execgen.c + +execgen.c: generate $(srcdir)/insnset.c + ./generate $(srcdir)/insnset.c execgen.c + +endif + +# If the simulator was first built without --enable-simple and then with it, +# then also remove these two files +CLEANFILES=execgen.c generate Index: . =================================================================== --- . (nonexistent) +++ . (revision 1765)
. Property changes : Added: svn:ignore ## -0,0 +1,3 ## +Makefile +.deps +generate

powered by: WebSVN 2.1.0

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