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