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

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1243 to Rev 1244
    Reverse comparison

Rev 1243 → Rev 1244

/trunk/or1ksim/debug/debug_unit.c
52,10 → 52,8
/* Current watchpoint state */
unsigned long watchpoints = 0;
 
static int calculate_watchpoints ();
static int calculate_watchpoints(DebugUnitAction action, unsigned long udata);
 
static int watchpoint[10];
 
void set_stall_state(int state)
{
development.riscop &= ~RISCOP_STALL;
71,6 → 69,11
set_stall_state (0);
}
 
void du_clock()
{
watchpoints=0;
};
 
inline int CheckDebugUnit(DebugUnitAction action, unsigned long udata)
{
/* Do not stop, if we have debug module disabled or during reset */
81,133 → 84,126
if(action == DebugInstructionFetch && testsprbits (SPR_DMR1, SPR_DMR1_ST))
return 1;
 
// is any watchpoint enabled to generate a break or count? If not, ignore
if(mfspr(SPR_DMR2) & (SPR_DMR2_WGB|SPR_DMR2_AWTC))
return calculate_watchpoints(action, udata);
 
return 0;
/* TODO: Enable matchpoints
switch(action)
{
case DebugInstructionFetch: condition = DCR_CT_InsnAddress; break;
case DebugLoadAddress: condition = DCR_CT_LoadAddress; break;
case DebugStoreAddress: condition = DCR_CT_StoreAddress; break;
case DebugLoadData: condition = DCR_CT_LoadData; break;
case DebugStoreData: condition = DCR_CT_StoreData; break;
}
 
return calculate_watchpoints(); */
}
 
/* Checks whether we should stall the RISC or cause an exception */
static int calculate_watchpoints()
static int calculate_watchpoints(DebugUnitAction action, unsigned long udata)
{
int breakpoint = 0;
int i, bit;
/* Hopefully this loop would be unrolled run at max. speed */
for(i = 0, bit = 1; i < 11; i++, bit <<= 1) {
int chain1, chain2;
int match = 0;
int DCR_hit = 0;
/* Calculate first 8 matchpoints, result is put into DCR_hit */
if (i < 8) {
unsigned long dcr = mfspr (SPR_DCR(i));
/* Whether this matchpoint is enabled, calculate conditions */
if ((dcr & SPR_DCR_DP) && (dcr & SPR_DCR_CT != SPR_DCR_CT_DISABLED)) {
/* Get one operand */
unsigned long op1;
unsigned long op2 = mfspr (SPR_DVR(i));
switch (dcr & SPR_DCR_CT) {
case SPR_DCR_CT_IFEA: op1 = runtime.cpu.ifea; break;
case SPR_DCR_CT_LEA: op1 = runtime.cpu.lea; break;
case SPR_DCR_CT_SEA: op1 = runtime.cpu.sea; break;
case SPR_DCR_CT_LD: op1 = runtime.cpu.ld; break;
case SPR_DCR_CT_SD: op1 = runtime.cpu.sd; break;
case SPR_DCR_CT_LSEA: op1 = runtime.cpu.lsea; break;
}
/* Perform signed comparison? */
if (dcr & SPR_DCR_SC) {
long sop1 = op1, sop2 = op2; /* Convert to signed */
switch(dcr & SPR_DCR_CC) {
case SPR_DCR_CC_MASKED: DCR_hit = sop1 & sop2; break;
case SPR_DCR_CC_EQUAL: DCR_hit = sop1 == sop2; break;
case SPR_DCR_CC_NEQUAL: DCR_hit = sop1 != sop2; break;
case SPR_DCR_CC_LESS: DCR_hit = sop1 < sop2; break;
case SPR_DCR_CC_LESSE: DCR_hit = sop1 <= sop2; break;
case SPR_DCR_CC_GREAT: DCR_hit = sop1 > sop2; break;
case SPR_DCR_CC_GREATE: DCR_hit = sop1 >= sop2; break;
}
} else {
switch(dcr & SPR_DCR_CC) {
case SPR_DCR_CC_MASKED: DCR_hit = op1 & op2; break;
case SPR_DCR_CC_EQUAL: DCR_hit = op1 == op2; break;
case SPR_DCR_CC_NEQUAL: DCR_hit = op1 != op2; break;
case SPR_DCR_CC_LESS: DCR_hit = op1 < op2; break;
case SPR_DCR_CC_LESSE: DCR_hit = op1 <= op2; break;
case SPR_DCR_CC_GREAT: DCR_hit = op1 > op2; break;
case SPR_DCR_CC_GREATE: DCR_hit = op1 >= op2; break;
}
}
}
}
int breakpoint = 0;
int i, bit;
 
/* Chain matchpoints */
switch(i) {
case 0:
chain1 = chain2 = DCR_hit;
break;
case 8:
chain1 = getsprbits (SPR_DWCR0, SPR_DWCR_COUNT) == getsprbits (SPR_DWCR0, SPR_DWCR_MATCH);
chain2 = watchpoints & (1 << 7);
break;
case 9:
chain1 = getsprbits (SPR_DWCR1, SPR_DWCR_COUNT) == getsprbits (SPR_DWCR1, SPR_DWCR_MATCH);
chain2 = watchpoints & (1 << 8);
break;
case 10:
/* TODO: External watchpoint - not yet handled! */
/* Hopefully this loop would be unrolled run at max. speed */
for(i = 0, bit = 1; i < 11; i++, bit <<= 1) {
int chain1, chain2;
int match = 0;
int DCR_hit = 0;
 
/* Calculate first 8 matchpoints, result is put into DCR_hit */
if (i < 8) {
unsigned long dcr = mfspr (SPR_DCR(i));
unsigned long dcr_ct=dcr&SPR_DCR_CT; // the CT field alone
/* Is this matchpoint a propos for the current action? */
if ( ((dcr & SPR_DCR_DP) && dcr_ct) &&// DVR/DCP pair present
(((action==DebugInstructionFetch) && (dcr_ct == SPR_DCR_CT_IFEA))
|| ((action==DebugLoadAddress) && ((dcr_ct == SPR_DCR_CT_LEA) || (dcr_ct == SPR_DCR_CT_LSEA)))
|| ((action==DebugStoreAddress) && ((dcr_ct == SPR_DCR_CT_SEA) || (dcr_ct == SPR_DCR_CT_LSEA)))
|| ((action==DebugLoadData) && ((dcr_ct == SPR_DCR_CT_LD) || (dcr_ct == SPR_DCR_CT_LSD)))
|| ((action==DebugStoreData) && ((dcr_ct == SPR_DCR_CT_SD) || (dcr_ct == SPR_DCR_CT_LSD)))) )
{
unsigned long op1=udata;
unsigned long op2 = mfspr (SPR_DVR(i));
/* Perform signed comparison? */
if (dcr & SPR_DCR_SC) {
long sop1 = op1, sop2 = op2; /* Convert to signed */
switch(dcr & SPR_DCR_CC) {
case SPR_DCR_CC_MASKED: DCR_hit = sop1 & sop2; break;
case SPR_DCR_CC_EQUAL: DCR_hit = sop1 == sop2; break;
case SPR_DCR_CC_NEQUAL: DCR_hit = sop1 != sop2; break;
case SPR_DCR_CC_LESS: DCR_hit = sop1 < sop2; break;
case SPR_DCR_CC_LESSE: DCR_hit = sop1 <= sop2; break;
case SPR_DCR_CC_GREAT: DCR_hit = sop1 > sop2; break;
case SPR_DCR_CC_GREATE: DCR_hit = sop1 >= sop2; break;
}
} else {
switch(dcr & SPR_DCR_CC) {
case SPR_DCR_CC_MASKED: DCR_hit = op1 & op2; break;
case SPR_DCR_CC_EQUAL: DCR_hit = op1 == op2; break;
case SPR_DCR_CC_NEQUAL: DCR_hit = op1 != op2; break;
case SPR_DCR_CC_LESS: DCR_hit = op1 < op2; break;
case SPR_DCR_CC_LESSE: DCR_hit = op1 <= op2; break;
case SPR_DCR_CC_GREAT: DCR_hit = op1 > op2; break;
case SPR_DCR_CC_GREATE: DCR_hit = op1 >= op2; break;
}
}
}
}
 
/* Chain matchpoints */
switch(i)
{
case 0:
chain1 = chain2 = DCR_hit;
break;
case 8:
chain1 = getsprbits (SPR_DWCR0, SPR_DWCR_COUNT) == getsprbits (SPR_DWCR0, SPR_DWCR_MATCH);
chain2 = watchpoints & (1 << 7);
break;
case 9:
chain1 = getsprbits (SPR_DWCR1, SPR_DWCR_COUNT) == getsprbits (SPR_DWCR1, SPR_DWCR_MATCH);
chain2 = watchpoints & (1 << 8);
break;
case 10:
/* TODO: External watchpoint - not yet handled! */
#if 0
chain1 = external_watchpoint;
chain2 = watchpoints & (1 << 9);
chain1 = external_watchpoint;
chain2 = watchpoints & (1 << 9);
#else
chain1 = chain2 = 0;
chain1 = chain2 = 0;
#endif
break;
default:
chain1 = DCR_hit;
chain2 = watchpoints & (bit >> 1);
break;
}
break;
default:
chain1 = DCR_hit;
chain2 = watchpoints & (bit >> 1);
break;
}
 
switch(getsprbits (SPR_DMR1, SPR_DMR1_CW0 << i)) {
case 0: match = chain1; break;
case 1: match = chain1 && chain2; break;
case 2: match = chain1 || chain2; break;
default:
break;
}
switch(getsprbits (SPR_DMR1, SPR_DMR1_CW0 << i)) {
case 0: match = chain1; break;
case 1: match = chain1 && chain2; break;
case 2: match = chain1 || chain2; break;
default:
break;
}
 
if(match & !(watchpoints & bit)) {
int counter = (getsprbits (SPR_DMR2, SPR_DMR2_AWTC) & bit) ? 1 : 0;
int enabled = counter ? getsprbits (SPR_DMR2, SPR_DMR2_WCE1) : getsprbits (SPR_DMR2, SPR_DMR2_WCE0);
// Increment counters & generate counter break
if(match)
{
if(!(watchpoints & bit)) // watchpoint did not appear before in this clock cycle
{
int counter = (getsprbits (SPR_DMR2, SPR_DMR2_AWTC) & bit) ? 1 : 0;
int enabled = counter ? getsprbits (SPR_DMR2, SPR_DMR2_WCE1) : getsprbits (SPR_DMR2, SPR_DMR2_WCE0);
if(enabled)
setsprbits (SPR_DWCR0 + counter, SPR_DWCR_COUNT, getsprbits (SPR_DWCR0 + counter, SPR_DWCR_COUNT) + 1);
watchpoints |= bit;
}
 
if(enabled)
setsprbits (SPR_DWCR0 + counter, SPR_DWCR_COUNT, getsprbits (SPR_DWCR0 + counter, SPR_DWCR_COUNT) + 1);
 
if(getsprbits (SPR_DMR2, SPR_DMR2_WGB) & bit)
breakpoint = 1;
}
watchpoints &= ~bit;
watchpoints |= bit;
}
 
return breakpoint;
// should this watchpoint generate a breakpoint?
if(getsprbits (SPR_DMR2, SPR_DMR2_WGB) & bit) breakpoint = 1;
}
}
return breakpoint;
}
 
static DebugScanChainIDs current_scan_chain = JTAG_CHAIN_GLOBAL;
 
int DebugGetRegister(unsigned int address, unsigned long* data)
{
int err;
int err=0;
#ifdef DEBUG_JTAG
PRINTF("Debug get register %x\n",address);
fflush(stdout);
223,13 → 219,12
break;
case JTAG_CHAIN_TRACE:
*data = 0; /* Scan chain not yet implemented */
err = 0;
break;
case JTAG_CHAIN_DEVELOPMENT:
err = get_devint_reg(address,data);
break;
case JTAG_CHAIN_WISHBONE:
err = GetWishboneMemory(address,data);
err = debug_get_mem(address,data);
break;
}
#ifdef DEBUG_JTAG
241,7 → 236,7
 
int DebugSetRegister(unsigned int address,unsigned long data)
{
int err;
int err=0;
#ifdef DEBUG_JTAG
PRINTF("Debug set register %x <- %x\n", address, data);
fflush(stdout);
387,22 → 382,14
if(!verify_memoryarea(address))
err = JTAG_PROXY_INVALID_ADDRESS;
else {
unsigned char t_data[4];
int *tmp = (int*)t_data;
extern char null_str[1]; /* From cpu/common/parse.c */
int i;
 
*tmp = htonl(data); /* We have already converted to host order */
 
setsim_mem8(address++, t_data[0]); /* Back to network byte order */
setsim_mem8(address++, t_data[1]);
setsim_mem8(address++, t_data[2]);
setsim_mem8(address++, t_data[3]);
// circumvent the read-only check usually done for mem accesses
// data is in host order, because that's what simmem_write_word needs
simmem_write_word(address, data);
}
return err;
}
 
int GetWishboneMemory(unsigned int address,unsigned long *data)
int debug_get_mem(unsigned int address,unsigned long *data)
{
int err = 0;
if(!verify_memoryarea(address))
409,16 → 396,7
err = JTAG_PROXY_INVALID_ADDRESS;
else
{
unsigned char t_data[4];
int *tmp = (int*)t_data;
int bp;
 
t_data[0] = evalsim_mem8(address++);
t_data[1] = evalsim_mem8(address++);
t_data[2] = evalsim_mem8(address++);
t_data[3] = evalsim_mem8(address++); /* Already in network byte order */
*data = ntohl(*tmp); /* But we assume it is in host order later */
*data=simmem_read_word(address);
}
debug (2, "MEMREAD (%08x) = %08x\n", address, *data);
return err;
/trunk/or1ksim/debug/debug_unit.h
88,6 → 88,9
/* Resets the debug unit */
void du_reset(void);
 
/* do cycle-related initialisation (watchpoints etc.) */
void du_clock();
 
/* set cpu_stalled flag */
void set_stall_state (int state);
 
/trunk/or1ksim/cpu/or32/execute.c
266,10 → 266,10
}
break_just_hit = 0;
}
runtime.cpu.instructions++;
pc_phy &= ~0x03;
runtime.cpu.instructions++;
 
/* Fetch instruction. */
iqueue[0].insn_addr = pc;
iqueue[0].insn = eval_insn (pc_phy, &breakpoint);
/trunk/or1ksim/cpu/or32/insnset.c
39,7 → 39,7
 
temp4 = temp1;
if (temp4 == temp1)
mstats.byteadd++;
or1k_mstats.byteadd++;
}
INSTRUCTION (l_addc) {
signed long temp1, temp2, temp3;
62,7 → 62,7
 
temp4 = temp1;
if (temp4 == temp1)
mstats.byteadd++;
or1k_mstats.byteadd++;
}
INSTRUCTION (l_sw) {
int old_cyc = 0;
227,7 → 227,7
if (config.bpb.enabled) {
int fwd = (eval_operand32(0, &breakpoint) >= pc) ? 1 : 0;
IFF (config.cpu.dependstats) current->func_unit = it_branch;
mstats.bf[flag][fwd]++;
or1k_mstats.bf[flag][fwd]++;
bpb_update(current->insn_addr, flag);
}
if (flag) {
242,7 → 242,7
if (config.bpb.enabled) {
int fwd = (eval_operand32(0, &breakpoint) >= pc) ? 1 : 0;
IFF (config.cpu.dependstats) current->func_unit = it_branch;
mstats.bnf[!flag][fwd]++;
or1k_mstats.bnf[!flag][fwd]++;
bpb_update(current->insn_addr, flag == 0);
}
if (flag == 0) {
/trunk/or1ksim/cpu/or32/generate.c
131,7 → 131,10
int output_function (FILE *fo, const char *func_name, int level)
{
FILE *fi;
if ((fi = fopen (in_file, "rt")) == NULL) return 1;
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);
165,6 → 168,7
}
SHIFT;
} while (olevel);
fclose(fi);
return 0;
}
}
174,6 → 178,8
SHIFT; fprintf (fo, "%s ();\n", func_name);
level--;
SHIFT; fprintf (fo, "}");
 
fclose(fi);
return 0;
}
 
270,7 → 276,7
level--;
SHIFT; fprintf (fo, "}\n");
if (write_to_reg) {
SHIFT; fprintf (fo, "reg[0] = 0; /* Repair in case we changed it */\n", i);
SHIFT; fprintf (fo, "reg[0] = 0; /* Repair in case we changed it */\n");
}
level--;
SHIFT; fprintf (fo, "}");
343,11 → 349,11
fprintf (fo, "\n");
SHIFT; fprintf (fo, "/* Not unique: real mask %08x and current mask %08x differ - do final check */\n", ti[i].insn_mask, cur_mask);
SHIFT; fprintf (fo, "if ((insn & 0x%08x) == 0x%08x) ", ti[i].insn_mask, ti[i].insn);
output_call (fo, i, level);
if (output_call (fo, i, level)) return 1; // Fail
fprintf (fo, " else ");
if (output_call (fo, -1, level)) return 1;
if (output_call (fo, -1, level)) return 1; // Fail
} else {
output_call (fo, i, level - 1);
if (output_call (fo, i, level - 1)) return 1; // Fail
}
fprintf (fo, " break;\n");
}
/trunk/or1ksim/cpu/common/stats.c
41,7 → 41,7
struct dstats_entry dstats[DSTATS_LEN]; /* dependency stats */
struct sstats_entry sstats[SSTATS_LEN]; /* single stats */
struct fstats_entry fstats[FSTATS_LEN]; /* functional units stats */
struct mstats_entry mstats = {0}; /* misc units stats */
struct mstats_entry or1k_mstats = {0}; /* misc units stats */
struct cachestats_entry ic_stats = {0}; /* instruction cache stats */
struct cachestats_entry dc_stats = {0}; /* data cache stats */
struct immustats_entry immu_stats = {0}; /* insn mmu stats */
127,7 → 127,7
for (i = 0; i < DSTATS_LEN; i++)
dstats[i].insn1 = dstats[i].insn2 = -1;
memset(fstats, 0, sizeof(fstats));
memset(&mstats, 0, sizeof(mstats));
memset(&or1k_mstats, 0, sizeof(or1k_mstats));
memset(&ic_stats, 0, sizeof(ic_stats));
memset(&dc_stats, 0, sizeof(dc_stats));
memset(&raw_stats, 0, sizeof(raw_stats));
142,16 → 142,16
struct branchstat bf;
struct branchstat bnf;
long bf_all, bnf_all;
bf.taken = mstats.bf[1][0] + mstats.bf[1][1];
bf.nottaken = mstats.bf[0][0] + mstats.bf[0][1];
bf.forward = mstats.bf[0][1] + mstats.bf[1][1];
bf.backward = mstats.bf[0][0] + mstats.bf[1][0];
bf.taken = or1k_mstats.bf[1][0] + or1k_mstats.bf[1][1];
bf.nottaken = or1k_mstats.bf[0][0] + or1k_mstats.bf[0][1];
bf.forward = or1k_mstats.bf[0][1] + or1k_mstats.bf[1][1];
bf.backward = or1k_mstats.bf[0][0] + or1k_mstats.bf[1][0];
bf_all = bf.forward + bf.backward;
bnf.taken = mstats.bnf[1][0] + mstats.bf[1][1];
bnf.nottaken = mstats.bnf[0][0] + mstats.bf[0][1];
bnf.forward = mstats.bnf[0][1] + mstats.bf[1][1];
bnf.backward = mstats.bnf[0][0] + mstats.bf[1][0];
bnf.taken = or1k_mstats.bnf[1][0] + or1k_mstats.bf[1][1];
bnf.nottaken = or1k_mstats.bnf[0][0] + or1k_mstats.bf[0][1];
bnf.forward = or1k_mstats.bnf[0][1] + or1k_mstats.bf[1][1];
bnf.backward = or1k_mstats.bnf[0][0] + or1k_mstats.bf[1][0];
bnf_all = bnf.forward + bnf.backward;
PRINTF("bnf: %d (%d%%) taken,", bf.taken, (bf.taken * 100) / SD(bf_all));
164,15 → 164,15
PRINTF(" %d (%d%%) backward\n", bnf.backward, (bnf.backward * 100) / SD(bnf_all));
PRINTF("StaticBP bnf(%s): correct %d%%\n", config.bpb.sbp_bnf_fwd ? "forward" : "backward",
(mstats.bnf[0][config.bpb.sbp_bnf_fwd] * 100) / SD(bnf_all));
(or1k_mstats.bnf[0][config.bpb.sbp_bnf_fwd] * 100) / SD(bnf_all));
PRINTF("StaticBP bf(%s): correct %d%%\n", config.bpb.sbp_bf_fwd ? "forward" : "backward",
(mstats.bnf[1][config.bpb.sbp_bf_fwd] * 100) / SD(bf_all));
PRINTF("BPB: hit %d (correct %d%%), miss %d\n", mstats.bpb.hit, (mstats.bpb.correct * 100) / SD(mstats.bpb.hit), mstats.bpb.miss);
(or1k_mstats.bnf[1][config.bpb.sbp_bf_fwd] * 100) / SD(bf_all));
PRINTF("BPB: hit %d (correct %d%%), miss %d\n", or1k_mstats.bpb.hit, (or1k_mstats.bpb.correct * 100) / SD(or1k_mstats.bpb.hit), or1k_mstats.bpb.miss);
} else
PRINTF("BPB simulation disabled. Enable it to see BPB analysis\n");
 
if (config.bpb.btic) {
PRINTF("BTIC: hit %d(%d%%), miss %d\n", mstats.btic.hit, (mstats.btic.hit * 100) / SD(mstats.btic.hit + mstats.btic.miss), mstats.btic.miss);
PRINTF("BTIC: hit %d(%d%%), miss %d\n", or1k_mstats.btic.hit, (or1k_mstats.btic.hit * 100) / SD(or1k_mstats.btic.hit + or1k_mstats.btic.miss), or1k_mstats.btic.miss);
} else
PRINTF("BTIC simulation disabled. Enabled it to see BTIC analysis\n");
 
286,6 → 286,6
break;
}
#if 0
PRINTF("Byte ADD: %d instructions\n", mstats.byteadd);
PRINTF("Byte ADD: %d instructions\n", or1k_mstats.byteadd);
#endif
}
/trunk/or1ksim/cpu/common/coff.h
1,3 → 1,7
#if HAVE_CONFIG_H
#include <config.h>
#endif
 
/* This file is derived from the GAS 2.1.4 assembler control file.
The GAS product is under the GNU Public License, version 2 or later.
As such, this file is also under that license.
20,23 → 24,34
* and the values loaded from the character positions. It also makes it
* nice to have it "endian" independent.
*/
#if !defined(WORDS_BIGENDIAN)
/* Load a short int from the following tables with little-endian formats */
#define COFF_SHORT_L(ps) ((short)(((unsigned short)((unsigned char)ps[1])<<8)|\
#define COFF_SHORT_L SWAP_ENDIAN_SHORT
/* Load a long int from the following tables with little-endian formats */
#define COFF_LONG_L SWAP_ENDIAN_LONG
/* Load a short int from the following tables with big-endian formats */
#define COFF_SHORT_H KEEP_ENDIAN_SHORT
/* Load a long int from the following tables with big-endian formats */
#define COFF_LONG_H KEEP_ENDIAN_LONG
#else
#define COFF_SHORT_L KEEP_ENDIAN_SHORT
#define COFF_LONG_L KEEP_ENDIAN_LONG
#define COFF_SHORT_H SWAP_ENDIAN_SHORT
#define COFF_LONG_H SWAP_ENDIAN_LONG
#endif
 
#define SWAP_ENDIAN_SHORT(ps) ((short)(((unsigned short)((unsigned char)ps[1])<<8)|\
((unsigned short)((unsigned char)ps[0]))))
 
/* Load a long int from the following tables with little-endian formats */
#define COFF_LONG_L(ps) (((long)(((unsigned long)((unsigned char)ps[3])<<24) |\
#define SWAP_ENDIAN_LONG(ps) (((long)(((unsigned long)((unsigned char)ps[3])<<24) |\
((unsigned long)((unsigned char)ps[2])<<16) |\
((unsigned long)((unsigned char)ps[1])<<8) |\
((unsigned long)((unsigned char)ps[0])))))
/* Load a short int from the following tables with big-endian formats */
#define COFF_SHORT_H(ps) ((short)(((unsigned short)((unsigned char)ps[0])<<8)|\
#define KEEP_ENDIAN_SHORT(ps) ((short)(((unsigned short)((unsigned char)ps[0])<<8)|\
((unsigned short)((unsigned char)ps[1]))))
 
/* Load a long int from the following tables with big-endian formats */
#define COFF_LONG_H(ps) (((long)(((unsigned long)((unsigned char)ps[0])<<24) |\
#define KEEP_ENDIAN_LONG(ps) (((long)(((unsigned long)((unsigned char)ps[0])<<24) |\
((unsigned long)((unsigned char)ps[1])<<16) |\
((unsigned long)((unsigned char)ps[2])<<8) |\
((unsigned long)((unsigned char)ps[3])))))
/trunk/or1ksim/cpu/common/abstract.c
362,8 → 362,14
mprofile (memaddr, MPROF_32 | MPROF_FETCH);
// memaddr = simulate_ic_mmu_fetch(memaddr);
cur_vadd = pc;
if (config.debug.enabled)
*breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */
 
// I think this does not belong into eval_insn() 2004-01-30 HP
// if (config.debug.enabled)
// *breakpoint += CheckDebugUnit(DebugLoadAddress,memaddr); /* 28/05/01 CZ */
 
// We could place the CheckDebugUnit(DebugInstructionFetch) here, but it is currently done
// in decode_execute_wrapper, so I leave it like this. 2004-01-30 HP
if (config.ic.enabled)
temp = ic_simulate_fetch(memaddr);
else {
375,8 → 381,9
}
}
 
if (config.debug.enabled)
*breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */
// I think this does not belong into eval_insn() 2004-01-30 HP
// if (config.debug.enabled)
// *breakpoint += CheckDebugUnit(DebugLoadData,temp); /* MM170901 */
return temp;
}
 
/trunk/or1ksim/cpu/common/stats.h
91,7 → 91,8
int range[RAW_RANGE];
}; /* RAW hazard stats */
 
extern struct mstats_entry mstats;
/* Renamed mstats to or1k_mstats because Mac OS X has a lib function called mstats */
extern struct mstats_entry or1k_mstats;
extern struct sstats_entry sstats[SSTATS_LEN];
extern struct dstats_entry dstats[DSTATS_LEN];
extern struct fstats_entry fstats[FSTATS_LEN];
/trunk/or1ksim/cpu/common/elf.h
1,6 → 1,14
#ifndef _LINUX_ELF_H
#define _LINUX_ELF_H
 
#if HAVE_CONFIG_H
#include <config.h>
#endif
 
#ifdef WORDS_BIGENDIAN
#define ELF_SHORT_H
#define ELF_LONG_H
#else
/* Load a short int from the following tables with big-endian formats */
#define ELF_SHORT_H(ps) ((((unsigned short)(ps) >> 8) & 0xff) |\
(((unsigned short)(ps) << 8) & 0xff00))
10,6 → 18,7
(((unsigned long)(ps) >> 8) & 0xff00)|\
(((unsigned long)(ps) << 8) & 0xff0000)|\
(((unsigned long)(ps) << 24) & 0xff000000))
#endif
 
typedef unsigned long Elf32_Addr;
typedef unsigned short Elf32_Half;
/trunk/or1ksim/cpu/or1k/spr_defs.h
267,12 → 267,12
 
/* Bit results with SPR_DCR_CC mask */
#define SPR_DCR_CC_MASKED 0x00000000
#define SPR_DCR_CC_EQUAL 0x00000001
#define SPR_DCR_CC_LESS 0x00000002
#define SPR_DCR_CC_LESSE 0x00000003
#define SPR_DCR_CC_GREAT 0x00000004
#define SPR_DCR_CC_GREATE 0x00000005
#define SPR_DCR_CC_NEQUAL 0x00000006
#define SPR_DCR_CC_EQUAL 0x00000002
#define SPR_DCR_CC_LESS 0x00000004
#define SPR_DCR_CC_LESSE 0x00000006
#define SPR_DCR_CC_GREAT 0x00000008
#define SPR_DCR_CC_GREATE 0x0000000a
#define SPR_DCR_CC_NEQUAL 0x0000000c
 
/* Bit results with SPR_DCR_CT mask */
#define SPR_DCR_CT_DISABLED 0x00000000
282,6 → 282,8
#define SPR_DCR_CT_LD 0x00000080
#define SPR_DCR_CT_SD 0x000000a0
#define SPR_DCR_CT_LSEA 0x000000c0
#define SPR_DCR_CT_LSD 0x000000e0
/* SPR_DCR_CT_LSD doesn't seem to be implemented anywhere in or1ksim. 2004-1-30 HP */
 
/*
* Bit definitions for Debug Mode 1 register
/trunk/or1ksim/extras/Makefile.in
0,0 → 1,332
# 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 cpu architecture independent 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@
LOCAL_LDFLAGS = @LOCAL_LDFLAGS@
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 = libextras.a
libextras_a_SOURCES = extras.c
subdir = extras
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
LIBRARIES = $(noinst_LIBRARIES)
 
libextras_a_AR = $(AR) cru
libextras_a_LIBADD =
am_libextras_a_OBJECTS = extras.$(OBJEXT)
libextras_a_OBJECTS = $(am_libextras_a_OBJECTS)
 
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)/extras.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 = $(libextras_a_SOURCES)
DIST_COMMON = Makefile.am Makefile.in
SOURCES = $(libextras_a_SOURCES)
 
all: all-am
 
.SUFFIXES:
.SUFFIXES: .c .o .obj
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu extras/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)
libextras.a: $(libextras_a_OBJECTS) $(libextras_a_DEPENDENCIES)
-rm -f libextras.a
$(libextras_a_AR) libextras.a $(libextras_a_OBJECTS) $(libextras_a_LIBADD)
$(RANLIB) libextras.a
 
mostlyclean-compile:
-rm -f *.$(OBJEXT) core *.core
 
distclean-compile:
-rm -f *.tab.c
 
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extras.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)
 
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:
 
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."
clean: clean-am
 
clean-am: clean-generic clean-noinstLIBRARIES 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 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
 
# 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:
/trunk/or1ksim/extras/extras.c
0,0 → 1,23
#include "extras.h"
 
#include "string.h"
 
#if !defined(HAVE_STRNDUP)
 
/* Taken from glibc */
char *
strndup (const char *s, size_t n)
{
size_t len = strlen (s);
if(len>n) len=n;
char *new = (char *) malloc (len + 1);
 
if (new == NULL)
return NULL;
 
new[len] = '\0';
return (char *) memcpy (new, s, len);
}
 
#endif
/trunk/or1ksim/extras/Makefile.am
0,0 → 1,22
# Makefile -- Makefile for cpu architecture independent 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 = libextras.a
libextras_a_SOURCES = extras.c
/trunk/or1ksim/extras/extras.h
0,0 → 1,10
#ifndef __STRNDUP__
#define __STRNDUP__
 
#include "stdlib.h"
 
#if !defined(HAVE_STRNDUP)
char * strndup (const char *s, size_t n);
#endif
 
#endif
/trunk/or1ksim/cuc/cuc.h
1,311 → 1,309
/* cuc.h -- OpenRISC Custom Unit Compiler, main header file
* Copyright (C) 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. */
 
#ifndef __DATAF_H__
#define __DATAF_H__
 
/* Maximum number of instructions per function */
#define MAX_INSNS 0x10000
#define MAX_OPERANDS 4
#define MAX_BB 0x1000
#define MAX_REGS 34
#define FLAG_REG (MAX_REGS - 2)
#define LRBB_REG (MAX_REGS - 1)
#define MAX_STACK 0x1000 /* if more, not converted */
#define MAX_PREROLL 32
#define MAX_UNROLL 32
 
#define IT_BRANCH 0x0001 /* Branch instruction */
#define IT_INDELAY 0x0002 /* Instruction is in delay slot */
#define IT_BBSTART 0x0004 /* BB start marker */
#define IT_BBEND 0x0008 /* BB end marker */
#define IT_OUTPUT 0x0010 /* this instruction holds final value of the register */
#define IT_SIGNED 0x0020 /* Instruction is signed */
#define IT_MEMORY 0x0040 /* Instruction does memory access */
#define IT_UNUSED 0x0080 /* dead instruction marker */
#define IT_FLAG1 0x0100 /* misc flags */
#define IT_FLAG2 0x0200
#define IT_VOLATILE 0x0400 /* Should not be moved/removed */
#define IT_MEMADD 0x0800 /* add before the load -- should not be removed */
#define IT_COND 0x1000 /* Conditional */
#define IT_LATCHED 0x2000 /* Output of this instruction is latched/registered */
#define IT_CUT 0x4000 /* After this instruction register is placed */
 
#define OPT_NONE 0x00
#define OPT_CONST 0x01
#define OPT_REGISTER 0x02
#define OPT_REF 0x04
#define OPT_JUMP 0x08 /* Jump to an instruction index */
#define OPT_DEST 0x10 /* This operand is dest */
#define OPT_BB 0x20 /* Jumpt to BB */
#define OPT_LRBB 0x40 /* 0 if we came in from left BB, or 1 otherwise */
 
#define MT_WIDTH 0x007 /* These bits hold memory access width in bytes */
#define MT_BURST 0x008 /* burst start & end markers */
#define MT_BURSTE 0x010
#define MT_CALL 0x020 /* This is a call */
#define MT_LOAD 0x040 /* This memory access does a read */
#define MT_STORE 0x080 /* This memory access does a write */
#define MT_SIGNED 0x100 /* Signed memory access */
 
#define MO_NONE 0 /* different memory ordering, even if there are dependencies,
burst can be made, width can change */
#define MO_WEAK 1 /* different memory ordering, if there cannot be dependencies,
burst can be made, width can change */
#define MO_STRONG 2 /* Same memory ordering, burst can be made, width can change */
#define MO_EXACT 3 /* Exacltly the same memory ordering and widths */
 
#define BB_INLOOP 0x01 /* This block is inside a loop */
#define BB_OPTIONAL 0x02
#define BB_DEAD 0x08 /* This block is unaccessible -> to be removed */
 
#define BBID_START MAX_BB /* Start BB pointer */
#define BBID_END (MAX_BB + 1) /* End BB pointer */
 
/* Various macros to minimize code size */
#define REF(bb,i) (((bb) * MAX_INSNS) + (i))
#define REF_BB(r) ((r) / MAX_INSNS)
#define REF_I(r) ((r) % MAX_INSNS)
#define INSN(ref) bb[REF_BB(ref)].insn[REF_I(ref)]
#ifndef MIN
# define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
 
#ifndef MAX
# define MAX(x,y) ((x) > (y) ? (x) : (y))
#endif
 
#define log(x...) {fprintf (flog, x); fflush (flog); }
 
#define cucdebug(x,s...) {if ((x) <= cuc_debug) PRINTF (s);}
 
#define CUC_WIDTH_ITERATIONS 256
 
/* Options */
/* Whether we are debugging cuc (0-9) */
extern int cuc_debug;
 
/* Temporary registers by software convention */
extern const int caller_saved[MAX_REGS];
 
typedef struct _dep_list_t {
unsigned long ref;
struct _dep_list_t *next;
} dep_list;
 
/* Shared list, if marked dead, entry is not used */
typedef struct _csm_list {
int ref;
int cnt;
int cmovs;
double size, osize;
int cmatch;
int dead;
int ninsn; /* Number of associated instructions */
struct _csm_list *from;
struct _csm_list *next;
} cuc_shared_list;
 
/* Shared resource item definition */
typedef struct {
int ref;
int cmatch;
} cuc_shared_item;
 
/* Implementation specific timings */
typedef struct {
int b; /* Basic block # this timing is referring to */
int preroll; /* How many times was this BB pre/unrolled */
int unroll;
int nshared;
cuc_shared_item *shared; /* List of shared resources */
int new_time;
double size;
} cuc_timings;
 
/* Instructionn entity */
typedef struct {
int type; /* type of the instruction */
int index; /* Instruction index */
int opt[MAX_OPERANDS]; /* operand types */
unsigned long op[MAX_OPERANDS]; /* operand values */
dep_list *dep; /* instruction dependencies */
unsigned long insn; /* Instruction opcode */
char disasm[40]; /* disassembled string */
unsigned long max; /* max result value */
int tmp;
} cuc_insn;
 
/* Basic block entity */
typedef struct {
unsigned long type; /* Type of the bb */
int first, last; /* Where this block lies */
int prev[2], next[2];
int tmp;
cuc_insn *insn; /* Instructions lie here */
int ninsn; /* Number of instructions */
int last_used_reg[MAX_REGS];
dep_list *mdep; /* Last memory access dependencies */
int nmemory;
int cnt; /* how many times was this block executed */
int unrolled; /* how many times has been this block unrolled */
int ntim; /* Basic block options */
cuc_timings *tim;
int selected_tim; /* Selected option, -1 if none */
} cuc_bb;
 
/* Function entity */
typedef struct _cuc_func {
/* Basic blocks */
int num_bb;
cuc_bb bb[MAX_BB];
int saved_regs[MAX_REGS];/* Whether this register was saved */
int lur[MAX_REGS]; /* Location of last use */
int used_regs[MAX_REGS]; /* Nonzero if it was used */
/* Schedule of memory instructions */
int nmsched;
int msched[MAX_INSNS];
int mtype[MAX_INSNS];
 
/* initial bb and their relocations to new block numbers */
int num_init_bb;
int *init_bb_reloc;
int orig_time; /* time in cyc required for SW implementation */
int num_runs; /* Number times this function was run */
cuc_timings timings; /* Base timings */
unsigned long start_addr; /* Address of first instruction inn function */
unsigned long end_addr; /* Address of last instruction inn function */
int memory_order; /* Memory order */
 
int nfdeps; /* Function dependencies */
struct _cuc_func **fdeps;
 
int tmp;
} cuc_func;
 
/* Instructions from function */
extern cuc_insn insn[MAX_INSNS];
extern int num_insn;
extern int reloc[MAX_INSNS];
extern FILE *flog;
 
/* returns log2(x) */
/*
int log2 (unsigned long x);
*/
 
/* Loads from file into global array insn */
int cuc_load (char *in_fn);
 
/* Negates conditional instruction */
void negate_conditional (cuc_insn *ii);
 
/* Scans sequence of BBs and set bb[].cnt */
void generate_bb_seq (cuc_func *f, char *mp_filename, char *bb_filename);
 
/* Prints out instructions */
void print_insns (int bb, cuc_insn *insn, int size, int verbose);
 
/* prints out bb string */
void print_bb_num (int num);
 
/* Print out basic blocks */
void print_cuc_bb (cuc_func *func, char *s);
 
/* Duplicates function */
cuc_func *dup_func (cuc_func *f);
 
/* Releases memory allocated by function */
void free_func (cuc_func *f);
 
/* Common subexpression matching -- resource sharing, analysis pass */
void csm (cuc_func *f);
 
/* Common subexpression matching -- resource sharing, generation pass */
void csm_gen (cuc_func *f, cuc_func *rf, cuc_shared_item *shared, int nshared);
 
/* Set the BB limits */
void detect_bb (cuc_func *func);
 
/* Optimize basic blocks */
int optimize_bb (cuc_func *func);
 
/* Search and optimize complex cmov assignments */
int optimize_cmovs (cuc_func *func);
 
/* Optimizes dataflow tree */
int optimize_tree (cuc_func *func);
 
/* Remove nop instructions */
int remove_nops (cuc_func *func);
 
/* Removes dead instruction */
int remove_dead (cuc_func *func);
 
/* Removes trivial register assignments */
int remove_trivial_regs (cuc_func *f);
 
/* Determine inputs and outputs */
void set_io (cuc_func *func);
 
/* Removes BBs marked as dead */
int remove_dead_bb (cuc_func *func);
 
/* Common subexpression elimination */
int cse (cuc_func *f);
 
/* Detect register dependencies */
void reg_dep (cuc_func *func);
 
/* Cuts the tree and marks registers */
void mark_cut (cuc_func *f);
 
/* Unroll loop b times times and return new function. Original
function is unmodified. */
cuc_func *preunroll_loop (cuc_func *func, int b, int preroll, int unroll, char *bb_filename);
 
/* Clean memory and data dependencies */
void clean_deps (cuc_func *func);
 
/* Schedule memory accesses
0 - exact; 1 - strong; 2 - weak; 3 - none */
int schedule_memory (cuc_func *func, int otype);
 
/* Generates verilog file out of insn dataflow */
void output_verilog (cuc_func *func, char *filename, char *funcname);
 
/* Recalculates bb[].cnt values, based on generated profile file */
void recalc_cnts (cuc_func *f, char *bb_filename);
 
/* Calculate timings */
void analyse_timings (cuc_func *func, cuc_timings *timings);
 
/* Calculates facts, that are determined by conditionals */
void insert_conditional_facts (cuc_func *func);
 
/* Width optimization -- detect maximum values */
void detect_max_values (cuc_func *f);
 
/* Inserts n nops before insn 'ref' */
void insert_insns (cuc_func *f, int ref, int n);
 
#endif /* __DATAF_H__ */
/* cuc.h -- OpenRISC Custom Unit Compiler, main header file
* Copyright (C) 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. */
 
#ifndef __DATAF_H__
#define __DATAF_H__
 
/* Maximum number of instructions per function */
#define MAX_INSNS 0x10000
#define MAX_OPERANDS 4
#define MAX_BB 0x1000
#define MAX_REGS 34
#define FLAG_REG (MAX_REGS - 2)
#define LRBB_REG (MAX_REGS - 1)
#define MAX_STACK 0x1000 /* if more, not converted */
#define MAX_PREROLL 32
#define MAX_UNROLL 32
 
#define IT_BRANCH 0x0001 /* Branch instruction */
#define IT_INDELAY 0x0002 /* Instruction is in delay slot */
#define IT_BBSTART 0x0004 /* BB start marker */
#define IT_BBEND 0x0008 /* BB end marker */
#define IT_OUTPUT 0x0010 /* this instruction holds final value of the register */
#define IT_SIGNED 0x0020 /* Instruction is signed */
#define IT_MEMORY 0x0040 /* Instruction does memory access */
#define IT_UNUSED 0x0080 /* dead instruction marker */
#define IT_FLAG1 0x0100 /* misc flags */
#define IT_FLAG2 0x0200
#define IT_VOLATILE 0x0400 /* Should not be moved/removed */
#define IT_MEMADD 0x0800 /* add before the load -- should not be removed */
#define IT_COND 0x1000 /* Conditional */
#define IT_LATCHED 0x2000 /* Output of this instruction is latched/registered */
#define IT_CUT 0x4000 /* After this instruction register is placed */
 
#define OPT_NONE 0x00
#define OPT_CONST 0x01
#define OPT_REGISTER 0x02
#define OPT_REF 0x04
#define OPT_JUMP 0x08 /* Jump to an instruction index */
#define OPT_DEST 0x10 /* This operand is dest */
#define OPT_BB 0x20 /* Jumpt to BB */
#define OPT_LRBB 0x40 /* 0 if we came in from left BB, or 1 otherwise */
 
#define MT_WIDTH 0x007 /* These bits hold memory access width in bytes */
#define MT_BURST 0x008 /* burst start & end markers */
#define MT_BURSTE 0x010
#define MT_CALL 0x020 /* This is a call */
#define MT_LOAD 0x040 /* This memory access does a read */
#define MT_STORE 0x080 /* This memory access does a write */
#define MT_SIGNED 0x100 /* Signed memory access */
 
#define MO_NONE 0 /* different memory ordering, even if there are dependencies,
burst can be made, width can change */
#define MO_WEAK 1 /* different memory ordering, if there cannot be dependencies,
burst can be made, width can change */
#define MO_STRONG 2 /* Same memory ordering, burst can be made, width can change */
#define MO_EXACT 3 /* Exacltly the same memory ordering and widths */
 
#define BB_INLOOP 0x01 /* This block is inside a loop */
#define BB_OPTIONAL 0x02
#define BB_DEAD 0x08 /* This block is unaccessible -> to be removed */
 
#define BBID_START MAX_BB /* Start BB pointer */
#define BBID_END (MAX_BB + 1) /* End BB pointer */
 
/* Various macros to minimize code size */
#define REF(bb,i) (((bb) * MAX_INSNS) + (i))
#define REF_BB(r) ((r) / MAX_INSNS)
#define REF_I(r) ((r) % MAX_INSNS)
#define INSN(ref) bb[REF_BB(ref)].insn[REF_I(ref)]
#ifndef MIN
# define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
 
#ifndef MAX
# define MAX(x,y) ((x) > (y) ? (x) : (y))
#endif
 
#define log(x...) {fprintf (flog, x); fflush (flog); }
 
#define cucdebug(x,s...) {if ((x) <= cuc_debug) PRINTF (s);}
 
#define CUC_WIDTH_ITERATIONS 256
 
/* Options */
/* Whether we are debugging cuc (0-9) */
extern int cuc_debug;
 
/* Temporary registers by software convention */
extern const int caller_saved[MAX_REGS];
 
typedef struct _dep_list_t {
unsigned long ref;
struct _dep_list_t *next;
} dep_list;
 
/* Shared list, if marked dead, entry is not used */
typedef struct _csm_list {
int ref;
int cnt;
int cmovs;
double size, osize;
int cmatch;
int dead;
int ninsn; /* Number of associated instructions */
struct _csm_list *from;
struct _csm_list *next;
} cuc_shared_list;
 
/* Shared resource item definition */
typedef struct {
int ref;
int cmatch;
} cuc_shared_item;
 
/* Implementation specific timings */
typedef struct {
int b; /* Basic block # this timing is referring to */
int preroll; /* How many times was this BB pre/unrolled */
int unroll;
int nshared;
cuc_shared_item *shared; /* List of shared resources */
int new_time;
double size;
} cuc_timings;
 
/* Instructionn entity */
typedef struct {
int type; /* type of the instruction */
int index; /* Instruction index */
int opt[MAX_OPERANDS]; /* operand types */
unsigned long op[MAX_OPERANDS]; /* operand values */
dep_list *dep; /* instruction dependencies */
unsigned long insn; /* Instruction opcode */
char disasm[40]; /* disassembled string */
unsigned long max; /* max result value */
int tmp;
} cuc_insn;
 
/* Basic block entity */
typedef struct {
unsigned long type; /* Type of the bb */
int first, last; /* Where this block lies */
int prev[2], next[2];
int tmp;
cuc_insn *insn; /* Instructions lie here */
int ninsn; /* Number of instructions */
int last_used_reg[MAX_REGS];
dep_list *mdep; /* Last memory access dependencies */
int nmemory;
int cnt; /* how many times was this block executed */
int unrolled; /* how many times has been this block unrolled */
int ntim; /* Basic block options */
cuc_timings *tim;
int selected_tim; /* Selected option, -1 if none */
} cuc_bb;
 
/* Function entity */
typedef struct _cuc_func {
/* Basic blocks */
int num_bb;
cuc_bb bb[MAX_BB];
int saved_regs[MAX_REGS];/* Whether this register was saved */
int lur[MAX_REGS]; /* Location of last use */
int used_regs[MAX_REGS]; /* Nonzero if it was used */
/* Schedule of memory instructions */
int nmsched;
int msched[MAX_INSNS];
int mtype[MAX_INSNS];
 
/* initial bb and their relocations to new block numbers */
int num_init_bb;
int *init_bb_reloc;
int orig_time; /* time in cyc required for SW implementation */
int num_runs; /* Number times this function was run */
cuc_timings timings; /* Base timings */
unsigned long start_addr; /* Address of first instruction inn function */
unsigned long end_addr; /* Address of last instruction inn function */
int memory_order; /* Memory order */
 
int nfdeps; /* Function dependencies */
struct _cuc_func **fdeps;
 
int tmp;
} cuc_func;
 
/* Instructions from function */
extern cuc_insn insn[MAX_INSNS];
extern int num_insn;
extern int reloc[MAX_INSNS];
extern FILE *flog;
 
/* returns log2(x) */
int log2_int (unsigned long x);
 
/* Loads from file into global array insn */
int cuc_load (char *in_fn);
 
/* Negates conditional instruction */
void negate_conditional (cuc_insn *ii);
 
/* Scans sequence of BBs and set bb[].cnt */
void generate_bb_seq (cuc_func *f, char *mp_filename, char *bb_filename);
 
/* Prints out instructions */
void print_insns (int bb, cuc_insn *insn, int size, int verbose);
 
/* prints out bb string */
void print_bb_num (int num);
 
/* Print out basic blocks */
void print_cuc_bb (cuc_func *func, char *s);
 
/* Duplicates function */
cuc_func *dup_func (cuc_func *f);
 
/* Releases memory allocated by function */
void free_func (cuc_func *f);
 
/* Common subexpression matching -- resource sharing, analysis pass */
void csm (cuc_func *f);
 
/* Common subexpression matching -- resource sharing, generation pass */
void csm_gen (cuc_func *f, cuc_func *rf, cuc_shared_item *shared, int nshared);
 
/* Set the BB limits */
void detect_bb (cuc_func *func);
 
/* Optimize basic blocks */
int optimize_bb (cuc_func *func);
 
/* Search and optimize complex cmov assignments */
int optimize_cmovs (cuc_func *func);
 
/* Optimizes dataflow tree */
int optimize_tree (cuc_func *func);
 
/* Remove nop instructions */
int remove_nops (cuc_func *func);
 
/* Removes dead instruction */
int remove_dead (cuc_func *func);
 
/* Removes trivial register assignments */
int remove_trivial_regs (cuc_func *f);
 
/* Determine inputs and outputs */
void set_io (cuc_func *func);
 
/* Removes BBs marked as dead */
int remove_dead_bb (cuc_func *func);
 
/* Common subexpression elimination */
int cse (cuc_func *f);
 
/* Detect register dependencies */
void reg_dep (cuc_func *func);
 
/* Cuts the tree and marks registers */
void mark_cut (cuc_func *f);
 
/* Unroll loop b times times and return new function. Original
function is unmodified. */
cuc_func *preunroll_loop (cuc_func *func, int b, int preroll, int unroll, char *bb_filename);
 
/* Clean memory and data dependencies */
void clean_deps (cuc_func *func);
 
/* Schedule memory accesses
0 - exact; 1 - strong; 2 - weak; 3 - none */
int schedule_memory (cuc_func *func, int otype);
 
/* Generates verilog file out of insn dataflow */
void output_verilog (cuc_func *func, char *filename, char *funcname);
 
