URL
https://opencores.org/ocsvn/m1_core/m1_core/trunk
Subversion Repositories m1_core
[/] [m1_core/] [trunk/] [hdl/] [rtl/] [wb_ddr_ctrl/] [wb_ddr.v] - Rev 54
Compare with Previous | Blame | View Log
//---------------------------------------------------------------------------- // Wishbone DDR Controller // // (c) Joerg Bornschein (<jb@capsec.org>) //---------------------------------------------------------------------------- `include "ddr_include.v" module wb_ddr #( parameter phase_shift = 0, parameter clk_multiply = 12, parameter clk_divide = 5, parameter wait200_init = 26 ) ( input clk, input reset, // XXX -- DCM phase control -- XXX input [2:0] rot, // DDR ports output ddr_clk, output ddr_clk_n, input ddr_clk_fb, output ddr_ras_n, output ddr_cas_n, output ddr_we_n, output ddr_cke, output ddr_cs_n, output [ `A_RNG] ddr_a, output [ `BA_RNG] ddr_ba, inout [ `DQ_RNG] ddr_dq, inout [`DQS_RNG] ddr_dqs, output [ `DM_RNG] ddr_dm, // Wishbone Slave Interface input [`WB_ADR_RNG] wb_adr_i, input [`WB_DAT_RNG] wb_dat_i, output reg [`WB_DAT_RNG] wb_dat_o, input [`WB_SEL_RNG] wb_sel_i, input wb_cyc_i, input wb_stb_i, input wb_we_i, output reg wb_ack_o ); //---------------------------------------------------------------------------- // Wishbone handling //---------------------------------------------------------------------------- wire wb_rd = wb_stb_i & wb_cyc_i & ~wb_we_i; wire wb_wr = wb_stb_i & wb_cyc_i & wb_we_i; wire [`WB_WORD_RNG] wb_adr_word = wb_adr_i[`WB_WORD_RNG]; // word in bufferline wire [`WB_SET_RNG] wb_adr_set = wb_adr_i[`WB_SET_RNG]; // index into wayX_ram wire [`WB_TAG_RNG] wb_adr_tag = wb_adr_i[`WB_TAG_RNG]; // more significant bits //---------------------------------------------------------------------------- // TAG RAM (2-way set assioziative) //---------------------------------------------------------------------------- wire [`TAG_LINE_RNG] tag_load; wire [`TAG_LINE_RNG] tag_store; wire tag_we; wire [`WB_TAG_RNG] tag_load_set0 = tag_load[`TAG_LINE_TAG0_RNG]; wire [`WB_TAG_RNG] tag_load_set1 = tag_load[`TAG_LINE_TAG1_RNG]; wire tag_load_dirty0 = tag_load[`TAG_LINE_DIRTY0_RNG]; wire tag_load_dirty1 = tag_load[`TAG_LINE_DIRTY1_RNG]; wire tag_load_lru = tag_load[`TAG_LINE_LRU_RNG]; reg [`WB_TAG_RNG] tag_store_set0; reg [`WB_TAG_RNG] tag_store_set1; reg tag_store_dirty0; reg tag_store_dirty1; reg tag_store_lru; assign tag_store[`TAG_LINE_TAG0_RNG] = tag_store_set0; assign tag_store[`TAG_LINE_TAG1_RNG] = tag_store_set1; assign tag_store[`TAG_LINE_DIRTY0_RNG] = tag_store_dirty0; assign tag_store[`TAG_LINE_DIRTY1_RNG] = tag_store_dirty1; assign tag_store[`TAG_LINE_LRU_RNG] = tag_store_lru; wire [`WB_SET_RNG] ls_tag_adr; wire [`TAG_LINE_RNG] ls_tag_load; reg [`TAG_LINE_RNG] ls_tag_store; reg ls_tag_we; dpram #( .adr_width( 7 ), .dat_width( 33 ) ) tag_ram ( .clk ( clk ), // .adr0( wb_adr_set ), .dout0( tag_load ), .din0( tag_store ), .we0( tag_we ), // .adr1( ls_tag_adr ), .dout1( ls_tag_load ), .din1( ls_tag_store ), .we1( ls_tag_we ) ); wire tag_load_match0 = (tag_load_set0 == wb_adr_tag); wire tag_load_match1 = (tag_load_set1 == wb_adr_tag); wire tag_load_match = tag_load_match0 | tag_load_match1; //---------------------------------------------------------------------------- // Buffer cache ram (2 ways) //---------------------------------------------------------------------------- wire [8:0] wayX_adr = { wb_adr_set, wb_adr_word }; wire [`WAY_LINE_RNG] way0_load, way1_load; wire [`WAY_LINE_RNG] wayX_store; wire [31:0] way0_load_dat = way0_load[`WAY_DAT_RNG]; wire [31:0] way1_load_dat = way1_load[`WAY_DAT_RNG]; wire [3:0] way0_load_valid = way0_load[`WAY_VALID_RNG]; wire [3:0] way1_load_valid = way1_load[`WAY_VALID_RNG]; wire way0_we; wire way1_we; reg [31:0] wayX_store_dat; reg [3:0] wayX_store_valid; assign wayX_store[`WAY_DAT_RNG] = wayX_store_dat; assign wayX_store[`WAY_VALID_RNG] = wayX_store_valid; wire [8:0] ls_wayX_adr; wire [`WAY_LINE_RNG] ls_way0_load; wire [`WAY_LINE_RNG] ls_way1_load; wire [`WAY_LINE_RNG] ls_wayX_store; wire ls_way0_we; wire ls_way1_we; reg ls_wayX_we; wire way0_sel_valid = ( (~way0_load_valid & wb_sel_i) == 'b0); wire way1_sel_valid = ( (~way1_load_valid & wb_sel_i) == 'b0); wire wayX_sel_valid = (tag_load_match0) ? way0_sel_valid : way1_sel_valid; // synthesis attribute ram_style of way0_ram is block dpram #( .adr_width( 9 ), .dat_width( 36 ) ) way0_ram ( .clk( clk ), // .adr0( wayX_adr ), .dout0( way0_load ), .din0( wayX_store ), .we0( way0_we ), // .adr1( ls_wayX_adr ), .dout1( ls_way0_load ), .we1( ls_way0_we ), .din1( ls_wayX_store ) ); // synthesis attribute ram_style of way1_ram is block dpram #( .adr_width( 9 ), .dat_width( 36 ) ) way1_ram ( .clk( clk ), // .adr0( wayX_adr ), .dout0( way1_load ), .din0( wayX_store ), .we0( way1_we ), // .adr1( ls_wayX_adr ), .dout1( ls_way1_load ), .we1( ls_way1_we ), .din1( ls_wayX_store ) ); //---------------------------------------------------------------------------- // Write/update buffer cache from wishbone side //---------------------------------------------------------------------------- wire store_to_way0 = tag_load_lru & ~tag_load_dirty0; // store new data into way0? XXX spill_done XXX wire store_to_way1 = ~tag_load_lru & ~tag_load_dirty1; // store new data into way1? XXX spill_done XXX wire store_to_way = store_to_way0 | store_to_way1; reg update_lru0; // reg update_lru1; reg update_way0; // reg update_way1; assign way0_we = update_way0; assign way1_we = update_way1; assign tag_we = way0_we | way1_we | update_lru0 | update_lru1; //---------------------------------------------------------------------------- // MUX wayX_store input //---------------------------------------------------------------------------- integer i; always @(*) begin /* for(i=0; i<4; i=i+1) begin if (wb_sel_i[i]) begin wayX_store_dat[8*i+7:8*i] = wb_dat_i[8*i+7:8*i]; wayX_store_valid[i] = 1; end else if (update_way0) begin wayX_store_dat[8*i+7:8*i] = way0_load_dat[8*i+7:8*i]; wayX_store_valid[i] = way0_load_valid[i]; end else begin wayX_store_dat[8*i+7:8*i] = way1_load_dat[8*i+7:8*i]; wayX_store_valid[i] = way1_load_valid[i]; end end */ if (wb_sel_i[0]) begin wayX_store_dat[8*0+7:8*0] = wb_dat_i[8*0+7:8*0]; wayX_store_valid[0] = 1; end else if (update_way0) begin wayX_store_dat[8*0+7:8*0] = way0_load_dat[8*0+7:8*0]; wayX_store_valid[0] = way0_load_valid[0]; end else begin wayX_store_dat[8*0+7:8*0] = way1_load_dat[8*0+7:8*0]; wayX_store_valid[0] = way1_load_valid[0]; end if (wb_sel_i[1]) begin wayX_store_dat[8*1+7:8*1] = wb_dat_i[8*1+7:8*1]; wayX_store_valid[1] = 1; end else if (update_way0) begin wayX_store_dat[8*1+7:8*1] = way0_load_dat[8*1+7:8*1]; wayX_store_valid[1] = way0_load_valid[1]; end else begin wayX_store_dat[8*1+7:8*1] = way1_load_dat[8*1+7:8*1]; wayX_store_valid[1] = way1_load_valid[1]; end if (wb_sel_i[2]) begin wayX_store_dat[8*2+7:8*2] = wb_dat_i[8*2+7:8*2]; wayX_store_valid[2] = 1; end else if (update_way0) begin wayX_store_dat[8*2+7:8*2] = way0_load_dat[8*2+7:8*2]; wayX_store_valid[2] = way0_load_valid[2]; end else begin wayX_store_dat[8*2+7:8*2] = way1_load_dat[8*2+7:8*2]; wayX_store_valid[2] = way1_load_valid[2]; end if (wb_sel_i[3]) begin wayX_store_dat[8*3+7:8*3] = wb_dat_i[8*3+7:8*3]; wayX_store_valid[3] = 1; end else if (update_way0) begin wayX_store_dat[8*3+7:8*3] = way0_load_dat[8*3+7:8*3]; wayX_store_valid[3] = way0_load_valid[3]; end else begin wayX_store_dat[8*3+7:8*3] = way1_load_dat[8*3+7:8*3]; wayX_store_valid[3] = way1_load_valid[3]; end end always @(*) begin if (update_way0) begin tag_store_set0 = wb_adr_tag; tag_store_dirty0 = 1; end else begin tag_store_set0 = tag_load_set0; tag_store_dirty0 = tag_load_dirty0; end if (update_way1) begin tag_store_set1 = wb_adr_tag; tag_store_dirty1 = 1; end else begin tag_store_set1 = tag_load_set1; tag_store_dirty1 = tag_load_dirty1; end if (update_lru0) tag_store_lru = 0; else if (update_lru1) tag_store_lru = 1; else tag_store_lru = tag_load_lru; end //---------------------------------------------------------------------------- // Wishbone FSM //---------------------------------------------------------------------------- reg ls_fill; reg ls_spill; reg ls_way; wire ls_busy; reg [`WB_TAG_RNG] ls_adr_tag; reg [`WB_SET_RNG] ls_adr_set; reg [`WB_WORD_RNG] ls_adr_word; reg [2:0] state; parameter s_idle = 0; parameter s_read = 1; parameter s_rspill = 2; parameter s_rfill = 3; parameter s_write = 4; parameter s_wspill = 5; // Syncronous part of FSM always @(posedge clk) begin if (reset) begin state <= s_idle; ls_spill <= 0; ls_fill <= 0; ls_way <= 0; end else begin ls_fill <= 0; ls_spill <= 0; case (state) s_idle: begin if (wb_rd) state <= s_read; if (wb_wr) state <= s_write; end s_read: begin if ((tag_load_match0 & way0_sel_valid) | (tag_load_match1 & way1_sel_valid)) begin state <= s_idle; end else if (store_to_way & ~ls_busy) begin state <= s_rfill; ls_fill <= 1; ls_way <= ~tag_load_lru; ls_adr_tag <= wb_adr_tag; ls_adr_set <= wb_adr_set; end else if (~ls_busy) begin state <= s_rspill; ls_spill <= 1; ls_way <= ~tag_load_lru; ls_adr_set <= wb_adr_set; if (tag_load_lru == 1) ls_adr_tag <= tag_load_set0; else ls_adr_tag <= tag_load_set1; end end s_rspill: begin if (~ls_busy) begin state <= s_rfill; ls_fill <= 1; ls_way <= ~tag_load_lru; ls_adr_tag <= wb_adr_tag; ls_adr_set <= wb_adr_set; end end s_rfill: begin if (tag_load_match & wayX_sel_valid) state <= s_idle; end s_write: begin if (tag_load_match | store_to_way) begin state <= s_idle; end else if (~ls_busy) begin state <= s_wspill; ls_spill <= 1; ls_way <= ~tag_load_lru; ls_adr_set <= wb_adr_set; if (tag_load_lru == 1) ls_adr_tag <= tag_load_set0; else ls_adr_tag <= tag_load_set1; end end s_wspill: begin if (tag_load_match | store_to_way) begin state <= s_idle; end end default: state <= s_idle; endcase end end // Asyncronous part of FSM always @(*) begin update_lru0 <= 0; update_lru1 <= 0; update_way0 <= 0; update_way1 <= 0; wb_dat_o <= 0; wb_ack_o <= 0; case (state) s_idle: begin end s_read: begin if (tag_load_match0 & way0_sel_valid) begin update_lru0 <= 1; wb_dat_o <= way0_load_dat; wb_ack_o <= 1; end else if (tag_load_match1 & way1_sel_valid) begin update_lru1 <= 1; wb_dat_o <= way1_load_dat; wb_ack_o <= 1; end end s_write: begin if (tag_load_match0 | store_to_way0) begin update_lru0 <= 1; update_way0 <= 1; wb_ack_o <= 1; end else if (tag_load_match1 | store_to_way1) begin update_lru1 <= 1; update_way1 <= 1; wb_ack_o <= 1; end end endcase end //---------------------------------------------------------------------------- // DDR Controller Engine (including clkgen, [rw]-path) //---------------------------------------------------------------------------- reg fml_rd; reg fml_wr; wire fml_done; wire [`FML_ADR_RNG] fml_adr; wire [`FML_DAT_RNG] fml_wdat; wire [`FML_BE_RNG] fml_wbe; reg fml_wnext; reg fml_wnext2; wire fml_rempty; reg fml_rnext; wire [`FML_DAT_RNG] fml_rdat; ddr_ctrl #( .phase_shift( phase_shift ), .clk_multiply( clk_multiply ), .clk_divide( clk_divide ), .wait200_init( wait200_init ) ) ctrl0 ( .clk( clk ), .reset( reset ), .rot( rot ), // DDR Ports .ddr_clk( ddr_clk ), .ddr_clk_n( ddr_clk_n ), .ddr_clk_fb( ddr_clk_fb ), .ddr_ras_n( ddr_ras_n ), .ddr_cas_n( ddr_cas_n ), .ddr_we_n( ddr_we_n ), .ddr_cke( ddr_cke ), .ddr_cs_n( ddr_cs_n ), .ddr_a( ddr_a ), .ddr_ba( ddr_ba ), .ddr_dq( ddr_dq ), .ddr_dqs( ddr_dqs ), .ddr_dm( ddr_dm ), // FML (FastMemoryLink) .fml_rd( fml_rd ), .fml_wr( fml_wr ), .fml_done( fml_done ), .fml_adr( fml_adr ), .fml_wdat( fml_wdat ), .fml_wbe( fml_wbe ), .fml_wnext( fml_wnext2 ), .fml_rempty( fml_rempty ), .fml_rdat( fml_rdat ), .fml_rnext( fml_rnext ) ); assign fml_adr = { ls_adr_tag, ls_adr_set }; assign fml_wdat = (ls_way) ? ls_way1_load[`WAY_DAT_RNG] : ls_way0_load[`WAY_DAT_RNG]; assign fml_wbe = (ls_way) ? ls_way1_load[`WAY_VALID_RNG] : ls_way0_load[`WAY_VALID_RNG]; assign ls_tag_adr = { ls_adr_set }; assign ls_wayX_adr = { ls_adr_set, ls_adr_word }; assign ls_way0_we = ls_wayX_we & ~ls_way; assign ls_way1_we = ls_wayX_we & ls_way; assign ls_wayX_store[`WAY_DAT_RNG] = fml_rdat; assign ls_wayX_store[`WAY_VALID_RNG] = 4'b1111; //---------------------------------------------------------------------------- // LS (Load and Store) Engine //---------------------------------------------------------------------------- parameter l_idle = 0; parameter l_fill = 1; parameter l_spill = 2; parameter l_waitdone = 3; reg [2:0] ls_state; assign ls_busy = (ls_state != l_idle) || ls_fill || ls_spill; // Syncronous part FSM always @(posedge clk) begin if (reset) begin ls_state <= l_idle; ls_adr_word <= 0; fml_wr <= 0; fml_rd <= 0; end else begin fml_wnext2 <= fml_wnext; case (ls_state) l_idle: begin ls_adr_word <= 0; if (ls_spill) begin ls_state <= l_spill; ls_adr_word <= ls_adr_word + 1; end if (ls_fill) begin ls_state <= l_fill; fml_rd <= 1; end end l_spill: begin ls_adr_word <= ls_adr_word + 1; if (ls_adr_word == 3) begin ls_state <= l_waitdone; fml_wr <= 1; end end l_waitdone: begin ls_adr_word <= 0; if (fml_done) begin ls_state <= l_idle; fml_wr <= 0; end end l_fill: begin if (fml_done) fml_rd <= 0; if (~fml_rempty) ls_adr_word <= ls_adr_word + 1; if (~fml_rempty & (ls_adr_word == 3)) ls_state <= l_idle; end endcase end end always @(*) begin fml_wnext <= 0; fml_rnext <= 0; ls_tag_we <= 0; ls_tag_store <= ls_tag_load; ls_wayX_we <= 0; case (ls_state) l_idle: begin if (ls_spill) begin fml_wnext <= 1; end end l_spill: begin fml_wnext <= 1; end l_waitdone: begin if (ls_way == 0) ls_tag_store[`TAG_LINE_DIRTY0_RNG] <= 0; else ls_tag_store[`TAG_LINE_DIRTY1_RNG] <= 0; if (fml_done) ls_tag_we <= 1; end l_fill: begin if (ls_way == 0) begin ls_tag_store[`TAG_LINE_DIRTY0_RNG] <= 0; ls_tag_store[`TAG_LINE_TAG0_RNG] <= ls_adr_tag; end else begin ls_tag_store[`TAG_LINE_DIRTY1_RNG] <= 0; ls_tag_store[`TAG_LINE_TAG1_RNG] <= ls_adr_tag; end if (~fml_rempty) begin ls_wayX_we <= 1; fml_rnext <= 1; end if (~fml_rempty & (ls_adr_word == 3)) ls_tag_we <= 1; end endcase end always @(posedge clk) begin if (ls_fill) $display ("At time %t WB_DDR fill cacheline: TAG = %h, SET = %h)", $time, ls_adr_tag, ls_adr_set); if (ls_spill) $display ("At time %t WB_DDR spill cacheline: TAG = %h, SET = %h)", $time, ls_adr_tag, ls_adr_set); end endmodule