URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [tags/] [nog_patch_52/] [or1ksim/] [debug/] [debug_unit.c] - Rev 221
Go to most recent revision | Compare with Previous | Blame | View Log
/* 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 "sprs.h" #include "../gdb.h" #include "../cpu/or1k/except.h" #include "opcode/or32.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*); static int CalculateWatchpoints(void); 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(unsigned long* insn) { int valid = induced; induced = false; if(valid) *insn = induced_insn; return valid; } void InduceImmediateInstruction(unsigned long insn) { induced = true; induced_insn = insn; if(in_reset) return; if(cpu_stalled) { 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; } #ifdef DEBUGMOD_OFF #define CheckDebugUnit(x,y) 0 #else inline 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; /* If we're single stepping, always stop */ if(debug_unit.DMR1.ST && action == DebugInstructionFetch) return 1; 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(); } #endif static 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) { iq_entry->insn = induced_insn; iq_entry->insn_index = insn_decode(induced_insn); iq_entry->insn_addr = pc_phy; iq_entry->op[0] = 0; iq_entry->op[MAX_OPERANDS] = OPTYPE_LAST; } static void ExecuteInducedInstruction(unsigned long insn) { struct iqueue_entry iq_entry; unsigned long pc_saved = pc; unsigned long pcnext_saved = pcnext; unsigned long pcdelay_saved = pcdelay; unsigned long pc_phy_saved = pc_phy; GetIQueueEntry(&iq_entry); decode_execute(&iq_entry); pc = pc_saved; pcnext = pcnext_saved; pcdelay = pcdelay_saved; pc_phy = pc_phy_saved; } static DebugScanChainIDs current_scan_chain = JTAG_CHAIN_GLOBAL; int DebugGetRegister(unsigned int address,int32_t* data) { int err; #ifdef DEBUG_JTAG printf("Debug get register %x\n",address); fflush(stdout); #endif 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; case JTAG_CHAIN_WISHBONE: err = GetWishboneMemory(address,data); break; } #ifdef DEBUG_JTAG printf("!get reg %x\n", *data); fflush(stdout); #endif return err; } int DebugSetRegister(unsigned int address,int32_t data) { int err; #ifdef DEBUG_JTAG printf("Debug set register %x <- %x\n",address, data); fflush(stdout); #endif 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; case JTAG_CHAIN_WISHBONE: err = SetWishboneMemory(address,data); break; } #ifdef DEBUG_JTAG printf("!set reg\n"); fflush(stdout); #endif return err; } int DebugSetChain(int chain) { #ifdef DEBUG_JTAG printf("Debug set chain %x\n",chain); fflush(stdout); #endif switch(chain) { case JTAG_CHAIN_DEBUG_UNIT: case JTAG_CHAIN_TRACE: case JTAG_CHAIN_DEVELOPMENT: case JTAG_CHAIN_WISHBONE: current_scan_chain = chain; break; default: /* All other chains not implemented */ return JTAG_PROXY_INVALID_CHAIN; } #ifdef DEBUG_JTAG printf("!set chain\n"); fflush(stdout); #endif 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; 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) { /* Assume that a write to the PC implies that the debugging software has recognized the exception and wants to do something else instead. */ if(address == SPR_PC) { ClearPendingException(); ClearPreparedPCState(); } mtspr(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; 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 = mfspr(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; } /* 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 SetWishboneMemory(unsigned int address,uint32_t data) { int err = 0; uint32_t value = data; int old_value; int group = address >> 11; address <<= 2; 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]); } return err; } int GetWishboneMemory(unsigned int address,uint32_t *data) { int err = 0; uint32_t value = 0; int group = address >> 11; address <<= 2; if(!verify_memoryarea(address)) 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 */ } return err; } /* DebugCheckException returns 1 if the exception should be ignored. Currently, this is true only if the exception is a breakpoint exception and debug_unit.DMR1.ST is set. Sorry, this is a quick hack to disable processing of breakpoint exceptions on single stepping. Just one of those historical accidents. Feel free to rewrite the behavior. */ int 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; case EXCEPT_TRAP: result = debug_unit.DRR.TE = debug_unit.DSR.TE; break; default: break; } if(result) SetCPUStallState(true); return (debug_unit.DMR1.ST && exception == EXCEPT_BREAK); }
Go to most recent revision | Compare with Previous | Blame | View Log