📄 cam.v
字号:
`include "definitions.v"module cam(cam_write_en_q1, cam_lsb_addr_q1, cam_msb_addr_s1, cam_dec_addr_q1, cam_true_in_s1, cam_false_in_s1, cam_true_out_v1, cam_false_out_v1, match_v1, reset_s1, phi1, phi2); input cam_write_en_q1; input [3:0] cam_lsb_addr_q1; // pre-decoded lsb's gated with phi1 input [4:0] cam_msb_addr_s1; // pre-decoded msb's output [19:0] cam_dec_addr_q1; // fully decoded address input [16:0] cam_true_in_s1; // [16] is occupancy bit input [14:0] cam_false_in_s1; // [14:0] of data can be masked output [19:0] match_v1; // CHANGE: jkassoff, 2/8/01 // making cam_data_v1 and cam_mask_v1 inputs, adding // outputs cam_data_s1, cam_mask_s1 output [16:0] cam_true_out_v1; // [16] is occupancy bit output [14:0] cam_false_out_v1; // [14:0] of data masked input reset_s1; input phi1; input phi2; reg [4:0] cam_decode_q1; reg [16:0] cam_data_storage_v1[19:0]; reg [14:0] cam_mask_storage_v1[19:0]; // will store like normal mask bits, meaning it doesn't mimic how the chip // will work with true/false bits (this gets tricky, because input and // output of data and mask is in true and false bit format) reg [16:0] cam_true_out_v1; reg [14:0] cam_false_out_v1; // reg for assignment inside always block reg [19:0] match_v1; // these are just counting variables, for my loops reg [31:0] i_v1; reg [31:0] j_v1; // act like the bit line driver reg [16:0] cam_true_in_v1; reg [14:0] cam_false_in_v1; always @ (phi2 or cam_write_en_q1 or cam_true_in_s1 or cam_false_in_s1) begin if (phi2) begin cam_true_in_v1 = 17'h1fff; cam_false_in_v1 = 15'h7fff; end else if (cam_write_en_q1) begin cam_true_in_v1 = cam_true_in_s1; cam_false_in_v1 = cam_false_in_s1; end end // complete the decoding for cam_dec_addr_q1 wire [19:0] cam_dec_addr_q1; assign cam_dec_addr_q1[0] = cam_msb_addr_s1[0] & cam_lsb_addr_q1[0]; assign cam_dec_addr_q1[1] = cam_msb_addr_s1[0] & cam_lsb_addr_q1[1]; assign cam_dec_addr_q1[2] = cam_msb_addr_s1[0] & cam_lsb_addr_q1[2]; assign cam_dec_addr_q1[3] = cam_msb_addr_s1[0] & cam_lsb_addr_q1[3]; assign cam_dec_addr_q1[4] = cam_msb_addr_s1[1] & cam_lsb_addr_q1[0]; assign cam_dec_addr_q1[5] = cam_msb_addr_s1[1] & cam_lsb_addr_q1[1]; assign cam_dec_addr_q1[6] = cam_msb_addr_s1[1] & cam_lsb_addr_q1[2]; assign cam_dec_addr_q1[7] = cam_msb_addr_s1[1] & cam_lsb_addr_q1[3]; assign cam_dec_addr_q1[8] = cam_msb_addr_s1[2] & cam_lsb_addr_q1[0]; assign cam_dec_addr_q1[9] = cam_msb_addr_s1[2] & cam_lsb_addr_q1[1]; assign cam_dec_addr_q1[10] = cam_msb_addr_s1[2] & cam_lsb_addr_q1[2]; assign cam_dec_addr_q1[11] = cam_msb_addr_s1[2] & cam_lsb_addr_q1[3]; assign cam_dec_addr_q1[12] = cam_msb_addr_s1[3] & cam_lsb_addr_q1[0]; assign cam_dec_addr_q1[13] = cam_msb_addr_s1[3] & cam_lsb_addr_q1[1]; assign cam_dec_addr_q1[14] = cam_msb_addr_s1[3] & cam_lsb_addr_q1[2]; assign cam_dec_addr_q1[15] = cam_msb_addr_s1[3] & cam_lsb_addr_q1[3]; assign cam_dec_addr_q1[16] = cam_msb_addr_s1[4] & cam_lsb_addr_q1[0]; assign cam_dec_addr_q1[17] = cam_msb_addr_s1[4] & cam_lsb_addr_q1[1]; assign cam_dec_addr_q1[18] = cam_msb_addr_s1[4] & cam_lsb_addr_q1[2]; assign cam_dec_addr_q1[19] = cam_msb_addr_s1[4] & cam_lsb_addr_q1[3]; // variables for keeping track of what we're doing // if no_wordlines_q1 is true, then we're either resetting or searching // depending on the value of reset_s1 wire no_wordlines_q1; assign no_wordlines_q1 = (cam_dec_addr_q1 == 20'h00000) ? 1'b1 : 1'b0; // interpret the word lines (cam_dec_addr_q1) always @ (cam_dec_addr_q1) begin case (cam_dec_addr_q1) 20'h00001: cam_decode_q1 = 0; 20'h00002: cam_decode_q1 = 1; 20'h00004: cam_decode_q1 = 2; 20'h00008: cam_decode_q1 = 3; 20'h00010: cam_decode_q1 = 4; 20'h00020: cam_decode_q1 = 5; 20'h00040: cam_decode_q1 = 6; 20'h00080: cam_decode_q1 = 7; 20'h00100: cam_decode_q1 = 8; 20'h00200: cam_decode_q1 = 9; 20'h00400: cam_decode_q1 = 10; 20'h00800: cam_decode_q1 = 11; 20'h01000: cam_decode_q1 = 12; 20'h02000: cam_decode_q1 = 13; 20'h04000: cam_decode_q1 = 14; 20'h08000: cam_decode_q1 = 15; 20'h10000: cam_decode_q1 = 16; 20'h20000: cam_decode_q1 = 17; 20'h40000: cam_decode_q1 = 18; 20'h80000: cam_decode_q1 = 19; // case 20'h00000 is recorded in variable no_wordlines_q1 20'h00000: cam_decode_q1 = `CAM_SIZE; // This should never happen default: ;//$display("ERROR: cam address decoding in cam.v at %d", $time); endcase end // writing the cam always @ (phi1 or cam_decode_q1 or cam_true_in_v1 or cam_false_in_v1 or cam_write_en_q1 or no_wordlines_q1 or reset_s1) // or i_v1 begin if (phi1) begin if (cam_write_en_q1 == 1'b1) begin // writing addr if (cam_decode_q1 < `CAM_SIZE) begin // write a single address // remember, stored as normal data and mask bits. // so mask bit is NOR of incoming true and false bits // because only if both are 0 is it a 1 cam_data_storage_v1[cam_decode_q1] = cam_true_in_v1; cam_mask_storage_v1[cam_decode_q1] = ~cam_true_in_v1[14:0] & ~cam_false_in_v1[14:0]; end // Note: this structure requires cam_write_en_q1 to be set // for RESET to work else if (reset_s1 && no_wordlines_q1) begin // access all addresses // loop through and write all addr for (i_v1 = 0; i_v1 < `CAM_SIZE; i_v1 = i_v1 + 1) begin //cam_data_storage_v1[i_v1][16] = 0; // reset valid bit // the above is what I want to do cam_data_storage_v1[i_v1] = {1'b0, cam_true_in_v1[15:0]}; // so instead I take advantage of the fact that the // [15:0] bits are unimportant in this case end end else if (reset_s1) begin $display("ERROR: reset didn't have all wordlines off at time %d", $time); end // don't need to do anything for search mode // which is what we assume we're doing if ~reset_s1 & no_wordlines_q1 end // write check end // if phi1 check end // end of always block // reading the cam always @ (cam_write_en_q1 or cam_decode_q1 or no_wordlines_q1 or cam_true_in_v1 or cam_false_in_v1 or phi1 or cam_true_out_v1) // or cam_data_storage_v1 or cam_mask_storage_v1 begin // if we are writing, then outputs will be whatever is written in if (cam_write_en_q1 == 1'b1) begin cam_true_out_v1 = cam_true_in_v1; cam_false_out_v1 = cam_false_in_v1; end // else if we have no wordlines selected (searching, resetting), // then outputs will be precharged high, then inverted low else if (no_wordlines_q1) begin cam_true_out_v1 = 17'h00000; cam_false_out_v1 = 15'h0000; end else begin // adding this 'if' statement to make data change only on rising // edge of cam_decode_q1 (rising edge of phi1) if (phi1) begin // we are doing a read, so need to set outputs appropriately // ouch, this is ugly. the order is important, because // cam_true_out_v1 is used as an intermediate variable for the // first two lines, to get around 2D indexing problems cam_true_out_v1 = cam_data_storage_v1[cam_decode_q1]; cam_false_out_v1 = ~cam_mask_storage_v1[cam_decode_q1] & ~cam_true_out_v1[14:0]; cam_true_out_v1[14:0] = ~cam_mask_storage_v1[cam_decode_q1] & cam_true_out_v1[14:0]; end end end reg [16:0] temp_v1; // searching the cam always @ (phi1 or phi2 or cam_decode_q1 or cam_write_en_q1 or /*i_v1 or j_v1 or*/ cam_true_in_v1 or no_wordlines_q1 or reset_s1 or temp_v1) // or cam_data_storage_v1 or cam_mask_storage_v1 begin // pre-discharge match lines if (phi2) begin match_v1 = 20'h00000; end // check for match during a valid search if (phi1) begin // Note: the write_en signal will be high because the bit lines are // driven by the controller. doesn't mean we should do any writing// always update match lines, since HW will do so // if (cam_write_en_q1 == 1'b1 && no_wordlines_q1 && ~reset_s1) // begin // we output all matches, priority selector will deal with them for (i_v1 = 0; i_v1 < `CAM_SIZE; i_v1 = i_v1+1) begin match_v1[i_v1] = 1; // start by assuming match// change to using cam_true_out_v1 so match line behavior matches reality if (~cam_write_en_q1 && no_wordlines_q1) begin temp_v1[16:0] = ~(cam_data_storage_v1[i_v1] ^ 17'h1fff); end else begin temp_v1[16:0] = ~(cam_data_storage_v1[i_v1] ^ cam_true_out_v1); end if (temp_v1[16]) begin // now MSB, which has no mask if (temp_v1[15] == 0) // if top bit doesn't match match_v1[i_v1] = 0; // now the occupied bit, which is at [16] if (temp_v1[16] == 0) // if valid bit doesn't match match_v1[i_v1] = 0; // mimic the change above if (~cam_write_en_q1 && no_wordlines_q1) begin temp_v1[14:0] = (~(cam_data_storage_v1[i_v1] ^ 17'h1fff)) | cam_mask_storage_v1[i_v1]; end else begin temp_v1[14:0] = (~(cam_data_storage_v1[i_v1] ^ cam_true_in_v1)) | cam_mask_storage_v1[i_v1]; end // dat dere used to be a bug-- was re-assignin' match_v1 // unconditionally overridin' our previous calkeelayshuns... // the only allowed change is to set match_v1 to zero if (&(temp_v1[14:0]) == 0) match_v1[i_v1] = 0; end else begin match_v1[i_v1] = 0; end // if match_v1[i_v1] came out of this still a 1, // then this word matched end // for loop through 20 addresses // end // if check end // if (phi1) end // always block endmodule // cam
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -