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 129 to Rev 130
    Reverse comparison

Rev 129 → Rev 130

/trunk/or1ksim/peripheral/debug_unit.c
0,0 → 1,728
/* debug_unit.c -- Simulation of Or1k debug unit
Copyright (C) 2001 Chris Ziomkowski, chris@asics.ws
 
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. */
 
/*
This is an architectural level simulation of the Or1k debug
unit as described in OpenRISC 1000 System Architecture Manual,
v. 0.1 on 22 April, 2001. This unit is described in Section 13.
 
Every attempt has been made to be as accurate as possible with
respect to the registers and the behavior. There are no known
limitations at this time.
*/
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
 
#include "debug_unit.h"
#include "sim-config.h"
#include "except.h"
#include "arch.h"
#include "abstract.h"
#include "parse.h"
#include "trace.h"
#include "../gdb.h"
#include "../cpu/or1k/except.h"
 
DebugUnit debug_unit;
DevelopmentInterface development;
 
typedef enum {
false = 0,
true = 1,
} Boolean;
static void ExecuteInducedInstruction(unsigned long);
 
/* External STALL signal to debug interface */
int cpu_stalled = false;
int in_reset = false;
 
/* An induced instruction has been written to the DIR register */
static Boolean induced = false;
static unsigned long induced_insn;
 
/* A flag to indicate that we must perform an ic mmu cycle */
static Boolean lookup_physical_address = false;
 
/* Variables for implementing ExecuteInducedInstruction */
extern unsigned long pc;
extern unsigned long pcnext;
extern unsigned long pcdelay;
extern unsigned long pc_phy;
extern int delay_insn;
static void GetIQueueEntry(struct iqueue_entry*,char*);
 
static int watchpoint[10];
 
/* This function returns true if an induced instruction has
been inserted into the instruction stream. It will remove
that instruction and return the result. This function is
called from the fetch() routine. */
int OverrideFetch(struct iqueue_entry *iq_entry,char* sTemp)
{
int valid = induced;
induced = false;
 
if(valid)
GetIQueueEntry(iq_entry,sTemp);
return valid;
}
 
void InduceImmediateInstruction(unsigned long insn)
{
induced = true;
induced_insn = insn;
 
if(in_reset)
return;
 
if(cpu_stalled)
{
if(lookup_physical_address)
pc_phy = simulate_ic_mmu_fetch(pc);
ExecuteInducedInstruction(insn);
induced_insn = 0;
induced = false;
}
}
 
void SetCPUStallState(int state)
{
if(debug_unit.DMR1.DXFW) /* If debugger disabled */
state = false;
 
if(state == cpu_stalled)
return;
 
if(state && induced)
{
ExecuteInducedInstruction(induced_insn);
induced_insn = 0;
induced = false;
}
 
cpu_stalled = state;
}
 
void ResetDebugUnit()
{
memset(&debug_unit,'\0',sizeof(DebugUnit));
cpu_stalled = 0;
}
 
int CheckDebugUnit(DebugUnitAction action,unsigned long udata)
{
int i;
DCR_CT_Settings condition = DCR_CT_Disabled;
long data = (long)udata;
int match;
 
if(in_reset)
return 0;
 
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;
}
 
for(i=0;i<8;i++)
{
if(debug_unit.DCR[i].DP == DCR_DP_Absent)
continue;
 
if(debug_unit.DCR[i].CT == condition)
{
if(debug_unit.DCR[i].SC == DCR_SC_Signed)
{
switch(debug_unit.DCR[i].CC)
{
case DCR_CC_Equal: match = data == (int)debug_unit.DVR[i]; break;
case DCR_CC_LessThan: match = data < (int)debug_unit.DVR[i]; break;
case DCR_CC_LessEqual: match = data <= (int)debug_unit.DVR[i]; break;
case DCR_CC_GreaterThan: match = data > (int)debug_unit.DVR[i]; break;
case DCR_CC_GreaterEqual: match = data >= (int)debug_unit.DVR[i]; break;
case DCR_CC_NotEqual: match = data != (int)debug_unit.DVR[i]; break;
default: match = 0; break;
}
}
else
{
switch(debug_unit.DCR[i].CC)
{
case DCR_CC_Equal: match = udata == debug_unit.DVR[i]; break;
case DCR_CC_LessThan: match = udata < debug_unit.DVR[i]; break;
case DCR_CC_LessEqual: match = udata <= debug_unit.DVR[i]; break;
case DCR_CC_GreaterThan: match = udata > debug_unit.DVR[i]; break;
case DCR_CC_GreaterEqual: match = udata >= debug_unit.DVR[i]; break;
case DCR_CC_NotEqual: match = udata != debug_unit.DVR[i]; break;
default: match = 0; break;
}
}
}
match <<= i;
debug_unit.DCR_hit &= ~match; /* Clear DCR compare if it has changed */
debug_unit.DCR_hit |= match; /* Save the state of each DCR compare */
}
 