/* Recalculates bb[].cnt values, based on generated profile file */
void recalc_cnts (cuc_func *f, char *bb_filename);
 
/* Calculate timings */
void analyse_timings (cuc_func *func, cuc_timings *timings);
 
/* Calculates facts, that are determined by conditionals */
void insert_conditional_facts (cuc_func *func);
 
/* Width optimization -- detect maximum values */
void detect_max_values (cuc_func *f);
 
/* Inserts n nops before insn 'ref' */
void insert_insns (cuc_func *f, int ref, int n);
 
#endif /* __DATAF_H__ */
/trunk/or1ksim/cuc/verilog.c
1,1026 → 1,1026
/* verilog.c -- OpenRISC Custom Unit Compiler, verilog generator
* Copyright (C) 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. */
 
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include "cuc.h"
#include "insn.h"
#include "profiler.h"
#include "sim-config.h"
 
/* Shortcut */
#define GEN(x...) fprintf (fo, x)
 
/* Find index of load/store/call */
int find_lsc_index (cuc_func *f, int ref)
{
int c = 0;
int i;
int load;
if (f->INSN(ref).index == II_CALL) {
for (i = 0; i < f->nmsched; i++) {
if (f->msched[i] == ref) break;
if (f->mtype[i] & MT_CALL) c++;
}
} else {
load = II_IS_LOAD (f->INSN(ref).index);
for (i = 0; i < f->nmsched; i++) {
if (f->msched[i] == ref) break;
if (load && (f->mtype[i] & MT_LOAD)
|| !load && (f->mtype[i] & MT_STORE)) c++;
}
}
return c;
}
 
/* Print out dependencies as verilog expression */
void print_deps (FILE *fo, cuc_func *f, int b, dep_list *t, int registered)
{
if (t) {
int first = 0;
while (t) {
if (f->INSN(t->ref).type & IT_MEMORY) {
GEN ("%s%c_end[%i]", first ? " && " : "",
II_IS_LOAD (f->INSN(t->ref).index) ? 'l' : 's', find_lsc_index (f, t->ref));
} else if (f->INSN(t->ref).index == II_CALL) {
int x;
GEN ("%sf_end[%i]", first ? " && " : "", find_lsc_index (f, t->ref));
} else {
PRINTF ("print_deps: err %x\n", t->ref);
assert (0);
}
first = 1;
t = t->next;
}
} else {
if (registered) GEN ("bb_start_r[%i]", b);
else GEN ("bb_start[%i]", b);
}
}
 
char *print_op_v (cuc_func *f, char *s, int ref, int j)
{
unsigned long op = f->INSN(ref).op[j];
unsigned long opt = f->INSN(ref).opt[j];
switch (opt & ~OPT_DEST) {
case OPT_NONE: assert (0); break;
case OPT_CONST: if (f->INSN(ref).type & IT_COND && (f->INSN(ref).index == II_CMOV
|| f->INSN(ref).index == II_ADD)) {
assert (op == 0 || op == 1);
sprintf (s, "1'b%x", op);
} else sprintf (s, "32'h%x", op);
break;
case OPT_REGISTER:
if (opt & OPT_DEST) sprintf (s, "t%x_%x", REF_BB(ref), REF_I(ref));
else sprintf (s, "r%i_%c", op, opt & OPT_DEST ? 'o' : 'i');
break;
#if 0
case OPT_FREG: assert (opt & OPT_DEST);
sprintf (s, "fr%i_o", op);
break;
#endif
case OPT_REF: sprintf (s, "t%x_%x", REF_BB(op), REF_I(op)); break;
}
return s;
}
 
/* Prints out specified instruction */
void print_insn_v (FILE *fo, cuc_func *f, int b, int i)
{
cuc_insn *ii = &f->bb[b].insn[i];
char *s = known[ii->index].rtl;
char tmp[200] = "";
 
assert (s);
while (*s) {
if (*s <= MAX_OPERANDS) {
char t[30];
sprintf (tmp, "%s%s", tmp, print_op_v (f, t, REF(b, i), *s - 1));
} else if (*s == '\b') sprintf (tmp, "%s%i", b);
else sprintf (tmp, "%s%c", tmp, *s);
s++;
}
GEN ("%-40s /* %s */\n", tmp, ii->disasm);
if (ii->type & IT_MEMORY) {
int j, nls = find_lsc_index (f, REF (b, i));
if (II_IS_LOAD (ii->index)) {
int nm;
for (nm = 0; nm < f->nmsched; nm++) if (f->msched[nm] == REF (b, i)) break;
assert (nm < f->nmsched);
 
GEN (" if (l_end[%i]) t%x_%x <= #Tp ", nls, b, i);
switch (f->mtype[nm] & (MT_WIDTH | MT_SIGNED)) {
case 1: GEN ("l_dat_i & 32'hff;\n");
break;
case 2: GEN ("l_dat_i & 32'hffff;\n");
break;
case 4 | MT_SIGNED:
case 4: GEN ("l_dat_i;\n");
break;
case 1 | MT_SIGNED:
GEN ("{24{l_dat_i[7]}, l_dat_i[7:0]};\n");
break;
case 2 | MT_SIGNED:
GEN ("{16{l_dat_i[15]}, l_dat_i[15:0]};\n");
break;
default: assert (0);
}
}
} else if (ii->index == II_LRBB) {
GEN (" if (rst) t%x_%x <= #Tp 1'b0;\n", b, i);
assert (f->bb[b].prev[0] >= 0);
if (f->bb[b].prev[0] == BBID_START)
GEN (" else if (bb_start[%i]) t%x_%x <= #Tp start_i;\n", b, b, i);
else
GEN (" else if (bb_start[%i]) t%x_%x <= #Tp bb_stb[%i];\n", b, b, i, f->bb[b].prev[0]);
} else if (ii->index == II_REG) {
assert (ii->opt[1] == OPT_REF);
GEN (" if (");
if (f->bb[b].mdep) print_deps (fo, f, b, f->bb[b].mdep, 0);
else GEN ("bb_stb[%i]", b);
GEN (") t%x_%x <= #Tp t%x_%x;\n", b, i,
REF_BB (ii->op[1]), REF_I (ii->op[1]));
}
}
 
/* Outputs binary number */
static char *bin_str (unsigned long x, int len)
{
static char bx[33];
char *s = bx;
while (len > 0) *s++ = '0' + ((x >> --len) & 1);
*s = '\0';
return bx;
}
 
/* Returns index of branch instruction inside a block b */
static int branch_index (cuc_bb *bb)
{
int i;
for (i = bb->ninsn - 1; i >= 0; i--)
if (bb->insn[i].type & IT_BRANCH) return i;
return -1;
}
 
static void print_turn_off_dep (FILE *fo, cuc_func *f, dep_list *dep)
{
while (dep) {
assert (f->INSN(dep->ref).type & IT_MEMORY || f->INSN(dep->ref).index == II_CALL);
GEN (" %c_stb[%i] <= #Tp 1'b0;\n", f->INSN(dep->ref).index == II_CALL ? 'f'
: II_IS_LOAD (f->INSN(dep->ref).index) ? 'l' : 's', find_lsc_index (f, dep->ref));
dep = dep->next;
}
}
 
static int func_index (cuc_func *f, int ref)
{
int i;
unsigned long addr;
assert (f->INSN(ref).index == II_CALL && f->INSN(ref).opt[0] & OPT_CONST);
addr = f->INSN(ref).op[0];
for (i = 0; i < f->nfdeps; i++)
if (f->fdeps[i]->start_addr == addr) return i;
 
assert (0);
return -1;
}
 
