mirror of
https://github.com/fairwaves/UHD-Fairwaves.git
synced 2025-10-30 11:33:32 +00:00
279 lines
6.9 KiB
Verilog
279 lines
6.9 KiB
Verilog
//
|
|
// Copyright 2011 Ettus Research LLC
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
module ram_loader
|
|
#(parameter AWIDTH=16, RAM_SIZE=16384)
|
|
(
|
|
// Wishbone I/F and clock domain
|
|
input wb_clk,
|
|
input dsp_clk,
|
|
input ram_loader_rst,
|
|
output wire [31:0] wb_dat,
|
|
output wire [AWIDTH-1:0] wb_adr,
|
|
output wb_stb,
|
|
output reg [3:0] wb_sel,
|
|
output wb_we,
|
|
output reg ram_loader_done,
|
|
// CPLD signals and clock domain
|
|
input cpld_clk,
|
|
input cpld_din,
|
|
output reg cpld_start,
|
|
output reg cpld_mode,
|
|
output reg cpld_done,
|
|
input cpld_detached
|
|
);
|
|
|
|
localparam S0 = 0;
|
|
localparam S1 = 1;
|
|
localparam S2 = 2;
|
|
localparam S3 = 3;
|
|
localparam S4 = 4;
|
|
localparam S5 = 5;
|
|
localparam S6 = 6;
|
|
localparam RESET = 7;
|
|
|
|
localparam WB_IDLE = 0;
|
|
localparam WB_WRITE = 1;
|
|
|
|
|
|
reg [AWIDTH+2:0] count; // 3 LSB's count bits in, the MSB's generate the Wishbone address
|
|
reg [6:0] shift_reg;
|
|
reg [7:0] data_reg;
|
|
reg sampled_clk;
|
|
reg sampled_clk_meta;
|
|
reg sampled_din;
|
|
reg inc_count;
|
|
reg load_data_reg;
|
|
reg shift;
|
|
reg wb_state, wb_next_state;
|
|
reg [2:0] state, next_state;
|
|
|
|
//
|
|
// CPLD clock doesn't free run and is approximately 12.5MHz.
|
|
// Use 50MHz Wishbone clock to sample it as a signal and avoid having
|
|
// an extra clock domain for no reason.
|
|
//
|
|
|
|
always @(posedge dsp_clk or posedge ram_loader_rst)
|
|
if (ram_loader_rst)
|
|
begin
|
|
sampled_clk_meta <= 1'b0;
|
|
sampled_clk <= 1'b0;
|
|
sampled_din <= 1'b0;
|
|
count <= 'h7FFF8; // Initialize so that address will be 0 when first byte fully received.
|
|
data_reg <= 0;
|
|
shift_reg <= 0;
|
|
end
|
|
else
|
|
begin
|
|
sampled_clk_meta <= cpld_clk;
|
|
sampled_clk <= sampled_clk_meta;
|
|
sampled_din <= cpld_din;
|
|
if (inc_count)
|
|
count <= count + 1'b1;
|
|
if (load_data_reg)
|
|
data_reg <= {shift_reg,sampled_din};
|
|
if (shift)
|
|
shift_reg <= {shift_reg[5:0],sampled_din};
|
|
end // else: !if(ram_loader_rst)
|
|
|
|
|
|
always @(posedge dsp_clk or posedge ram_loader_rst)
|
|
if (ram_loader_rst)
|
|
state <= RESET;
|
|
else
|
|
state <= next_state;
|
|
|
|
|
|
always @*
|
|
begin
|
|
// Defaults
|
|
next_state = state;
|
|
cpld_start = 1'b0;
|
|
shift = 1'b0;
|
|
inc_count = 0;
|
|
load_data_reg = 1'b0;
|
|
ram_loader_done = 1'b0;
|
|
cpld_mode = 1'b0;
|
|
cpld_done = 1'b1;
|
|
|
|
|
|
|
|
case (state) //synthesis parallel_case full_case
|
|
// After reset wait until CPLD indicates its detached.
|
|
RESET: begin
|
|
if (cpld_detached)
|
|
next_state = S0;
|
|
else
|
|
next_state = RESET;
|
|
end
|
|
|
|
// Assert cpld_start to signal the CPLD its to start sending serial clock and data.
|
|
// Assume cpld_clk is low as we transition into search for first rising edge
|
|
S0: begin
|
|
cpld_start = 1'b1;
|
|
cpld_done = 1'b0;
|
|
if (~cpld_detached)
|
|
next_state = S2;
|
|
else
|
|
next_state = S0;
|
|
end
|
|
|
|
//
|
|
S1: begin
|
|
cpld_start = 1'b1;
|
|
cpld_done = 1'b0;
|
|
if (sampled_clk)
|
|
begin
|
|
// Found rising edge on cpld_clk.
|
|
if (count[2:0] == 3'b111)
|
|
// Its the last bit of a byte, send it out to the Wishbone bus.
|
|
begin
|
|
load_data_reg = 1'b1;
|
|
inc_count = 1'b1;
|
|
end
|
|
else
|
|
// Shift databit into LSB of shift register and increment count
|
|
begin
|
|
shift = 1'b1;
|
|
inc_count = 1'b1;
|
|
end // else: !if(count[2:0] == 3'b111)
|
|
next_state = S2;
|
|
end // if (sampled_clk)
|
|
else
|
|
next_state = S1;
|
|
end // case: S1
|
|
|
|
//
|
|
S2: begin
|
|
cpld_start = 1'b1;
|
|
cpld_done = 1'b0;
|
|
if (~sampled_clk)
|
|
// Found negative edge of clock
|
|
if (count[AWIDTH+2:3] == RAM_SIZE-1) // NOTE need to change this constant
|
|
// All firmware now downloaded
|
|
next_state = S3;
|
|
else
|
|
next_state = S1;
|
|
else
|
|
next_state = S2;
|
|
end // case: S2
|
|
|
|
// Now that terminal count is reached and all firmware is downloaded signal CPLD that download is done
|
|
// and that mode is now SPI mode.
|
|
S3: begin
|
|
if (sampled_clk)
|
|
begin
|
|
cpld_mode = 1'b1;
|
|
cpld_done = 1'b1;
|
|
next_state = S4;
|
|
end
|
|
else
|
|
next_state = S3;
|
|
end
|
|
|
|
// Search for negedge of cpld_clk whilst keeping done sequence asserted.
|
|
// Keep done assserted
|
|
S4: begin
|
|
cpld_mode = 1'b1;
|
|
cpld_done = 1'b1;
|
|
if (~sampled_clk)
|
|
next_state = S5;
|
|
else
|
|
next_state = S4;
|
|
end
|
|
|
|
// Search for posedge of cpld_clk whilst keeping done sequence asserted.
|
|
S5: begin
|
|
cpld_mode = 1'b1;
|
|
cpld_done = 1'b1;
|
|
if (sampled_clk)
|
|
next_state = S6;
|
|
else
|
|
next_state = S5;
|
|
end
|
|
|
|
// Stay in this state until reset/power down
|
|
S6: begin
|
|
ram_loader_done = 1'b1;
|
|
cpld_done = 1'b1;
|
|
cpld_mode = 1'b1;
|
|
next_state = S6;
|
|
end
|
|
|
|
endcase // case(state)
|
|
end
|
|
|
|
always @(posedge dsp_clk or posedge ram_loader_rst)
|
|
if (ram_loader_rst)
|
|
wb_state <= WB_IDLE;
|
|
else
|
|
wb_state <= wb_next_state;
|
|
|
|
reg do_write;
|
|
wire empty, full;
|
|
|
|
always @*
|
|
begin
|
|
wb_next_state = wb_state;
|
|
do_write = 1'b0;
|
|
|
|
case (wb_state) //synthesis full_case parallel_case
|
|
//
|
|
WB_IDLE: begin
|
|
if (load_data_reg)
|
|
// Data reg will load ready to write wishbone @ next clock edge
|
|
wb_next_state = WB_WRITE;
|
|
else
|
|
wb_next_state = WB_IDLE;
|
|
end
|
|
|
|
// Drive address and data onto wishbone.
|
|
WB_WRITE: begin
|
|
do_write = 1'b1;
|
|
if (~full)
|
|
wb_next_state = WB_IDLE;
|
|
else
|
|
wb_next_state = WB_WRITE;
|
|
end
|
|
|
|
endcase // case(wb_state)
|
|
end // always @ *
|
|
|
|
wire [1:0] count_out;
|
|
wire [7:0] data_out;
|
|
|
|
fifo_xlnx_16x40_2clk crossclk
|
|
(.rst(ram_loader_rst),
|
|
.wr_clk(dsp_clk), .din({count[4:3],count[AWIDTH+2:3],data_reg}), .wr_en(do_write), .full(full),
|
|
.rd_clk(wb_clk), .dout({count_out,wb_adr,data_out}), .rd_en(~empty), .empty(empty));
|
|
|
|
assign wb_dat = {4{data_out}};
|
|
|
|
always @*
|
|
case(count_out[1:0]) //synthesis parallel_case full_case
|
|
2'b00 : wb_sel = 4'b1000;
|
|
2'b01 : wb_sel = 4'b0100;
|
|
2'b10 : wb_sel = 4'b0010;
|
|
2'b11 : wb_sel = 4'b0001;
|
|
endcase
|
|
|
|
assign wb_we = ~empty;
|
|
assign wb_stb = ~empty;
|
|
|
|
endmodule // ram_loader
|