return CalculateWatchpoints();
}
 
int CalculateWatchpoints()
{
int spec[11];
int breakpoint = 0;
int i,bit;
 
spec[0] = debug_unit.DMR1.CW0;
spec[1] = debug_unit.DMR1.CW1;
spec[2] = debug_unit.DMR1.CW2;
spec[3] = debug_unit.DMR1.CW3;
spec[4] = debug_unit.DMR1.CW4;
spec[5] = debug_unit.DMR1.CW5;
spec[6] = debug_unit.DMR1.CW6;
spec[7] = debug_unit.DMR1.CW7;
spec[8] = debug_unit.DMR1.CW8;
spec[9] = debug_unit.DMR1.CW9;
spec[10] = debug_unit.DMR1.CW10;
 
for(i=0,bit=1;i<11;i++,bit<<=1)
{
int chain1,chain2;
int match = 0;
 
switch(i)
{
case 0:
chain1 = chain2 = debug_unit.DCR_hit & 0x01;
break;
case 8:
chain1 = debug_unit.DWCR[0].COUNT == debug_unit.DWCR[0].MATCH;
chain2 = debug_unit.watchpoint & (1 << 7);
break;
case 9:
chain1 = debug_unit.DWCR[1].COUNT == debug_unit.DWCR[1].MATCH;
chain2 = debug_unit.watchpoint & (1 << 8);
break;
case 10:
chain1 = debug_unit.DCR_hit & 0x100; /* External hit */
chain2 = debug_unit.watchpoint & (1 << 9);
break;
default:
chain1 = debug_unit.DCR_hit & bit;
chain2 = debug_unit.watchpoint & (bit >> 1);
break;
}
 
switch(spec[i])
{
case 0: match = chain1; break;
case 1: match = chain1 && chain2; break;
case 2: match = chain1 || chain2; break;
default:
break;
}
 
if(match & !(debug_unit.watchpoint & bit))
{
int counter = (debug_unit.DMR2.AWPC & bit) ? 1 : 0;
int enabled = counter ? debug_unit.DMR2.WCE1 : debug_unit.DMR2.WCE0;
 
if(enabled)
debug_unit.DWCR[counter].COUNT++;
 
if(debug_unit.DMR2.WGB & bit)
breakpoint = 1;
}
debug_unit.watchpoint &= ~bit;
debug_unit.watchpoint |= bit;
}
 
return breakpoint;
}
 
static void GetIQueueEntry(struct iqueue_entry* iq_entry,char* sTemp)
{
int len = disassemble_insn(induced_insn);
extern char *disassembled;
char *code = NULL;
char *args[4];
char *s;
int n = 0; /* Number of arguments to this function */
 
strcpy(sTemp,disassembled);
/* Trim the whitespace from the end of the string */
for(len = strlen(sTemp);len > 0 && isspace(sTemp[len-1]); len--);
sTemp[len] = '\0';
 
/* Trim the whitespace from the beginning of the string */
for(s = sTemp;*s && isspace(*s);s++);
code = s;
 
args[0] = args[1] = args[2] = args[3] = "";
/* Skip over the opcode */
for(;*s && !isspace(*s);s++); /* A faster strcspn() */
 
if(!*s) /* If we hit the end, there are no arguments */
s = NULL;
 
while(s)
{
*s++ = '\0'; /* Terminate the previous string */
for(;*s && isspace(*s);s++); /* Skip leading white space */
args[n++] = s; /* Note where the arg begins */
if(s = strchr(s,OPERAND_DELIM[0])) /* Look for the terminator */
{
char *r;
for(r=s-1;*r && isspace(*r);r--); /* Nuke the trailing white space */
*(++r) = '\0'; /* Terminate the argument string */
}
}
iq_entry->insn_index = insn_index(code);
strcpy(iq_entry->op1,args[0]);
strcpy(iq_entry->op2,args[1]);
strcpy(iq_entry->op3,args[2]);
strcpy(iq_entry->op4,args[3]);
iq_entry->insn_addr = pc_phy;
iq_entry->dependdst = NULL;
iq_entry->dependsrc1 = NULL;
iq_entry->dependsrc2 = NULL;
}
 
