jtaglib: implement breakpoints.

This commit is contained in:
Peter Bägel (DF5EQ) 2015-02-24 11:58:40 +13:00 committed by Daniel Beer
parent 320e560b99
commit fdaad416b2
4 changed files with 354 additions and 6 deletions

192
drivers/eem_defs.h Normal file
View File

@ -0,0 +1,192 @@
/*
* EEM_defs.h
*
* <FILEBRIEF>
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _EEM_DEFS_H_
#define _EEM_DEFS_H_
#define FALSE 0
#define TRUE 1
#define WRITE 0
#define READ 1
#define TRIGFLAG 0x8E
#define EEMVER 0x86
/* Definition for EEM General Clock Control Register */
#define GENCLKCTRL 0x88
/* Definitions for EEM General Clock Control Register */
#define MCLK_SEL0 0x0000
#define SMCLK_SEL0 0x0000
#define ACLK_SEL0 0x0000
#define MCLK_SEL3 0x6000
#define SMCLK_SEL3 0x0C00
#define ACLK_SEL3 0x0180
#define STOP_MCLK 0x0008
#define STOP_SMCLK 0x0004
#define STOP_ACLK 0x0002
/* Definition for EEM Module Clock Control Register 0 */
#define MODCLKCTRL0 0x8A
/* Definition for EEM General Debug Control Register */
#define GENCTRL 0x82
/* Definitions for EEM General Debug Control Register */
#define EEM_EN 0x0001
#define CLEAR_STOP 0x0002
#define EMU_CLK_EN 0x0004
#define EMU_FEAT_EN 0x0008
#define DEB_TRIG_LATCH 0x0010
#define EEM_RST 0x0040
#define E_STOPPED 0x0080
/* Defintions for Trigger Block base addresses */
#define TB0 0x0000
#define TB1 0x0008
#define TB2 0x0010
#define TB3 0x0018
#define TB4 0x0020
#define TB5 0x0028
#define TB6 0x0030
#define TB7 0x0038
#define TB8 0x0040
#define TB9 0x0048
/* Definitions for Trigger Block register addresses */
#define MBTRIGxVAL 0x0000
#define MBTRIGxCTL 0x0002
#define MBTRIGxMSK 0x0004
#define MBTRIGxCMB 0x0006
/* Definitions for MAB/MDB Trigger Control Register */
#define MAB 0x0000
#define MDB 0x0001
#define TRIG_0 0x0000 // Instruction Fetch
#define TRIG_1 0x0002 // Instruction Fetch Hold
#define TRIG_2 0x0004 // No Instruction Fetch
#define TRIG_3 0x0006 // Don't care
#define TRIG_4 0x0020 // No Instruction Fetch & Read
#define TRIG_5 0x0022 // No Instruction Fetch & Write
#define TRIG_6 0x0024 // Read
#define TRIG_7 0x0026 // Write
#define TRIG_8 0x0040 // No Instruction Fetch & No DMA Access
#define TRIG_9 0x0042 // DMA Access (Read or Write)
#define TRIG_A 0x0044 // No DMA Access
#define TRIG_B 0x0046 // Write & No DMA Access
#define TRIG_C 0x0060 // No Instruction Fetch & Read & No DMA Access
#define TRIG_D 0x0062 // Read & No DMA Access
#define TRIG_E 0x0064 // Read & DMA Access
#define TRIG_F 0x0066 // Write & DMA Access
#define CMP_EQUAL 0x0000
#define CMP_GREATER 0x0008
#define CMP_LESS 0x0010
#define CMP_NOT_EQUAL 0x0018
/* Definitions for MAB/MDB Trigger Mask Register */
#define NO_MASK 0x00000
#define MASK_ALL 0xFFFFF
#define MASK_XADDR 0xF0000
#define MASK_HBYTE 0x0FF00
#define MASK_LBYTE 0x000FF
/* Definitions for MAB/MDB Combination Register & Reaction Registers*/
#define EN0 0x0001
#define EN1 0x0002
#define EN2 0x0004
#define EN3 0x0008
#define EN4 0x0010
#define EN5 0x0020
#define EN6 0x0040
#define EN7 0x0080
#define EN8 0x0100
#define EN9 0x0200
#define STOR_CTL 0x9E
/* Definitions for State Storage Control Register */
#define VAR_WATCH0 0x0000 // Two
#define VAR_WATCH1 0x2000 // Four
#define VAR_WATCH2 0x4000 // Six
#define VAR_WATCH3 0x6000 // Eight
#define STOR_FULL 0x0200
#define STOR_WRIT 0x0100
#define STOR_TEST 0x0080
#define STOR_RST 0x0040
#define STOR_STOP_ON_TRIG 0x0020
#define STOR_START_ON_TRIG 0x0010
#define STOR_ONE_SHOT 0x0008
#define STOR_MODE0 0x0000 // Store on enabled triggers
#define STOR_MODE1 0x0002 // Store on Instruction Fetch
#define STOR_MODE2 0x0004 // Variable Watch
#define STOR_MODE3 0x0006 // Store all bus cycles
#define STOR_EN 0x0001 // enable state storage
/* Definitions for Reaction Registers */
#define STOR_REACT 0x98
#define BREAKREACT 0x80
#define EVENT_REACT 0x94
#define EVENT_CTRL 0x96
#define EVENT_TRIG 0x0001
/* Definitions for Cycle Counters */
#define CCNT0CTL 0xB0
#define CCNT0L 0xB2
#define CCNT0H 0xB4
#define CCNT1CTL 0xB8
#define CCNT1L 0xBA
#define CCNT1H 0xBC
#define CCNT1REACT 0xBE
/* Definitions for Cycle Counter Control Register */
#define CCNTMODE0 0x0000 // Counter stopped
#define CCNTMODE1 0x0001 // Increment on reaction
#define CCNTMODE4 0x0004 // Increment on instruction fetch cycles
#define CCNTMODE5 0x0005 // Increment on all bus cycles (including DMA cycles)
#define CCNTMODE6 0x0006 // Increment on all CPU bus cycles (excluding DMA cycles)
#define CCNTMODE7 0x0007 // Increment on all DMA bus cycles
#define CCNT_RST 0x0040
#define CCNTSTT0 0x0000 // Start when CPU released from JTAG/EEM
#define CCNTSTT1 0x0100 // Start on reaction CCNT1REACT (only CCNT1)
#define CCNTSTT2 0x0200 // Start when other (second) counter is started (only if available)
#define CCNTSTT3 0x0300 // Start immediately
#define CCNTSTP0 0x0000 // Stop when CPU is stopped by EEM or under JTAG control
#define CCNTSTP1 0x0400 // Stop on reaction CCNT1REACT (only CCNT1)
#define CCNTSTP2 0x0800 // Stop when other (second) counter is started (only if available)
#define CCNTSTP3 0x0C00 // No stop event
#define CCNTCLR0 0x0000 // No clear event
#define CCNTCLR1 0x1000 // Clear on reaction CCNT1REACT (only CCNT1)
#define CCNTCLR2 0x2000 // Clear when other (second) counter is started (only if available)
#define CCNTCLR3 0x3000 // Reserved
#define GCC_NONE 0x0000 // No clock control
#define GCC_STANDARD 0x0001 // Standard clock control
#define GCC_EXTENDED 0x0002 // Extended clock control
#endif

