mirror of
git://projects.qi-hardware.com/nn-usb-fpga.git
synced 2025-04-21 12:27:27 +03:00
Adding lm32 demo to SAKC project
This commit is contained in:
116
lm32/logic/sakc/rtl/wb_ddr/async_fifo.v
Normal file
116
lm32/logic/sakc/rtl/wb_ddr/async_fifo.v
Normal file
@@ -0,0 +1,116 @@
|
||||
//==========================================
|
||||
// Function : Asynchronous FIFO (w/ 2 asynchronous clocks).
|
||||
// Coder : Alex Claros F.
|
||||
// Date : 15/May/2005.
|
||||
// Notes : This implementation is based on the article
|
||||
// 'Asynchronous FIFO in Virtex-II FPGAs'
|
||||
// writen by Peter Alfke. This TechXclusive
|
||||
// article can be downloaded from the
|
||||
// Xilinx website. It has some minor modifications.
|
||||
//=========================================
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module async_fifo
|
||||
#(parameter DATA_WIDTH = 8,
|
||||
ADDRESS_WIDTH = 4,
|
||||
FIFO_DEPTH = (1 << ADDRESS_WIDTH))
|
||||
//Reading port
|
||||
(output wire [DATA_WIDTH-1:0] Data_out,
|
||||
output reg Empty_out,
|
||||
input wire ReadEn_in,
|
||||
input wire RClk,
|
||||
//Writing port.
|
||||
input wire [DATA_WIDTH-1:0] Data_in,
|
||||
output reg Full_out,
|
||||
input wire WriteEn_in,
|
||||
input wire WClk,
|
||||
|
||||
input wire Clear_in);
|
||||
|
||||
/////Internal connections & variables//////
|
||||
reg [DATA_WIDTH-1:0] Mem [FIFO_DEPTH-1:0];
|
||||
wire [ADDRESS_WIDTH-1:0] pNextWordToWrite, pNextWordToRead;
|
||||
wire EqualAddresses;
|
||||
wire NextWriteAddressEn, NextReadAddressEn;
|
||||
wire Set_Status, Rst_Status;
|
||||
reg Status;
|
||||
wire PresetFull, PresetEmpty;
|
||||
|
||||
//////////////Code///////////////
|
||||
//Data ports logic:
|
||||
//(Uses a dual-port RAM).
|
||||
//'Data_out' logic:
|
||||
assign Data_out = Mem[pNextWordToRead];
|
||||
// always @ (posedge RClk)
|
||||
// if (!PresetEmpty)
|
||||
// Data_out <= Mem[pNextWordToRead];
|
||||
// if (ReadEn_in & !Empty_out)
|
||||
|
||||
//'Data_in' logic:
|
||||
always @ (posedge WClk)
|
||||
if (WriteEn_in & !Full_out)
|
||||
Mem[pNextWordToWrite] <= Data_in;
|
||||
|
||||
//Fifo addresses support logic:
|
||||
//'Next Addresses' enable logic:
|
||||
assign NextWriteAddressEn = WriteEn_in & ~Full_out;
|
||||
assign NextReadAddressEn = ReadEn_in & ~Empty_out;
|
||||
|
||||
//Addreses (Gray counters) logic:
|
||||
GrayCounter #(
|
||||
.COUNTER_WIDTH( ADDRESS_WIDTH )
|
||||
) GrayCounter_pWr (
|
||||
.GrayCount_out(pNextWordToWrite),
|
||||
.Enable_in(NextWriteAddressEn),
|
||||
.Clear_in(Clear_in),
|
||||
|
||||
.Clk(WClk)
|
||||
);
|
||||
|
||||
GrayCounter #(
|
||||
.COUNTER_WIDTH( ADDRESS_WIDTH )
|
||||
) GrayCounter_pRd (
|
||||
.GrayCount_out(pNextWordToRead),
|
||||
.Enable_in(NextReadAddressEn),
|
||||
.Clear_in(Clear_in),
|
||||
.Clk(RClk)
|
||||
);
|
||||
|
||||
|
||||
//'EqualAddresses' logic:
|
||||
assign EqualAddresses = (pNextWordToWrite == pNextWordToRead);
|
||||
|
||||
//'Quadrant selectors' logic:
|
||||
assign Set_Status = (pNextWordToWrite[ADDRESS_WIDTH-2] ~^ pNextWordToRead[ADDRESS_WIDTH-1]) &
|
||||
(pNextWordToWrite[ADDRESS_WIDTH-1] ^ pNextWordToRead[ADDRESS_WIDTH-2]);
|
||||
|
||||
assign Rst_Status = (pNextWordToWrite[ADDRESS_WIDTH-2] ^ pNextWordToRead[ADDRESS_WIDTH-1]) &
|
||||
(pNextWordToWrite[ADDRESS_WIDTH-1] ~^ pNextWordToRead[ADDRESS_WIDTH-2]);
|
||||
|
||||
//'Status' latch logic:
|
||||
always @ (Set_Status, Rst_Status, Clear_in) //D Latch w/ Asynchronous Clear & Preset.
|
||||
if (Rst_Status | Clear_in)
|
||||
Status = 0; //Going 'Empty'.
|
||||
else if (Set_Status)
|
||||
Status = 1; //Going 'Full'.
|
||||
|
||||
//'Full_out' logic for the writing port:
|
||||
assign PresetFull = Status & EqualAddresses; //'Full' Fifo.
|
||||
|
||||
always @ (posedge WClk, posedge PresetFull) //D Flip-Flop w/ Asynchronous Preset.
|
||||
if (PresetFull)
|
||||
Full_out <= 1;
|
||||
else
|
||||
Full_out <= 0;
|
||||
|
||||
//'Empty_out' logic for the reading port:
|
||||
assign PresetEmpty = ~Status & EqualAddresses; //'Empty' Fifo.
|
||||
|
||||
always @ (posedge RClk, posedge PresetEmpty) //D Flip-Flop w/ Asynchronous Preset.
|
||||
if (PresetEmpty)
|
||||
Empty_out <= 1;
|
||||
else
|
||||
Empty_out <= 0;
|
||||
|
||||
endmodule
|
||||
224
lm32/logic/sakc/rtl/wb_ddr/ddr_clkgen.v
Normal file
224
lm32/logic/sakc/rtl/wb_ddr/ddr_clkgen.v
Normal file
@@ -0,0 +1,224 @@
|
||||
//---------------------------------------------------------------------------
|
||||
// Wishbone DDR Controller
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
`include "ddr_include.v"
|
||||
|
||||
module ddr_clkgen
|
||||
#(
|
||||
parameter phase_shift = 0,
|
||||
parameter clk_multiply = 13,
|
||||
parameter clk_divide = 5
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
output locked,
|
||||
//
|
||||
output read_clk,
|
||||
output write_clk,
|
||||
output write_clk90,
|
||||
// DCM phase shift control
|
||||
output reg ps_ready,
|
||||
input ps_up,
|
||||
input ps_down
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ~133 MHz DDR Clock generator
|
||||
//----------------------------------------------------------------------------
|
||||
wire read_clk_u;
|
||||
wire dcm_fx_locked;
|
||||
|
||||
DCM #(
|
||||
.CLKDV_DIVIDE(2.0), // Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
|
||||
// 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
|
||||
.CLKFX_DIVIDE(clk_divide), // Can be any integer from 1 to 32
|
||||
.CLKFX_MULTIPLY(clk_multiply), // Can be any integer from 2 to 32
|
||||
.CLKIN_DIVIDE_BY_2("FALSE"), // TRUE/FALSE to enable CLKIN divide by two feature
|
||||
.CLKIN_PERIOD(), // Specify period of input clock
|
||||
.CLKOUT_PHASE_SHIFT("NONE"), // Specify phase shift of NONE, FIXED or VARIABLE
|
||||
.CLK_FEEDBACK("NONE"), // Specify clock feedback of NONE, 1X or 2X
|
||||
.DESKEW_ADJUST("SOURCE_SYNCHRONOUS"), // SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
|
||||
// an integer from 0 to 15
|
||||
.DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis
|
||||
.DLL_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for DLL
|
||||
.DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE
|
||||
.FACTORY_JF(16'hC080), // FACTORY JF values
|
||||
.PHASE_SHIFT(0), // Amount of fixed phase shift from -255 to 255
|
||||
.STARTUP_WAIT("FALSE") // Delay configuration DONE until DCM LOCK, TRUE/FALSE
|
||||
) dcm_fx (
|
||||
.DSSEN(),
|
||||
.CLK0(), // 0 degree DCM CLK output
|
||||
.CLK180(), // 180 degree DCM CLK output
|
||||
.CLK270(), // 270 degree DCM CLK output
|
||||
.CLK2X(), // 2X DCM CLK output
|
||||
.CLK2X180(), // 2X, 180 degree DCM CLK out
|
||||
.CLK90(), // 90 degree DCM CLK output
|
||||
.CLKDV(), // Divided DCM CLK out (CLKDV_DIVIDE)
|
||||
.CLKFX( read_clk_u ), // DCM CLK synthesis out (M/D)
|
||||
.CLKFX180(), // 180 degree CLK synthesis out
|
||||
.LOCKED( dcm_fx_locked), // DCM LOCK status output
|
||||
.PSDONE(), // Dynamic phase adjust done output
|
||||
.STATUS(), // 8-bit DCM status bits output
|
||||
.CLKFB(), // DCM clock feedback
|
||||
.CLKIN( clk ), // Clock input (from IBUFG, BUFG or DCM)
|
||||
.PSCLK( gnd ), // Dynamic phase adjust clock input
|
||||
.PSEN( gnd ), // Dynamic phase adjust enable input
|
||||
.PSINCDEC( gnd ), // Dynamic phase adjust increment/decrement
|
||||
.RST( reset ) // DCM asynchronous reset input
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// BUFG read clock
|
||||
//----------------------------------------------------------------------------
|
||||
BUFG bufg_fx_clk (
|
||||
.O(read_clk), // Clock buffer output
|
||||
.I(read_clk_u) // Clock buffer input
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Phase shifted clock for write path
|
||||
//----------------------------------------------------------------------------
|
||||
wire phase_dcm_reset;
|
||||
wire phase_dcm_locked;
|
||||
wire write_clk_u, write_clk90_u, write_clk180_u, write_clk270_u;
|
||||
reg psen, psincdec;
|
||||
wire psdone;
|
||||
|
||||
DCM #(
|
||||
.CLKDV_DIVIDE(2.0), // Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
|
||||
// 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
|
||||
.CLKFX_DIVIDE(2), // Can be any integer from 1 to 32
|
||||
.CLKFX_MULTIPLY(2), // Can be any integer from 2 to 32
|
||||
.CLKIN_DIVIDE_BY_2("FALSE"), // TRUE/FALSE to enable CLKIN divide by two feature
|
||||
.CLKIN_PERIOD(), // Specify period of input clock
|
||||
.CLK_FEEDBACK("1X"), // Specify clock feedback of NONE, 1X or 2X
|
||||
.DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), // SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
|
||||
// an integer from 0 to 15
|
||||
.DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis
|
||||
.DLL_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for DLL
|
||||
.DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE
|
||||
.FACTORY_JF(16'hC080), // FACTORY JF values
|
||||
.CLKOUT_PHASE_SHIFT("VARIABLE"), // Specify phase shift of NONE, FIXED or VARIABLE
|
||||
.PHASE_SHIFT( phase_shift ), // Amount of fixed phase shift from -255 to 255
|
||||
.STARTUP_WAIT("FALSE") // Delay configuration DONE until DCM LOCK, TRUE/FALSE
|
||||
) dcm_phase (
|
||||
.DSSEN(),
|
||||
.CLK0( write_clk_u ), // 0 degree DCM CLK output
|
||||
.CLK90( write_clk90_u ), // 90 degree DCM CLK output
|
||||
.CLK180( write_clk180_u ), // 180 degree DCM CLK output
|
||||
.CLK270( write_clk270_u ), // 270 degree DCM CLK output
|
||||
.CLK2X(), // 2X DCM CLK output
|
||||
.CLK2X180(), // 2X, 180 degree DCM CLK out
|
||||
.CLKDV(), // Divided DCM CLK out (CLKDV_DIVIDE)
|
||||
.CLKFX(), // DCM CLK synthesis out (M/D)
|
||||
.CLKFX180(), // 180 degree CLK synthesis out
|
||||
.LOCKED( phase_dcm_locked ), // DCM LOCK status output
|
||||
.STATUS(), // 8-bit DCM status bits output
|
||||
.CLKFB( write_clk ), // DCM clock feedback
|
||||
.CLKIN( read_clk ), // Clock input (from IBUFG, BUFG or DCM)
|
||||
.PSCLK( clk ), // Dynamic phase adjust clock input
|
||||
.PSEN( psen ), // Dynamic phase adjust enable input
|
||||
.PSINCDEC( psincdec ), // Dynamic phase adjust increment/decrement
|
||||
.PSDONE( psdone ), // Dynamic phase adjust done output
|
||||
.RST( phase_dcm_reset ) // DCM asynchronous reset input
|
||||
);
|
||||
|
||||
// delayed reset for phase shifting DCM
|
||||
reg [3:0] reset_counter;
|
||||
assign phase_dcm_reset = reset | (reset_counter != 0);
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset)
|
||||
reset_counter <= 1;
|
||||
else begin
|
||||
if (dcm_fx_locked & (reset_counter != 0))
|
||||
reset_counter <= reset_counter + 1;
|
||||
end
|
||||
end
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// DCM phase shifting state machine
|
||||
//----------------------------------------------------------------------------
|
||||
parameter s_init = 0;
|
||||
parameter s_idle = 1;
|
||||
parameter s_waitdone = 2;
|
||||
parameter s_waitdone2= 3;
|
||||
|
||||
reg [1:0] state;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset) begin
|
||||
state <= s_init;
|
||||
psen <= 0;
|
||||
ps_ready <= 0;
|
||||
end else begin
|
||||
case (state)
|
||||
s_init: begin
|
||||
if (phase_dcm_locked) begin
|
||||
ps_ready <= 1;
|
||||
state <= s_idle;
|
||||
end
|
||||
end
|
||||
s_idle: begin
|
||||
if (ps_up) begin
|
||||
ps_ready <= 0;
|
||||
psen <= 1;
|
||||
psincdec <= 1;
|
||||
state <= s_waitdone;
|
||||
end else if (ps_down) begin
|
||||
ps_ready <= 0;
|
||||
psen <= 1;
|
||||
psincdec <= 0;
|
||||
state <= s_waitdone;
|
||||
end
|
||||
end
|
||||
s_waitdone: begin
|
||||
psen <= 0;
|
||||
if (psdone) begin
|
||||
state <= s_waitdone2;
|
||||
end
|
||||
end
|
||||
s_waitdone2: begin
|
||||
if (~ps_up && ~ps_down) begin
|
||||
ps_ready <= 1;
|
||||
state <= s_idle;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// BUFG write clock
|
||||
//----------------------------------------------------------------------------
|
||||
BUFG bufg_write_clk (
|
||||
.O(write_clk ), // Clock buffer output
|
||||
.I(write_clk_u) // Clock buffer input
|
||||
);
|
||||
|
||||
BUFG bufg_write_clk90 (
|
||||
.O(write_clk90 ), // Clock buffer output
|
||||
.I(write_clk90_u) // Clock buffer input
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// LOCKED logic
|
||||
//----------------------------------------------------------------------------
|
||||
reg phase_dcm_locked_delayed;
|
||||
|
||||
always @(posedge write_clk)
|
||||
begin
|
||||
phase_dcm_locked_delayed <= phase_dcm_locked;
|
||||
end
|
||||
|
||||
assign locked = ~reset & phase_dcm_locked_delayed;
|
||||
|
||||
|
||||
endmodule
|
||||
370
lm32/logic/sakc/rtl/wb_ddr/ddr_ctrl.v
Normal file
370
lm32/logic/sakc/rtl/wb_ddr/ddr_ctrl.v
Normal file
@@ -0,0 +1,370 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Pipelined, asyncronous DDR Controller
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//----------------------------------------------------------------------------
|
||||
module ddr_ctrl
|
||||
#(
|
||||
parameter phase_shift = 0,
|
||||
parameter clk_freq = 100000000,
|
||||
parameter clk_multiply = 12,
|
||||
parameter clk_divide = 5,
|
||||
parameter wait200_init = 26
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
// DDR ports
|
||||
output [2:0] ddr_clk,
|
||||
output [2:0] ddr_clk_n,
|
||||
input ddr_clk_fb,
|
||||
output ddr_ras_n,
|
||||
output ddr_cas_n,
|
||||
output ddr_we_n,
|
||||
output [1:0] ddr_cke,
|
||||
output [1:0] 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,
|
||||
// FML (FastMemoryLink)
|
||||
output reg fml_done,
|
||||
input [`FML_ADR_RNG] fml_adr,
|
||||
input fml_rd,
|
||||
input fml_wr,
|
||||
input [`FML_DAT_RNG] fml_wdat,
|
||||
input [`FML_BE_RNG] fml_wbe,
|
||||
input fml_wnext,
|
||||
output fml_rempty,
|
||||
input fml_rnext,
|
||||
output [`FML_DAT_RNG] fml_rdat,
|
||||
// DCM phase shift control
|
||||
output ps_ready,
|
||||
input ps_up,
|
||||
input ps_down,
|
||||
// Logic Probe
|
||||
output probe_clk,
|
||||
input [7:0] probe_sel,
|
||||
output reg [7:0] probe
|
||||
);
|
||||
|
||||
wire [ `DQ_RNG] ddr_dq_i, ddr_dq_o;
|
||||
wire [`DQS_RNG] ddr_dqs_i, ddr_dqs_o;
|
||||
wire ddr_dqs_oe;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// clock generator
|
||||
//----------------------------------------------------------------------------
|
||||
wire clk_locked;
|
||||
wire write_clk, write_clk90;
|
||||
wire read_clk;
|
||||
|
||||
wire reset_int = reset | ~clk_locked;
|
||||
|
||||
ddr_clkgen #(
|
||||
.phase_shift( phase_shift ),
|
||||
.clk_multiply( clk_multiply ),
|
||||
.clk_divide( clk_divide )
|
||||
) clkgen (
|
||||
.clk( clk ),
|
||||
.reset( reset ),
|
||||
.locked( clk_locked ),
|
||||
// ddr-clk
|
||||
.read_clk( read_clk ),
|
||||
.write_clk( write_clk ),
|
||||
.write_clk90( write_clk90 ),
|
||||
// phase shift control
|
||||
.ps_ready( ps_ready ),
|
||||
.ps_up( ps_up ),
|
||||
.ps_down( ps_down )
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// async_fifos (cmd, wdata, rdata)
|
||||
//----------------------------------------------------------------------------
|
||||
wire cba_fifo_full;
|
||||
reg [`CBA_RNG] cba_fifo_din;
|
||||
reg cba_fifo_we;
|
||||
|
||||
wire wfifo_full;
|
||||
wire [`WFIFO_RNG] wfifo_din;
|
||||
wire wfifo_we;
|
||||
|
||||
wire [`RFIFO_RNG] rfifo_dout;
|
||||
wire rfifo_empty;
|
||||
wire rfifo_next;
|
||||
|
||||
assign wfifo_din = { ~fml_wbe, fml_wdat };
|
||||
assign wfifo_we = fml_wnext;
|
||||
|
||||
assign fml_rdat = rfifo_dout;
|
||||
assign fml_rempty = rfifo_empty;
|
||||
assign rfifo_next = fml_rnext;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// High-speed cmd, write and read datapath
|
||||
//----------------------------------------------------------------------------
|
||||
ddr_wpath wpath0 (
|
||||
.clk( write_clk ),
|
||||
.clk90( write_clk90 ),
|
||||
.reset( reset_int ),
|
||||
// CBA async fifo
|
||||
.cba_clk( clk ),
|
||||
.cba_din( cba_fifo_din ),
|
||||
.cba_wr( cba_fifo_we ),
|
||||
.cba_full( cba_fifo_full ),
|
||||
// WDATA async fifo
|
||||
.wdata_clk( clk ),
|
||||
.wdata_din( wfifo_din ),
|
||||
.wdata_wr( wfifo_we ),
|
||||
.wdata_full( wfifo_full ),
|
||||
//
|
||||
.sample( sample ),
|
||||
// DDR
|
||||
.ddr_clk( ddr_clk ),
|
||||
.ddr_clk_n( ddr_clk_n ),
|
||||
.ddr_ras_n( ddr_ras_n ),
|
||||
.ddr_cas_n( ddr_cas_n ),
|
||||
.ddr_we_n( ddr_we_n ),
|
||||
.ddr_a( ddr_a ),
|
||||
.ddr_ba( ddr_ba ),
|
||||
.ddr_dm( ddr_dm ),
|
||||
.ddr_dq( ddr_dq_o ),
|
||||
.ddr_dqs( ddr_dqs_o ),
|
||||
.ddr_dqs_oe( ddr_dqs_oe )
|
||||
);
|
||||
|
||||
ddr_rpath rpath0 (
|
||||
.clk( read_clk ),
|
||||
.reset( reset_int ),
|
||||
//
|
||||
.sample( sample ),
|
||||
//
|
||||
.rfifo_clk( clk ),
|
||||
.rfifo_empty( rfifo_empty),
|
||||
.rfifo_dout( rfifo_dout ),
|
||||
.rfifo_next( rfifo_next ),
|
||||
// DDR
|
||||
.ddr_dq( ddr_dq_i ),
|
||||
.ddr_dqs( ddr_dqs_i )
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// 7.8 us pulse generator
|
||||
//----------------------------------------------------------------------------
|
||||
wire pulse78;
|
||||
reg ar_req;
|
||||
reg ar_done;
|
||||
|
||||
ddr_pulse78 #(
|
||||
.clk_freq( clk_freq )
|
||||
) pulse78_gen (
|
||||
.clk( clk ),
|
||||
.reset( reset_int ),
|
||||
.pulse78( pulse78 )
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Auto Refresh request generator
|
||||
//----------------------------------------------------------------------------
|
||||
always @(posedge clk)
|
||||
if (reset_int)
|
||||
ar_req <= 0;
|
||||
else
|
||||
ar_req <= pulse78 | (ar_req & ~ar_done);
|
||||
|
||||
// operations we might want to submit
|
||||
wire [`CBA_RNG] ar_pre_cba;
|
||||
wire [`CBA_RNG] ar_ar_cba;
|
||||
|
||||
assign ar_pre_cba = { `DDR_CMD_PRE, 2'b00, 13'b1111111111111 };
|
||||
assign ar_ar_cba = { `DDR_CMD_AR, 2'b00, 13'b0000000000000 };
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Init & management
|
||||
//----------------------------------------------------------------------------
|
||||
wire init_req;
|
||||
reg init_ack;
|
||||
wire [`CBA_RNG] init_cba;
|
||||
wire init_done;
|
||||
wire wait200;
|
||||
|
||||
ddr_init #(
|
||||
.wait200_init( wait200_init )
|
||||
) init (
|
||||
.clk( clk ),
|
||||
.reset( reset_int ),
|
||||
.pulse78( pulse78 ),
|
||||
.wait200( wait200 ),
|
||||
.init_done( init_done ),
|
||||
//
|
||||
.mngt_req( init_req ),
|
||||
.mngt_ack( init_ack ),
|
||||
.mngt_cba( init_cba )
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Active Bank Information
|
||||
//----------------------------------------------------------------------------
|
||||
reg [`ROW_RNG] ba_row [3:0];
|
||||
reg [3:0] ba_active;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// FML decoding
|
||||
//----------------------------------------------------------------------------
|
||||
wire [`FML_ADR_BA_RNG] fml_ba = fml_adr[`FML_ADR_BA_RNG];
|
||||
wire [`FML_ADR_ROW_RNG] fml_row = fml_adr[`FML_ADR_ROW_RNG];
|
||||
wire [`FML_ADR_COL_RNG] fml_col = fml_adr[`FML_ADR_COL_RNG];
|
||||
|
||||
wire [`FML_ADR_ROW_RNG] fml_cur_row; // current active row in sel. bank
|
||||
assign fml_cur_row = ba_row[fml_ba];
|
||||
|
||||
wire fml_row_active; // is row in selected ba really active?
|
||||
assign fml_row_active = ba_active[fml_ba];
|
||||
|
||||
|
||||
/*
|
||||
wire fml_row_active = (fml_ba == 0) ? ba0_active : // is row in selected
|
||||
(fml_ba == 1) ? ba1_active : // bank really active?
|
||||
(fml_ba == 2) ? ba2_active :
|
||||
ba3_active ;
|
||||
*/
|
||||
|
||||
// request operation iff correct bank is active
|
||||
wire fml_req = fml_rd | fml_wr;
|
||||
wire fml_row_match = (fml_row == fml_cur_row) & fml_row_active;
|
||||
wire fml_pre_req = fml_req & ~fml_row_match & fml_row_active;
|
||||
wire fml_act_req = fml_req & ~fml_row_active;
|
||||
wire fml_read_req = fml_rd & fml_row_match & ~fml_done;
|
||||
wire fml_write_req = fml_wr & fml_row_match & ~fml_done;
|
||||
|
||||
// actual operations we might want to submit
|
||||
wire [`CBA_RNG] fml_pre_cba;
|
||||
wire [`CBA_RNG] fml_act_cba;
|
||||
wire [`CBA_RNG] fml_read_cba;
|
||||
wire [`CBA_RNG] fml_write_cba;
|
||||
|
||||
assign fml_pre_cba = { `DDR_CMD_PRE, fml_ba, 13'b0 };
|
||||
assign fml_act_cba = { `DDR_CMD_ACT, fml_ba, fml_row };
|
||||
assign fml_read_cba = { `DDR_CMD_READ, fml_ba, {3'b000}, fml_col, {3'b000} };
|
||||
assign fml_write_cba = { `DDR_CMD_WRITE, fml_ba, {3'b000}, fml_col, {3'b000} };
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Schedule and issue commands
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
parameter s_init = 0;
|
||||
parameter s_idle = 1;
|
||||
parameter s_ar = 2;
|
||||
parameter s_reading = 3;
|
||||
|
||||
reg [1:0] state;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset_int) begin
|
||||
state <= s_init;
|
||||
ba_active <= 0;
|
||||
ba_row[0] <= 0;
|
||||
ba_row[1] <= 0;
|
||||
ba_row[2] <= 0;
|
||||
ba_row[3] <= 0;
|
||||
|
||||
fml_done <= 0;
|
||||
init_ack <= 0;
|
||||
cba_fifo_we <= 0;
|
||||
ar_done <= 0;
|
||||
end else begin
|
||||
fml_done <= 0;
|
||||
init_ack <= 0;
|
||||
cba_fifo_we <= 0;
|
||||
ar_done <= 0;
|
||||
|
||||
case (state)
|
||||
s_init: begin
|
||||
if (init_done)
|
||||
state <= s_idle;
|
||||
|
||||
if (init_req & ~cba_fifo_full) begin
|
||||
cba_fifo_we <= 1;
|
||||
cba_fifo_din <= init_cba;
|
||||
init_ack <= 1;
|
||||
end
|
||||
end
|
||||
s_idle: begin
|
||||
if (fml_read_req & ~cba_fifo_full) begin
|
||||
cba_fifo_we <= 1;
|
||||
cba_fifo_din <= fml_read_cba;
|
||||
fml_done <= 1;
|
||||
end else if (fml_write_req & ~cba_fifo_full) begin
|
||||
cba_fifo_we <= 1;
|
||||
cba_fifo_din <= fml_write_cba;
|
||||
fml_done <= 1;
|
||||
end else if (ar_req & ~cba_fifo_full) begin
|
||||
cba_fifo_we <= 1;
|
||||
cba_fifo_din <= ar_pre_cba;
|
||||
ar_done <= 1;
|
||||
ba_active <= 'b0;
|
||||
state <= s_ar;
|
||||
end else if (fml_pre_req & ~cba_fifo_full) begin
|
||||
cba_fifo_we <= 1;
|
||||
cba_fifo_din <= fml_pre_cba;
|
||||
ba_active[fml_ba] <= 0;
|
||||
end else if (fml_act_req & ~cba_fifo_full) begin
|
||||
cba_fifo_we <= 1;
|
||||
cba_fifo_din <= fml_act_cba;
|
||||
ba_active[fml_ba] <= 1;
|
||||
ba_row[fml_ba] <= fml_row;
|
||||
end
|
||||
end
|
||||
s_ar: begin
|
||||
if (~cba_fifo_full) begin
|
||||
cba_fifo_we <= 1;
|
||||
cba_fifo_din <= ar_ar_cba;
|
||||
state <= s_idle;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Demux dqs and dq
|
||||
//----------------------------------------------------------------------------
|
||||
assign ddr_cke = {~wait200, ~wait200}; // bring up CKE as soon 200us wait is finished
|
||||
|
||||
assign ddr_dqs = ddr_dqs_oe!=1'b0 ? ddr_dqs_o : 'bz;
|
||||
assign ddr_dq = ddr_dqs_oe!=1'b0 ? ddr_dq_o : 'bz;
|
||||
|
||||
assign ddr_dqs_i = ddr_dqs;
|
||||
assign ddr_dq_i = ddr_dq;
|
||||
|
||||
assign ddr_cs_n = 2'b00;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Probes
|
||||
//----------------------------------------------------------------------------
|
||||
assign probe_clk = clk;
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
case (probe_sel)
|
||||
8'h00: probe <= { cba_fifo_we, wfifo_we, rfifo_next, 1'b0, cba_fifo_full, wfifo_full, rfifo_empty, 1'b0 };
|
||||
8'h01: probe <= { write_clk, write_clk90, read_clk, 5'b00000 };
|
||||
8'h10: probe <= { rfifo_empty, rfifo_next, rfifo_dout[ 5: 0] };
|
||||
8'h11: probe <= { rfifo_empty, rfifo_next, rfifo_dout[13: 8] };
|
||||
8'h12: probe <= { rfifo_empty, rfifo_next, rfifo_dout[21:16] };
|
||||
8'h13: probe <= { rfifo_empty, rfifo_next, rfifo_dout[29:24] };
|
||||
8'h20: probe <= wfifo_din[ 7:0];
|
||||
8'h21: probe <= wfifo_din[15:8];
|
||||
8'h20: probe <= wfifo_din[23:16];
|
||||
8'h21: probe <= wfifo_din[31:24];
|
||||
8'h30: probe <= cba_fifo_din[17:10];
|
||||
8'h31: probe <= cba_fifo_din[ 9:2];
|
||||
default: probe <= 0'b0;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
122
lm32/logic/sakc/rtl/wb_ddr/ddr_include.v
Normal file
122
lm32/logic/sakc/rtl/wb_ddr/ddr_include.v
Normal file
@@ -0,0 +1,122 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Wishbone DDR Controller
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
`ifdef WBDDR_INCLUDE_V
|
||||
`else
|
||||
`define WBDDR_INCLUDE_V
|
||||
|
||||
`timescale 1ns/10ps
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Frequency and timeouts
|
||||
//----------------------------------------------------------------------------
|
||||
`define SYS_CLK_FREQUENCY 50000 // in kHz
|
||||
`define DDR_CLK_MULTIPLY 5
|
||||
`define DDR_CLK_DIVIDE 2
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Width
|
||||
//----------------------------------------------------------------------------
|
||||
`define CMD_WIDTH 3
|
||||
`define A_WIDTH 13
|
||||
`define BA_WIDTH 2
|
||||
`define DQ_WIDTH 16
|
||||
`define DQS_WIDTH 2
|
||||
`define DM_WIDTH 2
|
||||
|
||||
`define RFIFO_WIDTH (2 * `DQ_WIDTH )
|
||||
`define WFIFO_WIDTH (2 * (`DQ_WIDTH + `DM_WIDTH))
|
||||
`define CBA_WIDTH (`CMD_WIDTH+`BA_WIDTH+`A_WIDTH)
|
||||
|
||||
// Ranges
|
||||
`define CMD_RNG (`CMD_WIDTH-1):0
|
||||
`define A_RNG (`A_WIDTH-1):0
|
||||
`define BA_RNG (`BA_WIDTH-1):0
|
||||
`define DQ_RNG (`DQ_WIDTH-1):0
|
||||
`define DQS_RNG (`DQS_WIDTH-1):0
|
||||
`define DM_RNG (`DM_WIDTH-1):0
|
||||
|
||||
`define RFIFO_RNG (`RFIFO_WIDTH-1):0
|
||||
`define WFIFO_RNG (`WFIFO_WIDTH-1):0
|
||||
`define WFIFO_D0_RNG (1*`DQ_WIDTH-1):0
|
||||
`define WFIFO_D1_RNG (2*`DQ_WIDTH-1):(`DQ_WIDTH)
|
||||
`define WFIFO_M0_RNG (2*`DQ_WIDTH+1*`DM_WIDTH-1):(2*`DQ_WIDTH+0*`DM_WIDTH)
|
||||
`define WFIFO_M1_RNG (2*`DQ_WIDTH+2*`DM_WIDTH-1):(2*`DQ_WIDTH+1*`DM_WIDTH)
|
||||
`define CBA_RNG (`CBA_WIDTH-1):0
|
||||
`define CBA_CMD_RNG (`CBA_WIDTH-1):(`CBA_WIDTH-3)
|
||||
`define CBA_BA_RNG (`CBA_WIDTH-4):(`CBA_WIDTH-5)
|
||||
`define CBA_A_RNG (`CBA_WIDTH-6):0
|
||||
|
||||
`define ROW_RNG 12:0
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Configuration registers
|
||||
//----------------------------------------------------------------------------
|
||||
`define DDR_INIT_EMRS `A_WIDTH'b0000000000000 // DLL enable
|
||||
`define DDR_INIT_MRS1 `A_WIDTH'b0000101100011 // BURST=8, CL=2.5, DLL RESET
|
||||
`define DDR_INIT_MRS2 `A_WIDTH'b0000001100011 // BURST=8, CL=2.5
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// FML constants
|
||||
//----------------------------------------------------------------------------
|
||||
`define FML_ADR_RNG 25:4
|
||||
`define FML_ADR_BA_RNG 25:24
|
||||
`define FML_ADR_ROW_RNG 23:11
|
||||
`define FML_ADR_COL_RNG 10:4
|
||||
`define FML_DAT_RNG 31:0
|
||||
`define FML_BE_RNG 3:0
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// DDR constants
|
||||
//----------------------------------------------------------------------------
|
||||
`define DDR_CMD_NOP 3'b111
|
||||
`define DDR_CMD_ACT 3'b011
|
||||
`define DDR_CMD_READ 3'b101
|
||||
`define DDR_CMD_WRITE 3'b100
|
||||
`define DDR_CMD_TERM 3'b110
|
||||
`define DDR_CMD_PRE 3'b010
|
||||
`define DDR_CMD_AR 3'b001
|
||||
`define DDR_CMD_MRS 3'b000
|
||||
|
||||
`define ADR_BA_RNG 25:24
|
||||
`define ADR_ROW_RNG 23:11
|
||||
`define ADR_COL_RNG 10:4
|
||||
|
||||
`define T_MRD 2 // Mode register set
|
||||
`define T_RP 2 // Precharge Command Period
|
||||
`define T_RFC 8 // Precharge Command Period
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Buffer Cache
|
||||
//----------------------------------------------------------------------------
|
||||
`define WAY_WIDTH (`WB_DAT_WIDTH + `WB_SEL_WIDTH)
|
||||
`define WAY_LINE_RNG (`WAY_WIDTH-1):0
|
||||
`define WAY_DAT_RNG 31:0
|
||||
`define WAY_VALID_RNG 35:32
|
||||
|
||||
`define TAG_LINE_RNG 32:0
|
||||
`define TAG_LINE_TAG0_RNG 14:0
|
||||
`define TAG_LINE_TAG1_RNG 29:15
|
||||
`define TAG_LINE_DIRTY0_RNG 30
|
||||
`define TAG_LINE_DIRTY1_RNG 31
|
||||
`define TAG_LINE_LRU_RNG 32
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Whishbone constants
|
||||
//----------------------------------------------------------------------------
|
||||
`define WB_ADR_WIDTH 32
|
||||
`define WB_DAT_WIDTH 32
|
||||
`define WB_SEL_WIDTH 4
|
||||
|
||||
`define WB_ADR_RNG (`WB_ADR_WIDTH-1):0
|
||||
`define WB_DAT_RNG (`WB_DAT_WIDTH-1):0
|
||||
`define WB_SEL_RNG (`WB_SEL_WIDTH-1):0
|
||||
|
||||
`define WB_WORD_RNG 3:2
|
||||
`define WB_SET_RNG 10:4
|
||||
`define WB_TAG_RNG 25:11
|
||||
|
||||
`endif
|
||||
164
lm32/logic/sakc/rtl/wb_ddr/ddr_init.v
Normal file
164
lm32/logic/sakc/rtl/wb_ddr/ddr_init.v
Normal file
@@ -0,0 +1,164 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Wishbone DDR Controller
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//----------------------------------------------------------------------------
|
||||
`include "ddr_include.v"
|
||||
|
||||
module ddr_init
|
||||
#(
|
||||
parameter wait200_init = 26
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
input pulse78,
|
||||
output wait200,
|
||||
output init_done,
|
||||
//
|
||||
output mngt_req,
|
||||
input mngt_ack,
|
||||
output [`CBA_RNG] mngt_cba // CMD, BA and ADDRESS
|
||||
);
|
||||
|
||||
reg cmd_req_reg;
|
||||
reg [`CMD_RNG] cmd_cmd_reg;
|
||||
reg [ `BA_RNG] cmd_ba_reg;
|
||||
reg [ `A_RNG] cmd_a_reg;
|
||||
reg [7:0] cmd_idle_reg;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Initial 200us delay
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// `define WAIT200_INIT 26
|
||||
// `define WAIT200_INIT 1
|
||||
|
||||
reg [4:0] wait200_counter;
|
||||
reg wait200_reg;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset) begin
|
||||
wait200_reg <= 1;
|
||||
wait200_counter <= wait200_init;
|
||||
end else begin
|
||||
if (wait200_counter == 0)
|
||||
wait200_reg <= 0;
|
||||
|
||||
if (wait200_reg & pulse78)
|
||||
wait200_counter <= wait200_counter - 1;
|
||||
end
|
||||
end
|
||||
|
||||
assign wait200 = wait200_reg;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// DDR Initialization State Machine
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
parameter s_wait200 = 0;
|
||||
parameter s_init1 = 1;
|
||||
parameter s_init2 = 2;
|
||||
parameter s_init3 = 3;
|
||||
parameter s_init4 = 4;
|
||||
parameter s_init5 = 5;
|
||||
parameter s_init6 = 6;
|
||||
parameter s_waitack = 7;
|
||||
parameter s_idle = 8;
|
||||
|
||||
reg [3:0] state;
|
||||
reg init_done_reg;
|
||||
|
||||
assign mngt_cba = {cmd_cmd_reg, cmd_ba_reg, cmd_a_reg};
|
||||
assign mngt_req = cmd_req_reg;
|
||||
assign mngt_pri_req = ~init_done_reg;
|
||||
assign init_done = init_done_reg;
|
||||
|
||||
always @(posedge clk or posedge reset)
|
||||
begin
|
||||
if (reset) begin
|
||||
init_done_reg <= 0;
|
||||
state <= s_wait200;
|
||||
cmd_idle_reg <= 0;
|
||||
cmd_req_reg <= 0;
|
||||
cmd_cmd_reg <= 'b0;
|
||||
cmd_ba_reg <= 'b0;
|
||||
cmd_a_reg <= 'b0;
|
||||
end else begin
|
||||
case (state)
|
||||
s_wait200: begin
|
||||
if (~wait200_reg) begin
|
||||
state <= s_init1;
|
||||
cmd_req_reg <= 1;
|
||||
cmd_cmd_reg <= `DDR_CMD_PRE; // PRE ALL
|
||||
cmd_a_reg[10] <= 1'b1;
|
||||
end
|
||||
end
|
||||
s_init1: begin
|
||||
if (mngt_ack) begin
|
||||
state <= s_init2;
|
||||
cmd_req_reg <= 1;
|
||||
cmd_cmd_reg <= `DDR_CMD_MRS; // EMRS
|
||||
cmd_ba_reg <= 2'b01;
|
||||
cmd_a_reg <= `DDR_INIT_EMRS;
|
||||
end
|
||||
end
|
||||
s_init2: begin
|
||||
if (mngt_ack) begin
|
||||
state <= s_init3;
|
||||
cmd_req_reg <= 1;
|
||||
cmd_cmd_reg <= `DDR_CMD_MRS; // MRS
|
||||
cmd_ba_reg <= 2'b00;
|
||||
cmd_a_reg <= `DDR_INIT_MRS1;
|
||||
end
|
||||
end
|
||||
s_init3: begin
|
||||
if (mngt_ack) begin
|
||||
state <= s_init4;
|
||||
cmd_req_reg <= 1;
|
||||
cmd_cmd_reg <= `DDR_CMD_PRE; // PRE ALL
|
||||
cmd_a_reg[10] <= 1'b1;
|
||||
end
|
||||
end
|
||||
s_init4: begin
|
||||
if (mngt_ack) begin
|
||||
state <= s_init5;
|
||||
cmd_req_reg <= 1;
|
||||
cmd_cmd_reg <= `DDR_CMD_AR; // AR
|
||||
end
|
||||
end
|
||||
s_init5: begin
|
||||
if (mngt_ack) begin
|
||||
state <= s_init6;
|
||||
cmd_req_reg <= 1;
|
||||
cmd_cmd_reg <= `DDR_CMD_AR; // AR
|
||||
end
|
||||
end
|
||||
s_init6: begin
|
||||
if (mngt_ack) begin
|
||||
init_done_reg <= 1;
|
||||
state <= s_waitack;
|
||||
cmd_req_reg <= 1;
|
||||
cmd_cmd_reg <= `DDR_CMD_MRS; // MRS
|
||||
cmd_ba_reg <= 2'b00;
|
||||
cmd_a_reg <= `DDR_INIT_MRS2;
|
||||
end
|
||||
end
|
||||
s_waitack: begin
|
||||
if (mngt_ack) begin
|
||||
state <= s_idle;
|
||||
cmd_req_reg <= 0;
|
||||
cmd_cmd_reg <= 'b0;
|
||||
cmd_ba_reg <= 'b0;
|
||||
cmd_a_reg <= 'b0;
|
||||
end
|
||||
end
|
||||
s_idle: begin
|
||||
end
|
||||
endcase ///////////////////////////////////////// INIT STATE MACHINE ///
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
43
lm32/logic/sakc/rtl/wb_ddr/ddr_pulse78.v
Normal file
43
lm32/logic/sakc/rtl/wb_ddr/ddr_pulse78.v
Normal file
@@ -0,0 +1,43 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Wishbone DDR Controller
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//----------------------------------------------------------------------------
|
||||
`include "ddr_include.v"
|
||||
|
||||
module ddr_pulse78 #(
|
||||
parameter clk_freq = 50000000
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
//
|
||||
output reg pulse78
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
`define PULSE78_RNG 10:0
|
||||
|
||||
parameter pulse78_init = 78 * (clk_freq/10000000);
|
||||
|
||||
reg [`PULSE78_RNG] counter;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset) begin
|
||||
counter <= pulse78_init;
|
||||
pulse78 <= 0;
|
||||
end else begin
|
||||
if (counter == 0) begin
|
||||
counter <= pulse78_init;
|
||||
pulse78 <= 1'b1;
|
||||
end else begin
|
||||
counter <= counter - 1;
|
||||
pulse78 <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
112
lm32/logic/sakc/rtl/wb_ddr/ddr_rpath.v
Normal file
112
lm32/logic/sakc/rtl/wb_ddr/ddr_rpath.v
Normal file
@@ -0,0 +1,112 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Wishbone DDR Controller
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
`include "ddr_include.v"
|
||||
|
||||
module ddr_rpath
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
// sample activate
|
||||
input sample,
|
||||
// RDATA async fifo
|
||||
input rfifo_clk,
|
||||
output rfifo_empty,
|
||||
output [`RFIFO_RNG] rfifo_dout,
|
||||
input rfifo_next,
|
||||
// DDR
|
||||
input [ `DQ_RNG] ddr_dq,
|
||||
input [`DQS_RNG] ddr_dqs
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RDATA async. fifo
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
wire [`RFIFO_RNG] rfifo_din;
|
||||
wire rfifo_wr;
|
||||
wire rfifo_full;
|
||||
|
||||
async_fifo #(
|
||||
.DATA_WIDTH( `RFIFO_WIDTH ),
|
||||
.ADDRESS_WIDTH( 4 )
|
||||
) rfifo (
|
||||
.Data_out( rfifo_dout ),
|
||||
.Empty_out( rfifo_empty ),
|
||||
.ReadEn_in( rfifo_next ),
|
||||
.RClk( rfifo_clk ),
|
||||
//
|
||||
.Data_in( rfifo_din ),
|
||||
.WriteEn_in( rfifo_wr ),
|
||||
.Full_out( rfifo_full ),
|
||||
.WClk( ~clk ),
|
||||
.Clear_in( reset )
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Clean up incoming 'sample' signal and generate sample_dq
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// anti-meta-state
|
||||
//reg sample180;
|
||||
//always @(negedge clk) sample180 <= sample;
|
||||
wire sample180 = sample;
|
||||
|
||||
|
||||
reg sample_dq; // authoritive sample flag (after cleanup)
|
||||
reg sample_dq_delayed; // write to rfifo?
|
||||
reg [3:0] sample_count; // make sure sample_dq is up exactly
|
||||
// BURSTLENGTH/2 cycles
|
||||
|
||||
always @(posedge clk or posedge reset)
|
||||
begin
|
||||
if (reset) begin
|
||||
sample_dq <= 0;
|
||||
sample_dq_delayed <= 0;
|
||||
sample_count <= 0;
|
||||
end else begin
|
||||
sample_dq_delayed <= sample_dq;
|
||||
if (sample_count == 0) begin
|
||||
if (sample180) begin
|
||||
sample_dq <= 1;
|
||||
sample_count <= 1;
|
||||
end
|
||||
end else if (sample_count == 4) begin
|
||||
sample_dq <= 0;
|
||||
sample_count <= 0;
|
||||
end else
|
||||
sample_count <= sample_count + 1;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Sampe DQ and fill RFIFO
|
||||
//----------------------------------------------------------------------------
|
||||
reg [15:0] ddr_dq_low, ddr_dq_high;
|
||||
|
||||
always @(negedge clk )
|
||||
begin
|
||||
if (reset)
|
||||
ddr_dq_low <= 'b0;
|
||||
else
|
||||
ddr_dq_low <= ddr_dq;
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset)
|
||||
ddr_dq_high <= 'b0;
|
||||
else
|
||||
ddr_dq_high <= ddr_dq;
|
||||
end
|
||||
|
||||
assign rfifo_wr = sample_dq_delayed;
|
||||
assign rfifo_din = { ddr_dq_high, ddr_dq_low };
|
||||
|
||||
endmodule
|
||||
|
||||
286
lm32/logic/sakc/rtl/wb_ddr/ddr_wpath.v
Normal file
286
lm32/logic/sakc/rtl/wb_ddr/ddr_wpath.v
Normal file
@@ -0,0 +1,286 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Wishbone DDR Controller -- fast write data-path
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//----------------------------------------------------------------------------
|
||||
`include "ddr_include.v"
|
||||
|
||||
module ddr_wpath (
|
||||
input clk,
|
||||
input clk90,
|
||||
input reset,
|
||||
// CBA async fifo
|
||||
input cba_clk,
|
||||
input [`CBA_RNG] cba_din,
|
||||
input cba_wr,
|
||||
output cba_full,
|
||||
// WDATA async fifo
|
||||
input wdata_clk,
|
||||
input [`WFIFO_RNG] wdata_din,
|
||||
input wdata_wr,
|
||||
output wdata_full,
|
||||
// sample to rdata
|
||||
output sample,
|
||||
// DDR
|
||||
output [2:0] ddr_clk,
|
||||
output [2:0] ddr_clk_n,
|
||||
output ddr_ras_n,
|
||||
output ddr_cas_n,
|
||||
output ddr_we_n,
|
||||
output [ `A_RNG] ddr_a,
|
||||
output [ `BA_RNG] ddr_ba,
|
||||
output [ `DM_RNG] ddr_dm,
|
||||
output [ `DQ_RNG] ddr_dq,
|
||||
output [`DQS_RNG] ddr_dqs,
|
||||
output ddr_dqs_oe
|
||||
);
|
||||
|
||||
wire gnd = 1'b0;
|
||||
wire vcc = 1'b1;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// CBA async. fifo
|
||||
//----------------------------------------------------------------------------
|
||||
wire [`CBA_RNG] cba_data;
|
||||
wire cba_empty;
|
||||
wire cba_ack;
|
||||
|
||||
wire cba_avail = ~cba_empty;
|
||||
|
||||
async_fifo #(
|
||||
.DATA_WIDTH( `CBA_WIDTH ),
|
||||
.ADDRESS_WIDTH( 4 )
|
||||
) cba_fifo (
|
||||
.Data_out( cba_data ),
|
||||
.Empty_out( cba_empty ),
|
||||
.ReadEn_in( cba_ack ),
|
||||
.RClk( clk ),
|
||||
//
|
||||
.Data_in( cba_din ),
|
||||
.WriteEn_in( cba_wr ),
|
||||
.Full_out( cba_full ),
|
||||
.WClk( cba_clk ),
|
||||
.Clear_in( reset )
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// WDATA async. fifo
|
||||
//----------------------------------------------------------------------------
|
||||
wire [`WFIFO_RNG] wdata_data;
|
||||
wire wdata_empty;
|
||||
wire wdata_ack;
|
||||
|
||||
wire wdata_avail = ~wdata_empty;
|
||||
|
||||
async_fifo #(
|
||||
.DATA_WIDTH( `WFIFO_WIDTH ),
|
||||
.ADDRESS_WIDTH( 4 )
|
||||
) wdata_fifo (
|
||||
.Data_out( wdata_data ),
|
||||
.Empty_out( wdata_empty ),
|
||||
.ReadEn_in( wdata_ack ),
|
||||
.RClk( ~clk90 ),
|
||||
//
|
||||
.Data_in( wdata_din ),
|
||||
.WriteEn_in( wdata_wr ),
|
||||
.Full_out( wdata_full ),
|
||||
.WClk( wdata_clk ),
|
||||
.Clear_in( reset )
|
||||
);
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Handle CBA
|
||||
//----------------------------------------------------------------------------
|
||||
reg [3:0] delay_count;
|
||||
|
||||
reg [`CBA_RNG] ddr_cba;
|
||||
wire [`CBA_RNG] CBA_NOP = { `DDR_CMD_NOP, 15'b0 };
|
||||
|
||||
assign cba_ack = cba_avail & (delay_count == 0);
|
||||
|
||||
wire [`CMD_RNG] cba_cmd = cba_data[(`CBA_WIDTH-1):(`CBA_WIDTH-3)];
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset) begin
|
||||
delay_count <= 0;
|
||||
ddr_cba <= CBA_NOP;
|
||||
end else begin
|
||||
if (delay_count != 0) begin
|
||||
delay_count <= delay_count - 1;
|
||||
ddr_cba <= CBA_NOP;
|
||||
end
|
||||
|
||||
if (!cba_ack) begin
|
||||
ddr_cba <= CBA_NOP;
|
||||
end else begin
|
||||
ddr_cba <= cba_data;
|
||||
|
||||
case (cba_cmd)
|
||||
`DDR_CMD_MRS : delay_count <= 2;
|
||||
`DDR_CMD_AR : delay_count <= 14;
|
||||
`DDR_CMD_ACT : delay_count <= 4;
|
||||
`DDR_CMD_PRE : delay_count <= 2;
|
||||
`DDR_CMD_READ : delay_count <= 6; // XXX
|
||||
`DDR_CMD_WRITE : delay_count <= 8; // XXX
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// READ-SHIFT-REGISTER
|
||||
//----------------------------------------------------------------------------
|
||||
reg [7:0] read_shr;
|
||||
wire read_cmd = (cba_cmd == `DDR_CMD_READ) & cba_ack;
|
||||
assign sample = read_shr[6];
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset)
|
||||
read_shr <= 'b0;
|
||||
else begin
|
||||
if (read_cmd)
|
||||
read_shr <= { 8'b00011000 };
|
||||
else
|
||||
read_shr <= { read_shr[6:0], 1'b0 };
|
||||
end
|
||||
end
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// WRITE-SHIFT-REGISTER
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
reg [0:4] write_shr;
|
||||
wire write_cmd = (cba_cmd == `DDR_CMD_WRITE) & cba_ack;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset)
|
||||
write_shr <= 'b0;
|
||||
else begin
|
||||
if (write_cmd)
|
||||
write_shr <= { 5'b11111 };
|
||||
else
|
||||
write_shr <= { write_shr[1:4], 1'b0 };
|
||||
end
|
||||
end
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// DDR_DQS, DDR_DQS_OE
|
||||
//----------------------------------------------------------------------------
|
||||
genvar i;
|
||||
|
||||
reg ddr_dqs_oe_reg;
|
||||
assign ddr_dqs_oe = ddr_dqs_oe_reg;
|
||||
|
||||
always @(negedge clk)
|
||||
begin
|
||||
ddr_dqs_oe_reg <= write_shr[0];
|
||||
end
|
||||
|
||||
generate
|
||||
for (i=0; i<3; i=i+1) begin : CLK
|
||||
FDDRRSE ddr_clk_reg (
|
||||
.Q( ddr_clk[i] ),
|
||||
.C0( clk90 ),
|
||||
.C1( ~clk90 ),
|
||||
.CE( vcc ),
|
||||
.D0( vcc ),
|
||||
.D1( gnd ),
|
||||
.R( gnd ),
|
||||
.S( gnd )
|
||||
);
|
||||
|
||||
FDDRRSE ddr_clk_n_reg (
|
||||
.Q( ddr_clk_n[i] ),
|
||||
.C0( clk90 ),
|
||||
.C1( ~clk90 ),
|
||||
.CE( vcc ),
|
||||
.D0( gnd ),
|
||||
.D1( vcc ),
|
||||
.R( gnd ),
|
||||
.S( gnd )
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
generate
|
||||
for (i=0; i<`DQS_WIDTH; i=i+1) begin : DQS
|
||||
FDDRRSE ddr_dqs_reg (
|
||||
.Q( ddr_dqs[i] ),
|
||||
.C0( clk ),
|
||||
.C1( ~clk ),
|
||||
.CE( vcc ),
|
||||
.D0( write_shr[1] ),
|
||||
.D1( gnd ),
|
||||
.R( gnd ),
|
||||
.S( gnd )
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// DQ data output
|
||||
//----------------------------------------------------------------------------
|
||||
wire [`DQ_RNG] buf_d0;
|
||||
wire [`DM_RNG] buf_m0;
|
||||
reg [`DQ_RNG] buf_d1; // pipleine high word data
|
||||
reg [`DM_RNG] buf_m1; // pipleine high word mask
|
||||
|
||||
assign buf_d0 = wdata_data[`WFIFO_D0_RNG];
|
||||
assign buf_m0 = wdata_data[`WFIFO_M0_RNG];
|
||||
|
||||
always @(negedge clk90)
|
||||
begin
|
||||
buf_d1 <= wdata_data[`WFIFO_D1_RNG];
|
||||
buf_m1 <= wdata_data[`WFIFO_M1_RNG];
|
||||
end
|
||||
|
||||
assign wdata_ack = write_shr[1];
|
||||
|
||||
// generate DDR_DQ register
|
||||
generate
|
||||
for (i=0; i<`DQ_WIDTH; i=i+1) begin : DQ_REG
|
||||
FDDRRSE ddr_dq_reg (
|
||||
.Q( ddr_dq[i] ),
|
||||
.C0( ~clk90 ),
|
||||
.C1( clk90 ),
|
||||
.CE( vcc ),
|
||||
.D0( buf_d0[i] ),
|
||||
.D1( buf_d1[i] ),
|
||||
.R( gnd ),
|
||||
.S( gnd )
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// generate DDR_DM register
|
||||
generate
|
||||
for (i=0; i<`DM_WIDTH; i=i+1) begin : DM_REG
|
||||
FDDRRSE ddr_dm_reg (
|
||||
.Q( ddr_dm[i] ),
|
||||
.C0( ~clk90 ),
|
||||
.C1( clk90 ),
|
||||
.CE( vcc ),
|
||||
.D0( buf_m0[i] ),
|
||||
.D1( buf_m1[i] ),
|
||||
.R( gnd ),
|
||||
.S( gnd )
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Connect ddr_cba to actual DDR pins
|
||||
//----------------------------------------------------------------------------
|
||||
assign ddr_a = ddr_cba[(`A_WIDTH-1):0];
|
||||
assign ddr_ba = ddr_cba[(`A_WIDTH+`BA_WIDTH-1):(`A_WIDTH)];
|
||||
assign ddr_ras_n = ddr_cba[(`CBA_WIDTH-1)];
|
||||
assign ddr_cas_n = ddr_cba[(`CBA_WIDTH-2)];
|
||||
assign ddr_we_n = ddr_cba[(`CBA_WIDTH-3)];
|
||||
|
||||
endmodule
|
||||
64
lm32/logic/sakc/rtl/wb_ddr/dpram.v
Normal file
64
lm32/logic/sakc/rtl/wb_ddr/dpram.v
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Wishbone DDR Controller
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
module dpram
|
||||
#(
|
||||
parameter adr_width = 9,
|
||||
parameter dat_width = 36
|
||||
) (
|
||||
input clk,
|
||||
// Port 0
|
||||
input [adr_width-1:0] adr0,
|
||||
input we0,
|
||||
input [dat_width-1:0] din0,
|
||||
output reg [dat_width-1:0] dout0,
|
||||
// Port 1
|
||||
input [adr_width-1:0] adr1,
|
||||
input we1,
|
||||
input [dat_width-1:0] din1,
|
||||
output reg [dat_width-1:0] dout1
|
||||
);
|
||||
|
||||
parameter depth = (1 << adr_width);
|
||||
|
||||
// actual ram
|
||||
reg [dat_width-1:0] ram [0:depth-1];
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Syncronous Dual Port RAM Access
|
||||
//------------------------------------------------------------------
|
||||
always @(posedge clk)
|
||||
begin
|
||||
// Frst port
|
||||
if (we0)
|
||||
ram[adr0] <= din0;
|
||||
|
||||
dout0 <= ram[adr0];
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
// Second port
|
||||
if (we1)
|
||||
ram[adr1] <= din1;
|
||||
|
||||
dout1 <= ram[adr1];
|
||||
end
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Initialize content to Zero
|
||||
//------------------------------------------------------------------
|
||||
integer i;
|
||||
|
||||
initial
|
||||
begin
|
||||
for(i=0; i<depth; i=i+1)
|
||||
ram[i] <= 'b0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
35
lm32/logic/sakc/rtl/wb_ddr/gray_counter.v
Normal file
35
lm32/logic/sakc/rtl/wb_ddr/gray_counter.v
Normal file
@@ -0,0 +1,35 @@
|
||||
//==========================================
|
||||
// Function : Code Gray counter.
|
||||
// Coder : Alex Claros F.
|
||||
// Date : 15/May/2005.
|
||||
//=======================================
|
||||
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module GrayCounter
|
||||
#(parameter COUNTER_WIDTH = 2)
|
||||
|
||||
(output reg [COUNTER_WIDTH-1:0] GrayCount_out, //'Gray' code count output.
|
||||
|
||||
input wire Enable_in, //Count enable.
|
||||
input wire Clear_in, //Count reset.
|
||||
|
||||
input wire Clk);
|
||||
|
||||
/////////Internal connections & variables///////
|
||||
reg [COUNTER_WIDTH-1:0] BinaryCount;
|
||||
|
||||
/////////Code///////////////////////
|
||||
|
||||
always @ (posedge Clk)
|
||||
if (Clear_in) begin
|
||||
BinaryCount <= {COUNTER_WIDTH{1'b 0}} + 1; //Gray count begins @ '1' with
|
||||
GrayCount_out <= {COUNTER_WIDTH{1'b 0}}; // first 'Enable_in'.
|
||||
end
|
||||
else if (Enable_in) begin
|
||||
BinaryCount <= BinaryCount + 1;
|
||||
GrayCount_out <= {BinaryCount[COUNTER_WIDTH-1],
|
||||
BinaryCount[COUNTER_WIDTH-2:0] ^ BinaryCount[COUNTER_WIDTH-1:1]};
|
||||
end
|
||||
|
||||
endmodule
|
||||
621
lm32/logic/sakc/rtl/wb_ddr/wb_ddr.v
Normal file
621
lm32/logic/sakc/rtl/wb_ddr/wb_ddr.v
Normal file
@@ -0,0 +1,621 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Wishbone DDR Controller
|
||||
//
|
||||
// (c) Joerg Bornschein (<jb@capsec.org>)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
`include "ddr_include.v"
|
||||
|
||||
module wb_ddr
|
||||
#(
|
||||
parameter clk_freq = 100000000,
|
||||
parameter clk_multiply = 12,
|
||||
parameter clk_divide = 5,
|
||||
parameter phase_shift = 0,
|
||||
parameter wait200_init = 26
|
||||
) (
|
||||
input clk,
|
||||
input reset,
|
||||
// DDR ports
|
||||
output [2:0] ddr_clk,
|
||||
output [2:0] ddr_clk_n,
|
||||
input ddr_clk_fb,
|
||||
output ddr_ras_n,
|
||||
output ddr_cas_n,
|
||||
output ddr_we_n,
|
||||
output [1:0] ddr_cke,
|
||||
output [1:0] 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,
|
||||
// XXX Temporary DCM control input XXX
|
||||
output ps_ready,
|
||||
input ps_up,
|
||||
input ps_down,
|
||||
// XXX probe wires XXX
|
||||
output probe_clk,
|
||||
input [7:0] probe_sel,
|
||||
output reg [7:0] probe
|
||||
);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// 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 ),
|
||||
// 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 ),
|
||||
// DCM phase shift control
|
||||
.ps_ready( ps_ready ),
|
||||
.ps_up( ps_up ),
|
||||
.ps_down( ps_down )
|
||||
);
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user