static void ExecuteInducedInstruction(unsigned long insn)
{
struct iqueue_entry iq_entry;
char sTemp[256];
 
GetIQueueEntry(&iq_entry,sTemp);
decode_execute(&iq_entry);
if(delay_insn)
{
pc = pcdelay;
pcnext = pcdelay;
lookup_physical_address = true;
delay_insn = 0;
}
else
lookup_physical_address = false;
}
 
static DebugScanChainIDs current_scan_chain = JTAG_CHAIN_GLOBAL;
 
int DebugGetRegister(unsigned int address,int32_t* data)
{
int err;
 
switch(current_scan_chain)
{
case JTAG_CHAIN_DEBUG_UNIT:
err = GetDebugUnitRegister(address,data);
break;
case JTAG_CHAIN_TRACE:
*data = 0; /* Scan chain not yet implemented */
err = 0;
break;
case JTAG_CHAIN_DEVELOPMENT:
err = GetDevelopmentInterfaceRegister(address,data);
break;
}
return err;
}
 
int DebugSetRegister(unsigned int address,int32_t data)
{
int err;
 
switch(current_scan_chain)
{
case JTAG_CHAIN_DEBUG_UNIT:
err = SetDebugUnitRegister(address,data);
break;
case JTAG_CHAIN_TRACE:
err = JTAG_PROXY_ACCESS_EXCEPTION;
break;
case JTAG_CHAIN_DEVELOPMENT:
err = SetDevelopmentInterfaceRegister(address,data);
break;
}
return err;
}
 
int DebugSetChain(int chain)
{
switch(chain)
{
case JTAG_CHAIN_DEBUG_UNIT:
case JTAG_CHAIN_TRACE:
case JTAG_CHAIN_DEVELOPMENT:
current_scan_chain = chain;
break;
default: /* All other chains not implemented */
return JTAG_PROXY_INVALID_CHAIN;
}
 
return 0;
}
 
/* Nearly all compilers today store these bit fields as a packed structure
in network byte order (Big Endian). If you happen to be unlucky enough
to be working in a non standard environment, you may need to rewrite
this routine or the SET_REG32 macro. */
int SetDevelopmentInterfaceRegister(unsigned int address,uint32_t data)
{
int err = 0;
uint32_t value = data;
int old_value;
char *t_ptr = (char*)&development.RISCOP;
 
switch(address)
{
case DEVELOPINT_MODER:
SET_REG32(development.MODER,value);
break;
case DEVELOPINT_TSEL:
SET_REG32(development.TSEL,value);
break;
case DEVELOPINT_QSEL:
SET_REG32(development.QSEL,value);
break;
case DEVELOPINT_SSEL:
SET_REG32(development.SSEL,value);
break;
case DEVELOPINT_RISCOP:
old_value = development.RISCOP.RESET;
SET_REG32(development.RISCOP,value);
in_reset = development.RISCOP.RESET;
 
/* Reset the cpu on the negative edge of RESET */
if(old_value && !development.RISCOP.RESET)
{
uart_reset();
tick_reset();
pm_reset();
pic_reset();
reset(); /* Old or new mode */
}
 
SetCPUStallState(development.RISCOP.RISCSTALL);
break;
case DEVELOPINT_RECWP0:
case DEVELOPINT_RECWP1:
case DEVELOPINT_RECWP2:
case DEVELOPINT_RECWP3:
case DEVELOPINT_RECWP4:
case DEVELOPINT_RECWP5:
case DEVELOPINT_RECWP6:
case DEVELOPINT_RECWP7:
case DEVELOPINT_RECWP8:
case DEVELOPINT_RECWP9:
case DEVELOPINT_RECWP10:
SET_REG32(development.RECWP[address-DEVELOPINT_RECWP0],value);
break;
case DEVELOPINT_RECBP0:
SET_REG32(development.RECBP[0],value);
break;
default:
err = JTAG_PROXY_INVALID_ADDRESS;
break;
}
return err;
}
 