View File

@ -1,6 +1,6 @@
/* MSPDebug - debugging tool for MSP430 MCUs /* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2012 Daniel Beer * Copyright (C) 2009-2012 Daniel Beer
* Copyright (C) 2012-2014 Peter Bägel * Copyright (C) 2012-2015 Peter Bägel
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,17 +18,24 @@
*/ */
/* jtag functions are taken from TIs SLAA149September 2002 /* jtag functions are taken from TIs SLAA149September 2002
*
* breakpoint implementation influenced by a posting of Ruisheng Lin
* to Travis Goodspeed at 2012-09-20 found at:
* http://sourceforge.net/p/goodfet/mailman/message/29860790/
* *
* 2012-10-03 Peter Bägel (DF5EQ) * 2012-10-03 Peter Bägel (DF5EQ)
* 2012-10-03 initial release Peter Bägel (DF5EQ) * 2012-10-03 initial release Peter Bägel (DF5EQ)
* 2014-12-26 jtag_single_step added Peter Bägel (DF5EQ) * 2014-12-26 jtag_single_step added Peter Bägel (DF5EQ)
* jtag_read_reg corrected * jtag_read_reg corrected
* jtag_write_reg corrected * jtag_write_reg corrected
* 2015-02-21 jtag_set_breakpoint added Peter Bägel (DF5EQ)
* jtag_cpu_state added
*/ */
#include <stdlib.h> #include <stdlib.h>
#include "jtaglib.h" #include "jtaglib.h"
#include "output.h" #include "output.h"
#include "eem_defs.h"
/* JTAG identification value for all existing Flash-based MSP430 devices /* JTAG identification value for all existing Flash-based MSP430 devices
*/ */
@ -55,6 +62,10 @@
#define IR_EX_BLOW 0x24 /* 0x24 */ #define IR_EX_BLOW 0x24 /* 0x24 */
/* Bypass instruction */ /* Bypass instruction */
#define IR_BYPASS 0xFF /* 0xFF */ #define IR_BYPASS 0xFF /* 0xFF */
/* Instructions for the EEM */
#define IR_EMEX_DATA_EXCHANGE 0x90 /* 0x09 */
#define IR_EMEX_WRITE_CONTROL 0x30 /* 0x0C */
#define IR_EMEX_READ_CONTROL 0xD0 /* 0x0B */
#define jtag_tms_set(p) p->f->jtdev_tms(p, 1) #define jtag_tms_set(p) p->f->jtdev_tms(p, 1)
#define jtag_tms_clr(p) p->f->jtdev_tms(p, 0) #define jtag_tms_clr(p) p->f->jtdev_tms(p, 0)
@ -658,6 +669,9 @@ void jtag_release_device(struct jtdev *p, address_t address)
case 0xffff: /* Nothing to do */ case 0xffff: /* Nothing to do */
break; break;
case 0xfffe: /* Perform reset */ case 0xfffe: /* Perform reset */
/* delete all breakpoints */
jtag_set_breakpoint(p,-1,0);
/* issue reset */
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT); jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
jtag_dr_shift(p, 0x2C01); jtag_dr_shift(p, 0x2C01);
jtag_dr_shift(p, 0x2401); jtag_dr_shift(p, 0x2401);
@ -667,6 +681,15 @@ void jtag_release_device(struct jtdev *p, address_t address)
break; break;
} }
jtag_set_instruction_fetch(p);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE);
jtag_dr_shift(p, BREAKREACT + READ);
jtag_dr_shift(p, 0x0000);
jtag_ir_shift(p, IR_EMEX_WRITE_CONTROL);
jtag_dr_shift(p, 0x000f);
jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE); jtag_ir_shift(p, IR_CNTRL_SIG_RELEASE);
} }
@ -1015,3 +1038,78 @@ void jtag_single_step( struct jtdev *p )
p->failed = 1; p->failed = 1;
} }
} }
/*----------------------------------------------------------------------------*/
unsigned int jtag_set_breakpoint( struct jtdev *p,int bp_num, address_t bp_addr )
{
/* The breakpoint logic is explained in 'SLAU414c EEM.pdf' */
/* A good overview is given with Figure 1-1 */
/* MBx is TBx in EEM_defs.h */
/* CPU Stop is BREAKREACT in EEM_defs.h */
/* State Storage is STOR_REACT in EEM_defs.h */
/* Cycle Counter is EVENT_REACT in EEM_defs.h */
unsigned int breakreact;
if (bp_num >= 8) {
/* there are no more than 8 breakpoints in EEM */
printc_err("jtag_set_breakpoint: failed setting "
"breakpoint %d at %04x\n", bp_num, bp_addr);
p->failed = 1;
return 0;
}
if (bp_num < 0) {
/* disable all breakpoints by deleting the BREAKREACT
* register */
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE);
jtag_dr_shift(p, BREAKREACT + WRITE);
jtag_dr_shift(p, 0x0000);
return 1;
}
/* set breakpoint */
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE);
jtag_dr_shift(p, GENCTRL + WRITE);
jtag_dr_shift(p, EEM_EN + CLEAR_STOP + EMU_CLK_EN + EMU_FEAT_EN);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
jtag_dr_shift(p, 8*bp_num + MBTRIGxVAL + WRITE);
jtag_dr_shift(p, bp_addr);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
jtag_dr_shift(p, 8*bp_num + MBTRIGxCTL + WRITE);
jtag_dr_shift(p, MAB + TRIG_0 + CMP_EQUAL);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
jtag_dr_shift(p, 8*bp_num + MBTRIGxMSK + WRITE);
jtag_dr_shift(p, NO_MASK);
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
jtag_dr_shift(p, 8*bp_num + MBTRIGxCMB + WRITE);
jtag_dr_shift(p, 1<<bp_num);
/* read the actual setting of the BREAKREACT register */
/* while reading a 1 is automatically shifted into LSB */
/* this will be undone and the bit for the new breakpoint set */
/* then the updated value is stored back */
jtag_ir_shift(p, IR_EMEX_DATA_EXCHANGE); //repeating may not needed
breakreact = jtag_dr_shift(p, BREAKREACT + READ);
breakreact += jtag_dr_shift(p, 0x000);
breakreact = (breakreact >> 1) | (1 << bp_num);
jtag_dr_shift(p, BREAKREACT + WRITE);
jtag_dr_shift(p, breakreact);
return 1;
}
/*----------------------------------------------------------------------------*/
unsigned int jtag_cpu_state( struct jtdev *p )
{
jtag_ir_shift(p, IR_EMEX_READ_CONTROL);
if ((jtag_dr_shift(p, 0x0000) & 0x0080) == 0x0080) {
return 1; /* halted */
} else {
return 0; /* running */
}
}