/* Generates verilog file out of insn dataflow */
void output_verilog (cuc_func *f, char *filename, char *funcname)
{
FILE *fo;
int b, i, j;
int ci = 0, co = 0;
int nloads = 0, nstores = 0, ncalls = 0;
char tmp[256];
sprintf (tmp, "%s.v", filename);
 
log ("Generating verilog file \"%s\"\n", tmp);
PRINTF ("Generating verilog file \"%s\"\n", tmp);
if ((fo = fopen (tmp, "wt+")) == NULL) {
fprintf (stderr, "Cannot open '%s'\n", tmp);
exit (1);
}
 
/* output header */
GEN ("/* %s -- generated by Custom Unit Compiler\n", tmp);
GEN (" (C) 2002 Opencores\n");
GEN (" function \"%s\"\n", funcname);
GEN (" at %08x - %08x\n", f->start_addr, f->end_addr);
GEN (" num BBs %i */\n\n", f->num_bb);
 
GEN ("`include \"timescale.v\"\n\n");
GEN ("module %s (clk, rst,\n", filename);
GEN (" l_adr_o, l_dat_i, l_req_o,\n");
GEN (" l_sel_o, l_linbrst_o, l_rdy_i,\n");
GEN (" s_adr_o, s_dat_o, s_req_o,\n");
GEN (" s_sel_o, s_linbrst_o, s_rdy_i,\n");
 
GEN ("/* inputs */ ");
for (i = 0; i < MAX_REGS; i++)
if (f->used_regs[i]) {
GEN ("r%i_i, ", i);
ci++;
}
if (!ci) GEN ("/* NONE */");
 
GEN ("\n/* outputs */ ");
for (i = 0; i < MAX_REGS; i++)
if (f->lur[i] >= 0 && !f->saved_regs[i]) {
GEN ("r%i_o, ", i);
co++;
}
 
if (!co) GEN ("/* NONE */");
if (f->nfdeps) {
GEN ("\n/* f. calls */, fstart_o, %sfend_i, fr11_i, ",
log2 (f->nfdeps) > 0 ? "fid_o, " : "");
for (i = 0; i < 6; i++) GEN ("fr%i_o, ", i + 3);
}
GEN ("\n start_i, end_o, busy_o);\n\n");
 
GEN ("parameter Tp = 1;\n\n");
GEN ("input clk, rst;\n");
GEN ("input start_i;\t/* Module starts when set to 1 */ \n");
GEN ("output end_o;\t/* Set when module finishes, cleared upon start_i == 1 */\n");
GEN ("output busy_o;\t/* Set when module should not be interrupted */\n");
GEN ("\n/* Bus signals */\n");
GEN ("output l_req_o, s_req_o;\n");
GEN ("input l_rdy_i, s_rdy_i;\n");
GEN ("output [3:0] l_sel_o, s_sel_o;\n");
GEN ("output [31:0] l_adr_o, s_adr_o;\n");
GEN ("output l_linbrst_o, s_linbrst_o;\n");
GEN ("input [31:0] l_dat_i;\n");
GEN ("output [31:0] s_dat_o;\n\n");
 
GEN ("reg l_req_o, s_req_o;\n");
GEN ("reg [31:0] l_adr_o, s_adr_o;\n");
GEN ("reg [3:0] l_sel_o, s_sel_o;\n");
GEN ("reg [31:0] s_dat_o;\n");
GEN ("reg l_linbrst_o, s_linbrst_o;\n");
if (ci || co) GEN ("\n/* module ports */\n");
if (ci) {
int first = 1;
GEN ("input [31:0]");
for (i = 0; i < MAX_REGS; i++)
if (f->used_regs[i]) {
GEN ("%sr%i_i", first ? " " : ", ", i);
first = 0;
}
GEN (";\n");
}
 
if (co) {
int first = 1;
GEN ("output [31:0]");
for (i = 0; i < MAX_REGS; i++)
if (f->lur[i] >= 0 && !f->saved_regs[i]) {
GEN ("%sr%i_o", first ? " " : ", ", i);
first = 0;
}
GEN (";\n");
}
 
if (f->nfdeps) {
GEN ("\n/* Function calls */\n");
GEN ("output [31:0] fr3_o");
for (i = 1; i < 6; i++) GEN (", fr%i_o", i + 3);
GEN (";\n");
GEN ("input [31:0] fr11_i;\n");
if (log2(f->nfdeps) > 0) GEN ("output [%i:0] fid_o;\n", log2(f->nfdeps));
GEN ("output fstart_o;\n");
GEN ("input fend_i;\n");
}
/* Count loads & stores */
for (i = 0; i < f->nmsched; i++)
if (f->mtype[i] & MT_STORE) nstores++;
else if (f->mtype[i] & MT_LOAD) nloads++;
else if (f->mtype[i] & MT_CALL) ncalls++;
 
/* Output internal registers for loads */
if (nloads) {
int first = 1;
int num = 0;
GEN ("\n/* internal registers for loads */\n");
for (i = 0; i < f->nmsched; i++)
if (f->mtype[i] & MT_LOAD) {
GEN ("%st%x_%x", first ? "reg [31:0] " : ", ",
REF_BB(f->msched[i]), REF_I(f->msched[i]));
 
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
}
 
/* Internal register for function return value */
if (f->nfdeps) {
GEN ("\n/* Internal register for function return value */\n");
GEN ("reg [31:0] fr11_r;\n");
}
GEN ("\n/* 'zero or one' hot state machines */\n");
if (nloads) GEN ("reg [%i:0] l_stb; /* loads */\n", nloads - 1);
if (nstores) GEN ("reg [%i:0] s_stb; /* stores */\n", nstores - 1);
GEN ("reg [%i:0] bb_stb; /* basic blocks */\n", f->num_bb - 1);
 
{
int first = 2;
int num = 0;
for (b = 0; b < f->num_bb; b++)
for (i = 0; i < f->bb[b].ninsn; i++)
if (f->bb[b].insn[i].type & IT_COND
&& f->bb[b].insn[i].index != II_REG
&& f->bb[b].insn[i].index != II_LRBB) {
if (first == 2) GEN ("\n/* basic block condition wires */\n");
GEN ("%st%x_%x", first ? "wire " : ", ", b, i);
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
 
GEN ("\n/* forward declaration of normal wires */\n");
num = 0;
first = 1;
for (b = 0; b < f->num_bb; b++)
for (i = 0; i < f->bb[b].ninsn; i++)
if (!(f->bb[b].insn[i].type & (IT_COND | IT_BRANCH))
&& f->bb[b].insn[i].index != II_REG
&& f->bb[b].insn[i].index != II_LRBB) {
/* Exclude loads */
if (f->bb[b].insn[i].type & IT_MEMORY && II_IS_LOAD (f->bb[b].insn[i].index)) continue;
GEN ("%st%x_%x", first ? "wire [31:0] " : ", ", b, i);
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
GEN ("\n/* forward declaration registers */\n");
num = 0;
first = 1;
for (b = 0; b < f->num_bb; b++)
for (i = 0; i < f->bb[b].ninsn; i++)
if (f->bb[b].insn[i].index == II_REG
&& f->bb[b].insn[i].index != II_LRBB) {
GEN ("%st%x_%x", first ? "reg [31:0] " : ", ", b, i);
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
 
num = 0;
first = 1;
for (b = 0; b < f->num_bb; b++)
for (i = 0; i < f->bb[b].ninsn; i++)
if (f->bb[b].insn[i].index != II_REG
&& f->bb[b].insn[i].index == II_LRBB) {
GEN ("%st%x_%x", first ? "reg " : ", ", b, i);
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
}
 
if (nloads || nstores) GEN ("\n/* dependencies */\n");
if (nloads) GEN ("wire [%i:0] l_end = l_stb & {%i{l_rdy_i}};\n",
nloads - 1, nloads);
if (nstores) GEN ("wire [%i:0] s_end = s_stb & {%i{s_rdy_i}};\n",
nstores - 1, nstores);
if (ncalls) GEN ("wire [%i:0] f_end = f_stb & {%i{fend_i}};\n",
ncalls - 1, ncalls);
 
GEN ("\n/* last dependency */\n");
GEN ("wire end_o = ");
for (b = 0; b < f->num_bb; b++) {
for (i = 0; i < 2; i++) if (f->bb[b].next[i] == BBID_END) {
GEN ("bb_stb[%i]", b);
if (f->bb[b].mdep) {
GEN (" && ");
print_deps (fo, f, b, f->bb[b].mdep, 0);
}
/* Is branch to BBID_END conditional? */
if (f->bb[b].next[1 - i] >= 0) {
int bidx = branch_index (&f->bb[b]);
char t[30];
print_op_v (f, t, REF (b, bidx), 1);
GEN (" && %s%s", i ? "" : "!", t);
}
}
}
GEN (";\n");
GEN ("wire busy_o = |bb_stb;\n");
 
GEN ("\n/* Basic block triggers */\n");
GEN ("wire [%2i:0] bb_start = {\n", f->num_bb - 1);
for (b = f->num_bb - 1; b >= 0; b--) {
GEN (" /* bb_start[%2i] */ ", b);
for (i = 0; i < 2; i++) if (f->bb[b].prev[i] >= 0 && f->bb[b].prev[i] != BBID_START) {
cuc_bb *prev = &f->bb[f->bb[b].prev[i]];
int t;
if (i) GEN ("\n || ");
if (prev->mdep) {
print_deps (fo, f, f->bb[b].prev[i], prev->mdep, 0);
GEN (" && ");
}
GEN ("bb_stb[%i]", f->bb[b].prev[i]);
if (prev->next[0] >= 0 && prev->next[0] != BBID_END
&& prev->next[1] >= 0 && prev->next[1] != BBID_END) {
int bi = REF (f->bb[b].prev[i], branch_index (&f->bb[f->bb[b].prev[i]]));
int ci;
assert (bi >= 0);
ci = f->INSN(bi).op[1];
t = prev->next[0] == b;
GEN (" && ");
if (f->INSN(bi).opt[1] & OPT_REF) {
GEN ("%st%x_%x", t ? "" : "!", REF_BB(ci), REF_I(ci));
} else {
cucdebug (5, "%x!%x!%x\n", bi, ci, f->INSN(bi).opt[1]);
assert (f->INSN(bi).opt[1] & OPT_CONST);
GEN ("%s%i", t ? "" : "!", ci);
}
}
} else break;
if (!i) GEN ("start_i");
if (b == 0) GEN ("};\n");
else GEN (",\n");
}
 
GEN ("\n/* Register the bb_start */\n");
GEN ("reg [%2i:0] bb_start_r;\n\n", f->num_bb - 1);
GEN ("always @(posedge rst or posedge clk)\n");
GEN ("begin\n");
GEN (" if (rst) bb_start_r <= #Tp %i'b0;\n", f->num_bb);
GEN (" else if (end_o) bb_start_r <= #Tp %i'b0;\n", f->num_bb);
GEN (" else bb_start_r <= #Tp bb_start;\n");
GEN ("end\n");
 
GEN ("\n/* Logic */\n");
/* output body */
for (b = 0; b < f->num_bb; b++) {
GEN ("\t\t/* BB%i */\n", b);
for (i = 0; i < f->bb[b].ninsn; i++)
print_insn_v (fo, f, b, i);
GEN ("\n");
}
 
if (co) {
GEN ("\n/* Outputs */\n");
for (i = 0; i < MAX_REGS; i++)
if (f->lur[i] >= 0 && !f->saved_regs[i])
GEN ("assign r%i_o = t%x_%x;\n", i, REF_BB(f->lur[i]),
REF_I(f->lur[i]));
}
 
if (nstores) {
int cur_store;
GEN ("\n/* Memory stores */\n");
GEN ("always @(s_stb");
for (i = 0; i < f->nmsched; i++)
if (f->mtype[i] & MT_STORE) {
char t[30];
unsigned long opt = f->INSN(f->msched[i]).opt[0];
if ((opt & ~OPT_DEST) != OPT_CONST) {
GEN (" or %s", print_op_v (f, t, f->msched[i], 0));
}
}
cur_store = 0;
GEN (")\nbegin\n");
for (i = 0; i < f->nmsched; i++) if (f->mtype[i] & MT_STORE) {
char t[30];
GEN (" %sif (s_stb[%i]) s_dat_o = %s;\n", cur_store == 0 ? "" : "else ", cur_store,
print_op_v (f, t, f->msched[i], 0));
cur_store++;
//PRINTF ("msched[%i] = %x (mtype %x) %x\n", i, f->msched[i], f->mtype[i], f->INSN(f->msched[i]).op[0]);
}
GEN (" else s_dat_o = 32'hx;\n");
GEN ("end\n");
}
 
/* Generate load and store state machine */
#if 0
GEN ("\n/* Load&store state machine */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN (" if (rst) begin\n");
if (nloads) GEN (" l_stb <= #Tp %i'h0;\n", nloads);
if (nstores) GEN (" s_stb <= #Tp %i'h0;\n", nstores);
GEN (" end else begin\n");
for (i = 0; i < f->nmsched; i++) if (f->mtype[i] & MT_LOAD || f->mtype[i] & MT_STORE) {
int cur = 0;
dep_list *dep = f->INSN(f->msched[i]).dep;
assert (f->INSN(f->msched[i]).opt[1] & (OPT_REF | OPT_REGISTER));
GEN (" if (");
print_deps (fo, f, REF_BB(f->msched[i]), f->INSN(f->msched[i]).dep, 1);
GEN (") begin\n");
print_turn_off_dep (fo, f, dep);
GEN (" %c_stb[%i] <= #Tp 1'b1;\n", f->mtype[i] & MT_LOAD ? 'l' : 's', cur++);
GEN (" end\n");
}
GEN (" if (%c_end[%i]) %c_stb <= #Tp %i'h0;\n", c, cur - 1, c, cur);
GEN (" end\n");
#endif
 
/* Generate state generator machine */
for (j = 0; j < 2; j++) {
char c;
char *s;
switch (j) {
case 0: c = 'l'; s = "Load"; break;
case 1: c = 's'; s = "Store"; break;
case 2: c = 'c'; s = "Calls"; break;
}
if (j == 0 && nloads
|| j == 1 && nstores
|| j == 2 && ncalls) {
int cur = 0;
char t[30];
 
GEN ("\n/* %s state generator machine */\n", s);
GEN ("always @(");
for (i = 0; i < f->nmsched; i++) {
print_op_v (f, t, f->msched[i], 1);
GEN ("%s or ", t);
}
GEN ("bb_start_r");
if (nloads) GEN (" or l_end");
if (nstores) GEN (" or s_end");
GEN (")\n");
GEN ("begin\n ");
cucdebug (1, "%s\n", s);
for (i = 0; i < f->nmsched; i++)
if (j == 0 && f->mtype[i] & MT_LOAD
|| j == 1 && f->mtype[i] & MT_STORE
|| j == 2 && f->mtype[i] & MT_CALL) {
dep_list *dep = f->INSN(f->msched[i]).dep;
cucdebug (1, "msched[%i] = %x (mtype %x)\n", i, f->msched[i], f->mtype[i]);
assert (f->INSN(f->msched[i]).opt[1] & (OPT_REF | OPT_REGISTER));
GEN ("if (");
print_deps (fo, f, REF_BB(f->msched[i]), f->INSN(f->msched[i]).dep, 1);
GEN (") begin\n");
GEN (" %c_req_o = 1'b1;\n", c);
GEN (" %c_sel_o[3:0] = 4'b", c);
switch (f->mtype[i] & MT_WIDTH) {
case 1: GEN ("0001 << (%s & 32'h3);\n",
print_op_v (f, t, f->msched[i], 1)); break;
case 2: GEN ("0011 << ((%s & 32'h1) << 1);\n",
print_op_v (f, t, f->msched[i], 1)); break;
case 4: GEN ("1111;\n"); break;
default: assert (0);
}
GEN (" %c_linbrst_o = 1'b%i;\n", c,
(f->mtype[i] & MT_BURST) && !(f->mtype[i] & MT_BURSTE) ? 1 : 0);
GEN (" %c_adr_o = t%x_%x & ~32'h3;\n", c,
REF_BB(f->INSN(f->msched[i]).op[1]), REF_I(f->INSN(f->msched[i]).op[1]));
GEN (" end else ");
}
GEN ("if (%c_end[%i]) begin\n", c, cur - 1);
GEN (" %c_req_o = 1'b0;\n", c);
GEN (" %c_sel_o[3:0] = 4'bx;\n", c);
GEN (" %c_linbrst_o = 1'b0;\n", c);
GEN (" %c_adr_o = 32'hx;\n", c);
GEN (" end else begin\n");
GEN (" %c_req_o = 1'b0;\n", c);
GEN (" %c_sel_o[3:0] = 4'bx;\n", c);
GEN (" %c_linbrst_o = 1'b0;\n", c);
GEN (" %c_adr_o = 32'hx;\n", c);
GEN (" end\n");
GEN ("end\n");
}
}
 
if (ncalls) {
int cur_call = 0;
GEN ("\n/* Function calls state machine */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN ("begin\n");
GEN (" if (rst) begin\n");
GEN (" f_stb <= #Tp %i'h0;\n", nstores);
for (i = 0; i < 6; i++) GEN (" fr%i_o <= #Tp 32'h0;\n", i + 3);
if (log2(ncalls)) GEN (" fid_o <= #Tp %i'h0;\n", log2 (f->nfdeps));
GEN (" fstart_o <= #Tp 1'b0;\n");
//GEN (" f11_r <= #Tp 32'h0;\n");
GEN (" end else begin\n");
cucdebug (1, "calls \n");
for (i = 0; i < f->nmsched; i++) if (f->mtype[i] & MT_CALL) {
char t[30];
dep_list *dep = f->INSN(f->msched[i]).dep;
cucdebug (1, "msched[%i] = %x (mtype %x)\n", i, f->msched[i], f->mtype[i]);
assert (f->INSN(f->msched[i]).opt[1] & (OPT_REF | OPT_REGISTER));
GEN (" if (");
print_deps (fo, f, REF_BB(f->msched[i]), f->INSN(f->msched[i]).dep, 1);
GEN (") begin\n");
print_turn_off_dep (fo, f, dep);
GEN (" f_stb[%i] <= #Tp 1'b1;\n", cur_call++);
GEN (" fstart_o <= #Tp 1'b1;\n");
if (log2 (f->nfdeps))
GEN (" fid_o <= #Tp %i'h%x;\n", log2 (f->nfdeps), func_index (f, f->msched[i]));
 
for (j = 0; j < 6; j++)
GEN (" fr%i_o <= #Tp t%x_%x;\n", j + 3,
REF_BB (f->msched[i]), REF_I (f->msched[i]) - 6 + i);
GEN (" end\n");
}
GEN (" if (f_end[%i]) begin\n", ncalls - 1);
GEN (" f_stb <= #Tp %i'h0;\n", ncalls);
GEN (" f_start_o <= #Tp 1'b0;\n");
GEN (" end\n");
GEN (" end\n");
GEN ("end\n");
}
 
GEN ("\n/* Basic blocks state machine */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN ("begin\n");
GEN (" if (rst) bb_stb <= #Tp %i'h%x;\n", f->num_bb, 0);
GEN (" else if (end_o) begin\n");
GEN (" bb_stb <= #Tp %i'h%x;\n", f->num_bb, 0);
for (i = 0; i < f->num_bb; i++) {
GEN (" end else if (bb_start[%i]) begin\n", i);
GEN (" bb_stb <= #Tp %i'h%x;\n", f->num_bb, 1 << i);
}
GEN (" end else if (end_o) begin\n");
GEN (" bb_stb <= #Tp %i'h%x;\n", f->num_bb, 0);
GEN (" end\n");
GEN ("end\n");
 
/* output footer */
GEN ("\nendmodule\n");
 
fclose (fo);
}
 
void generate_main (int nfuncs, cuc_func **f, char *filename)
{
FILE *fo;
int i, j, nrf, first;
char tmp[256];
int ncallees[MAX_FUNCS];
int nl[MAX_FUNCS], ns[MAX_FUNCS];
int maxncallees = 0;
sprintf (tmp, "%s_top.v", filename);
 
for (i = 0, nrf = 0; i < nfuncs; i++) {
nl[i] = ns[i] = 0;
ncallees[i] = 0;
if (f[i]) {
f[i]->tmp = nrf++;
for (j = 0; j < f[i]->nmsched; j++)
if (f[i]->mtype[j] & MT_LOAD) nl[i]++;
else if (f[i]->mtype[j] & MT_STORE) ns[i]++;
for (j = 0; j < f[i]->nfdeps; j++)
ncallees[f[i]->fdeps[j]->tmp]++;
}
}
if (!nrf) return;
for (i = 0; i < nrf; i++)
if (maxncallees < ncallees[i]) maxncallees = ncallees[i];
log ("Generating verilog file \"%s\"\n", tmp);
PRINTF ("Generating verilog file \"%s\"\n", tmp);
if ((fo = fopen (tmp, "wt+")) == NULL) {
fprintf (stderr, "Cannot open '%s'\n", tmp);
exit (1);
}
 
/* output header */
GEN ("/* %s -- generated by Custom Unit Compiler\n", tmp);
GEN (" (C) 2002 Opencores */\n\n");
GEN ("/* Includes %i functions:", nrf);
for (i = 0; i < nfuncs; i++) if (f[i])
GEN ("\n%s", prof_func[i].name);
GEN (" */\n\n");
 
GEN ("`include \"timescale.v\"\n\n");
GEN ("module %s (clk, rst,\n", filename);
GEN (" /* Load and store master Wishbone ports */\n");
GEN (" l_adr_o, l_dat_i, l_cyc_o, l_stb_o,\n");
GEN (" l_sel_o, l_linbrst_o, l_rdy_i, l_we_o,\n");
GEN (" s_adr_o, s_dat_o, s_cyc_o, s_stb_o,\n");
GEN (" s_sel_o, s_linbrst_o, s_rdy_i, s_we_o,\n\n");
GEN (" /* cuc interface */\n");
GEN (" cuc_stb_i, cuc_adr_i, cuc_dat_i, cuc_dat_o, cuc_we_i, cuc_rdy_o);\n\n");
 
GEN ("parameter Tp = 1;\n");
GEN ("\n/* module ports */\n");
GEN ("input clk, rst, cuc_stb_i, cuc_we_i;\n");
GEN ("input l_rdy_i, s_rdy_i;\n");
GEN ("output l_cyc_o, l_stb_o, l_we_o, l_linbrst_o;\n");
GEN ("reg l_cyc_o, l_stb_o, l_we_o, l_linbrst_o;\n");
GEN ("output s_cyc_o, s_stb_o, s_we_o, s_linbrst_o;\n");
GEN ("reg s_cyc_o, s_stb_o, s_we_o, s_linbrst_o;\n");
GEN ("output cuc_rdy_o; /* Not registered ! */\n");
GEN ("output [3:0] l_sel_o, s_sel_o;\n");
GEN ("reg [3:0] l_sel_o, s_sel_o;\n");
GEN ("output [31:0] l_adr_o, s_adr_o, s_dat_o, cuc_dat_o;\n");
GEN ("reg [31:0] l_adr_o, s_adr_o, s_dat_o, cuc_dat_o;\n");
GEN ("input [15:0] cuc_adr_i;\n");
GEN ("input [31:0] l_dat_i, cuc_dat_i;\n\n");
GEN ("wire [%2i:0] i_we, i_re, i_finish, i_selected, i_first_reg;\n", nrf - 1);
GEN ("wire [%2i:0] i_bidok, i_start_bid, i_start_bidok, main_start, main_end;\n", nrf - 1);
GEN ("wire [%2i:0] i_start, i_end, i_start_block, i_busy;\n", nrf - 1);
GEN ("wire [%2i:0] i_l_req, i_s_req;\n", nrf - 1);
GEN ("reg [%2i:0] i_go_bsy, main_start_r;\n", nrf - 1);
 
GEN ("assign i_selected = {\n");
for (i = 0; i < nrf; i++)
GEN (" cuc_adr_i[15:6] == %i%s\n", i, i < nrf - 1 ? "," : "};");
 
GEN ("assign i_first_reg = {\n");
for (i = 0; i < nfuncs; i++) if (f[i]) {
for (j = 0; j <= MAX_REGS; j++) if (f[i]->used_regs[j]) break;
GEN (" cuc_adr_i[5:0] == %i%s\n", j, f[i]->tmp < nrf - 1 ? "," : "};");
}
 
GEN ("assign i_we = {%i{cuc_stb_i && cuc_we_i}} & i_selected;\n", nrf);
GEN ("assign i_re = {%i{cuc_stb_i && !cuc_we_i}} & i_selected;\n", nrf);
 
GEN ("assign i_start = i_go_bsy & {%i{cuc_rdy_o}};\n", nrf);
GEN ("assign i_start_bidok = {\n");
for (i = 0; i < nrf; i++)
GEN (" i_start_bid[%i] < %i%s\n", i, i, i < nrf - 1 ? "," : "};");
GEN ("assign main_start = i_start & i_selected & i_first_reg & i_we;\n");
GEN ("assign main_end = {%i{i_end}} & i_selected;\n");
 
GEN ("\nalways @(posedge clk or posedge rst)\n");
GEN ("begin\n");
GEN (" if (rst) i_go_bsy <= #Tp %i'b0;\n", nrf);
GEN (" else i_go_bsy <= #Tp i_we | ~i_finish & i_go_bsy;\n");
GEN ("end\n");
 
 
/* Function specific data */
for (i = 0; i < nfuncs; i++) if (f[i]) {
int ci = 0, co = 0;
int fn = f[i]->tmp;
GEN ("\n/* Registers for function %s */\n", prof_func[i].name);
for (j = 0, first = 1; j < MAX_REGS; j++) if (f[i]->used_regs[j]) {
GEN ("%s i%i_r%ii", first ? "/* inputs */\nreg [31:0]" : ",", fn, j);
first = 0;
ci++;
}
if (ci) GEN (";\n");
 
for (j = 0, first = 1; j < MAX_REGS; j++)
if (f[i]->lur[j] >= 0 && !f[i]->saved_regs[j]) {
GEN ("%s i%i_r%io", first ? "/* outputs */\nwire [31:0]" : ",", fn, j);
first = 0;
co++;
}
if (co) GEN (";\n");
GEN ("wire [31:0] i%i_l_adr, i%i_s_adr;\n", fn, fn);
GEN ("always @(posedge clk or posedge rst)\n");
GEN (" if (rst) main_start_r <= #Tp %i'b0;\n", nrf);
GEN (" else main_start_r <= #Tp main_start & i_start_bidok | i_busy | ~i_end & main_start_r;\n");
if (ci) {
GEN ("\n/* write register access */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN ("begin\n");
GEN (" if (rst) begin\n");
for (j = 0; j < MAX_REGS; j++) if (f[i]->used_regs[j])
GEN (" i%i_r%ii <= #Tp 32'h0;\n", fn, j);
GEN (" end else if (!i_go_bsy[%i] && i_we[%i])\n", fn, fn);
GEN (" case (cuc_adr_i[5:0])\n");
for (j = 0; j < MAX_REGS; j++) if (f[i]->used_regs[j])
GEN (" %-2i: i%i_r%ii <= #Tp cuc_dat_i;\n", j, fn, j);
GEN (" endcase\n");
GEN ("end\n");
}
 
GEN ("\n");
}
 
/* Generate machine for reading all function registers. Register read can be
delayed till function completion */
{
int co;
GEN ("/* read register access - data */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN (" if (rst) cuc_dat_o <= #Tp 32'h0;\n");
GEN (" else if (cuc_stb_i && cuc_we_i) begin\n");
GEN (" ");
 
for (i = 0; i < nfuncs; i++) if (f[i]) {
co = 0;
for (j = 0; j < MAX_REGS; j++)
if (f[i]->lur[j] >= 0 && !f[i]->saved_regs[j]) co++;
GEN ("if (cuc_adr_i[15:6] == %i)", f[i]->tmp);
if (co) {
first = 1;
GEN ("\n case (cuc_adr_i[5:0])\n");
for (j = 0; j < MAX_REGS; j++)
if (f[i]->lur[j] >= 0 && !f[i]->saved_regs[j])
GEN (" %-2i: cuc_dat_o <= #Tp i%i_r%io;\n", j, f[i]->tmp, j);
GEN (" endcase\n");
} else {
GEN (" cuc_dat_o <= #Tp 32'hx;\n");
}
GEN (" else ");
}
GEN ("cuc_dat_o <= #Tp 32'hx;\n");
GEN (" end else cuc_dat_o <= #Tp 32'hx;\n");
GEN ("\n/* read register access - acknowledge */\n");
GEN ("assign cuc_rdy_o = cuc_stb_i && cuc_we_i && |(i_selected & main_end);\n");
}
 
/* Store/load Wishbone bridge */
for (j = 0; j < 2; j++) {
char t = j ? 's' : 'l';
GEN ("\n/* %s Wishbone bridge */\n", j ? "store" : "load");
GEN ("reg [%i:0] %cm_sel;\n", log2 (nrf), t);
GEN ("reg [%i:0] %cm_bid;\n", log2 (nrf), t);
GEN ("reg %ccyc_ip;\n\n", t);
GEN ("always @(posedge clk)\n");
GEN ("begin\n");
GEN (" %c_we_o <= #Tp 1'b%i;\n", t, j);
GEN (" %c_cyc_o <= #Tp |i_%c_req;\n", t, t);
GEN (" %c_stb_o <= #Tp |i_%c_req;\n", t, t);
GEN ("end\n");
 
GEN ("\n/* highest bid */\n");
GEN ("always @(");
for (i = 0; i < nrf; i++) GEN ("%si_%c_req", i > 0 ? " or " : "", t);
GEN (")\n");
for (i = 0; i < nrf; i++) GEN (" %sif (i_%c_req) %cm_bid = %i'h%x;\n",
i ? "else " : "", t, t, log2 (nrf) + 1, i);
 
GEN ("\n/* selected transfer */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN (" if (rst) %cm_sel <= #Tp %i'h0;\n", t, log2 (nrf) + 1);
GEN (" else if (%c_rdy_i) %cm_sel <= #Tp %i'h0;\n", t, t, log2 (nrf) + 1);
GEN (" else if (!%ccyc_ip) %cm_sel <= #Tp %cm_bid;\n", t, t, t);
 
GEN ("\n/* Cycle */\n");
GEN ("\nalways @(posedge clk or posedge rst)\n");
GEN (" if (rst) %ccyc_ip <= #Tp 1'b0;\n", t);
GEN (" else if (%c_rdy_i) %ccyc_ip <= #Tp 1'b0;\n", t, t);
GEN (" else %ccyc_ip <= #Tp %c_cyc_o;\n", t, t);
}
 
GEN ("\n/* Acknowledge */\n");
for (i = 0; i < nrf; i++) {
GEN ("wire i%i_s_rdy = ((sm_bid == %i & !scyc_ip) | sm_sel == %i) & s_rdy_i;\n", i, i, i);
GEN ("wire i%i_l_rdy = ((lm_bid == %i & !lcyc_ip) | lm_sel == %i) & l_rdy_i;\n", i, i, i);
}
 
GEN ("\n/* data, address selects and burst enables */\n");
for (i = 0; i < nrf; i++) GEN ("wire [31:0] i%i_s_dat;\n", i);
for (i = 0; i < nrf; i++) GEN ("wire i%i_s_linbrst, i%i_l_linbrst;\n", i, i);
for (i = 0; i < nrf; i++) GEN ("wire [3:0] i%i_s_sel, i%i_l_sel;\n", i, i);
for (i = 0; i < nrf; i++) GEN ("wire [31:0] i%i_l_dat = l_dat_i;\n", i);
GEN ("\nalways @(posedge clk)\n");
GEN ("begin\n");
GEN (" s_dat_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n sm_bid == %i ? i%i_s_dat : ", i, i);
GEN ("i%i_s_dat;\n", nrf - 1);
GEN (" s_adr_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n sm_bid == %i ? i%i_s_adr : ", i, i);
GEN ("i%i_s_adr;\n", nrf - 1);
GEN (" s_sel_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n sm_bid == %i ? i%i_s_sel : ", i, i);
GEN ("i%i_s_sel;\n", nrf - 1);
GEN (" s_linbrst_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n sm_bid == %i ? i%i_s_linbrst : ", i, i);
GEN ("i%i_s_linbrst;\n", nrf - 1);
GEN ("end\n\n");
 
GEN ("always @(posedge clk)\n");
GEN ("begin\n");
GEN (" l_adr_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n lm_bid == %i ? i%i_l_adr : ", i, i);
GEN ("i%i_l_adr;\n", nrf - 1);
GEN (" l_sel_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n lm_bid == %i ? i%i_l_sel : ", i, i);
GEN ("i%i_l_sel;\n", nrf - 1);
GEN (" l_linbrst_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n lm_bid == %i ? i%i_l_linbrst : ", i, i);
GEN ("i%i_l_linbrst;\n", nrf - 1);
GEN ("end\n\n");
/* start/end signals */
GEN ("\n\n/* start/end signals */\n");
for (i = 0; i < nrf; i++) {
if (log2 (maxncallees + 1))
GEN ("wire [%i:0] i%i_current = i%i_busy ? i%i_current_r : i%i_start_bid;\n",
log2 (maxncallees + 1), i, i, i, i, i);
else GEN ("wire i%i_current = 0;\n", i);
}
GEN ("\n");
for (i = 0, j = 0; i < nfuncs; i++) if (f[i]) {
if (log2 (ncallees[i])) {
GEN ("reg [%i:0] i%i_start_bid;\n", log2 (ncallees[i]), j);
GEN ("always @(start%i", f[i]->tmp);
for (j = 0, first = 1; j < f[i]->nfdeps; j++)
if (f[i]->fdeps[j]) GEN (", ");
GEN (")\n");
GEN ("begin !!!\n"); //TODO
GEN (" \n");
GEN ("end\n");
}
GEN ("wire i%i_start = main_start[%i];\n", j, j);
j++;
}
GEN ("\n");
 
for (i = 0; i < nfuncs; i++) if (f[i]) {
int nf = f[i]->tmp;
GEN ("\n%s%s i%i(.clk(clk), .rst(rst),\n", filename, prof_func[i].name, nf);
GEN ("");
GEN (" .l_adr_o(i%i_l_adr), .l_dat_i(i%i_l_dat), .l_req_o(i_l_req[%i]),\n",
nf, nf, nf);
GEN (" .l_sel_o(i%i_l_sel), .l_linbrst_o(i%i_l_linbrst), .l_rdy_i(i%i_l_rdy),\n",
nf, nf, nf);
GEN (" .s_adr_o(i%i_s_adr), .s_dat_o(i%i_s_dat), .s_req_o(i_s_req[%i]),\n",
nf, nf, nf);
GEN (" .s_sel_o(i%i_s_sel), .s_linbrst_o(i%i_s_linbrst), .s_rdy_i(i%i_s_rdy),\n",
nf, nf, nf);
GEN (" ");
for (j = 0, first = 1; j < MAX_REGS; j++) if (f[i]->used_regs[j])
GEN (".r%i_i(i%i_r%ii), ", j, nf, j), first = 0;
 
if (first) GEN ("\n ");
for (j = 0, first = 1; j < MAX_REGS; j++)
if (f[i]->lur[j] >= 0 && !f[i]->saved_regs[j])
GEN (".r%i_o(i%i_r%io), ", j, nf, j), first = 0;
if (first) GEN ("\n ");
if (f[i]->nfdeps) {
GEN (".fstart_o(i_fstart[%i]), .fend_i(i_fend[%i]), .fid_o(i%i_fid),\n", i, i, i),
GEN (" .fr3_o(i%i_fr3), .fr4_o(i%i_fr4), .fr5_o(i%i_fr5), .fr6_o(i%i_fr6),\n");
GEN (" .fr7_o(i%i_fr7), .fr8_o(i%i_fr8), .fr11_i(i%i_fr11i),\n ");
}
GEN (".start_i(i_start[%i]), .end_o(i_end[%i]), .busy_o(i_busy[%i]));\n", nf, nf, nf);
}
 
/* output footer */
GEN ("\nendmodule\n");
 
fclose (fo);
}
 
/* verilog.c -- OpenRISC Custom Unit Compiler, verilog generator
* Copyright (C) 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. */
 
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include "cuc.h"
#include "insn.h"
#include "profiler.h"
#include "sim-config.h"
 
/* Shortcut */
#define GEN(x...) fprintf (fo, x)
 
/* Find index of load/store/call */
int find_lsc_index (cuc_func *f, int ref)
{
int c = 0;
int i;
int load;
if (f->INSN(ref).index == II_CALL) {
for (i = 0; i < f->nmsched; i++) {
if (f->msched[i] == ref) break;
if (f->mtype[i] & MT_CALL) c++;
}
} else {
load = II_IS_LOAD (f->INSN(ref).index);
for (i = 0; i < f->nmsched; i++) {
if (f->msched[i] == ref) break;
if (load && (f->mtype[i] & MT_LOAD)
|| !load && (f->mtype[i] & MT_STORE)) c++;
}
}
return c;
}
 
/* Print out dependencies as verilog expression */
void print_deps (FILE *fo, cuc_func *f, int b, dep_list *t, int registered)
{
if (t) {
int first = 0;
while (t) {
if (f->INSN(t->ref).type & IT_MEMORY) {
GEN ("%s%c_end[%i]", first ? " && " : "",
II_IS_LOAD (f->INSN(t->ref).index) ? 'l' : 's', find_lsc_index (f, t->ref));
} else if (f->INSN(t->ref).index == II_CALL) {
int x;
GEN ("%sf_end[%i]", first ? " && " : "", find_lsc_index (f, t->ref));
} else {
PRINTF ("print_deps: err %x\n", t->ref);
assert (0);
}
first = 1;
t = t->next;
}
} else {
if (registered) GEN ("bb_start_r[%i]", b);
else GEN ("bb_start[%i]", b);
}
}
 
char *print_op_v (cuc_func *f, char *s, int ref, int j)
{
unsigned long op = f->INSN(ref).op[j];
unsigned long opt = f->INSN(ref).opt[j];
switch (opt & ~OPT_DEST) {
case OPT_NONE: assert (0); break;
case OPT_CONST: if (f->INSN(ref).type & IT_COND && (f->INSN(ref).index == II_CMOV
|| f->INSN(ref).index == II_ADD)) {
assert (op == 0 || op == 1);
sprintf (s, "1'b%x", op);
} else sprintf (s, "32'h%x", op);
break;
case OPT_REGISTER:
if (opt & OPT_DEST) sprintf (s, "t%x_%x", REF_BB(ref), REF_I(ref));
else sprintf (s, "r%i_%c", op, opt & OPT_DEST ? 'o' : 'i');
break;
#if 0
case OPT_FREG: assert (opt & OPT_DEST);
sprintf (s, "fr%i_o", op);
break;
#endif
case OPT_REF: sprintf (s, "t%x_%x", REF_BB(op), REF_I(op)); break;
}
return s;
}
 
/* Prints out specified instruction */
void print_insn_v (FILE *fo, cuc_func *f, int b, int i)
{
cuc_insn *ii = &f->bb[b].insn[i];
char *s = known[ii->index].rtl;
char tmp[200] = "";
 
assert (s);
while (*s) {
if (*s <= MAX_OPERANDS) {
char t[30];
sprintf (tmp, "%s%s", tmp, print_op_v (f, t, REF(b, i), *s - 1));
} else if (*s == '\b') sprintf (tmp, "%s%i", b);
else sprintf (tmp, "%s%c", tmp, *s);
s++;
}
GEN ("%-40s /* %s */\n", tmp, ii->disasm);
if (ii->type & IT_MEMORY) {
int j, nls = find_lsc_index (f, REF (b, i));
if (II_IS_LOAD (ii->index)) {
int nm;
for (nm = 0; nm < f->nmsched; nm++) if (f->msched[nm] == REF (b, i)) break;
assert (nm < f->nmsched);
 
GEN (" if (l_end[%i]) t%x_%x <= #Tp ", nls, b, i);
switch (f->mtype[nm] & (MT_WIDTH | MT_SIGNED)) {
case 1: GEN ("l_dat_i & 32'hff;\n");
break;
case 2: GEN ("l_dat_i & 32'hffff;\n");
break;
case 4 | MT_SIGNED:
case 4: GEN ("l_dat_i;\n");
break;
case 1 | MT_SIGNED:
GEN ("{24{l_dat_i[7]}, l_dat_i[7:0]};\n");
break;
case 2 | MT_SIGNED:
GEN ("{16{l_dat_i[15]}, l_dat_i[15:0]};\n");
break;
default: assert (0);
}
}
} else if (ii->index == II_LRBB) {
GEN (" if (rst) t%x_%x <= #Tp 1'b0;\n", b, i);
assert (f->bb[b].prev[0] >= 0);
if (f->bb[b].prev[0] == BBID_START)
GEN (" else if (bb_start[%i]) t%x_%x <= #Tp start_i;\n", b, b, i);
else
GEN (" else if (bb_start[%i]) t%x_%x <= #Tp bb_stb[%i];\n", b, b, i, f->bb[b].prev[0]);
} else if (ii->index == II_REG) {
assert (ii->opt[1] == OPT_REF);
GEN (" if (");
if (f->bb[b].mdep) print_deps (fo, f, b, f->bb[b].mdep, 0);
else GEN ("bb_stb[%i]", b);
GEN (") t%x_%x <= #Tp t%x_%x;\n", b, i,
REF_BB (ii->op[1]), REF_I (ii->op[1]));
}
}
 
/* Outputs binary number */
static char *bin_str (unsigned long x, int len)
{
static char bx[33];
char *s = bx;
while (len > 0) *s++ = '0' + ((x >> --len) & 1);
*s = '\0';
return bx;
}
 
/* Returns index of branch instruction inside a block b */
static int branch_index (cuc_bb *bb)
{
int i;
for (i = bb->ninsn - 1; i >= 0; i--)
if (bb->insn[i].type & IT_BRANCH) return i;
return -1;
}
 
static void print_turn_off_dep (FILE *fo, cuc_func *f, dep_list *dep)
{
while (dep) {
assert (f->INSN(dep->ref).type & IT_MEMORY || f->INSN(dep->ref).index == II_CALL);
GEN (" %c_stb[%i] <= #Tp 1'b0;\n", f->INSN(dep->ref).index == II_CALL ? 'f'
: II_IS_LOAD (f->INSN(dep->ref).index) ? 'l' : 's', find_lsc_index (f, dep->ref));
dep = dep->next;
}
}
 
static int func_index (cuc_func *f, int ref)
{
int i;
unsigned long addr;
assert (f->INSN(ref).index == II_CALL && f->INSN(ref).opt[0] & OPT_CONST);
addr = f->INSN(ref).op[0];
for (i = 0; i < f->nfdeps; i++)
if (f->fdeps[i]->start_addr == addr) return i;
 
assert (0);
return -1;
}
 
/* Generates verilog file out of insn dataflow */
void output_verilog (cuc_func *f, char *filename, char *funcname)
{
FILE *fo;
int b, i, j;
int ci = 0, co = 0;
int nloads = 0, nstores = 0, ncalls = 0;
char tmp[256];
sprintf (tmp, "%s.v", filename);
 
log ("Generating verilog file \"%s\"\n", tmp);
PRINTF ("Generating verilog file \"%s\"\n", tmp);
if ((fo = fopen (tmp, "wt+")) == NULL) {
fprintf (stderr, "Cannot open '%s'\n", tmp);
exit (1);
}
 
/* output header */
GEN ("/* %s -- generated by Custom Unit Compiler\n", tmp);
GEN (" (C) 2002 Opencores\n");
GEN (" function \"%s\"\n", funcname);
GEN (" at %08x - %08x\n", f->start_addr, f->end_addr);
GEN (" num BBs %i */\n\n", f->num_bb);
 
GEN ("`include \"timescale.v\"\n\n");
GEN ("module %s (clk, rst,\n", filename);
GEN (" l_adr_o, l_dat_i, l_req_o,\n");
GEN (" l_sel_o, l_linbrst_o, l_rdy_i,\n");
GEN (" s_adr_o, s_dat_o, s_req_o,\n");
GEN (" s_sel_o, s_linbrst_o, s_rdy_i,\n");
 
GEN ("/* inputs */ ");
for (i = 0; i < MAX_REGS; i++)
if (f->used_regs[i]) {
GEN ("r%i_i, ", i);
ci++;
}
if (!ci) GEN ("/* NONE */");
 
GEN ("\n/* outputs */ ");
for (i = 0; i < MAX_REGS; i++)
if (f->lur[i] >= 0 && !f->saved_regs[i]) {
GEN ("r%i_o, ", i);
co++;
}
 
if (!co) GEN ("/* NONE */");
if (f->nfdeps) {
GEN ("\n/* f. calls */, fstart_o, %sfend_i, fr11_i, ",
log2_int (f->nfdeps) > 0 ? "fid_o, " : "");
for (i = 0; i < 6; i++) GEN ("fr%i_o, ", i + 3);
}
GEN ("\n start_i, end_o, busy_o);\n\n");
 
GEN ("parameter Tp = 1;\n\n");
GEN ("input clk, rst;\n");
GEN ("input start_i;\t/* Module starts when set to 1 */ \n");
GEN ("output end_o;\t/* Set when module finishes, cleared upon start_i == 1 */\n");
GEN ("output busy_o;\t/* Set when module should not be interrupted */\n");
GEN ("\n/* Bus signals */\n");
GEN ("output l_req_o, s_req_o;\n");
GEN ("input l_rdy_i, s_rdy_i;\n");
GEN ("output [3:0] l_sel_o, s_sel_o;\n");
GEN ("output [31:0] l_adr_o, s_adr_o;\n");
GEN ("output l_linbrst_o, s_linbrst_o;\n");
GEN ("input [31:0] l_dat_i;\n");
GEN ("output [31:0] s_dat_o;\n\n");
 
GEN ("reg l_req_o, s_req_o;\n");
GEN ("reg [31:0] l_adr_o, s_adr_o;\n");
GEN ("reg [3:0] l_sel_o, s_sel_o;\n");
GEN ("reg [31:0] s_dat_o;\n");
GEN ("reg l_linbrst_o, s_linbrst_o;\n");
if (ci || co) GEN ("\n/* module ports */\n");
if (ci) {
int first = 1;
GEN ("input [31:0]");
for (i = 0; i < MAX_REGS; i++)
if (f->used_regs[i]) {
GEN ("%sr%i_i", first ? " " : ", ", i);
first = 0;
}
GEN (";\n");
}
 
if (co) {
int first = 1;
GEN ("output [31:0]");
for (i = 0; i < MAX_REGS; i++)
if (f->lur[i] >= 0 && !f->saved_regs[i]) {
GEN ("%sr%i_o", first ? " " : ", ", i);
first = 0;
}
GEN (";\n");
}
 
if (f->nfdeps) {
GEN ("\n/* Function calls */\n");
GEN ("output [31:0] fr3_o");
for (i = 1; i < 6; i++) GEN (", fr%i_o", i + 3);
GEN (";\n");
GEN ("input [31:0] fr11_i;\n");
if (log2_int(f->nfdeps) > 0) GEN ("output [%i:0] fid_o;\n", log2_int(f->nfdeps));
GEN ("output fstart_o;\n");
GEN ("input fend_i;\n");
}
/* Count loads & stores */
for (i = 0; i < f->nmsched; i++)
if (f->mtype[i] & MT_STORE) nstores++;
else if (f->mtype[i] & MT_LOAD) nloads++;
else if (f->mtype[i] & MT_CALL) ncalls++;
 
/* Output internal registers for loads */
if (nloads) {
int first = 1;
int num = 0;
GEN ("\n/* internal registers for loads */\n");
for (i = 0; i < f->nmsched; i++)
if (f->mtype[i] & MT_LOAD) {
GEN ("%st%x_%x", first ? "reg [31:0] " : ", ",
REF_BB(f->msched[i]), REF_I(f->msched[i]));
 
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
}
 
/* Internal register for function return value */
if (f->nfdeps) {
GEN ("\n/* Internal register for function return value */\n");
GEN ("reg [31:0] fr11_r;\n");
}
GEN ("\n/* 'zero or one' hot state machines */\n");
if (nloads) GEN ("reg [%i:0] l_stb; /* loads */\n", nloads - 1);
if (nstores) GEN ("reg [%i:0] s_stb; /* stores */\n", nstores - 1);
GEN ("reg [%i:0] bb_stb; /* basic blocks */\n", f->num_bb - 1);
 
{
int first = 2;
int num = 0;
for (b = 0; b < f->num_bb; b++)
for (i = 0; i < f->bb[b].ninsn; i++)
if (f->bb[b].insn[i].type & IT_COND
&& f->bb[b].insn[i].index != II_REG
&& f->bb[b].insn[i].index != II_LRBB) {
if (first == 2) GEN ("\n/* basic block condition wires */\n");
GEN ("%st%x_%x", first ? "wire " : ", ", b, i);
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
 
GEN ("\n/* forward declaration of normal wires */\n");
num = 0;
first = 1;
for (b = 0; b < f->num_bb; b++)
for (i = 0; i < f->bb[b].ninsn; i++)
if (!(f->bb[b].insn[i].type & (IT_COND | IT_BRANCH))
&& f->bb[b].insn[i].index != II_REG
&& f->bb[b].insn[i].index != II_LRBB) {
/* Exclude loads */
if (f->bb[b].insn[i].type & IT_MEMORY && II_IS_LOAD (f->bb[b].insn[i].index)) continue;
GEN ("%st%x_%x", first ? "wire [31:0] " : ", ", b, i);
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
GEN ("\n/* forward declaration registers */\n");
num = 0;
first = 1;
for (b = 0; b < f->num_bb; b++)
for (i = 0; i < f->bb[b].ninsn; i++)
if (f->bb[b].insn[i].index == II_REG
&& f->bb[b].insn[i].index != II_LRBB) {
GEN ("%st%x_%x", first ? "reg [31:0] " : ", ", b, i);
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
 
num = 0;
first = 1;
for (b = 0; b < f->num_bb; b++)
for (i = 0; i < f->bb[b].ninsn; i++)
if (f->bb[b].insn[i].index != II_REG
&& f->bb[b].insn[i].index == II_LRBB) {
GEN ("%st%x_%x", first ? "reg " : ", ", b, i);
if (num >= 8) {
GEN (";\n");
first = 1;
num = 0;
} else {
first = 0;
num++;
}
}
if (!first) GEN (";\n");
}
 
if (nloads || nstores) GEN ("\n/* dependencies */\n");
if (nloads) GEN ("wire [%i:0] l_end = l_stb & {%i{l_rdy_i}};\n",
nloads - 1, nloads);
if (nstores) GEN ("wire [%i:0] s_end = s_stb & {%i{s_rdy_i}};\n",
nstores - 1, nstores);
if (ncalls) GEN ("wire [%i:0] f_end = f_stb & {%i{fend_i}};\n",
ncalls - 1, ncalls);
 
GEN ("\n/* last dependency */\n");
GEN ("wire end_o = ");
for (b = 0; b < f->num_bb; b++) {
for (i = 0; i < 2; i++) if (f->bb[b].next[i] == BBID_END) {
GEN ("bb_stb[%i]", b);
if (f->bb[b].mdep) {
GEN (" && ");
print_deps (fo, f, b, f->bb[b].mdep, 0);
}
/* Is branch to BBID_END conditional? */
if (f->bb[b].next[1 - i] >= 0) {
int bidx = branch_index (&f->bb[b]);
char t[30];
print_op_v (f, t, REF (b, bidx), 1);
GEN (" && %s%s", i ? "" : "!", t);
}
}
}
GEN (";\n");
GEN ("wire busy_o = |bb_stb;\n");
 
GEN ("\n/* Basic block triggers */\n");
GEN ("wire [%2i:0] bb_start = {\n", f->num_bb - 1);
for (b = f->num_bb - 1; b >= 0; b--) {
GEN (" /* bb_start[%2i] */ ", b);
for (i = 0; i < 2; i++) if (f->bb[b].prev[i] >= 0 && f->bb[b].prev[i] != BBID_START) {
cuc_bb *prev = &f->bb[f->bb[b].prev[i]];
int t;
if (i) GEN ("\n || ");
if (prev->mdep) {
print_deps (fo, f, f->bb[b].prev[i], prev->mdep, 0);
GEN (" && ");
}
GEN ("bb_stb[%i]", f->bb[b].prev[i]);
if (prev->next[0] >= 0 && prev->next[0] != BBID_END
&& prev->next[1] >= 0 && prev->next[1] != BBID_END) {
int bi = REF (f->bb[b].prev[i], branch_index (&f->bb[f->bb[b].prev[i]]));
int ci;
assert (bi >= 0);
ci = f->INSN(bi).op[1];
t = prev->next[0] == b;
GEN (" && ");
if (f->INSN(bi).opt[1] & OPT_REF) {
GEN ("%st%x_%x", t ? "" : "!", REF_BB(ci), REF_I(ci));
} else {
cucdebug (5, "%x!%x!%x\n", bi, ci, f->INSN(bi).opt[1]);
assert (f->INSN(bi).opt[1] & OPT_CONST);
GEN ("%s%i", t ? "" : "!", ci);
}
}
} else break;
if (!i) GEN ("start_i");
if (b == 0) GEN ("};\n");
else GEN (",\n");
}
 
GEN ("\n/* Register the bb_start */\n");
GEN ("reg [%2i:0] bb_start_r;\n\n", f->num_bb - 1);
GEN ("always @(posedge rst or posedge clk)\n");
GEN ("begin\n");
GEN (" if (rst) bb_start_r <= #Tp %i'b0;\n", f->num_bb);
GEN (" else if (end_o) bb_start_r <= #Tp %i'b0;\n", f->num_bb);
GEN (" else bb_start_r <= #Tp bb_start;\n");
GEN ("end\n");
 
GEN ("\n/* Logic */\n");
/* output body */
for (b = 0; b < f->num_bb; b++) {
GEN ("\t\t/* BB%i */\n", b);
for (i = 0; i < f->bb[b].ninsn; i++)
print_insn_v (fo, f, b, i);
GEN ("\n");
}
 
if (co) {
GEN ("\n/* Outputs */\n");
for (i = 0; i < MAX_REGS; i++)
if (f->lur[i] >= 0 && !f->saved_regs[i])
GEN ("assign r%i_o = t%x_%x;\n", i, REF_BB(f->lur[i]),
REF_I(f->lur[i]));
}
 
if (nstores) {
int cur_store;
GEN ("\n/* Memory stores */\n");
GEN ("always @(s_stb");
for (i = 0; i < f->nmsched; i++)
if (f->mtype[i] & MT_STORE) {
char t[30];
unsigned long opt = f->INSN(f->msched[i]).opt[0];
if ((opt & ~OPT_DEST) != OPT_CONST) {
GEN (" or %s", print_op_v (f, t, f->msched[i], 0));
}
}
cur_store = 0;
GEN (")\nbegin\n");
for (i = 0; i < f->nmsched; i++) if (f->mtype[i] & MT_STORE) {
char t[30];
GEN (" %sif (s_stb[%i]) s_dat_o = %s;\n", cur_store == 0 ? "" : "else ", cur_store,
print_op_v (f, t, f->msched[i], 0));
cur_store++;
//PRINTF ("msched[%i] = %x (mtype %x) %x\n", i, f->msched[i], f->mtype[i], f->INSN(f->msched[i]).op[0]);
}
GEN (" else s_dat_o = 32'hx;\n");
GEN ("end\n");
}
 
/* Generate load and store state machine */
#if 0
GEN ("\n/* Load&store state machine */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN (" if (rst) begin\n");
if (nloads) GEN (" l_stb <= #Tp %i'h0;\n", nloads);
if (nstores) GEN (" s_stb <= #Tp %i'h0;\n", nstores);
GEN (" end else begin\n");
for (i = 0; i < f->nmsched; i++) if (f->mtype[i] & MT_LOAD || f->mtype[i] & MT_STORE) {
int cur = 0;
dep_list *dep = f->INSN(f->msched[i]).dep;
assert (f->INSN(f->msched[i]).opt[1] & (OPT_REF | OPT_REGISTER));
GEN (" if (");
print_deps (fo, f, REF_BB(f->msched[i]), f->INSN(f->msched[i]).dep, 1);
GEN (") begin\n");
print_turn_off_dep (fo, f, dep);
GEN (" %c_stb[%i] <= #Tp 1'b1;\n", f->mtype[i] & MT_LOAD ? 'l' : 's', cur++);
GEN (" end\n");
}
GEN (" if (%c_end[%i]) %c_stb <= #Tp %i'h0;\n", c, cur - 1, c, cur);
GEN (" end\n");
#endif
 
/* Generate state generator machine */
for (j = 0; j < 2; j++) {
char c;
char *s;
switch (j) {
case 0: c = 'l'; s = "Load"; break;
case 1: c = 's'; s = "Store"; break;
case 2: c = 'c'; s = "Calls"; break;
}
if (j == 0 && nloads
|| j == 1 && nstores
|| j == 2 && ncalls) {
int cur = 0;
char t[30];
 
GEN ("\n/* %s state generator machine */\n", s);
GEN ("always @(");
for (i = 0; i < f->nmsched; i++) {
print_op_v (f, t, f->msched[i], 1);
GEN ("%s or ", t);
}
GEN ("bb_start_r");
if (nloads) GEN (" or l_end");
if (nstores) GEN (" or s_end");
GEN (")\n");
GEN ("begin\n ");
cucdebug (1, "%s\n", s);
for (i = 0; i < f->nmsched; i++)
if (j == 0 && f->mtype[i] & MT_LOAD
|| j == 1 && f->mtype[i] & MT_STORE
|| j == 2 && f->mtype[i] & MT_CALL) {
dep_list *dep = f->INSN(f->msched[i]).dep;
cucdebug (1, "msched[%i] = %x (mtype %x)\n", i, f->msched[i], f->mtype[i]);
assert (f->INSN(f->msched[i]).opt[1] & (OPT_REF | OPT_REGISTER));
GEN ("if (");
print_deps (fo, f, REF_BB(f->msched[i]), f->INSN(f->msched[i]).dep, 1);
GEN (") begin\n");
GEN (" %c_req_o = 1'b1;\n", c);
GEN (" %c_sel_o[3:0] = 4'b", c);
switch (f->mtype[i] & MT_WIDTH) {
case 1: GEN ("0001 << (%s & 32'h3);\n",
print_op_v (f, t, f->msched[i], 1)); break;
case 2: GEN ("0011 << ((%s & 32'h1) << 1);\n",
print_op_v (f, t, f->msched[i], 1)); break;
case 4: GEN ("1111;\n"); break;
default: assert (0);
}
GEN (" %c_linbrst_o = 1'b%i;\n", c,
(f->mtype[i] & MT_BURST) && !(f->mtype[i] & MT_BURSTE) ? 1 : 0);
GEN (" %c_adr_o = t%x_%x & ~32'h3;\n", c,
REF_BB(f->INSN(f->msched[i]).op[1]), REF_I(f->INSN(f->msched[i]).op[1]));
GEN (" end else ");
}
GEN ("if (%c_end[%i]) begin\n", c, cur - 1);
GEN (" %c_req_o = 1'b0;\n", c);
GEN (" %c_sel_o[3:0] = 4'bx;\n", c);
GEN (" %c_linbrst_o = 1'b0;\n", c);
GEN (" %c_adr_o = 32'hx;\n", c);
GEN (" end else begin\n");
GEN (" %c_req_o = 1'b0;\n", c);
GEN (" %c_sel_o[3:0] = 4'bx;\n", c);
GEN (" %c_linbrst_o = 1'b0;\n", c);
GEN (" %c_adr_o = 32'hx;\n", c);
GEN (" end\n");
GEN ("end\n");
}
}
 
if (ncalls) {
int cur_call = 0;
GEN ("\n/* Function calls state machine */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN ("begin\n");
GEN (" if (rst) begin\n");
GEN (" f_stb <= #Tp %i'h0;\n", nstores);
for (i = 0; i < 6; i++) GEN (" fr%i_o <= #Tp 32'h0;\n", i + 3);
if (log2_int(ncalls)) GEN (" fid_o <= #Tp %i'h0;\n", log2_int (f->nfdeps));
GEN (" fstart_o <= #Tp 1'b0;\n");
//GEN (" f11_r <= #Tp 32'h0;\n");
GEN (" end else begin\n");
cucdebug (1, "calls \n");
for (i = 0; i < f->nmsched; i++) if (f->mtype[i] & MT_CALL) {
char t[30];
dep_list *dep = f->INSN(f->msched[i]).dep;
cucdebug (1, "msched[%i] = %x (mtype %x)\n", i, f->msched[i], f->mtype[i]);
assert (f->INSN(f->msched[i]).opt[1] & (OPT_REF | OPT_REGISTER));
GEN (" if (");
print_deps (fo, f, REF_BB(f->msched[i]), f->INSN(f->msched[i]).dep, 1);
GEN (") begin\n");
print_turn_off_dep (fo, f, dep);
GEN (" f_stb[%i] <= #Tp 1'b1;\n", cur_call++);
GEN (" fstart_o <= #Tp 1'b1;\n");
if (log2_int (f->nfdeps))
GEN (" fid_o <= #Tp %i'h%x;\n", log2_int (f->nfdeps), func_index (f, f->msched[i]));
 
for (j = 0; j < 6; j++)
GEN (" fr%i_o <= #Tp t%x_%x;\n", j + 3,
REF_BB (f->msched[i]), REF_I (f->msched[i]) - 6 + i);
GEN (" end\n");
}
GEN (" if (f_end[%i]) begin\n", ncalls - 1);
GEN (" f_stb <= #Tp %i'h0;\n", ncalls);
GEN (" f_start_o <= #Tp 1'b0;\n");
GEN (" end\n");
GEN (" end\n");
GEN ("end\n");
}
 
GEN ("\n/* Basic blocks state machine */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN ("begin\n");
GEN (" if (rst) bb_stb <= #Tp %i'h%x;\n", f->num_bb, 0);
GEN (" else if (end_o) begin\n");
GEN (" bb_stb <= #Tp %i'h%x;\n", f->num_bb, 0);
for (i = 0; i < f->num_bb; i++) {
GEN (" end else if (bb_start[%i]) begin\n", i);
GEN (" bb_stb <= #Tp %i'h%x;\n", f->num_bb, 1 << i);
}
GEN (" end else if (end_o) begin\n");
GEN (" bb_stb <= #Tp %i'h%x;\n", f->num_bb, 0);
GEN (" end\n");
GEN ("end\n");
 
/* output footer */
GEN ("\nendmodule\n");
 
fclose (fo);
}
 
void generate_main (int nfuncs, cuc_func **f, char *filename)
{
FILE *fo;
int i, j, nrf, first;
char tmp[256];
int ncallees[MAX_FUNCS];
int nl[MAX_FUNCS], ns[MAX_FUNCS];
int maxncallees = 0;
sprintf (tmp, "%s_top.v", filename);
 
for (i = 0, nrf = 0; i < nfuncs; i++) {
nl[i] = ns[i] = 0;
ncallees[i] = 0;
if (f[i]) {
f[i]->tmp = nrf++;
for (j = 0; j < f[i]->nmsched; j++)
if (f[i]->mtype[j] & MT_LOAD) nl[i]++;
else if (f[i]->mtype[j] & MT_STORE) ns[i]++;
for (j = 0; j < f[i]->nfdeps; j++)
ncallees[f[i]->fdeps[j]->tmp]++;
}
}
if (!nrf) return;
for (i = 0; i < nrf; i++)
if (maxncallees < ncallees[i]) maxncallees = ncallees[i];
log ("Generating verilog file \"%s\"\n", tmp);
PRINTF ("Generating verilog file \"%s\"\n", tmp);
if ((fo = fopen (tmp, "wt+")) == NULL) {
fprintf (stderr, "Cannot open '%s'\n", tmp);
exit (1);
}
 
/* output header */
GEN ("/* %s -- generated by Custom Unit Compiler\n", tmp);
GEN (" (C) 2002 Opencores */\n\n");
GEN ("/* Includes %i functions:", nrf);
for (i = 0; i < nfuncs; i++) if (f[i])
GEN ("\n%s", prof_func[i].name);
GEN (" */\n\n");
 
GEN ("`include \"timescale.v\"\n\n");
GEN ("module %s (clk, rst,\n", filename);
GEN (" /* Load and store master Wishbone ports */\n");
GEN (" l_adr_o, l_dat_i, l_cyc_o, l_stb_o,\n");
GEN (" l_sel_o, l_linbrst_o, l_rdy_i, l_we_o,\n");
GEN (" s_adr_o, s_dat_o, s_cyc_o, s_stb_o,\n");
GEN (" s_sel_o, s_linbrst_o, s_rdy_i, s_we_o,\n\n");
GEN (" /* cuc interface */\n");
GEN (" cuc_stb_i, cuc_adr_i, cuc_dat_i, cuc_dat_o, cuc_we_i, cuc_rdy_o);\n\n");
 
GEN ("parameter Tp = 1;\n");
GEN ("\n/* module ports */\n");
GEN ("input clk, rst, cuc_stb_i, cuc_we_i;\n");
GEN ("input l_rdy_i, s_rdy_i;\n");
GEN ("output l_cyc_o, l_stb_o, l_we_o, l_linbrst_o;\n");
GEN ("reg l_cyc_o, l_stb_o, l_we_o, l_linbrst_o;\n");
GEN ("output s_cyc_o, s_stb_o, s_we_o, s_linbrst_o;\n");
GEN ("reg s_cyc_o, s_stb_o, s_we_o, s_linbrst_o;\n");
GEN ("output cuc_rdy_o; /* Not registered ! */\n");
GEN ("output [3:0] l_sel_o, s_sel_o;\n");
GEN ("reg [3:0] l_sel_o, s_sel_o;\n");
GEN ("output [31:0] l_adr_o, s_adr_o, s_dat_o, cuc_dat_o;\n");
GEN ("reg [31:0] l_adr_o, s_adr_o, s_dat_o, cuc_dat_o;\n");
GEN ("input [15:0] cuc_adr_i;\n");
GEN ("input [31:0] l_dat_i, cuc_dat_i;\n\n");
GEN ("wire [%2i:0] i_we, i_re, i_finish, i_selected, i_first_reg;\n", nrf - 1);
GEN ("wire [%2i:0] i_bidok, i_start_bid, i_start_bidok, main_start, main_end;\n", nrf - 1);
GEN ("wire [%2i:0] i_start, i_end, i_start_block, i_busy;\n", nrf - 1);
GEN ("wire [%2i:0] i_l_req, i_s_req;\n", nrf - 1);
GEN ("reg [%2i:0] i_go_bsy, main_start_r;\n", nrf - 1);
 
GEN ("assign i_selected = {\n");
for (i = 0; i < nrf; i++)
GEN (" cuc_adr_i[15:6] == %i%s\n", i, i < nrf - 1 ? "," : "};");
 
GEN ("assign i_first_reg = {\n");
for (i = 0; i < nfuncs; i++) if (f[i]) {
for (j = 0; j <= MAX_REGS; j++) if (f[i]->used_regs[j]) break;
GEN (" cuc_adr_i[5:0] == %i%s\n", j, f[i]->tmp < nrf - 1 ? "," : "};");
}
 
GEN ("assign i_we = {%i{cuc_stb_i && cuc_we_i}} & i_selected;\n", nrf);
GEN ("assign i_re = {%i{cuc_stb_i && !cuc_we_i}} & i_selected;\n", nrf);
 
GEN ("assign i_start = i_go_bsy & {%i{cuc_rdy_o}};\n", nrf);
GEN ("assign i_start_bidok = {\n");
for (i = 0; i < nrf; i++)
GEN (" i_start_bid[%i] < %i%s\n", i, i, i < nrf - 1 ? "," : "};");
GEN ("assign main_start = i_start & i_selected & i_first_reg & i_we;\n");
GEN ("assign main_end = {%i{i_end}} & i_selected;\n");
 
GEN ("\nalways @(posedge clk or posedge rst)\n");
GEN ("begin\n");
GEN (" if (rst) i_go_bsy <= #Tp %i'b0;\n", nrf);
GEN (" else i_go_bsy <= #Tp i_we | ~i_finish & i_go_bsy;\n");
GEN ("end\n");
 
 
/* Function specific data */
for (i = 0; i < nfuncs; i++) if (f[i]) {
int ci = 0, co = 0;
int fn = f[i]->tmp;
GEN ("\n/* Registers for function %s */\n", prof_func[i].name);
for (j = 0, first = 1; j < MAX_REGS; j++) if (f[i]->used_regs[j]) {
GEN ("%s i%i_r%ii", first ? "/* inputs */\nreg [31:0]" : ",", fn, j);
first = 0;
ci++;
}
if (ci) GEN (";\n");
 
for (j = 0, first = 1; j < MAX_REGS; j++)
if (f[i]->lur[j] >= 0 && !f[i]->saved_regs[j]) {
GEN ("%s i%i_r%io", first ? "/* outputs */\nwire [31:0]" : ",", fn, j);
first = 0;
co++;
}
if (co) GEN (";\n");
GEN ("wire [31:0] i%i_l_adr, i%i_s_adr;\n", fn, fn);
GEN ("always @(posedge clk or posedge rst)\n");
GEN (" if (rst) main_start_r <= #Tp %i'b0;\n", nrf);
GEN (" else main_start_r <= #Tp main_start & i_start_bidok | i_busy | ~i_end & main_start_r;\n");
if (ci) {
GEN ("\n/* write register access */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN ("begin\n");
GEN (" if (rst) begin\n");
for (j = 0; j < MAX_REGS; j++) if (f[i]->used_regs[j])
GEN (" i%i_r%ii <= #Tp 32'h0;\n", fn, j);
GEN (" end else if (!i_go_bsy[%i] && i_we[%i])\n", fn, fn);
GEN (" case (cuc_adr_i[5:0])\n");
for (j = 0; j < MAX_REGS; j++) if (f[i]->used_regs[j])
GEN (" %-2i: i%i_r%ii <= #Tp cuc_dat_i;\n", j, fn, j);
GEN (" endcase\n");
GEN ("end\n");
}
 
GEN ("\n");
}
 
/* Generate machine for reading all function registers. Register read can be
delayed till function completion */
{
int co;
GEN ("/* read register access - data */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN (" if (rst) cuc_dat_o <= #Tp 32'h0;\n");
GEN (" else if (cuc_stb_i && cuc_we_i) begin\n");
GEN (" ");
 
for (i = 0; i < nfuncs; i++) if (f[i]) {
co = 0;
for (j = 0; j < MAX_REGS; j++)
if (f[i]->lur[j] >= 0 && !f[i]->saved_regs[j]) co++;
GEN ("if (cuc_adr_i[15:6] == %i)", f[i]->tmp);
if (co) {
first = 1;
GEN ("\n case (cuc_adr_i[5:0])\n");
for (j = 0; j < MAX_REGS; j++)
if (f[i]->lur[j] >= 0 && !f[i]->saved_regs[j])
GEN (" %-2i: cuc_dat_o <= #Tp i%i_r%io;\n", j, f[i]->tmp, j);
GEN (" endcase\n");
} else {
GEN (" cuc_dat_o <= #Tp 32'hx;\n");
}
GEN (" else ");
}
GEN ("cuc_dat_o <= #Tp 32'hx;\n");
GEN (" end else cuc_dat_o <= #Tp 32'hx;\n");
GEN ("\n/* read register access - acknowledge */\n");
GEN ("assign cuc_rdy_o = cuc_stb_i && cuc_we_i && |(i_selected & main_end);\n");
}
 
/* Store/load Wishbone bridge */
for (j = 0; j < 2; j++) {
char t = j ? 's' : 'l';
GEN ("\n/* %s Wishbone bridge */\n", j ? "store" : "load");
GEN ("reg [%i:0] %cm_sel;\n", log2_int (nrf), t);
GEN ("reg [%i:0] %cm_bid;\n", log2_int (nrf), t);
GEN ("reg %ccyc_ip;\n\n", t);
GEN ("always @(posedge clk)\n");
GEN ("begin\n");
GEN (" %c_we_o <= #Tp 1'b%i;\n", t, j);
GEN (" %c_cyc_o <= #Tp |i_%c_req;\n", t, t);
GEN (" %c_stb_o <= #Tp |i_%c_req;\n", t, t);
GEN ("end\n");
 
GEN ("\n/* highest bid */\n");
GEN ("always @(");
for (i = 0; i < nrf; i++) GEN ("%si_%c_req", i > 0 ? " or " : "", t);
GEN (")\n");
for (i = 0; i < nrf; i++) GEN (" %sif (i_%c_req) %cm_bid = %i'h%x;\n",
i ? "else " : "", t, t, log2_int (nrf) + 1, i);
 
GEN ("\n/* selected transfer */\n");
GEN ("always @(posedge clk or posedge rst)\n");
GEN (" if (rst) %cm_sel <= #Tp %i'h0;\n", t, log2_int (nrf) + 1);
GEN (" else if (%c_rdy_i) %cm_sel <= #Tp %i'h0;\n", t, t, log2_int (nrf) + 1);
GEN (" else if (!%ccyc_ip) %cm_sel <= #Tp %cm_bid;\n", t, t, t);
 
GEN ("\n/* Cycle */\n");
GEN ("\nalways @(posedge clk or posedge rst)\n");
GEN (" if (rst) %ccyc_ip <= #Tp 1'b0;\n", t);
GEN (" else if (%c_rdy_i) %ccyc_ip <= #Tp 1'b0;\n", t, t);
GEN (" else %ccyc_ip <= #Tp %c_cyc_o;\n", t, t);
}
 
GEN ("\n/* Acknowledge */\n");
for (i = 0; i < nrf; i++) {
GEN ("wire i%i_s_rdy = ((sm_bid == %i & !scyc_ip) | sm_sel == %i) & s_rdy_i;\n", i, i, i);
GEN ("wire i%i_l_rdy = ((lm_bid == %i & !lcyc_ip) | lm_sel == %i) & l_rdy_i;\n", i, i, i);
}
 
GEN ("\n/* data, address selects and burst enables */\n");
for (i = 0; i < nrf; i++) GEN ("wire [31:0] i%i_s_dat;\n", i);
for (i = 0; i < nrf; i++) GEN ("wire i%i_s_linbrst, i%i_l_linbrst;\n", i, i);
for (i = 0; i < nrf; i++) GEN ("wire [3:0] i%i_s_sel, i%i_l_sel;\n", i, i);
for (i = 0; i < nrf; i++) GEN ("wire [31:0] i%i_l_dat = l_dat_i;\n", i);
GEN ("\nalways @(posedge clk)\n");
GEN ("begin\n");
GEN (" s_dat_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n sm_bid == %i ? i%i_s_dat : ", i, i);
GEN ("i%i_s_dat;\n", nrf - 1);
GEN (" s_adr_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n sm_bid == %i ? i%i_s_adr : ", i, i);
GEN ("i%i_s_adr;\n", nrf - 1);
GEN (" s_sel_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n sm_bid == %i ? i%i_s_sel : ", i, i);
GEN ("i%i_s_sel;\n", nrf - 1);
GEN (" s_linbrst_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n sm_bid == %i ? i%i_s_linbrst : ", i, i);
GEN ("i%i_s_linbrst;\n", nrf - 1);
GEN ("end\n\n");
 
GEN ("always @(posedge clk)\n");
GEN ("begin\n");
GEN (" l_adr_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n lm_bid == %i ? i%i_l_adr : ", i, i);
GEN ("i%i_l_adr;\n", nrf - 1);
GEN (" l_sel_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n lm_bid == %i ? i%i_l_sel : ", i, i);
GEN ("i%i_l_sel;\n", nrf - 1);
GEN (" l_linbrst_o <= #Tp ");
for (i = 0; i < nrf - 1; i++)
GEN ("\n lm_bid == %i ? i%i_l_linbrst : ", i, i);
GEN ("i%i_l_linbrst;\n", nrf - 1);
GEN ("end\n\n");
/* start/end signals */
GEN ("\n\n/* start/end signals */\n");
for (i = 0; i < nrf; i++) {
if (log2_int (maxncallees + 1))
GEN ("wire [%i:0] i%i_current = i%i_busy ? i%i_current_r : i%i_start_bid;\n",
log2_int (maxncallees + 1), i, i, i, i, i);
else GEN ("wire i%i_current = 0;\n", i);
}
GEN ("\n");
for (i = 0, j = 0; i < nfuncs; i++) if (f[i]) {
if (log2_int (ncallees[i])) {
GEN ("reg [%i:0] i%i_start_bid;\n", log2_int (ncallees[i]), j);
GEN ("always @(start%i", f[i]->tmp);
for (j = 0, first = 1; j < f[i]->nfdeps; j++)
if (f[i]->fdeps[j]) GEN (", ");
GEN (")\n");
GEN ("begin !!!\n"); //TODO
GEN (" \n");
GEN ("end\n");
}
GEN ("wire i%i_start = main_start[%i];\n", j, j);
j++;
}
GEN ("\n");
 
for (i = 0; i < nfuncs; i++) if (f[i]) {
int nf = f[i]->tmp;
GEN ("\n%s%s i%i(.clk(clk), .rst(rst),\n", filename, prof_func[i].name, nf);
GEN ("");
GEN (" .l_adr_o(i%i_l_adr), .l_dat_i(i%i_l_dat), .l_req_o(i_l_req[%i]),\n",
nf, nf, nf);
GEN (" .l_sel_o(i%i_l_sel), .l_linbrst_o(i%i_l_linbrst), .l_rdy_i(i%i_l_rdy),\n",
nf, nf, nf);
GEN (" .s_adr_o(i%i_s_adr), .s_dat_o(i%i_s_dat), .s_req_o(i_s_req[%i]),\n",
nf, nf, nf);
GEN (" .s_sel_o(i%i_s_sel), .s_linbrst_o(i%i_s_linbrst), .s_rdy_i(i%i_s_rdy),\n",
nf, nf, nf);
GEN (" ");
for (j = 0, first = 1; j < MAX_REGS; j++) if (f[i]->used_regs[j])
GEN (".r%i_i(i%i_r%ii), ", j, nf, j), first = 0;
 
if (first) GEN ("\n ");
for (j = 0, first = 1; j < MAX_REGS; j++)
if (f[i]->lur[j] >= 0 && !f[i]->saved_regs[j])
GEN (".r%i_o(i%i_r%io), ", j, nf, j), first = 0;
if (first) GEN ("\n ");
if (f[i]->nfdeps) {
GEN (".fstart_o(i_fstart[%i]), .fend_i(i_fend[%i]), .fid_o(i%i_fid),\n", i, i, i),
GEN (" .fr3_o(i%i_fr3), .fr4_o(i%i_fr4), .fr5_o(i%i_fr5), .fr6_o(i%i_fr6),\n");
GEN (" .fr7_o(i%i_fr7), .fr8_o(i%i_fr8), .fr11_i(i%i_fr11i),\n ");
}
GEN (".start_i(i_start[%i]), .end_o(i_end[%i]), .busy_o(i_busy[%i]));\n", nf, nf, nf);
}
 
/* output footer */
GEN ("\nendmodule\n");
 
fclose (fo);
}
 
/trunk/or1ksim/cuc/adv.c
41,7 → 41,7
 
static unsigned long mask (unsigned long c)
{
if (c) return (1 << (log2 (c) + 1)) - 1;
if (c) return (1 << (log2_int (c) + 1)) - 1;
else return 0;
}
 
/trunk/or1ksim/cuc/cuc.c
1,824 → 1,825
/* cuc.c -- OpenRISC Custom Unit Compiler
* Copyright (C) 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. */
 
/* Main file, including code optimization and command prompt */
 
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include "sim-config.h"
#include "cuc.h"
#include "insn.h"
#include "profiler.h"
#include "opcode/or32.h"
#include "parse.h"
 
FILE *flog;
int cuc_debug = 0;
 
/* Last used registers by software convention */
/* Note that r11 is caller saved register, and we can destroy it.
Due to CUC architecture we must always return something, even garbage (so that
caller knows, we are finished, when we send acknowledge).
In case r11 was not used (trivial register assignment) we will remove it later,
but if we assigned a value to it, it must not be removed, so caller_saved[11] = 0 */
const int caller_saved[MAX_REGS] = {
0, 0, 0, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1,
1, 1};
 
/* returns log2(x) */
int log2 (unsigned long x)
{
int c = 0;
assert (x >= 0);
if (!x) return 0; /* not by the book, but practical */
while (x != 1) x >>= 1, c++;
return c;
}
 
/* Does all known instruction optimizations */
void cuc_optimize (cuc_func *func)
{
int modified = 0;
int first = 1;
log ("Optimizing.\n");
do {
modified = 0;
clean_deps (func);
if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_CLEAN_DEPS");
if (optimize_cmovs (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_OPT_CMOVS");
modified = 1;
}
if (cuc_debug) cuc_check (func);
if (optimize_tree (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_OPT_TREE1");
modified = 1;
}
if (remove_nops (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
modified = 1;
}
if (cuc_debug) cuc_check (func);
if (remove_dead (func)) {
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD");
modified = 1;
}
if (cuc_debug) cuc_check (func);
if (cse (func)) {
log ("Common subexpression elimination.\n");
if (cuc_debug >= 3) print_cuc_bb (func, "AFTER_CSE");
modified = 1;
}
if (first) {
insert_conditional_facts (func);
if (cuc_debug >= 3) print_cuc_bb (func, "AFTER_COND_FACT");
if (cuc_debug) cuc_check (func);
first = 0;
}
if (optimize_bb (func)) {
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_OPT_BB");
modified = 1;
}
if (cuc_debug) cuc_check (func);
if (remove_nops (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
modified = 1;
}
if (remove_dead_bb (func)) {
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD_BB");
modified = 1;
}
if (remove_trivial_regs (func)) {
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_TRIVIAL");
modified = 1;
}
if (remove_nops (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
modified = 1;
}
add_memory_dep (func, func->memory_order);
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_MEMORY_DEP");
add_data_dep (func);
if (cuc_debug >= 8) print_cuc_bb (func, "AFTER_DATA_DEP");
if (schedule_memory (func, func->memory_order)) {
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_SCHEDULE_MEM");
modified = 1;
}
} while (modified);
set_io (func);
#if 0
detect_max_values (func);
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_MAX_VALUES");
#endif
}
 
/* Pre/unrolls basic block and optimizes it */
cuc_timings *preunroll_bb (char *bb_filename, cuc_func *f, cuc_timings *timings, int b, int i, int j)
{
cuc_func *func;
cucdebug (2, "BB%i unroll %i times preroll %i times\n", b, j, i);
log ("BB%i unroll %i times preroll %i times\n", b, j, i);
func = preunroll_loop (f, b, i, j, bb_filename);
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_PREUNROLL");
cuc_optimize (func);
analyse_timings (func, timings);
 
cucdebug (2, "new_time = %i, old_time = %i, size = %f\n",
timings->new_time, func->orig_time, timings->size);
log ("new time = %icyc, old_time = %icyc, size = %.0f gates\n",
timings->new_time, func->orig_time, timings->size);
//output_verilog (func, argv[1]);
free_func (func);
timings->b = b;
timings->unroll = j;
timings->preroll = i;
timings->nshared = 0;
return timings;
}
 
/* Simple comparison function */
int tim_comp (cuc_timings *a, cuc_timings *b)
{
if (a->new_time < b->new_time) return -1;
else if (a->new_time > b->new_time) return 1;
else return 0;
}
 
/* Analyses function; done when cuc command is entered in (sim) prompt */
cuc_func *analyse_function (char *module_name, long orig_time,
unsigned long start_addr, unsigned long end_addr,
int memory_order, int num_runs)
{
cuc_timings timings;
cuc_func *func = (cuc_func *) malloc (sizeof (cuc_func));
cuc_func *saved;
int b, i, j;
char tmp1[256];
char tmp2[256];
 
func->orig_time = orig_time;
func->start_addr = start_addr;
func->end_addr = end_addr;
func->memory_order = memory_order;
func->nfdeps = 0;
func->fdeps = NULL;
func->num_runs = num_runs;
 
sprintf (tmp1, "%s.bin", module_name);
cucdebug (2, "Loading %s.bin\n", module_name);
if (cuc_load (tmp1)) {
free (func);
return NULL;
}
 
log ("Detecting basic blocks\n");
detect_bb (func);
if (cuc_debug >= 2) print_cuc_insns ("WITH_BB_LIMITS", 0);
 
//sprintf (tmp1, "%s.bin.mp", module_name);
sprintf (tmp2, "%s.bin.bb", module_name);
generate_bb_seq (func, config.sim.mprof_fn, tmp2);
log ("Assuming %i clk cycle load (%i cyc burst)\n", runtime.cuc.mdelay[0], runtime.cuc.mdelay[2]);
log ("Assuming %i clk cycle store (%i cyc burst)\n", runtime.cuc.mdelay[1], runtime.cuc.mdelay[3]);
build_bb (func);
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_BUILD_BB");
reg_dep (func);
 
log ("Detecting dependencies\n");
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_REG_DEP");
cuc_optimize (func);
#if 0
csm (func);
#endif
assert (saved = dup_func (func));
 
timings.preroll = timings.unroll = 1;
timings.nshared = 0;
 
add_latches (func);
if (cuc_debug >= 1) print_cuc_bb (func, "AFTER_LATCHES");
analyse_timings (func, &timings);
 
free_func (func);
log ("Base option: pre%i,un%i,sha%i: %icyc %.1f\n",
timings.preroll, timings.unroll, timings.nshared, timings.new_time, timings.size);
saved->timings = timings;
#if 1
/* detect and unroll simple loops */
for (b = 0; b < saved->num_bb; b++) {
cuc_timings t[MAX_UNROLL * MAX_PREROLL];
cuc_timings *ut;
cuc_timings *cut = &t[0];
int nt = 1;
double csize;
saved->bb[b].selected_tim = -1;
 
/* Is it a loop? */
if (saved->bb[b].next[0] != b && saved->bb[b].next[1] != b) continue;
log ("Found loop at BB%x. Trying to unroll.\n", b);
t[0] = timings;
t[0].b = b;
t[0].preroll = 1;
t[0].unroll = 1;
t[0].nshared = 0;
sprintf (tmp1, "%s.bin.bb", module_name);
i = 1;
do {
cuc_timings *pt;
cuc_timings *cpt = cut;
j = 1;
 
do {
pt = cpt;
cpt = preunroll_bb (tmp1, saved, &t[nt++], b, ++j, i);
} while (j <= MAX_PREROLL && pt->new_time > cpt->new_time);
i++;
ut = cut;
cut = preunroll_bb (tmp1, saved, &t[nt++], b, 1, i);
} while (i <= MAX_UNROLL && ut->new_time > cut->new_time);
 
/* Sort the timings */
#if 0
if (cuc_debug >= 3)
for (i = 0; i < nt; i++) PRINTF ("%i:%i,%i: %icyc\n",
t[i].b, t[i].preroll, t[i].unroll, t[i].new_time);
#endif
 
qsort (t, nt, sizeof (cuc_timings), (int (*)(const void *, const void *))tim_comp);
 
/* Delete timings, that have worst time and bigger size than other */
j = 1;
csize = t[0].size;
for (i = 1; i < nt; i++)
if (t[i].size < csize) t[j++] = t[i];
nt = j;
cucdebug (1, "Available options\n");
for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
/* Add results from CSM */
j = nt;
for (i = 0; i < saved->bb[b].ntim; i++) {
int i1;
for (i1 = 0; i1 < nt; i1++) {
t[j] = t[i1];
t[j].size += saved->bb[b].tim[i].size - timings.size;
t[j].new_time += saved->bb[b].tim[i].new_time - timings.new_time;
t[j].nshared = saved->bb[b].tim[i].nshared;
t[j].shared = saved->bb[b].tim[i].shared;
if (++j >= MAX_UNROLL * MAX_PREROLL) goto full;
}
}
full:
nt = j;
 
cucdebug (1, "Available options:\n");
for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
 
/* Sort again with new timings added */
qsort (t, nt, sizeof (cuc_timings), (int (*)(const void *, const void *))tim_comp);
 
/* Delete timings, that have worst time and bigger size than other */
j = 1;
csize = t[0].size;
for (i = 1; i < nt; i++)
if (t[i].size < csize) t[j++] = t[i];
nt = j;
 
cucdebug (1, "Available options:\n");
for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
 
if (saved->bb[b].ntim) free (saved->bb[b].tim);
saved->bb[b].ntim = nt;
assert (saved->bb[b].tim = (cuc_timings *) malloc (sizeof (cuc_timings) * nt));
 
/* Copy options in reverse order -- smallest first */
for (i = 0; i < nt; i++) saved->bb[b].tim[i] = t[nt - 1 - i];
 
log ("Available options:\n");
for (i = 0; i < saved->bb[b].ntim; i++) {
log ("%i:pre%i,un%i,sha%i: %icyc %.1f\n",
saved->bb[b].tim[i].b, saved->bb[b].tim[i].preroll, saved->bb[b].tim[i].unroll,
saved->bb[b].tim[i].nshared, saved->bb[b].tim[i].new_time, saved->bb[b].tim[i].size);
}
}
#endif
return saved;
}
 
/* Utility option formatting functions */
static const char *option_char = "?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
/*static */char *gen_option (char *s, int bb_no, int f_opt)
{
if (bb_no >= 0) sprintf (s, "%i", bb_no);
assert (f_opt <= strlen (option_char));
sprintf (s, "%s%c", s, option_char[f_opt]);
return s;
}
 
/*static */void print_option (int bb_no, int f_opt)
{
char tmp1[10];
char tmp2[10];
sprintf (tmp2, "%s", gen_option (tmp1, bb_no, f_opt));
PRINTF ("%3s", tmp2);
}
 
static char *format_func_options (char *s, cuc_func *f)
{
int b, first = 1;
*s = '\0';
for (b = 0; b < f->num_bb; b++)
if (f->bb[b].selected_tim >= 0) {
char tmp[10];
sprintf (s, "%s%s%s", s, first ? "" : ",", gen_option (tmp, b, f->bb[b].selected_tim));
first = 0;
}
return s;
}
 
static void options_cmd (int func_no, cuc_func *f)
{
int b, i;
char tmp[30];
char *name = prof_func[func_no].name;
PRINTF ("-----------------------------------------------------------------------------\n");
PRINTF ("|%-28s|pre/unrolled|shared| time | gates |old_time|\n",
strstrip (tmp, name, 28));
PRINTF ("| BASE |%4i / %4i | %4i |%8i|%8.f|%8i|\n", 1, 1, 0,
f->timings.new_time, f->timings.size, f->orig_time);
for (b = 0; b < f->num_bb; b++) {
/* Print out results */
for (i = 1; i < f->bb[b].ntim; i++) { /* First one is base option */
int time = f->bb[b].tim[i].new_time - f->timings.new_time;
double size = f->bb[b].tim[i].size - f->timings.size;
PRINTF ("| ");
print_option (b, i);
PRINTF (" |%4i / %4i | %4i |%+8i|%+8.f| |\n",
f->bb[b].tim[i].preroll, f->bb[b].tim[i].unroll, f->bb[b].tim[i].nshared,
time, size);
}
}
}
 
/* Generates a function, based on specified parameters */
cuc_func *generate_function (cuc_func *rf, char *name, char *cut_filename)
{
int b, i, j;
char tmp[256];
cuc_timings tt;
cuc_func *f;
assert (f = dup_func (rf));
 
if (cuc_debug >= 2) print_cuc_bb (f, "BEFORE_GENERATE");
log ("Generating function %s.\n", name);
PRINTF ("Generating function %s.\n", name);
 
format_func_options (tmp, rf);
if (strlen (tmp)) PRINTF ("Applying options: %s\n", tmp);
else PRINTF ("Using basic options.\n");
 
/* Generate function as specified by options */
for (b = 0; b < f->num_bb; b++) {
cuc_timings *st;
if (rf->bb[b].selected_tim < 0) continue;
st = &rf->bb[b].tim[rf->bb[b].selected_tim];
sprintf (tmp, "%s.bin.bb", name);
preunroll_bb (&tmp[0], f, &tt, b, st->preroll, st->unroll);
if (cuc_debug >= 1) print_cuc_bb (f, "AFTER_PREUNROLL");
}
for (b = 0; b < f->num_bb; b++) {
cuc_timings *st;
if (rf->bb[b].selected_tim < 0) continue;
st = &rf->bb[b].tim[rf->bb[b].selected_tim];
if (!st->nshared) continue;
assert (0);
//csm_gen (f, rf, st->nshared, st->shared);
}
add_latches (f);
if (cuc_debug >= 1) print_cuc_bb (f, "AFTER_LATCHES");
analyse_timings (f, &tt);
sprintf (tmp, "%s%s", cut_filename, name);
output_verilog (f, tmp, name);
return f;
}
 
/* Calculates required time, based on selected options */
int calc_cycles (cuc_func *f)
{
int b, i, ntime = f->timings.new_time;
for (b = 0; b < f->num_bb; b++)
if (f->bb[b].selected_tim >= 0) {
assert (f->bb[b].selected_tim < f->bb[b].ntim);
ntime += f->bb[b].tim[f->bb[b].selected_tim].new_time - f->timings.new_time;
}
return ntime;
}
 
/* Calculates required size, based on selected options */
double calc_size (cuc_func *f)
{
int b, i;
double size = f->timings.size;
for (b = 0; b < f->num_bb; b++)
if (f->bb[b].selected_tim >= 0) {
assert (f->bb[b].selected_tim < f->bb[b].ntim);
size += f->bb[b].tim[f->bb[b].selected_tim].size - f->timings.size;
}
return size;
}
 
/* Dumps specified function to file (hex) */
unsigned long extract_function (char *out_fn, unsigned long start_addr)
{
FILE *fo;
unsigned long a = start_addr;
int x = 0;
assert (fo = fopen (out_fn, "wt+"));
 
do {
unsigned long d = evalsim_mem32 (a);
int index = insn_decode (d);
assert (index >= 0);
if (x) x++;
if (strcmp (insn_name (index), "l.jr") == 0) x = 1;
a += 4;
fprintf (fo, "%08x\n", d);
} while (x < 2);
 
fclose (fo);
return a - 4;
}
 
static cuc_func *func[MAX_FUNCS];
static int func_v[MAX_FUNCS];
 
/* Detects function dependencies and removes */
static void set_func_deps ()
{
int f, b, i, j;
restart:
for (f = 0; f < prof_nfuncs - 1; f++) if (func[f]) {
int fused[MAX_FUNCS] = {0};
int c;
for (b = 0; b < func[f]->num_bb; b++)
for (i = 0; i < func[f]->bb[b].ninsn; i++) {
cuc_insn *ii = &func[f]->bb[b].insn[i];
if (ii->index == II_CALL) {
assert (ii->opt[0] == OPT_CONST);
for (j = 0; j < prof_nfuncs - 1; j++)
if (func[j] && func[j]->start_addr == ii->op[0]) break;
if (j >= prof_nfuncs - 1) {
log ("%s is calling unknown function, address %08x\n",
prof_func[f].name, ii->op[0]);
debug (1, "%s is calling unknown function, address %08x\n",
prof_func[f].name, ii->op[0]);
free_func (func[f]);
func[f] = NULL;
goto restart;
} else if (f == j) {
log ("%s is recursive, ignoring\n", prof_func[f].name);
debug (1, "%s is recursive, ignoring\n", prof_func[f].name);
free_func (func[f]);
func[f] = NULL;
goto restart;
} else fused[j]++;
}
}
for (i = 0; i < MAX_FUNCS; i++) if (fused[i]) c++;
if (func[f]->nfdeps) free (func[f]->fdeps);
func[f]->nfdeps = c;
func[f]->fdeps = (cuc_func **) malloc (sizeof (cuc_func *) * c);
for (i = 0, j = 0; i < MAX_FUNCS; i++)
if (fused[i]) func[f]->fdeps[j++] = func[i];
}
 
/* Detect loops */
{
int change;
for (f = 0; f < MAX_FUNCS; f++) if (func[f]) func[f]->tmp = 0;
do {
change = 0;
for (f = 0; f < MAX_FUNCS; f++) if (func[f] && !func[f]->tmp) {
int o = 1;
for (i = 0; i < func[f]->nfdeps; i++)
if (!func[f]->fdeps[i]->tmp) {o = 0; break;}
if (o) {
func[f]->tmp = 1;
change = 1;
}
}
} while (change);
change = 0;
for (f = 0; f < MAX_FUNCS; f++) if (func[f] && !func[f]->tmp) {
free_func (func[f]);
func[f] = NULL;
change = 1;
}
if (change) goto restart;
}
}
 
void main_cuc (char *filename)
{
int i, j;
char tmp1[256];
char filename_cut[256];
#if 0 /* Select prefix, based on binary program name */
for (i = 0; i < sizeof (filename_cut); i++) {
if (isalpha(filename[i])) filename_cut[i] = filename[i];
else {
filename_cut[i] = '\0';
break;
}
}
#else
strcpy (filename_cut, "cu");
#endif
 
PRINTF ("Entering OpenRISC Custom Unit Compiler command prompt\n");
PRINTF ("Using profile file \"%s\" and memory profile file \"%s\".\n", config.sim.prof_fn, config.sim.mprof_fn);
sprintf (tmp1, "%s.log", filename_cut);
PRINTF ("Analyzing. (log file \"%s\").\n", tmp1);
assert (flog = fopen (tmp1, "wt+"));
 
/* Loads in the specified timings table */
PRINTF ("Using timings from \"%s\" at %s\n",config.cuc.timings_fn,
generate_time_pretty (tmp1, config.sim.clkcycle_ps));
load_timing_table (config.cuc.timings_fn);
runtime.cuc.cycle_duration = 1000. * config.sim.clkcycle_ps;
PRINTF ("Multicycle logic %s, bursts %s, %s memory order.\n",
config.cuc.no_multicycle ? "OFF" : "ON", config.cuc.enable_bursts ? "ON" : "OFF",
config.cuc.memory_order == MO_NONE ? "no" : config.cuc.memory_order == MO_WEAK ? "weak" :
config.cuc.memory_order == MO_STRONG ? "strong" : "exact");
 
prof_set (1, 0);
assert (prof_acquire (config.sim.prof_fn) == 0);
if (config.cuc.calling_convention)
PRINTF ("Assuming OpenRISC standard calling convention.\n");
 
/* Try all functions except "total" */
for (i = 0; i < prof_nfuncs - 1; i++) {
long orig_time;
unsigned long start_addr, end_addr;
orig_time = prof_func[i].cum_cycles;
start_addr = prof_func[i].addr;
/* Extract the function from the binary */
sprintf (tmp1, "%s.bin", prof_func[i].name);
end_addr = extract_function (tmp1, start_addr);
log ("Testing function %s (%08x - %08x)\n", prof_func[i].name, start_addr, end_addr);
PRINTF ("Testing function %s (%08x - %08x)\n", prof_func[i].name, start_addr, end_addr);
func[i] = analyse_function (prof_func[i].name, orig_time, start_addr,
end_addr, config.cuc.memory_order, prof_func[i].calls);
func_v[i] = 0;
}
set_func_deps ();
while (1) {
char *s;
wait_command:
PRINTF ("(cuc) ");
fflush (stdout);
wait_command_empty:
s = fgets(tmp1, sizeof tmp1, stdin);
usleep (100);
if (!s) goto wait_command_empty;
for (s = tmp1; *s != '\0' && *s != '\n' && *s != '\r'; s++);
*s = '\0';
 
/* quit command */
if (strcmp (tmp1, "q") == 0 || strcmp (tmp1, "quit") == 0) {
/* Delete temporary files */
for (i = 0; i < prof_nfuncs - 1; i++) {
sprintf (tmp1, "%s.bin", prof_func[i].name);
log ("Deleting temporary file %s %s\n", tmp1, remove (tmp1) ? "FAILED" : "OK");
sprintf (tmp1, "%s.bin.bb", prof_func[i].name);
log ("Deleting temporary file %s %s\n", tmp1, remove (tmp1) ? "FAILED" : "OK");
}
break;
/* profile command */
} else if (strcmp (tmp1, "p") == 0 || strcmp (tmp1, "profile") == 0) {
int ntime = 0;
int size = 0;
PRINTF ("-----------------------------------------------------------------------------\n");
PRINTF ("|function name |calls|avg cycles |old%| max. f. | impr. f.| options |\n");
PRINTF ("|--------------------+-----+------------+----+----------|---------+---------|\n");
for (j = 0; j < prof_nfuncs; j++) {
int bestcyc = 0, besti = 0;
char tmp[100];
for (i = 0; i < prof_nfuncs; i++)
if (prof_func[i].cum_cycles > bestcyc) {
bestcyc = prof_func[i].cum_cycles;
besti = i;
}
i = besti;
PRINTF ("|%-20s|%5i|%12.1f|%3.0f%%| ",
strstrip (tmp, prof_func[i].name, 20), prof_func[i].calls,
((double)prof_func[i].cum_cycles / prof_func[i].calls),
(100. * prof_func[i].cum_cycles / prof_cycles));
if (func[i]) {
double f = 1.0;
if (func_v[i]) {
int nt = calc_cycles (func[i]);
int s = calc_size (func[i]);
f = 1. * func[i]->orig_time / nt;
ntime += nt;
size += s;
} else ntime += prof_func[i].cum_cycles;
PRINTF ("%8.1f |%8.1f | %-8s|\n", 1.f * prof_func[i].cum_cycles
/ func[i]->timings.new_time, f, format_func_options (tmp, func[i]));
} else {
PRINTF (" N/A | N/A | N/A |\n");
ntime += prof_func[i].cum_cycles;
}
prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
}
for (i = 0; i < prof_nfuncs; i++)
prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
PRINTF ("-----------------------------------------------------------------------------\n");
PRINTF ("Total %i cycles (was %i), total added gates = %i. Speed factor %.1f\n",
ntime, prof_cycles, size, 1. * prof_cycles / ntime);
/* debug command */
} else if (strncmp (tmp1, "d", 1) == 0 || strncmp (tmp1, "debug", 5) == 0) {
sscanf (tmp1, "%*s %i", &cuc_debug);
if (cuc_debug < 0) cuc_debug = 0;
if (cuc_debug > 9) cuc_debug = 9;
 
/* generate command */
} else if (strcmp (tmp1, "g") == 0 || strcmp (tmp1, "generate") == 0) {
/* check for function dependencies */
for (i = 0; i < prof_nfuncs; i++)
if (func[i]) func[i]->tmp = func_v[i];
for (i = 0; i < prof_nfuncs; i++) if (func[i])
for (j = 0; j < func[i]->nfdeps; j++)
if (!func[i]->fdeps[j] || !func[i]->fdeps[j]->tmp) {
PRINTF ("Function %s must be selected for translation (required by %s)\n",
prof_func[j].name, prof_func[i].name);
goto wait_command;
}
for (i = 0; i < prof_nfuncs; i++)
if (func[i] && func_v[i]) generate_function (func[i], prof_func[i].name, filename_cut);
generate_main (prof_nfuncs, func, filename_cut);
 
/* list command */
} else if (strcmp (tmp1, "l") == 0 || strcmp (tmp1, "list") == 0) {
/* check for function dependencies */
for (i = 0; i < prof_nfuncs; i++)
if (func_v[i]) {
PRINTF ("%s\n", prof_func[j].name);
}
 
/* selectall command */
} else if (strcmp (tmp1, "sa") == 0 || strcmp (tmp1, "selectall") == 0) {
char tmp[50], ch;
int p, o, b, f;
for (f = 0; f < prof_nfuncs; f++) if (func[f]) {
func_v[f] = 1;
PRINTF ("Function %s selected for translation.\n", prof_func[f].name);
}
/* select command */
} else if (strncmp (tmp1, "s", 1) == 0 || strncmp (tmp1, "select", 6) == 0) {
char tmp[50], ch;
int p, o, b, f;
p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
if (p < 1) PRINTF ("Invalid parameters.\n");
else {
/* Check if we have valid option */
for (f = 0; f < prof_nfuncs; f++)
if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
if (f < prof_nfuncs) {
if (p == 1) {
if (func[f]) {
func_v[f] = 1;
PRINTF ("Function %s selected for translation.\n", prof_func[f].name);
} else PRINTF ("Function %s not suitable for translation.\n", prof_func[f].name);
} else {
if (!func_v[f])
PRINTF ("Function %s not yet selected for translation.\n", prof_func[f].name);
if (p < 3) goto invalid_option;
for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
if (!option_char[o]) goto invalid_option;
if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
/* select an option */
func[f]->bb[b].selected_tim = o;
if (func[f]->bb[b].tim[o].nshared) {
PRINTF ("Option has shared instructions: ");
print_shared (func[f], func[f]->bb[b].tim[o].shared, func[f]->bb[b].tim[o].nshared);
PRINTF ("\n");
}
goto wait_command;
invalid_option:
PRINTF ("Invalid option.\n");
}
} else PRINTF ("Invalid function.\n");
}
 
/* unselect command */
} else if (strncmp (tmp1, "u", 1) == 0 || strncmp (tmp1, "unselect", 8) == 0) {
char tmp[50], ch;
int p, o, b, f;
p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
if (p < 1) PRINTF ("Invalid parameters.\n");
else {
/* Check if we have valid option */
for (f = 0; f < prof_nfuncs; f++)
if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
if (f < prof_nfuncs) {
if (p == 1) {
if (func[f]) {
func_v[f] = 0;
PRINTF ("Function %s unselected for translation.\n", prof_func[f].name);
} else PRINTF ("Function %s not suitable for translation.\n", prof_func[f].name);
} else {
if (p < 3) goto invalid_option;
for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
if (!option_char[o]) goto invalid_option;
if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
/* select an option */
func[f]->bb[b].selected_tim = -1;
}
} else PRINTF ("Invalid function.\n");
}
/* options command */
} else if (strcmp (tmp1, "o") == 0 || strcmp (tmp1, "options") == 0) {
int any = 0;
PRINTF ("Available options:\n");
for (i = 0; i < prof_nfuncs; i++)
if (func[i]) {
options_cmd (i, func[i]);
any = 1;
}
if (any) PRINTF ("-----------------------------------------------------------------------------\n");
else PRINTF ("Sorry. No available options.\n");
 
/* Ignore empty string */
} else if (strcmp (tmp1, "") == 0) {
 
/* help command */
} else {
if (strcmp (tmp1, "h") != 0 && strcmp (tmp1, "help") != 0)
PRINTF ("Unknown command.\n");
PRINTF ("OpenRISC Custom Unit Compiler command prompt\n");
PRINTF ("Available commands:\n");
PRINTF (" h | help displays this help\n");
PRINTF (" q | quit returns to or1ksim prompt\n");
PRINTF (" p | profile displays function profiling\n");
PRINTF (" d | debug # sets debug level (0-9)\n");
PRINTF (" o | options displays available options\n");
PRINTF (" s | select func [option] selects an option/function\n");
PRINTF (" u | unselect func [option] unselects an option/function\n");
PRINTF (" g | generate generates verilog file\n");
PRINTF (" l | list displays selected functions\n");
}
}
 
/* Dispose memory */
for (i = 0; i < prof_nfuncs -1; i++)
if (func[i]) free_func (func[i]);
 
fclose (flog);
}
 
/* cuc.c -- OpenRISC Custom Unit Compiler
* Copyright (C) 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. */
 
/* Main file, including code optimization and command prompt */
 
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include "sim-config.h"
#include "cuc.h"
#include "insn.h"
#include "profiler.h"
#include "opcode/or32.h"
#include "parse.h"
 
FILE *flog;
int cuc_debug = 0;
 
/* Last used registers by software convention */
/* Note that r11 is caller saved register, and we can destroy it.
Due to CUC architecture we must always return something, even garbage (so that
caller knows, we are finished, when we send acknowledge).
In case r11 was not used (trivial register assignment) we will remove it later,
but if we assigned a value to it, it must not be removed, so caller_saved[11] = 0 */
const int caller_saved[MAX_REGS] = {
0, 0, 0, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1,
1, 1};
 
/* returns log2(x) */
/* Call this log2_int, because there is a library function named log2 */
int log2_int (unsigned long x)
{
int c = 0;
assert (x >= 0);
if (!x) return 0; /* not by the book, but practical */
while (x != 1) x >>= 1, c++;
return c;
}
 
/* Does all known instruction optimizations */
void cuc_optimize (cuc_func *func)
{
int modified = 0;
int first = 1;
log ("Optimizing.\n");
do {
modified = 0;
clean_deps (func);
if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_CLEAN_DEPS");
if (optimize_cmovs (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_OPT_CMOVS");
modified = 1;
}
if (cuc_debug) cuc_check (func);
if (optimize_tree (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "AFTER_OPT_TREE1");
modified = 1;
}
if (remove_nops (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
modified = 1;
}
if (cuc_debug) cuc_check (func);
if (remove_dead (func)) {
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD");
modified = 1;
}
if (cuc_debug) cuc_check (func);
if (cse (func)) {
log ("Common subexpression elimination.\n");
if (cuc_debug >= 3) print_cuc_bb (func, "AFTER_CSE");
modified = 1;
}
if (first) {
insert_conditional_facts (func);
if (cuc_debug >= 3) print_cuc_bb (func, "AFTER_COND_FACT");
if (cuc_debug) cuc_check (func);
first = 0;
}
if (optimize_bb (func)) {
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_OPT_BB");
modified = 1;
}
if (cuc_debug) cuc_check (func);
if (remove_nops (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
modified = 1;
}
if (remove_dead_bb (func)) {
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_DEAD_BB");
modified = 1;
}
if (remove_trivial_regs (func)) {
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_TRIVIAL");
modified = 1;
}
if (remove_nops (func)) {
if (cuc_debug >= 6) print_cuc_bb (func, "NO_NOPS");
modified = 1;
}
add_memory_dep (func, func->memory_order);
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_MEMORY_DEP");
add_data_dep (func);
if (cuc_debug >= 8) print_cuc_bb (func, "AFTER_DATA_DEP");
if (schedule_memory (func, func->memory_order)) {
if (cuc_debug >= 7) print_cuc_bb (func, "AFTER_SCHEDULE_MEM");
modified = 1;
}
} while (modified);
set_io (func);
#if 0
detect_max_values (func);
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_MAX_VALUES");
#endif
}
 
/* Pre/unrolls basic block and optimizes it */
cuc_timings *preunroll_bb (char *bb_filename, cuc_func *f, cuc_timings *timings, int b, int i, int j)
{
cuc_func *func;
cucdebug (2, "BB%i unroll %i times preroll %i times\n", b, j, i);
log ("BB%i unroll %i times preroll %i times\n", b, j, i);
func = preunroll_loop (f, b, i, j, bb_filename);
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_PREUNROLL");
cuc_optimize (func);
analyse_timings (func, timings);
 
cucdebug (2, "new_time = %i, old_time = %i, size = %f\n",
timings->new_time, func->orig_time, timings->size);
log ("new time = %icyc, old_time = %icyc, size = %.0f gates\n",
timings->new_time, func->orig_time, timings->size);
//output_verilog (func, argv[1]);
free_func (func);
timings->b = b;
timings->unroll = j;
timings->preroll = i;
timings->nshared = 0;
return timings;
}
 
/* Simple comparison function */
int tim_comp (cuc_timings *a, cuc_timings *b)
{
if (a->new_time < b->new_time) return -1;
else if (a->new_time > b->new_time) return 1;
else return 0;
}
 
/* Analyses function; done when cuc command is entered in (sim) prompt */
cuc_func *analyse_function (char *module_name, long orig_time,
unsigned long start_addr, unsigned long end_addr,
int memory_order, int num_runs)
{
cuc_timings timings;
cuc_func *func = (cuc_func *) malloc (sizeof (cuc_func));
cuc_func *saved;
int b, i, j;
char tmp1[256];
char tmp2[256];
 
func->orig_time = orig_time;
func->start_addr = start_addr;
func->end_addr = end_addr;
func->memory_order = memory_order;
func->nfdeps = 0;
func->fdeps = NULL;
func->num_runs = num_runs;
 
sprintf (tmp1, "%s.bin", module_name);
cucdebug (2, "Loading %s.bin\n", module_name);
if (cuc_load (tmp1)) {
free (func);
return NULL;
}
 
log ("Detecting basic blocks\n");
detect_bb (func);
if (cuc_debug >= 2) print_cuc_insns ("WITH_BB_LIMITS", 0);
 
//sprintf (tmp1, "%s.bin.mp", module_name);
sprintf (tmp2, "%s.bin.bb", module_name);
generate_bb_seq (func, config.sim.mprof_fn, tmp2);
log ("Assuming %i clk cycle load (%i cyc burst)\n", runtime.cuc.mdelay[0], runtime.cuc.mdelay[2]);
log ("Assuming %i clk cycle store (%i cyc burst)\n", runtime.cuc.mdelay[1], runtime.cuc.mdelay[3]);
build_bb (func);
if (cuc_debug >= 5) print_cuc_bb (func, "AFTER_BUILD_BB");
reg_dep (func);
 
log ("Detecting dependencies\n");
if (cuc_debug >= 2) print_cuc_bb (func, "AFTER_REG_DEP");
cuc_optimize (func);
#if 0
csm (func);
#endif
assert (saved = dup_func (func));
 
timings.preroll = timings.unroll = 1;
timings.nshared = 0;
 
add_latches (func);
if (cuc_debug >= 1) print_cuc_bb (func, "AFTER_LATCHES");
analyse_timings (func, &timings);
 
free_func (func);
log ("Base option: pre%i,un%i,sha%i: %icyc %.1f\n",
timings.preroll, timings.unroll, timings.nshared, timings.new_time, timings.size);
saved->timings = timings;
#if 1
/* detect and unroll simple loops */
for (b = 0; b < saved->num_bb; b++) {
cuc_timings t[MAX_UNROLL * MAX_PREROLL];
cuc_timings *ut;
cuc_timings *cut = &t[0];
int nt = 1;
double csize;
saved->bb[b].selected_tim = -1;
 
/* Is it a loop? */
if (saved->bb[b].next[0] != b && saved->bb[b].next[1] != b) continue;
log ("Found loop at BB%x. Trying to unroll.\n", b);
t[0] = timings;
t[0].b = b;
t[0].preroll = 1;
t[0].unroll = 1;
t[0].nshared = 0;
sprintf (tmp1, "%s.bin.bb", module_name);
i = 1;
do {
cuc_timings *pt;
cuc_timings *cpt = cut;
j = 1;
 
do {
pt = cpt;
cpt = preunroll_bb (tmp1, saved, &t[nt++], b, ++j, i);
} while (j <= MAX_PREROLL && pt->new_time > cpt->new_time);
i++;
ut = cut;
cut = preunroll_bb (tmp1, saved, &t[nt++], b, 1, i);
} while (i <= MAX_UNROLL && ut->new_time > cut->new_time);
 
/* Sort the timings */
#if 0
if (cuc_debug >= 3)
for (i = 0; i < nt; i++) PRINTF ("%i:%i,%i: %icyc\n",
t[i].b, t[i].preroll, t[i].unroll, t[i].new_time);
#endif
 
qsort (t, nt, sizeof (cuc_timings), (int (*)(const void *, const void *))tim_comp);
 
/* Delete timings, that have worst time and bigger size than other */
j = 1;
csize = t[0].size;
for (i = 1; i < nt; i++)
if (t[i].size < csize) t[j++] = t[i];
nt = j;
cucdebug (1, "Available options\n");
for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
/* Add results from CSM */
j = nt;
for (i = 0; i < saved->bb[b].ntim; i++) {
int i1;
for (i1 = 0; i1 < nt; i1++) {
t[j] = t[i1];
t[j].size += saved->bb[b].tim[i].size - timings.size;
t[j].new_time += saved->bb[b].tim[i].new_time - timings.new_time;
t[j].nshared = saved->bb[b].tim[i].nshared;
t[j].shared = saved->bb[b].tim[i].shared;
if (++j >= MAX_UNROLL * MAX_PREROLL) goto full;
}
}
full:
nt = j;
 
cucdebug (1, "Available options:\n");
for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
 
/* Sort again with new timings added */
qsort (t, nt, sizeof (cuc_timings), (int (*)(const void *, const void *))tim_comp);
 
/* Delete timings, that have worst time and bigger size than other */
j = 1;
csize = t[0].size;
for (i = 1; i < nt; i++)
if (t[i].size < csize) t[j++] = t[i];
nt = j;
 
cucdebug (1, "Available options:\n");
for (i = 0; i < nt; i++) cucdebug (1, "%i:%i,%i: %icyc %.1f\n",
t[i].b, t[i].preroll, t[i].unroll, t[i].new_time, t[i].size);
 
if (saved->bb[b].ntim) free (saved->bb[b].tim);
saved->bb[b].ntim = nt;
assert (saved->bb[b].tim = (cuc_timings *) malloc (sizeof (cuc_timings) * nt));
 
/* Copy options in reverse order -- smallest first */
for (i = 0; i < nt; i++) saved->bb[b].tim[i] = t[nt - 1 - i];
 
log ("Available options:\n");
for (i = 0; i < saved->bb[b].ntim; i++) {
log ("%i:pre%i,un%i,sha%i: %icyc %.1f\n",
saved->bb[b].tim[i].b, saved->bb[b].tim[i].preroll, saved->bb[b].tim[i].unroll,
saved->bb[b].tim[i].nshared, saved->bb[b].tim[i].new_time, saved->bb[b].tim[i].size);
}
}
#endif
return saved;
}
 
/* Utility option formatting functions */
static const char *option_char = "?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
/*static */char *gen_option (char *s, int bb_no, int f_opt)
{
if (bb_no >= 0) sprintf (s, "%i", bb_no);
assert (f_opt <= strlen (option_char));
sprintf (s, "%s%c", s, option_char[f_opt]);
return s;
}
 
/*static */void print_option (int bb_no, int f_opt)
{
char tmp1[10];
char tmp2[10];
sprintf (tmp2, "%s", gen_option (tmp1, bb_no, f_opt));
PRINTF ("%3s", tmp2);
}
 
static char *format_func_options (char *s, cuc_func *f)
{
int b, first = 1;
*s = '\0';
for (b = 0; b < f->num_bb; b++)
if (f->bb[b].selected_tim >= 0) {
char tmp[10];
sprintf (s, "%s%s%s", s, first ? "" : ",", gen_option (tmp, b, f->bb[b].selected_tim));
first = 0;
}
return s;
}
 
static void options_cmd (int func_no, cuc_func *f)
{
int b, i;
char tmp[30];
char *name = prof_func[func_no].name;
PRINTF ("-----------------------------------------------------------------------------\n");
PRINTF ("|%-28s|pre/unrolled|shared| time | gates |old_time|\n",
strstrip (tmp, name, 28));
PRINTF ("| BASE |%4i / %4i | %4i |%8i|%8.f|%8i|\n", 1, 1, 0,
f->timings.new_time, f->timings.size, f->orig_time);
for (b = 0; b < f->num_bb; b++) {
/* Print out results */
for (i = 1; i < f->bb[b].ntim; i++) { /* First one is base option */
int time = f->bb[b].tim[i].new_time - f->timings.new_time;
double size = f->bb[b].tim[i].size - f->timings.size;
PRINTF ("| ");
print_option (b, i);
PRINTF (" |%4i / %4i | %4i |%+8i|%+8.f| |\n",
f->bb[b].tim[i].preroll, f->bb[b].tim[i].unroll, f->bb[b].tim[i].nshared,
time, size);
}
}
}
 
/* Generates a function, based on specified parameters */
cuc_func *generate_function (cuc_func *rf, char *name, char *cut_filename)
{
int b, i, j;
char tmp[256];
cuc_timings tt;
cuc_func *f;
assert (f = dup_func (rf));
 
if (cuc_debug >= 2) print_cuc_bb (f, "BEFORE_GENERATE");
log ("Generating function %s.\n", name);
PRINTF ("Generating function %s.\n", name);
 
format_func_options (tmp, rf);
if (strlen (tmp)) PRINTF ("Applying options: %s\n", tmp);
else PRINTF ("Using basic options.\n");
 
/* Generate function as specified by options */
for (b = 0; b < f->num_bb; b++) {
cuc_timings *st;
if (rf->bb[b].selected_tim < 0) continue;
st = &rf->bb[b].tim[rf->bb[b].selected_tim];
sprintf (tmp, "%s.bin.bb", name);
preunroll_bb (&tmp[0], f, &tt, b, st->preroll, st->unroll);
if (cuc_debug >= 1) print_cuc_bb (f, "AFTER_PREUNROLL");
}
for (b = 0; b < f->num_bb; b++) {
cuc_timings *st;
if (rf->bb[b].selected_tim < 0) continue;
st = &rf->bb[b].tim[rf->bb[b].selected_tim];
if (!st->nshared) continue;
assert (0);
//csm_gen (f, rf, st->nshared, st->shared);
}
add_latches (f);
if (cuc_debug >= 1) print_cuc_bb (f, "AFTER_LATCHES");
analyse_timings (f, &tt);
sprintf (tmp, "%s%s", cut_filename, name);
output_verilog (f, tmp, name);
return f;
}
 
/* Calculates required time, based on selected options */
int calc_cycles (cuc_func *f)
{
int b, i, ntime = f->timings.new_time;
for (b = 0; b < f->num_bb; b++)
if (f->bb[b].selected_tim >= 0) {
assert (f->bb[b].selected_tim < f->bb[b].ntim);
ntime += f->bb[b].tim[f->bb[b].selected_tim].new_time - f->timings.new_time;
}
return ntime;
}
 
/* Calculates required size, based on selected options */
double calc_size (cuc_func *f)
{
int b, i;
double size = f->timings.size;
for (b = 0; b < f->num_bb; b++)
if (f->bb[b].selected_tim >= 0) {
assert (f->bb[b].selected_tim < f->bb[b].ntim);
size += f->bb[b].tim[f->bb[b].selected_tim].size - f->timings.size;
}
return size;
}
 
/* Dumps specified function to file (hex) */
unsigned long extract_function (char *out_fn, unsigned long start_addr)
{
FILE *fo;
unsigned long a = start_addr;
int x = 0;
assert (fo = fopen (out_fn, "wt+"));
 
do {
unsigned long d = evalsim_mem32 (a);
int index = insn_decode (d);
assert (index >= 0);
if (x) x++;
if (strcmp (insn_name (index), "l.jr") == 0) x = 1;
a += 4;
fprintf (fo, "%08x\n", d);
} while (x < 2);
 
fclose (fo);
return a - 4;
}
 
static cuc_func *func[MAX_FUNCS];
static int func_v[MAX_FUNCS];
 
/* Detects function dependencies and removes */
static void set_func_deps ()
{
int f, b, i, j;
restart:
for (f = 0; f < prof_nfuncs - 1; f++) if (func[f]) {
int fused[MAX_FUNCS] = {0};
int c;
for (b = 0; b < func[f]->num_bb; b++)
for (i = 0; i < func[f]->bb[b].ninsn; i++) {
cuc_insn *ii = &func[f]->bb[b].insn[i];
if (ii->index == II_CALL) {
assert (ii->opt[0] == OPT_CONST);
for (j = 0; j < prof_nfuncs - 1; j++)
if (func[j] && func[j]->start_addr == ii->op[0]) break;
if (j >= prof_nfuncs - 1) {
log ("%s is calling unknown function, address %08x\n",
prof_func[f].name, ii->op[0]);
debug (1, "%s is calling unknown function, address %08x\n",
prof_func[f].name, ii->op[0]);
free_func (func[f]);
func[f] = NULL;
goto restart;
} else if (f == j) {
log ("%s is recursive, ignoring\n", prof_func[f].name);
debug (1, "%s is recursive, ignoring\n", prof_func[f].name);
free_func (func[f]);
func[f] = NULL;
goto restart;
} else fused[j]++;
}
}
for (i = 0; i < MAX_FUNCS; i++) if (fused[i]) c++;
if (func[f]->nfdeps) free (func[f]->fdeps);
func[f]->nfdeps = c;
func[f]->fdeps = (cuc_func **) malloc (sizeof (cuc_func *) * c);
for (i = 0, j = 0; i < MAX_FUNCS; i++)
if (fused[i]) func[f]->fdeps[j++] = func[i];
}
 
/* Detect loops */
{
int change;
for (f = 0; f < MAX_FUNCS; f++) if (func[f]) func[f]->tmp = 0;
do {
change = 0;
for (f = 0; f < MAX_FUNCS; f++) if (func[f] && !func[f]->tmp) {
int o = 1;
for (i = 0; i < func[f]->nfdeps; i++)
if (!func[f]->fdeps[i]->tmp) {o = 0; break;}
if (o) {
func[f]->tmp = 1;
change = 1;
}
}
} while (change);
change = 0;
for (f = 0; f < MAX_FUNCS; f++) if (func[f] && !func[f]->tmp) {
free_func (func[f]);
func[f] = NULL;
change = 1;
}
if (change) goto restart;
}
}
 
void main_cuc (char *filename)
{
int i, j;
char tmp1[256];
char filename_cut[256];
#if 0 /* Select prefix, based on binary program name */
for (i = 0; i < sizeof (filename_cut); i++) {
if (isalpha(filename[i])) filename_cut[i] = filename[i];
else {
filename_cut[i] = '\0';
break;
}
}
#else
strcpy (filename_cut, "cu");
#endif
 
PRINTF ("Entering OpenRISC Custom Unit Compiler command prompt\n");
PRINTF ("Using profile file \"%s\" and memory profile file \"%s\".\n", config.sim.prof_fn, config.sim.mprof_fn);
sprintf (tmp1, "%s.log", filename_cut);
PRINTF ("Analyzing. (log file \"%s\").\n", tmp1);
assert (flog = fopen (tmp1, "wt+"));
 
/* Loads in the specified timings table */
PRINTF ("Using timings from \"%s\" at %s\n",config.cuc.timings_fn,
generate_time_pretty (tmp1, config.sim.clkcycle_ps));
load_timing_table (config.cuc.timings_fn);
runtime.cuc.cycle_duration = 1000. * config.sim.clkcycle_ps;
PRINTF ("Multicycle logic %s, bursts %s, %s memory order.\n",
config.cuc.no_multicycle ? "OFF" : "ON", config.cuc.enable_bursts ? "ON" : "OFF",
config.cuc.memory_order == MO_NONE ? "no" : config.cuc.memory_order == MO_WEAK ? "weak" :
config.cuc.memory_order == MO_STRONG ? "strong" : "exact");
 
prof_set (1, 0);
assert (prof_acquire (config.sim.prof_fn) == 0);
if (config.cuc.calling_convention)
PRINTF ("Assuming OpenRISC standard calling convention.\n");
 
/* Try all functions except "total" */
for (i = 0; i < prof_nfuncs - 1; i++) {
long orig_time;
unsigned long start_addr, end_addr;
orig_time = prof_func[i].cum_cycles;
start_addr = prof_func[i].addr;
/* Extract the function from the binary */
sprintf (tmp1, "%s.bin", prof_func[i].name);
end_addr = extract_function (tmp1, start_addr);
log ("Testing function %s (%08x - %08x)\n", prof_func[i].name, start_addr, end_addr);
PRINTF ("Testing function %s (%08x - %08x)\n", prof_func[i].name, start_addr, end_addr);
func[i] = analyse_function (prof_func[i].name, orig_time, start_addr,
end_addr, config.cuc.memory_order, prof_func[i].calls);
func_v[i] = 0;
}
set_func_deps ();
while (1) {
char *s;
wait_command:
PRINTF ("(cuc) ");
fflush (stdout);
wait_command_empty:
s = fgets(tmp1, sizeof tmp1, stdin);
usleep (100);
if (!s) goto wait_command_empty;
for (s = tmp1; *s != '\0' && *s != '\n' && *s != '\r'; s++);
*s = '\0';
 
/* quit command */
if (strcmp (tmp1, "q") == 0 || strcmp (tmp1, "quit") == 0) {
/* Delete temporary files */
for (i = 0; i < prof_nfuncs - 1; i++) {
sprintf (tmp1, "%s.bin", prof_func[i].name);
log ("Deleting temporary file %s %s\n", tmp1, remove (tmp1) ? "FAILED" : "OK");
sprintf (tmp1, "%s.bin.bb", prof_func[i].name);
log ("Deleting temporary file %s %s\n", tmp1, remove (tmp1) ? "FAILED" : "OK");
}
break;
/* profile command */
} else if (strcmp (tmp1, "p") == 0 || strcmp (tmp1, "profile") == 0) {
int ntime = 0;
int size = 0;
PRINTF ("-----------------------------------------------------------------------------\n");
PRINTF ("|function name |calls|avg cycles |old%| max. f. | impr. f.| options |\n");
PRINTF ("|--------------------+-----+------------+----+----------|---------+---------|\n");
for (j = 0; j < prof_nfuncs; j++) {
int bestcyc = 0, besti = 0;
char tmp[100];
for (i = 0; i < prof_nfuncs; i++)
if (prof_func[i].cum_cycles > bestcyc) {
bestcyc = prof_func[i].cum_cycles;
besti = i;
}
i = besti;
PRINTF ("|%-20s|%5i|%12.1f|%3.0f%%| ",
strstrip (tmp, prof_func[i].name, 20), prof_func[i].calls,
((double)prof_func[i].cum_cycles / prof_func[i].calls),
(100. * prof_func[i].cum_cycles / prof_cycles));
if (func[i]) {
double f = 1.0;
if (func_v[i]) {
int nt = calc_cycles (func[i]);
int s = calc_size (func[i]);
f = 1. * func[i]->orig_time / nt;
ntime += nt;
size += s;
} else ntime += prof_func[i].cum_cycles;
PRINTF ("%8.1f |%8.1f | %-8s|\n", 1.f * prof_func[i].cum_cycles
/ func[i]->timings.new_time, f, format_func_options (tmp, func[i]));
} else {
PRINTF (" N/A | N/A | N/A |\n");
ntime += prof_func[i].cum_cycles;
}
prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
}
for (i = 0; i < prof_nfuncs; i++)
prof_func[i].cum_cycles = -prof_func[i].cum_cycles;
PRINTF ("-----------------------------------------------------------------------------\n");
PRINTF ("Total %i cycles (was %i), total added gates = %i. Speed factor %.1f\n",
ntime, prof_cycles, size, 1. * prof_cycles / ntime);
/* debug command */
} else if (strncmp (tmp1, "d", 1) == 0 || strncmp (tmp1, "debug", 5) == 0) {
sscanf (tmp1, "%*s %i", &cuc_debug);
if (cuc_debug < 0) cuc_debug = 0;
if (cuc_debug > 9) cuc_debug = 9;
 
/* generate command */
} else if (strcmp (tmp1, "g") == 0 || strcmp (tmp1, "generate") == 0) {
/* check for function dependencies */
for (i = 0; i < prof_nfuncs; i++)
if (func[i]) func[i]->tmp = func_v[i];
for (i = 0; i < prof_nfuncs; i++) if (func[i])
for (j = 0; j < func[i]->nfdeps; j++)
if (!func[i]->fdeps[j] || !func[i]->fdeps[j]->tmp) {
PRINTF ("Function %s must be selected for translation (required by %s)\n",
prof_func[j].name, prof_func[i].name);
goto wait_command;
}
for (i = 0; i < prof_nfuncs; i++)
if (func[i] && func_v[i]) generate_function (func[i], prof_func[i].name, filename_cut);
generate_main (prof_nfuncs, func, filename_cut);
 
/* list command */
} else if (strcmp (tmp1, "l") == 0 || strcmp (tmp1, "list") == 0) {
/* check for function dependencies */
for (i = 0; i < prof_nfuncs; i++)
if (func_v[i]) {
PRINTF ("%s\n", prof_func[j].name);
}
 
/* selectall command */
} else if (strcmp (tmp1, "sa") == 0 || strcmp (tmp1, "selectall") == 0) {
char tmp[50], ch;
int p, o, b, f;
for (f = 0; f < prof_nfuncs; f++) if (func[f]) {
func_v[f] = 1;
PRINTF ("Function %s selected for translation.\n", prof_func[f].name);
}
/* select command */
} else if (strncmp (tmp1, "s", 1) == 0 || strncmp (tmp1, "select", 6) == 0) {
char tmp[50], ch;
int p, o, b, f;
p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
if (p < 1) PRINTF ("Invalid parameters.\n");
else {
/* Check if we have valid option */
for (f = 0; f < prof_nfuncs; f++)
if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
if (f < prof_nfuncs) {
if (p == 1) {
if (func[f]) {
func_v[f] = 1;
PRINTF ("Function %s selected for translation.\n", prof_func[f].name);
} else PRINTF ("Function %s not suitable for translation.\n", prof_func[f].name);
} else {
if (!func_v[f])
PRINTF ("Function %s not yet selected for translation.\n", prof_func[f].name);
if (p < 3) goto invalid_option;
for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
if (!option_char[o]) goto invalid_option;
if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
/* select an option */
func[f]->bb[b].selected_tim = o;
if (func[f]->bb[b].tim[o].nshared) {
PRINTF ("Option has shared instructions: ");
print_shared (func[f], func[f]->bb[b].tim[o].shared, func[f]->bb[b].tim[o].nshared);
PRINTF ("\n");
}
goto wait_command;
invalid_option:
PRINTF ("Invalid option.\n");
}
} else PRINTF ("Invalid function.\n");
}
 
/* unselect command */
} else if (strncmp (tmp1, "u", 1) == 0 || strncmp (tmp1, "unselect", 8) == 0) {
char tmp[50], ch;
int p, o, b, f;
p = sscanf (tmp1, "%*s %s %i%c", tmp, &b, &ch);
if (p < 1) PRINTF ("Invalid parameters.\n");
else {
/* Check if we have valid option */
for (f = 0; f < prof_nfuncs; f++)
if (strcmp (prof_func[f].name, tmp) == 0 && func[f]) break;
if (f < prof_nfuncs) {
if (p == 1) {
if (func[f]) {
func_v[f] = 0;
PRINTF ("Function %s unselected for translation.\n", prof_func[f].name);
} else PRINTF ("Function %s not suitable for translation.\n", prof_func[f].name);
} else {
if (p < 3) goto invalid_option;
for (o = 0; option_char[o] != '\0' && option_char[o] != ch; o++);
if (!option_char[o]) goto invalid_option;
if (b < 0 || b >= func[f]->num_bb) goto invalid_option;
if (o < 0 || o >= func[f]->bb[b].ntim) goto invalid_option;
/* select an option */
func[f]->bb[b].selected_tim = -1;
}
} else PRINTF ("Invalid function.\n");
}
/* options command */
} else if (strcmp (tmp1, "o") == 0 || strcmp (tmp1, "options") == 0) {
int any = 0;
PRINTF ("Available options:\n");
for (i = 0; i < prof_nfuncs; i++)
if (func[i]) {
options_cmd (i, func[i]);
any = 1;
}
if (any) PRINTF ("-----------------------------------------------------------------------------\n");
else PRINTF ("Sorry. No available options.\n");
 
/* Ignore empty string */
} else if (strcmp (tmp1, "") == 0) {
 
/* help command */
} else {
if (strcmp (tmp1, "h") != 0 && strcmp (tmp1, "help") != 0)
PRINTF ("Unknown command.\n");
PRINTF ("OpenRISC Custom Unit Compiler command prompt\n");
PRINTF ("Available commands:\n");
PRINTF (" h | help displays this help\n");
PRINTF (" q | quit returns to or1ksim prompt\n");
PRINTF (" p | profile displays function profiling\n");
PRINTF (" d | debug # sets debug level (0-9)\n");
PRINTF (" o | options displays available options\n");
PRINTF (" s | select func [option] selects an option/function\n");
PRINTF (" u | unselect func [option] unselects an option/function\n");
PRINTF (" g | generate generates verilog file\n");
PRINTF (" l | list displays selected functions\n");
}
}
 
/* Dispose memory */
for (i = 0; i < prof_nfuncs -1; i++)
if (func[i]) free_func (func[i]);
 
fclose (flog);
}
 
/trunk/or1ksim/peripheral/channels/file.c
19,12 → 19,18
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
#if HAVE_CONFIG_H
#include <config.h>
#endif
 
#define _GNU_SOURCE /* for strndup */
 
#include <sys/types.h> /* open() */
#include <sys/stat.h> /* open() */
#include <fcntl.h> /* open() */
#include <malloc.h> /* calloc(), free() */
#if HAVE_MALLOC_H
#include <malloc.h> /* calloc, free */
#endif
#include <string.h> /* strndup(), strchr() */
#include <errno.h> /* errno */
#include <unistd.h> /* close() */
/trunk/or1ksim/peripheral/channels/xterm.c
26,6 → 26,10
* They are suppose to be reserved for the compiler
* as explained in C standards.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
 
#define _XOPEN_SOURCE /* grantpt() and al. */
#define _GNU_SOURCE /* on_exit */
 
38,7 → 42,9
#include <string.h> /* strchr() */
 
#ifndef __CYGWIN__
#if HAVE_SYS_STROPTS_H
#include <sys/stropts.h> /* grantpt(), unlockpt() */
#endif
#include <libgen.h> /* basename() */
#endif /* __CYGWIN__ */
 
109,9 → 115,12
retval->fds.fdin = -1;
retval->fds.fdout = -1;
retval->pid = -1;
 
#if defined(HAS_ON_EXIT)
/* reset cause exit(1), leaving an xterm opened */
on_exit(xterm_exit, retval);
 
#endif
i = 2;
arglist = (char*)input;
retval->argv = malloc(sizeof(char*) * MAX_XTERM_ARGS);
136,6 → 145,7
 
static int xterm_open(void * data)
{
#if defined(HAS_GRANTPT) && defined(HAS_UNLOCKPT) && defined(HAS_PTSNAME)
struct xterm_channel * xt = data;
int master, retval;
char * slavename;
166,7 → 176,8
xt->fds.fdout = xt->fds.fdin = open(slavename, O_RDWR);
if(xt->fds.fdout < 0) goto closemastererror;
 
#if !defined(linux) && !defined(__CYGWIN__)
//#if !defined(linux) && !defined(__CYGWIN__)
#if defined(I_PUSH)
/* Linux does not support STREAMS-style line discipline, even with LiS. */
retval = ioctl(xt->fds.fdin, I_PUSH, "ptem");
if(retval < 0) goto closeslaveerror;
226,6 → 237,14
close(master);
xt->pid = xt->fds.fdin = xt->fds.fdout = -1;
return -1;
 
#else
/* I don't see how this stuff should be working on a system that doesn't know
grantpt(), unlockpt(), ptsname(). Mac OS X also does not have /dev/ptmx.
-hpanther
*/
return -1;
#endif
}
struct channel_ops xterm_channel_ops =
/trunk/or1ksim/peripheral/channels/channel.c
19,14 → 19,26
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
#if HAVE_CONFIG_H
#include <config.h>
#endif
 
#define _GNU_SOURCE /* for strndup */
 
#include <stdio.h> /* perror */
#include <stdlib.h> /* exit */
 
#if HAVE_MALLOC_H
#include <malloc.h> /* calloc, free */
#endif
 
#include <string.h> /* strndup, strcmp, strlen, strchr */
#include <errno.h> /* errno */
 
#ifndef HAVE_STRNDUP
#include "extras/extras.h"
#endif
 
#include "channel.h"
 
struct channel_factory
/trunk/or1ksim/peripheral/channels/fd.c
19,12 → 19,18
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
#if HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <sys/time.h> /* struct timeval */
#include <sys/types.h> /* fd_set */
#include <stdio.h> /* perror */
#include <stdlib.h> /* atoi */
#include <unistd.h> /* read, write, select */
#if HAVE_MALLOC_H
#include <malloc.h> /* calloc, free */
#endif
#include <string.h> /* strchr */
#include <errno.h> /* errno */
 
/trunk/or1ksim/peripheral/channels/generic.c
19,7 → 19,14
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
#include <malloc.h> /* free */
#if HAVE_CONFIG_H
#include <config.h>
#endif
 
#if HAVE_MALLOC_H
#include <malloc.h> /* calloc, free */
#endif
 
#include <errno.h> /* errno */
 
 
/trunk/or1ksim/peripheral/eth.c
52,7 → 52,7
static void eth_controller_rx_clock( struct eth_device * );
/* utility functions */
static int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr );
struct eth_device *eth_find_vapi_device (unsigned long id, unsigned *which);
struct eth_device *eth_find_vapi_device (unsigned long id, unsigned long *which);
static ssize_t eth_read_rx_file( struct eth_device *, void *, size_t );
static void eth_skip_rx_file( struct eth_device *, off_t );
static void eth_rewind_rx_file( struct eth_device *, off_t );
314,7 → 314,7
}
 
/* Packet must be big enough to hold a header */
if ( eth->rx.packet_length < ETH_HLEN ){
if ( eth->rx.packet_length < ETHER_HDR_LEN ){
debug( 3, "eth_start_rx(): Packet too small\n" );
eth_rx_next_packet( eth );
 
549,7 → 549,12
if ( (eth->rxfd = open( eth->rxfile, O_RDONLY )) < 0 )
fprintf( stderr, "Cannot open Ethernet RX file \"%s\"\n", eth->rxfile );
if ( (eth->txfd = open( eth->txfile,
O_RDWR | O_CREAT | O_APPEND | O_SYNC,
O_RDWR | O_CREAT | O_APPEND
#if defined(O_SYNC) /* BSD / Mac OS X manual doesn't know about O_SYNC */
| O_SYNC
#endif
,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )) < 0 )
fprintf( stderr, "Cannot open Ethernet TX file \"%s\"\n", eth->txfile );
eth->loopback_offset = lseek( eth->txfd, 0, SEEK_END );
858,7 → 863,7
/*
* Convert VAPI id to controller struct and relative address.
*/
struct eth_device *eth_find_vapi_device( unsigned long id, unsigned *which )
struct eth_device *eth_find_vapi_device( unsigned long id, unsigned long *which )
{
unsigned i;
 
/trunk/or1ksim/peripheral/fb.c
86,13 → 86,13
 
/* define these also for big endian */
#if __BIG_ENDIAN__
#define CNV32(x) (x) (\
#define CNV32(x) (\
((((x) >> 24) & 0xff) << 0)\
| ((((x) >> 16) & 0xff) << 8)\
| ((((x) >> 8) & 0xff) << 16)\
| ((((x) >> 0) & 0xff) << 24))
#define CNV16(x) (x) (\
| ((((x) >> 8) & 0xff) << 0)\
#define CNV16(x) (\
((((x) >> 8) & 0xff) << 0)\
| ((((x) >> 0) & 0xff) << 8))
#else
#define CNV16(x) (x)
/trunk/or1ksim/peripheral/ethernet_i.h
132,7 → 132,7
unsigned rx_channel;
 
/* Our address */
unsigned char mac_address[ETH_ALEN];
unsigned char mac_address[ETHER_ADDR_LEN];
/* interrupt line */
unsigned long mac_int;
/trunk/or1ksim/peripheral/16450.c
244,7 → 244,7
 
static void send_char (int uart, int bits_send)
{
PRINTF ("'%c'\n", uarts[uart].iregs.txser);
PRINTF ("%c", uarts[uart].iregs.txser);
debug(4, "TX \'%c\' via UART%d...\n", uarts[uart].iregs.txser, uart);
if (uarts[uart].regs.mcr & UART_MCR_LOOP)
uarts[uart].iregs.loopback = uarts[uart].iregs.txser;
424,6 → 424,7
/* Set unused character bits to zero and allow lsr register in fifo */
uarts[i].iregs.rxser &= ((1 << ((uarts[i].regs.lcr & 3) + 5)) - 1) | 0xff00;
debug(4, "Receiving 0x%02x'%c' via UART%d...\n", uarts[i].iregs.rxser, uarts[i].iregs.rxser, i);
PRINTF ("%c", uarts[i].iregs.rxser);
uarts[i].istat.rxser_full = 0;
uarts[i].istat.rxser_clks = 0;
uart_add_char (i, uarts[i].iregs.rxser);

powered by: WebSVN 2.1.0

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