int GetDevelopmentInterfaceRegister(unsigned int address,uint32_t *data)
{
int err = 0;
uint32_t value = 0;
 
switch(address)
{
case DEVELOPINT_MODER: GET_REG32(development.MODER,value); break;
case DEVELOPINT_TSEL: GET_REG32(development.TSEL,value); break;
case DEVELOPINT_QSEL: GET_REG32(development.QSEL,value); break;
case DEVELOPINT_SSEL: GET_REG32(development.SSEL,value); break;
case DEVELOPINT_RISCOP: GET_REG32(development.RISCOP,value); break;
case DEVELOPINT_RECWP0:
case DEVELOPINT_RECWP1:
case DEVELOPINT_RECWP2:
case DEVELOPINT_RECWP3:
case DEVELOPINT_RECWP4:
case DEVELOPINT_RECWP5:
case DEVELOPINT_RECWP6:
case DEVELOPINT_RECWP7:
case DEVELOPINT_RECWP8:
case DEVELOPINT_RECWP9:
case DEVELOPINT_RECWP10: GET_REG32(development.RECWP[address-DEVELOPINT_RECWP0],value); break;
case DEVELOPINT_RECBP0: GET_REG32(development.RECBP[0],value); break;
default: err = JTAG_PROXY_INVALID_ADDRESS; break;
}
*data = value;
return err;
}
 
/* Nearly all compilers today store these bit fields as a packed structure
in network byte order (Big Endian). If you happen to be unlucky enough
to be working in a non standard environment, you may need to rewrite
this routine or the SET_REG32 macro. */
int SetDebugUnitRegister(unsigned int address,uint32_t data)
{
int err = 0;
uint32_t value = data;
int old_value;
int group = address >> 11;
 
/* This is a memory location */
if(address & 0x80000000)
{
address &= 0x7FFFFFFF;
address <<= 2;
 
if(address < MEMORY_START || address >= MEMORY_LEN)
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 */
 
/* Make sure we clear out any cached instruction references */
for(i=address;i<address+4;i++)
{
if(mem[i].insn)
{
mem[i].insn->insn_index = -1;
if(mem[i].insn->op1 != null_str) free(mem[i].insn->op1);
if(mem[i].insn->op2 != null_str) free(mem[i].insn->op2);
if(mem[i].insn->op3 != null_str) free(mem[i].insn->op3);
if(mem[i].insn->op4 != null_str) free(mem[i].insn->op4);
free(mem[i].insn);
mem[i].insn = NULL;
}
}
 
mem[address++].data = t_data[0]; /* Back to network byte order */
mem[address++].data = t_data[1];
mem[address++].data = t_data[2];
mem[address++].data = t_data[3];
}
return err;
}
 
address &= 0x07FF;
/*****************************************************/
/* TEMPORARY!!!! */
/*****************************************************/
if(group == 6)
address -= 32;
 
if(group == 6)
{
switch(address)
{
case DEBUGINT_DVR0:
case DEBUGINT_DVR1:
case DEBUGINT_DVR2:
case DEBUGINT_DVR3:
case DEBUGINT_DVR4:
case DEBUGINT_DVR5:
case DEBUGINT_DVR6:
case DEBUGINT_DVR7:
printf("DVR %d set to 0x%08x\n",address-DEBUGINT_DVR0,value);
SET_REG32(debug_unit.DVR[address-DEBUGINT_DVR0],value);
break;
case DEBUGINT_DCR0:
case DEBUGINT_DCR1:
case DEBUGINT_DCR2:
case DEBUGINT_DCR3:
case DEBUGINT_DCR4:
case DEBUGINT_DCR5:
case DEBUGINT_DCR6:
case DEBUGINT_DCR7:
printf("DCR %d set to 0x%08x\n",address-DEBUGINT_DCR0,value);
SET_REG32(debug_unit.DCR[address-DEBUGINT_DCR0],value);
break;
case DEBUGINT_DMR1:
SET_REG32(debug_unit.DMR1,value);
break;
case DEBUGINT_DMR2:
SET_REG32(debug_unit.DMR2,value);
break;
case DEBUGINT_DWCR0:
SET_REG32(debug_unit.DWCR[0],value);
break;
case DEBUGINT_DWCR1:
SET_REG32(debug_unit.DWCR[1],value);
break;
case DEBUGINT_DSR:
SET_REG32(debug_unit.DSR,value);
break;
case DEBUGINT_DRR:
SET_REG32(debug_unit.DRR,value);
break;
case DEBUGINT_DIR:
InduceImmediateInstruction(value);
break;
default:
err = JTAG_PROXY_INVALID_ADDRESS;
break;
}
}
else if(group == 0)
{
extern unsigned long reg[32];
 
if(!address)
err = JTAG_PROXY_ACCESS_EXCEPTION;
else if(address < 32)
reg[address] = data;
else if(address >= 0x0400 && address < 0x0420)
reg[address - 0x0400] = data;
else if(address < 0x0600 || address >= 0x0620)
err = JTAG_PROXY_INVALID_ADDRESS;
}
else
err = JTAG_PROXY_INVALID_ADDRESS;
 
return err;
}
 
