Sat, 06 Aug 2011 01:26:56 +0100
remove synthesis delay entities to ease merge
philpem@26 | 1 | // ================================================================== |
philpem@26 | 2 | // >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< |
philpem@26 | 3 | // ------------------------------------------------------------------ |
philpem@26 | 4 | // Copyright (c) 2006-2011 by Lattice Semiconductor Corporation |
philpem@26 | 5 | // ALL RIGHTS RESERVED |
philpem@26 | 6 | // ------------------------------------------------------------------ |
philpem@26 | 7 | // |
philpem@26 | 8 | // IMPORTANT: THIS FILE IS AUTO-GENERATED BY THE LATTICEMICO SYSTEM. |
philpem@26 | 9 | // |
philpem@26 | 10 | // Permission: |
philpem@26 | 11 | // |
philpem@26 | 12 | // Lattice Semiconductor grants permission to use this code |
philpem@26 | 13 | // pursuant to the terms of the Lattice Semiconductor Corporation |
philpem@26 | 14 | // Open Source License Agreement. |
philpem@26 | 15 | // |
philpem@26 | 16 | // Disclaimer: |
philpem@0 | 17 | // |
philpem@26 | 18 | // Lattice Semiconductor provides no warranty regarding the use or |
philpem@26 | 19 | // functionality of this code. It is the user's responsibility to |
philpem@26 | 20 | // verify the user’s design for consistency and functionality through |
philpem@26 | 21 | // the use of formal verification methods. |
philpem@26 | 22 | // |
philpem@26 | 23 | // -------------------------------------------------------------------- |
philpem@26 | 24 | // |
philpem@26 | 25 | // Lattice Semiconductor Corporation |
philpem@26 | 26 | // 5555 NE Moore Court |
philpem@26 | 27 | // Hillsboro, OR 97214 |
philpem@26 | 28 | // U.S.A |
philpem@26 | 29 | // |
philpem@26 | 30 | // TEL: 1-800-Lattice (USA and Canada) |
philpem@26 | 31 | // 503-286-8001 (other locations) |
philpem@26 | 32 | // |
philpem@26 | 33 | // web: http://www.latticesemi.com/ |
philpem@26 | 34 | // email: techsupport@latticesemi.com |
philpem@26 | 35 | // |
philpem@26 | 36 | // -------------------------------------------------------------------- |
philpem@0 | 37 | // FILE DETAILS |
philpem@0 | 38 | // Project : LatticeMico32 |
philpem@0 | 39 | // File : lm32_trace.v |
philpem@0 | 40 | // Title : PC Trace and associated logic. |
philpem@0 | 41 | // Dependencies : lm32_include.v, lm32_functions.v |
philpem@0 | 42 | // Version : 6.1.17 |
philpem@0 | 43 | // : Initial Release |
philpem@0 | 44 | // Version : 7.0SP2, 3.0 |
philpem@0 | 45 | // : No Change |
philpem@0 | 46 | // Version : 3.1 |
philpem@0 | 47 | // : No Change |
philpem@26 | 48 | // Version : 3.7 |
philpem@26 | 49 | // : Removed syntax error. |
philpem@0 | 50 | // ============================================================================= |
philpem@0 | 51 | |
philpem@0 | 52 | `include "lm32_include.v" |
philpem@0 | 53 | `include "system_conf.v" |
philpem@0 | 54 | |
philpem@0 | 55 | `ifdef CFG_TRACE_ENABLED |
philpem@0 | 56 | module lm32_trace( |
philpem@0 | 57 | // ----- Inputs ------- |
philpem@0 | 58 | clk_i, |
philpem@0 | 59 | rst_i, |
philpem@0 | 60 | stb_i, |
philpem@0 | 61 | we_i, |
philpem@0 | 62 | sel_i, |
philpem@0 | 63 | dat_i, |
philpem@0 | 64 | adr_i, |
philpem@0 | 65 | |
philpem@0 | 66 | trace_pc, |
philpem@0 | 67 | trace_eid, |
philpem@0 | 68 | trace_eret, |
philpem@0 | 69 | trace_bret, |
philpem@0 | 70 | trace_pc_valid, |
philpem@0 | 71 | trace_exception, |
philpem@0 | 72 | |
philpem@0 | 73 | // -- outputs |
philpem@0 | 74 | ack_o, |
philpem@0 | 75 | dat_o); |
philpem@0 | 76 | |
philpem@0 | 77 | input clk_i; |
philpem@0 | 78 | input rst_i; |
philpem@0 | 79 | input stb_i; |
philpem@0 | 80 | input we_i; |
philpem@0 | 81 | input [3:0] sel_i; |
philpem@0 | 82 | input [`LM32_WORD_RNG] dat_i; |
philpem@0 | 83 | input [`LM32_WORD_RNG] adr_i; |
philpem@0 | 84 | input [`LM32_PC_RNG] trace_pc; |
philpem@0 | 85 | input [`LM32_EID_RNG] trace_eid; |
philpem@0 | 86 | input trace_eret; |
philpem@0 | 87 | input trace_bret; |
philpem@0 | 88 | input trace_pc_valid; |
philpem@0 | 89 | input trace_exception; |
philpem@0 | 90 | // -- outputs |
philpem@0 | 91 | output ack_o; |
philpem@0 | 92 | output [`LM32_WORD_RNG] dat_o; |
philpem@0 | 93 | reg ovrflw; |
philpem@0 | 94 | |
philpem@0 | 95 | function integer clogb2; |
philpem@0 | 96 | input [31:0] value; |
philpem@0 | 97 | begin |
philpem@0 | 98 | for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1) |
philpem@0 | 99 | value = value >> 1; |
philpem@0 | 100 | end |
philpem@0 | 101 | endfunction |
philpem@0 | 102 | |
philpem@0 | 103 | // instantiate the trace memory |
philpem@0 | 104 | parameter mem_data_width = `LM32_PC_WIDTH; |
philpem@0 | 105 | parameter mem_addr_width = clogb2(`CFG_TRACE_DEPTH-1); |
philpem@0 | 106 | |
philpem@0 | 107 | wire [`LM32_PC_RNG] trace_dat_o; |
philpem@0 | 108 | wire [mem_addr_width-1:0] trace_raddr; |
philpem@0 | 109 | wire [mem_addr_width-1:0] trace_waddr; |
philpem@0 | 110 | reg trace_we; |
philpem@0 | 111 | wire trace_be, trace_last; |
philpem@0 | 112 | wire rw_creg = adr_i[12]; |
philpem@0 | 113 | |
philpem@0 | 114 | lm32_ram #(.data_width (mem_data_width), |
philpem@0 | 115 | .address_width (mem_addr_width)) |
philpem@0 | 116 | trace_mem (.read_clk (clk_i), |
philpem@0 | 117 | .write_clk (clk_i), |
philpem@0 | 118 | .reset (rst_i), |
philpem@0 | 119 | .read_address (adr_i[mem_addr_width+1:2]), |
philpem@0 | 120 | .write_address (trace_waddr), |
philpem@0 | 121 | .enable_read (`TRUE), |
philpem@0 | 122 | .enable_write ((trace_we | trace_be) & trace_pc_valid & !trace_last), |
philpem@0 | 123 | .write_enable (`TRUE), |
philpem@0 | 124 | .write_data (trace_pc), |
philpem@0 | 125 | .read_data (trace_dat_o)); |
philpem@0 | 126 | |
philpem@0 | 127 | // trigger type & stop type |
philpem@0 | 128 | // trig_type [0] = start capture when bret |
philpem@0 | 129 | // trig_type [1] = start capture when eret |
philpem@0 | 130 | // trig_type [2] = start capture when PC within a range |
philpem@0 | 131 | // trig_type [3] = start when an exception happens (other than breakpoint) |
philpem@0 | 132 | // trig_type [4] = start when a breakpoint exception happens |
philpem@0 | 133 | |
philpem@0 | 134 | |
philpem@0 | 135 | reg [4:0] trig_type; // at address 0 |
philpem@0 | 136 | reg [4:0] stop_type; // at address 16 |
philpem@0 | 137 | reg [`LM32_WORD_RNG] trace_len; // at address 4 |
philpem@0 | 138 | reg [`LM32_WORD_RNG] pc_low; // at address 8 |
philpem@0 | 139 | reg [`LM32_WORD_RNG] pc_high; // at address 12 |
philpem@0 | 140 | reg trace_start,trace_stop; |
philpem@0 | 141 | reg ack_o; |
philpem@0 | 142 | reg mem_valid; |
philpem@0 | 143 | reg [`LM32_WORD_RNG] reg_dat_o; |
philpem@0 | 144 | reg started; |
philpem@0 | 145 | reg capturing; |
philpem@0 | 146 | assign dat_o = (rw_creg ? reg_dat_o : trace_dat_o); |
philpem@0 | 147 | |
philpem@0 | 148 | initial begin |
philpem@27 | 149 | trig_type <= 0; |
philpem@27 | 150 | stop_type <= 0; |
philpem@27 | 151 | trace_len <= 0; |
philpem@27 | 152 | pc_low <= 0; |
philpem@27 | 153 | pc_high <= 0; |
philpem@27 | 154 | trace_start <= 0; |
philpem@27 | 155 | trace_stop <= 0; |
philpem@27 | 156 | ack_o <= 0; |
philpem@27 | 157 | reg_dat_o <= 0; |
philpem@27 | 158 | mem_valid <= 0; |
philpem@27 | 159 | started <= 0; |
philpem@27 | 160 | capturing <= 0; |
philpem@0 | 161 | end |
philpem@0 | 162 | |
philpem@0 | 163 | // the host side control |
philpem@0 | 164 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 165 | begin |
philpem@0 | 166 | if (rst_i == `TRUE) begin |
philpem@27 | 167 | trig_type <= 0; |
philpem@27 | 168 | trace_stop <= 0; |
philpem@27 | 169 | trace_start <= 0; |
philpem@27 | 170 | pc_low <= 0; |
philpem@27 | 171 | pc_high <= 0; |
philpem@27 | 172 | ack_o <= 0; |
philpem@0 | 173 | end else begin |
philpem@0 | 174 | if (stb_i == `TRUE && ack_o == `FALSE) begin |
philpem@0 | 175 | if (rw_creg) begin // control register access |
philpem@27 | 176 | ack_o <= `TRUE; |
philpem@0 | 177 | if (we_i == `TRUE) begin |
philpem@0 | 178 | case ({adr_i[11:2],2'b0}) |
philpem@0 | 179 | // write to trig type |
philpem@0 | 180 | 12'd0: |
philpem@0 | 181 | begin |
philpem@0 | 182 | if (sel_i[0]) begin |
philpem@27 | 183 | trig_type[4:0] <= dat_i[4:0]; |
philpem@0 | 184 | end |
philpem@0 | 185 | if (sel_i[3]) begin |
philpem@27 | 186 | trace_start <= dat_i[31]; |
philpem@27 | 187 | trace_stop <= dat_i[30]; |
philpem@0 | 188 | end |
philpem@0 | 189 | end |
philpem@0 | 190 | 12'd8: |
philpem@0 | 191 | begin |
philpem@27 | 192 | if (sel_i[3]) pc_low[31:24] <= dat_i[31:24]; |
philpem@27 | 193 | if (sel_i[2]) pc_low[23:16] <= dat_i[23:16]; |
philpem@27 | 194 | if (sel_i[1]) pc_low[15:8] <= dat_i[15:8]; |
philpem@27 | 195 | if (sel_i[0]) pc_low[7:0] <= dat_i[7:0]; |
philpem@0 | 196 | end |
philpem@0 | 197 | 12'd12: |
philpem@0 | 198 | begin |
philpem@27 | 199 | if (sel_i[3]) pc_high[31:24] <= dat_i[31:24]; |
philpem@27 | 200 | if (sel_i[2]) pc_high[23:16] <= dat_i[23:16]; |
philpem@27 | 201 | if (sel_i[1]) pc_high[15:8] <= dat_i[15:8]; |
philpem@27 | 202 | if (sel_i[0]) pc_high[7:0] <= dat_i[7:0]; |
philpem@0 | 203 | end |
philpem@0 | 204 | 12'd16: |
philpem@0 | 205 | begin |
philpem@0 | 206 | if (sel_i[0])begin |
philpem@27 | 207 | stop_type[4:0] <= dat_i[4:0]; |
philpem@0 | 208 | end |
philpem@0 | 209 | end |
philpem@0 | 210 | endcase |
philpem@0 | 211 | end else begin // read control registers |
philpem@0 | 212 | case ({adr_i[11:2],2'b0}) |
philpem@0 | 213 | // read the trig type |
philpem@0 | 214 | 12'd0: |
philpem@27 | 215 | reg_dat_o <= {22'b1,capturing,mem_valid,ovrflw,trace_we,started,trig_type}; |
philpem@0 | 216 | 12'd4: |
philpem@27 | 217 | reg_dat_o <= trace_len; |
philpem@0 | 218 | 12'd8: |
philpem@27 | 219 | reg_dat_o <= pc_low; |
philpem@0 | 220 | 12'd12: |
philpem@27 | 221 | reg_dat_o <= pc_high; |
philpem@0 | 222 | default: |
philpem@27 | 223 | reg_dat_o <= {27'b0,stop_type}; |
philpem@0 | 224 | endcase |
philpem@0 | 225 | end // else: !if(we_i == `TRUE) |
philpem@0 | 226 | end else // read / write memory |
philpem@0 | 227 | if (we_i == `FALSE) begin |
philpem@27 | 228 | ack_o <= `TRUE; |
philpem@0 | 229 | end else |
philpem@27 | 230 | ack_o <= `FALSE; |
philpem@0 | 231 | // not allowed to write to trace memory |
philpem@0 | 232 | end else begin // if (stb_i == `TRUE) |
philpem@27 | 233 | trace_start <= `FALSE; |
philpem@27 | 234 | trace_stop <= `FALSE; |
philpem@27 | 235 | ack_o <= `FALSE; |
philpem@0 | 236 | end // else: !if(stb_i == `TRUE) |
philpem@0 | 237 | end // else: !if(rst_i == `TRUE) |
philpem@0 | 238 | end |
philpem@0 | 239 | |
philpem@0 | 240 | wire [`LM32_WORD_RNG] trace_pc_tmp = {trace_pc,2'b0}; |
philpem@0 | 241 | |
philpem@0 | 242 | // trace state machine |
philpem@0 | 243 | reg [2:0] tstate; |
philpem@0 | 244 | wire pc_in_range = {trace_pc,2'b0} >= pc_low && |
philpem@0 | 245 | {trace_pc,2'b0} <= pc_high; |
philpem@0 | 246 | |
philpem@0 | 247 | assign trace_waddr = trace_len[mem_addr_width-1:0]; |
philpem@0 | 248 | |
philpem@0 | 249 | wire trace_begin = ((trig_type[0] & trace_bret) || |
philpem@0 | 250 | (trig_type[1] & trace_eret) || |
philpem@0 | 251 | (trig_type[2] & pc_in_range & trace_pc_valid) || |
philpem@0 | 252 | (trig_type[3] & trace_exception & (trace_eid != `LM32_EID_BREAKPOINT)) || |
philpem@0 | 253 | (trig_type[4] & trace_exception & (trace_eid == `LM32_EID_BREAKPOINT)) |
philpem@0 | 254 | ); |
philpem@0 | 255 | |
philpem@0 | 256 | |
philpem@0 | 257 | wire trace_end = (trace_stop || |
philpem@0 | 258 | (stop_type[0] & trace_bret) || |
philpem@0 | 259 | (stop_type[1] & trace_eret) || |
philpem@0 | 260 | (stop_type[2] & !pc_in_range & trace_pc_valid) || |
philpem@0 | 261 | (stop_type[3] & trace_exception & (trace_eid != `LM32_EID_BREAKPOINT)) || |
philpem@0 | 262 | (stop_type[4] & trace_exception & (trace_eid == `LM32_EID_BREAKPOINT)) |
philpem@0 | 263 | ); |
philpem@0 | 264 | |
philpem@0 | 265 | assign trace_be = (trace_begin & (tstate == 3'd1)); |
philpem@0 | 266 | assign trace_last = (trace_stop & (tstate == 3'd2)); |
philpem@0 | 267 | |
philpem@0 | 268 | always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
philpem@0 | 269 | begin |
philpem@0 | 270 | if (rst_i == `TRUE) begin |
philpem@27 | 271 | tstate <= 0; |
philpem@27 | 272 | trace_we <= 0; |
philpem@27 | 273 | trace_len <= 0; |
philpem@27 | 274 | ovrflw <= `FALSE; |
philpem@27 | 275 | mem_valid <= 0; |
philpem@27 | 276 | started <= 0; |
philpem@27 | 277 | capturing <= 0; |
philpem@0 | 278 | end else begin |
philpem@0 | 279 | case (tstate) |
philpem@0 | 280 | 3'd0: |
philpem@0 | 281 | // start capture |
philpem@0 | 282 | if (trace_start) begin |
philpem@27 | 283 | tstate <= 3'd1; |
philpem@27 | 284 | mem_valid <= 0; |
philpem@27 | 285 | started <= 1; |
philpem@0 | 286 | end |
philpem@0 | 287 | 3'd1: |
philpem@0 | 288 | begin |
philpem@0 | 289 | // wait for trigger |
philpem@0 | 290 | if (trace_begin) begin |
philpem@27 | 291 | capturing <= 1; |
philpem@27 | 292 | tstate <= 3'd2; |
philpem@27 | 293 | trace_we <= `TRUE; |
philpem@27 | 294 | trace_len <= 0; |
philpem@27 | 295 | ovrflw <= `FALSE; |
philpem@0 | 296 | end |
philpem@0 | 297 | end // case: 3'd1 |
philpem@0 | 298 | |
philpem@0 | 299 | 3'd2: |
philpem@0 | 300 | begin |
philpem@0 | 301 | if (trace_pc_valid) begin |
philpem@0 | 302 | if (trace_len[mem_addr_width]) |
philpem@27 | 303 | trace_len <= 0; |
philpem@0 | 304 | else |
philpem@27 | 305 | trace_len <= trace_len + 1; |
philpem@0 | 306 | end |
philpem@27 | 307 | if (!ovrflw) ovrflw <= trace_len[mem_addr_width]; |
philpem@0 | 308 | // wait for stop condition |
philpem@0 | 309 | if (trace_end) begin |
philpem@27 | 310 | tstate <= 3'd0; |
philpem@27 | 311 | trace_we <= 0; |
philpem@27 | 312 | mem_valid <= 1; |
philpem@27 | 313 | started <= 0; |
philpem@27 | 314 | capturing <= 0; |
philpem@0 | 315 | end |
philpem@0 | 316 | end // case: 3'd2 |
philpem@0 | 317 | endcase |
philpem@0 | 318 | end // else: !if(rst_i == `TRUE) |
philpem@0 | 319 | end |
philpem@0 | 320 | endmodule |
philpem@0 | 321 | `endif |