View File

@ -1,6 +1,6 @@
/* MSPDebug - debugging tool for MSP430 MCUs /* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2012 Daniel Beer * Copyright (C) 2009-2012 Daniel Beer
* Copyright (C) 2012-2014 Peter Bägel * Copyright (C) 2012-2015 Peter Bägel
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,10 +18,17 @@
*/ */
/* jtag functions are taken from TIs SLAA149September 2002 /* jtag functions are taken from TIs SLAA149September 2002
*
* breakpoint implementation influenced by a posting of Ruisheng Lin
* to Travis Goodspeed at 2012-09-20 found at:
* http://sourceforge.net/p/goodfet/mailman/message/29860790/
*
* *
* 2012-10-03 Peter Bägel (DF5EQ) * 2012-10-03 Peter Bägel (DF5EQ)
* 2012-10-03 initial release Peter Bägel (DF5EQ) * 2012-10-03 initial release Peter Bägel (DF5EQ)
* 2014-12-26 jtag_single_step added Peter Bägel (DF5EQ) * 2014-12-26 jtag_single_step added Peter Bägel (DF5EQ)
* 2015-02-21 jtag_set_breakpoint added Peter Bägel (DF5EQ)
* jtag_cpu_state added
*/ */
#ifndef JTAGLIB_H_ #ifndef JTAGLIB_H_
@ -105,5 +112,8 @@ address_t jtag_read_reg(struct jtdev *p, int reg);
/* Writes a value into a register of the target CPU */ /* Writes a value into a register of the target CPU */
void jtag_write_reg(struct jtdev *p, int reg, address_t value); void jtag_write_reg(struct jtdev *p, int reg, address_t value);
void jtag_single_step(struct jtdev *p); void jtag_single_step(struct jtdev *p);
unsigned int jtag_set_breakpoint(struct jtdev *p,
int bp_num, address_t bp_addr);
unsigned int jtag_cpu_state(struct jtdev *p);
#endif #endif