int GetDebugUnitRegister(unsigned int address,uint32_t *data)
{
int err = 0;
uint32_t value = 0;
int group = address >> 11;
 
/* This is a memory location */
if(address & 0x80000000)
{
address &= 0x7FFFFFFF;
if(address < MEMORY_START || address >= MEMORY_LEN)
err = JTAG_PROXY_INVALID_ADDRESS;
else
{
unsigned char t_data[4];
int *tmp = (int*)t_data;
 
t_data[0] = mem[address++].data;
t_data[1] = mem[address++].data;
t_data[2] = mem[address++].data;
t_data[3] = mem[address++].data; /* Already in network byte order */
*data = ntohl(*tmp); /* But we assume it is in host order later */
}
return err;
}
address &= 0x07FF;
/*****************************************************/
/* TEMPORARY!!!! */
/*****************************************************/
if(group == 6)
address -= 32;
 
if(group == 6)
{
switch(address)
{
case DEBUGINT_DVR0:
case DEBUGINT_DVR1:
case DEBUGINT_DVR2:
case DEBUGINT_DVR3:
case DEBUGINT_DVR4:
case DEBUGINT_DVR5:
case DEBUGINT_DVR6:
case DEBUGINT_DVR7: GET_REG32(debug_unit.DVR[address-DEBUGINT_DVR0],value); break;
case DEBUGINT_DCR0:
case DEBUGINT_DCR1:
case DEBUGINT_DCR2:
case DEBUGINT_DCR3:
case DEBUGINT_DCR4:
case DEBUGINT_DCR5:
case DEBUGINT_DCR6:
case DEBUGINT_DCR7: GET_REG32(debug_unit.DCR[address-DEBUGINT_DCR0],value); break;
case DEBUGINT_DMR1: GET_REG32(debug_unit.DMR1,value); break;
case DEBUGINT_DMR2: GET_REG32(debug_unit.DMR2,value); break;
case DEBUGINT_DWCR0: GET_REG32(debug_unit.DWCR[0],value); break;
case DEBUGINT_DWCR1: GET_REG32(debug_unit.DWCR[1],value); break;
case DEBUGINT_DSR: GET_REG32(debug_unit.DSR,value); break;
case DEBUGINT_DRR: GET_REG32(debug_unit.DRR,value); break;
case DEBUGINT_DIR: err = JTAG_PROXY_ACCESS_EXCEPTION; break;
default: err = JTAG_PROXY_INVALID_ADDRESS; break;
}
}
else if(group == 0)
{
extern unsigned long reg[32];
 
if(address < 32)
value = reg[address];
else if(address >= 0x0400 && address < 0x0420)
value = reg[address - 0x400];
else if(address >= 0x0600 && address < 0x0620)
value = 0;
else
err = JTAG_PROXY_INVALID_ADDRESS;
}
else
err = JTAG_PROXY_INVALID_ADDRESS;
 
*data = value;
return err;
}
 
void DebugCheckException(int exception)
{
int result = 0;
 
switch(exception)
{
case EXCEPT_RESET: result = debug_unit.DRR.RSTE = debug_unit.DSR.RSTE; break;
case EXCEPT_BUSERR: result = debug_unit.DRR.BUSEE = debug_unit.DSR.BUSEE; break;
case EXCEPT_DPF: result = debug_unit.DRR.DPFE = debug_unit.DSR.DPFE; break;
case EXCEPT_IPF: result = debug_unit.DRR.IPFE = debug_unit.DSR.IPFE; break;
case EXCEPT_LPINT: result = debug_unit.DRR.LPINTE = debug_unit.DSR.LPINTE; break;
case EXCEPT_ALIGN: result = debug_unit.DRR.AE = debug_unit.DSR.AE; break;
case EXCEPT_ILLEGAL: result = debug_unit.DRR.IIE = debug_unit.DSR.IIE; break;
case EXCEPT_HPINT: result = debug_unit.DRR.HPINTE = debug_unit.DSR.HPINTE; break;
case EXCEPT_DTLBMISS: result = debug_unit.DRR.DME = debug_unit.DSR.DME; break;
case EXCEPT_ITLBMISS: result = debug_unit.DRR.IME = debug_unit.DSR.IME; break;
case EXCEPT_RANGE: result = debug_unit.DRR.RE = debug_unit.DSR.RE; break;
case EXCEPT_SYSCALL: result = debug_unit.DRR.SCE = debug_unit.DSR.SCE; break;
case EXCEPT_BREAK: result = debug_unit.DRR.BE = debug_unit.DSR.BE; break;
default:
break;
}
 
if(result)
SetCPUStallState(true);
}

powered by: WebSVN 2.1.0

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