lm32_trace.v

Sun, 04 Apr 2010 20:52:32 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 04 Apr 2010 20:52:32 +0100
changeset 2
a61bb364ae1f
parent 0
cd0b58aa6f83
child 26
73de224304c1
permissions
-rw-r--r--

Disable Lattice-specific stuff by default

To build on Lattice platforms, `define PLATFORM_LATTICE in lm32_include.v.
Otherwise, non-optimal "platform independent" HDL will be used.
This means LM32 can now be built for non-Lattice FPGAs.

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