View File

@ -1,6 +1,6 @@
/* MSPDebug - debugging tool for MSP430 MCUs /* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2012 Daniel Beer * Copyright (C) 2009-2012 Daniel Beer
* Copyright (C) 2012-2014 Peter Bägel * Copyright (C) 2012-2015 Peter Bägel
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,8 +20,9 @@
/* Driver for parallel port interface like the Olimex MSP430-JTAG /* Driver for parallel port interface like the Olimex MSP430-JTAG
* Starting point was the goodfet driver * Starting point was the goodfet driver
* *
* 2012-10-03 Peter Bägel (DF5EQ) * 2012-10-03 initial release Peter Bägel (DF5EQ)
* 2014-12-26 single step implemented Peter Bägel (DF5EQ) * 2014-12-26 single step implemented Peter Bägel (DF5EQ)
* 2015-02-21 breakpoints implemented Peter Bägel (DF5EQ)
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -147,6 +148,43 @@ struct pif_device {
struct jtdev jtag; struct jtdev jtag;
}; };
/*----------------------------------------------------------------------------*/
static int refresh_bps(struct pif_device *dev)
{
int i;
int ret;
struct device_breakpoint *bp;
address_t addr;
ret = 0;
for (i = 0; i < dev->base.max_breakpoints; i++) {
bp = &dev->base.breakpoints[i];
printc_dbg("refresh breakpoint %d: type=%d "
"addr=%04x flags=%04x\n",
i, bp->type, bp->addr, bp->flags);
if ( (bp->flags & DEVICE_BP_DIRTY) &&
(bp->type == DEVICE_BPTYPE_BREAK) ) {
addr = bp->addr;
if ( !(bp->flags & DEVICE_BP_ENABLED) ) {
addr = 0;
}
if ( jtag_set_breakpoint (&dev->jtag, i, addr) == 0) {
printc_err("pif: failed to refresh "
"breakpoint #%d\n", i);
ret = -1;
} else {
bp->flags &= ~DEVICE_BP_DIRTY;
}
}
}
return ret;
}
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static int pif_readmem( device_t dev_base, static int pif_readmem( device_t dev_base,
address_t addr, address_t addr,
@ -278,6 +316,10 @@ static int pif_ctl(device_t dev_base, device_ctl_t type)
break; break;
case DEVICE_CTL_RUN: case DEVICE_CTL_RUN:
/* transfer changed breakpoints to device */
if (refresh_bps(dev) < 0) {
return -1;
}
/* start program execution at current PC */ /* start program execution at current PC */
jtag_release_device(&dev->jtag, 0xffff); jtag_release_device(&dev->jtag, 0xffff);
break; break;
@ -303,9 +345,15 @@ static int pif_ctl(device_t dev_base, device_ctl_t type)
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static device_status_t pif_poll(device_t dev_base) static device_status_t pif_poll(device_t dev_base)
{ {
if (delay_ms(100) < 0) struct pif_device *dev = (struct pif_device *)dev_base;
if (delay_ms(100) < 0 || ctrlc_check())
return DEVICE_STATUS_INTR; return DEVICE_STATUS_INTR;
if (jtag_cpu_state(&dev->jtag) == 1) {
return DEVICE_STATUS_HALTED;
}
return DEVICE_STATUS_RUNNING; return DEVICE_STATUS_RUNNING;
} }
@ -360,7 +408,7 @@ static device_t pif_open(const struct device_args *args)
memset(dev, 0, sizeof(*dev)); memset(dev, 0, sizeof(*dev));
dev->base.type = &device_pif; dev->base.type = &device_pif;
dev->base.max_breakpoints = 0; dev->base.max_breakpoints = 2; //supported by all devices
(&dev->jtag)->f = &jtdev_func_pif; (&dev->jtag)->f = &jtdev_func_pif;
if ((&dev->jtag)->f->jtdev_open(&dev->jtag, args->path) < 0) { if ((&dev->jtag)->f->jtdev_open(&dev->jtag, args->path) < 0) {