| 1 | 64 | olivier.gi | //----------------------------------------------------------------------------
 | 
      
         | 2 |  |  | // Copyright (C) 2001 Authors
 | 
      
         | 3 |  |  | //
 | 
      
         | 4 |  |  | // This source file may be used and distributed without restriction provided
 | 
      
         | 5 |  |  | // that this copyright statement is not removed from the file and that any
 | 
      
         | 6 |  |  | // derivative work contains the original copyright notice and the associated
 | 
      
         | 7 |  |  | // disclaimer.
 | 
      
         | 8 |  |  | //
 | 
      
         | 9 |  |  | // This source file is free software; you can redistribute it and/or modify
 | 
      
         | 10 |  |  | // it under the terms of the GNU Lesser General Public License as published
 | 
      
         | 11 |  |  | // by the Free Software Foundation; either version 2.1 of the License, or
 | 
      
         | 12 |  |  | // (at your option) any later version.
 | 
      
         | 13 |  |  | //
 | 
      
         | 14 |  |  | // This source is distributed in the hope that it will be useful, but WITHOUT
 | 
      
         | 15 |  |  | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
      
         | 16 |  |  | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 | 
      
         | 17 |  |  | // License for more details.
 | 
      
         | 18 |  |  | //
 | 
      
         | 19 |  |  | // You should have received a copy of the GNU Lesser General Public License
 | 
      
         | 20 |  |  | // along with this source; if not, write to the Free Software Foundation,
 | 
      
         | 21 |  |  | // Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 | 
      
         | 22 |  |  | //
 | 
      
         | 23 |  |  | //----------------------------------------------------------------------------
 | 
      
         | 24 |  |  | //
 | 
      
         | 25 |  |  | // *File Name: omsp_dbg_hwbrk.v
 | 
      
         | 26 |  |  | // 
 | 
      
         | 27 |  |  | // *Module Description:
 | 
      
         | 28 |  |  | //                       Hardware Breakpoint / Watchpoint module
 | 
      
         | 29 |  |  | //
 | 
      
         | 30 |  |  | // *Author(s):
 | 
      
         | 31 |  |  | //              - Olivier Girard,    olgirard@gmail.com
 | 
      
         | 32 |  |  | //
 | 
      
         | 33 |  |  | //----------------------------------------------------------------------------
 | 
      
         | 34 |  |  | // $Rev: 57 $
 | 
      
         | 35 |  |  | // $LastChangedBy: olivier.girard $
 | 
      
         | 36 |  |  | // $LastChangedDate: 2010-02-01 23:56:03 +0100 (Mo, 01 Feb 2010) $
 | 
      
         | 37 |  |  | //----------------------------------------------------------------------------
 | 
      
         | 38 |  |  | `include "timescale.v"
 | 
      
         | 39 |  |  | `include "openMSP430_defines.v"
 | 
      
         | 40 |  |  |  
 | 
      
         | 41 |  |  | module  omsp_dbg_hwbrk (
 | 
      
         | 42 |  |  |  
 | 
      
         | 43 |  |  | // OUTPUTs
 | 
      
         | 44 |  |  |     brk_halt,                // Hardware breakpoint command
 | 
      
         | 45 |  |  |     brk_pnd,                 // Hardware break/watch-point pending
 | 
      
         | 46 |  |  |     brk_dout,                // Hardware break/watch-point register data input
 | 
      
         | 47 |  |  |  
 | 
      
         | 48 |  |  | // INPUTs
 | 
      
         | 49 |  |  |     brk_reg_rd,              // Hardware break/watch-point register read select
 | 
      
         | 50 |  |  |     brk_reg_wr,              // Hardware break/watch-point register write select
 | 
      
         | 51 |  |  |     dbg_din,                 // Debug register data input
 | 
      
         | 52 |  |  |     eu_mab,                  // Execution-Unit Memory address bus
 | 
      
         | 53 |  |  |     eu_mb_en,                // Execution-Unit Memory bus enable
 | 
      
         | 54 |  |  |     eu_mb_wr,                // Execution-Unit Memory bus write transfer
 | 
      
         | 55 |  |  |     eu_mdb_in,               // Memory data bus input
 | 
      
         | 56 |  |  |     eu_mdb_out,              // Memory data bus output
 | 
      
         | 57 |  |  |     exec_done,               // Execution completed
 | 
      
         | 58 |  |  |     fe_mb_en,                // Frontend Memory bus enable
 | 
      
         | 59 |  |  |     mclk,                    // Main system clock
 | 
      
         | 60 |  |  |     pc,                      // Program counter
 | 
      
         | 61 |  |  |     por                      // Power on reset
 | 
      
         | 62 |  |  | );
 | 
      
         | 63 |  |  |  
 | 
      
         | 64 |  |  | // OUTPUTs
 | 
      
         | 65 |  |  | //=========
 | 
      
         | 66 |  |  | output         brk_halt;     // Hardware breakpoint command
 | 
      
         | 67 |  |  | output         brk_pnd;      // Hardware break/watch-point pending
 | 
      
         | 68 |  |  | output  [15:0] brk_dout;     // Hardware break/watch-point register data input
 | 
      
         | 69 |  |  |  
 | 
      
         | 70 |  |  | // INPUTs
 | 
      
         | 71 |  |  | //=========
 | 
      
         | 72 |  |  | input    [3:0] brk_reg_rd;   // Hardware break/watch-point register read select
 | 
      
         | 73 |  |  | input    [3:0] brk_reg_wr;   // Hardware break/watch-point register write select
 | 
      
         | 74 |  |  | input   [15:0] dbg_din;      // Debug register data input
 | 
      
         | 75 |  |  | input   [15:0] eu_mab;       // Execution-Unit Memory address bus
 | 
      
         | 76 |  |  | input          eu_mb_en;     // Execution-Unit Memory bus enable
 | 
      
         | 77 |  |  | input    [1:0] eu_mb_wr;     // Execution-Unit Memory bus write transfer
 | 
      
         | 78 |  |  | input   [15:0] eu_mdb_in;    // Memory data bus input
 | 
      
         | 79 |  |  | input   [15:0] eu_mdb_out;   // Memory data bus output
 | 
      
         | 80 |  |  | input          exec_done;    // Execution completed
 | 
      
         | 81 |  |  | input          fe_mb_en;     // Frontend Memory bus enable
 | 
      
         | 82 |  |  | input          mclk;         // Main system clock
 | 
      
         | 83 |  |  | input   [15:0] pc;           // Program counter
 | 
      
         | 84 |  |  | input          por;          // Power on reset
 | 
      
         | 85 |  |  |  
 | 
      
         | 86 |  |  |  
 | 
      
         | 87 |  |  | //=============================================================================
 | 
      
         | 88 |  |  | // 1)  WIRE & PARAMETER DECLARATION
 | 
      
         | 89 |  |  | //=============================================================================
 | 
      
         | 90 |  |  |  
 | 
      
         | 91 |  |  | wire      range_wr_set;
 | 
      
         | 92 |  |  | wire      range_rd_set;
 | 
      
         | 93 |  |  | wire      addr1_wr_set;
 | 
      
         | 94 |  |  | wire      addr1_rd_set;
 | 
      
         | 95 |  |  | wire      addr0_wr_set;
 | 
      
         | 96 |  |  | wire      addr0_rd_set;
 | 
      
         | 97 |  |  |  
 | 
      
         | 98 |  |  |  
 | 
      
         | 99 |  |  | parameter BRK_CTL   = 0,
 | 
      
         | 100 |  |  |           BRK_STAT  = 1,
 | 
      
         | 101 |  |  |           BRK_ADDR0 = 2,
 | 
      
         | 102 |  |  |           BRK_ADDR1 = 3;
 | 
      
         | 103 |  |  |  
 | 
      
         | 104 |  |  |  
 | 
      
         | 105 |  |  | //=============================================================================
 | 
      
         | 106 |  |  | // 2)  CONFIGURATION REGISTERS
 | 
      
         | 107 |  |  | //=============================================================================
 | 
      
         | 108 |  |  |  
 | 
      
         | 109 |  |  | // BRK_CTL Register
 | 
      
         | 110 |  |  | //-----------------------------------------------------------------------------
 | 
      
         | 111 |  |  | //       7   6   5        4            3          2            1  0
 | 
      
         | 112 |  |  | //        Reserved    RANGE_MODE    INST_EN    BREAK_EN    ACCESS_MODE
 | 
      
         | 113 |  |  | //
 | 
      
         | 114 |  |  | // ACCESS_MODE: - 00 : Disabled
 | 
      
         | 115 |  |  | //              - 01 : Detect read access
 | 
      
         | 116 |  |  | //              - 10 : Detect write access
 | 
      
         | 117 |  |  | //              - 11 : Detect read/write access
 | 
      
         | 118 |  |  | //              NOTE: '10' & '11' modes are not supported on the instruction flow
 | 
      
         | 119 |  |  | //
 | 
      
         | 120 |  |  | // BREAK_EN:    -  0 : Watchmode enable
 | 
      
         | 121 |  |  | //              -  1 : Break enable
 | 
      
         | 122 |  |  | //
 | 
      
         | 123 |  |  | // INST_EN:     -  0 : Checks are done on the execution unit (data flow)
 | 
      
         | 124 |  |  | //              -  1 : Checks are done on the frontend (instruction flow)
 | 
      
         | 125 |  |  | //
 | 
      
         | 126 |  |  | // RANGE_MODE:  -  0 : Address match on BRK_ADDR0 or BRK_ADDR1
 | 
      
         | 127 |  |  | //              -  1 : Address match on BRK_ADDR0->BRK_ADDR1 range
 | 
      
         | 128 |  |  | //
 | 
      
         | 129 |  |  | //-----------------------------------------------------------------------------
 | 
      
         | 130 |  |  | reg   [4:0] brk_ctl;
 | 
      
         | 131 |  |  |  
 | 
      
         | 132 |  |  | wire        brk_ctl_wr = brk_reg_wr[BRK_CTL];
 | 
      
         | 133 |  |  |  
 | 
      
         | 134 |  |  | always @ (posedge mclk or posedge por)
 | 
      
         | 135 |  |  |   if (por)             brk_ctl <=  5'h00;
 | 
      
         | 136 |  |  |   else if (brk_ctl_wr) brk_ctl <=  {`HWBRK_RANGE & dbg_din[4], dbg_din[3:0]};
 | 
      
         | 137 |  |  |  
 | 
      
         | 138 |  |  | wire  [7:0] brk_ctl_full = {3'b000, brk_ctl};
 | 
      
         | 139 |  |  |  
 | 
      
         | 140 |  |  |  
 | 
      
         | 141 |  |  | // BRK_STAT Register
 | 
      
         | 142 |  |  | //-----------------------------------------------------------------------------
 | 
      
         | 143 |  |  | //     7    6       5         4         3         2         1         0
 | 
      
         | 144 |  |  | //    Reserved  RANGE_WR  RANGE_RD  ADDR1_WR  ADDR1_RD  ADDR0_WR  ADDR0_RD
 | 
      
         | 145 |  |  | //-----------------------------------------------------------------------------
 | 
      
         | 146 |  |  | reg   [5:0] brk_stat;
 | 
      
         | 147 |  |  |  
 | 
      
         | 148 |  |  | wire        brk_stat_wr  = brk_reg_wr[BRK_STAT];
 | 
      
         | 149 |  |  | wire  [5:0] brk_stat_set = {range_wr_set & `HWBRK_RANGE,
 | 
      
         | 150 |  |  |                             range_rd_set & `HWBRK_RANGE,
 | 
      
         | 151 |  |  |                             addr1_wr_set, addr1_rd_set,
 | 
      
         | 152 |  |  |                             addr0_wr_set, addr0_rd_set};
 | 
      
         | 153 |  |  | wire  [5:0] brk_stat_clr = ~dbg_din[5:0];
 | 
      
         | 154 |  |  |  
 | 
      
         | 155 |  |  | always @ (posedge mclk or posedge por)
 | 
      
         | 156 |  |  |   if (por)              brk_stat <=  6'h00;
 | 
      
         | 157 |  |  |   else if (brk_stat_wr) brk_stat <= ((brk_stat & brk_stat_clr) | brk_stat_set);
 | 
      
         | 158 |  |  |   else                  brk_stat <=  (brk_stat                 | brk_stat_set);
 | 
      
         | 159 |  |  |  
 | 
      
         | 160 |  |  | wire  [7:0] brk_stat_full = {2'b00, brk_stat};
 | 
      
         | 161 |  |  | wire        brk_pnd       = |brk_stat;
 | 
      
         | 162 |  |  |  
 | 
      
         | 163 |  |  |  
 | 
      
         | 164 |  |  | // BRK_ADDR0 Register
 | 
      
         | 165 |  |  | //-----------------------------------------------------------------------------
 | 
      
         | 166 |  |  | reg  [15:0] brk_addr0;
 | 
      
         | 167 |  |  |  
 | 
      
         | 168 |  |  | wire        brk_addr0_wr = brk_reg_wr[BRK_ADDR0];
 | 
      
         | 169 |  |  |  
 | 
      
         | 170 |  |  | always @ (posedge mclk or posedge por)
 | 
      
         | 171 |  |  |   if (por)               brk_addr0 <=  16'h0000;
 | 
      
         | 172 |  |  |   else if (brk_addr0_wr) brk_addr0 <=  dbg_din;
 | 
      
         | 173 |  |  |  
 | 
      
         | 174 |  |  |  
 | 
      
         | 175 |  |  | // BRK_ADDR1/DATA0 Register
 | 
      
         | 176 |  |  | //-----------------------------------------------------------------------------
 | 
      
         | 177 |  |  | reg  [15:0] brk_addr1;
 | 
      
         | 178 |  |  |  
 | 
      
         | 179 |  |  | wire        brk_addr1_wr = brk_reg_wr[BRK_ADDR1];
 | 
      
         | 180 |  |  |  
 | 
      
         | 181 |  |  | always @ (posedge mclk or posedge por)
 | 
      
         | 182 |  |  |   if (por)               brk_addr1 <=  16'h0000;
 | 
      
         | 183 |  |  |   else if (brk_addr1_wr) brk_addr1 <=  dbg_din;
 | 
      
         | 184 |  |  |  
 | 
      
         | 185 |  |  |  
 | 
      
         | 186 |  |  | //============================================================================
 | 
      
         | 187 |  |  | // 3) DATA OUTPUT GENERATION
 | 
      
         | 188 |  |  | //============================================================================
 | 
      
         | 189 |  |  |  
 | 
      
         | 190 |  |  | wire [15:0] brk_ctl_rd   = {8'h00, brk_ctl_full}  & {16{brk_reg_rd[BRK_CTL]}};
 | 
      
         | 191 |  |  | wire [15:0] brk_stat_rd  = {8'h00, brk_stat_full} & {16{brk_reg_rd[BRK_STAT]}};
 | 
      
         | 192 |  |  | wire [15:0] brk_addr0_rd = brk_addr0              & {16{brk_reg_rd[BRK_ADDR0]}};
 | 
      
         | 193 |  |  | wire [15:0] brk_addr1_rd = brk_addr1              & {16{brk_reg_rd[BRK_ADDR1]}};
 | 
      
         | 194 |  |  |  
 | 
      
         | 195 |  |  | wire [15:0] brk_dout = brk_ctl_rd   |
 | 
      
         | 196 |  |  |                        brk_stat_rd  |
 | 
      
         | 197 |  |  |                        brk_addr0_rd |
 | 
      
         | 198 |  |  |                        brk_addr1_rd;
 | 
      
         | 199 |  |  |  
 | 
      
         | 200 |  |  |  
 | 
      
         | 201 |  |  | //============================================================================
 | 
      
         | 202 |  |  | // 4) BREAKPOINT / WATCHPOINT GENERATION
 | 
      
         | 203 |  |  | //============================================================================
 | 
      
         | 204 |  |  |  
 | 
      
         | 205 |  |  | // Comparators
 | 
      
         | 206 |  |  | //---------------------------
 | 
      
         | 207 |  |  | // Note: here the comparison logic is instanciated several times in order
 | 
      
         | 208 |  |  | //       to improve the timings, at the cost of a bit more area.
 | 
      
         | 209 |  |  |  
 | 
      
         | 210 |  |  | wire        equ_d_addr0 = eu_mb_en & (eu_mab==brk_addr0) & ~brk_ctl[`BRK_RANGE];
 | 
      
         | 211 |  |  | wire        equ_d_addr1 = eu_mb_en & (eu_mab==brk_addr1) & ~brk_ctl[`BRK_RANGE];
 | 
      
         | 212 |  |  | wire        equ_d_range = eu_mb_en & ((eu_mab>=brk_addr0) & (eu_mab<=brk_addr1)) &
 | 
      
         | 213 |  |  |                           brk_ctl[`BRK_RANGE] & `HWBRK_RANGE;
 | 
      
         | 214 |  |  |  
 | 
      
         | 215 |  |  | reg         fe_mb_en_buf;
 | 
      
         | 216 |  |  | always @ (posedge mclk or posedge por)
 | 
      
         | 217 |  |  |   if (por)  fe_mb_en_buf <=  1'b0;
 | 
      
         | 218 |  |  |   else      fe_mb_en_buf <=  fe_mb_en;
 | 
      
         | 219 |  |  |  
 | 
      
         | 220 |  |  | wire        equ_i_addr0 = fe_mb_en_buf & (pc==brk_addr0) & ~brk_ctl[`BRK_RANGE];
 | 
      
         | 221 |  |  | wire        equ_i_addr1 = fe_mb_en_buf & (pc==brk_addr1) & ~brk_ctl[`BRK_RANGE];
 | 
      
         | 222 |  |  | wire        equ_i_range = fe_mb_en_buf & ((pc>=brk_addr0) & (pc<=brk_addr1)) &
 | 
      
         | 223 |  |  |                           brk_ctl[`BRK_RANGE] & `HWBRK_RANGE;
 | 
      
         | 224 |  |  |  
 | 
      
         | 225 |  |  |  
 | 
      
         | 226 |  |  | // Detect accesses
 | 
      
         | 227 |  |  | //---------------------------
 | 
      
         | 228 |  |  |  
 | 
      
         | 229 |  |  | // Detect Instruction read access
 | 
      
         | 230 |  |  | wire i_addr0_rd =  equ_i_addr0 &  brk_ctl[`BRK_I_EN];
 | 
      
         | 231 |  |  | wire i_addr1_rd =  equ_i_addr1 &  brk_ctl[`BRK_I_EN];
 | 
      
         | 232 |  |  | wire i_range_rd =  equ_i_range &  brk_ctl[`BRK_I_EN];
 | 
      
         | 233 |  |  |  
 | 
      
         | 234 |  |  | // Detect Execution-Unit write access
 | 
      
         | 235 |  |  | wire d_addr0_wr =  equ_d_addr0 & ~brk_ctl[`BRK_I_EN] &  |eu_mb_wr;
 | 
      
         | 236 |  |  | wire d_addr1_wr =  equ_d_addr1 & ~brk_ctl[`BRK_I_EN] &  |eu_mb_wr;
 | 
      
         | 237 |  |  | wire d_range_wr =  equ_d_range & ~brk_ctl[`BRK_I_EN] &  |eu_mb_wr;
 | 
      
         | 238 |  |  |  
 | 
      
         | 239 |  |  | // Detect DATA read access
 | 
      
         | 240 |  |  | // Whenever an "ADD r9. &0x200" instruction is executed, &0x200 will be read
 | 
      
         | 241 |  |  | // before being written back. In that case, the read flag should not be set.
 | 
      
         | 242 |  |  | // In general, We should here make sure no write access occures during the
 | 
      
         | 243 |  |  | // same instruction cycle before setting the read flag.
 | 
      
         | 244 |  |  | reg [2:0] d_rd_trig;
 | 
      
         | 245 |  |  | always @ (posedge mclk or posedge por)
 | 
      
         | 246 |  |  |   if (por)            d_rd_trig <=  3'h0;
 | 
      
         | 247 |  |  |   else if (exec_done) d_rd_trig <=  3'h0;
 | 
      
         | 248 |  |  |   else                d_rd_trig <=  {equ_d_range & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr,
 | 
      
         | 249 |  |  |                                      equ_d_addr1 & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr,
 | 
      
         | 250 |  |  |                                      equ_d_addr0 & ~brk_ctl[`BRK_I_EN] & ~|eu_mb_wr};
 | 
      
         | 251 |  |  |  
 | 
      
         | 252 |  |  | wire d_addr0_rd =  d_rd_trig[0] & exec_done & ~d_addr0_wr;
 | 
      
         | 253 |  |  | wire d_addr1_rd =  d_rd_trig[1] & exec_done & ~d_addr1_wr;
 | 
      
         | 254 |  |  | wire d_range_rd =  d_rd_trig[2] & exec_done & ~d_range_wr;
 | 
      
         | 255 |  |  |  
 | 
      
         | 256 |  |  |  
 | 
      
         | 257 |  |  | // Set flags
 | 
      
         | 258 |  |  | assign addr0_rd_set = brk_ctl[`BRK_MODE_RD] & (d_addr0_rd  | i_addr0_rd);
 | 
      
         | 259 |  |  | assign addr0_wr_set = brk_ctl[`BRK_MODE_WR] &  d_addr0_wr;
 | 
      
         | 260 |  |  | assign addr1_rd_set = brk_ctl[`BRK_MODE_RD] & (d_addr1_rd  | i_addr1_rd);
 | 
      
         | 261 |  |  | assign addr1_wr_set = brk_ctl[`BRK_MODE_WR] &  d_addr1_wr;
 | 
      
         | 262 |  |  | assign range_rd_set = brk_ctl[`BRK_MODE_RD] & (d_range_rd  | i_range_rd);
 | 
      
         | 263 |  |  | assign range_wr_set = brk_ctl[`BRK_MODE_WR] &  d_range_wr;
 | 
      
         | 264 |  |  |  
 | 
      
         | 265 |  |  |  
 | 
      
         | 266 |  |  | // Break CPU
 | 
      
         | 267 |  |  | assign brk_halt     = brk_ctl[`BRK_EN] & |brk_stat_set;
 | 
      
         | 268 |  |  |  
 | 
      
         | 269 |  |  |  
 | 
      
         | 270 |  |  | endmodule // omsp_dbg_hwbrk
 | 
      
         | 271 |  |  |  
 | 
      
         | 272 |  |  | `include "openMSP430_undefines.v"
 |