From 61f2f0214c5999ea42a368a4fc99f03d8eb28d1e Mon Sep 17 00:00:00 2001 From: jcorgan Date: Mon, 8 Sep 2008 01:00:12 +0000 Subject: Merged r9433:9527 from features/gr-usrp2 into trunk. Adds usrp2 and gr-usrp2 top-level components. Trunk passes distcheck with mb-gcc installed, but currently not without them. The key issue is that when mb-gcc is not installed, the build system skips over the usrp2/firmware directory, and the firmware include files don't get put into the dist tarball. But we can't do the usual DIST_SUBDIRS method as the firmware is a subpackage. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9528 221aa14e-8319-0410-a670-987f0aec2ac5 --- control_lib/CRC16_D16.v | 89 ++++++++ control_lib/SYSCTRL.sav | 24 ++ control_lib/WB_SIM.sav | 47 ++++ control_lib/atr_controller.v | 57 +++++ control_lib/bin2gray.v | 10 + control_lib/bootrom.mem | 26 +++ control_lib/buffer_int.v | 191 ++++++++++++++++ control_lib/buffer_int_tb.v | 447 ++++++++++++++++++++++++++++++++++++++ control_lib/buffer_pool.v | 323 +++++++++++++++++++++++++++ control_lib/buffer_pool_tb.v | 50 +++++ control_lib/cascadefifo.v | 50 +++++ control_lib/cascadefifo2.v | 56 +++++ control_lib/clock_bootstrap_rom.v | 34 +++ control_lib/clock_control.v | 115 ++++++++++ control_lib/clock_control_tb.sav | 28 +++ control_lib/clock_control_tb.v | 35 +++ control_lib/cmdfile | 18 ++ control_lib/dcache.v | 165 ++++++++++++++ control_lib/decoder_3_8.v | 21 ++ control_lib/dpram32.v | 82 +++++++ control_lib/extram_interface.v | 53 +++++ control_lib/fifo_2clock.v | 66 ++++++ control_lib/fifo_2clock_casc.v | 31 +++ control_lib/fifo_reader.v | 28 +++ control_lib/fifo_tb.v | 153 +++++++++++++ control_lib/fifo_writer.v | 31 +++ control_lib/gray2bin.v | 13 ++ control_lib/gray_send.v | 29 +++ control_lib/icache.v | 134 ++++++++++++ control_lib/longfifo.v | 122 +++++++++++ control_lib/medfifo.v | 49 +++++ control_lib/mux4.v | 16 ++ control_lib/mux8.v | 21 ++ control_lib/mux_32_4.v | 13 ++ control_lib/nsgpio.v | 107 +++++++++ control_lib/oneshot_2clk.v | 35 +++ control_lib/ram_2port.v | 42 ++++ control_lib/ram_harv_cache.v | 72 ++++++ control_lib/ram_loader.v | 225 +++++++++++++++++++ control_lib/ram_wb_harvard.v | 86 ++++++++ control_lib/sd_spi.v | 70 ++++++ control_lib/sd_spi_tb.v | 40 ++++ control_lib/sd_spi_wb.v | 66 ++++++ control_lib/setting_reg.v | 23 ++ control_lib/settings_bus.v | 49 +++++ control_lib/shortfifo.v | 63 ++++++ control_lib/simple_uart.v | 61 ++++++ control_lib/simple_uart_rx.v | 64 ++++++ control_lib/simple_uart_tx.v | 60 +++++ control_lib/spi.v | 84 +++++++ control_lib/srl.v | 21 ++ control_lib/ss_rcvr.v | 81 +++++++ control_lib/system_control.v | 47 ++++ control_lib/system_control_tb.v | 57 +++++ control_lib/traffic_cop.v | 25 +++ control_lib/wb_1master.v | 430 ++++++++++++++++++++++++++++++++++++ control_lib/wb_bus_writer.v | 57 +++++ control_lib/wb_output_pins32.v | 49 +++++ control_lib/wb_ram_block.v | 36 +++ control_lib/wb_ram_dist.v | 33 +++ control_lib/wb_readback_mux.v | 60 +++++ control_lib/wb_regfile_2clock.v | 107 +++++++++ control_lib/wb_semaphore.v | 42 ++++ control_lib/wb_sim.v | 79 +++++++ 64 files changed, 4898 insertions(+) create mode 100644 control_lib/CRC16_D16.v create mode 100644 control_lib/SYSCTRL.sav create mode 100644 control_lib/WB_SIM.sav create mode 100644 control_lib/atr_controller.v create mode 100644 control_lib/bin2gray.v create mode 100644 control_lib/bootrom.mem create mode 100644 control_lib/buffer_int.v create mode 100644 control_lib/buffer_int_tb.v create mode 100644 control_lib/buffer_pool.v create mode 100644 control_lib/buffer_pool_tb.v create mode 100644 control_lib/cascadefifo.v create mode 100644 control_lib/cascadefifo2.v create mode 100644 control_lib/clock_bootstrap_rom.v create mode 100644 control_lib/clock_control.v create mode 100644 control_lib/clock_control_tb.sav create mode 100644 control_lib/clock_control_tb.v create mode 100644 control_lib/cmdfile create mode 100644 control_lib/dcache.v create mode 100644 control_lib/decoder_3_8.v create mode 100644 control_lib/dpram32.v create mode 100644 control_lib/extram_interface.v create mode 100644 control_lib/fifo_2clock.v create mode 100644 control_lib/fifo_2clock_casc.v create mode 100644 control_lib/fifo_reader.v create mode 100644 control_lib/fifo_tb.v create mode 100644 control_lib/fifo_writer.v create mode 100644 control_lib/gray2bin.v create mode 100644 control_lib/gray_send.v create mode 100644 control_lib/icache.v create mode 100644 control_lib/longfifo.v create mode 100644 control_lib/medfifo.v create mode 100644 control_lib/mux4.v create mode 100644 control_lib/mux8.v create mode 100644 control_lib/mux_32_4.v create mode 100644 control_lib/nsgpio.v create mode 100644 control_lib/oneshot_2clk.v create mode 100644 control_lib/ram_2port.v create mode 100644 control_lib/ram_harv_cache.v create mode 100644 control_lib/ram_loader.v create mode 100644 control_lib/ram_wb_harvard.v create mode 100644 control_lib/sd_spi.v create mode 100644 control_lib/sd_spi_tb.v create mode 100644 control_lib/sd_spi_wb.v create mode 100644 control_lib/setting_reg.v create mode 100644 control_lib/settings_bus.v create mode 100644 control_lib/shortfifo.v create mode 100644 control_lib/simple_uart.v create mode 100644 control_lib/simple_uart_rx.v create mode 100644 control_lib/simple_uart_tx.v create mode 100644 control_lib/spi.v create mode 100644 control_lib/srl.v create mode 100644 control_lib/ss_rcvr.v create mode 100644 control_lib/system_control.v create mode 100644 control_lib/system_control_tb.v create mode 100644 control_lib/traffic_cop.v create mode 100644 control_lib/wb_1master.v create mode 100644 control_lib/wb_bus_writer.v create mode 100644 control_lib/wb_output_pins32.v create mode 100644 control_lib/wb_ram_block.v create mode 100644 control_lib/wb_ram_dist.v create mode 100644 control_lib/wb_readback_mux.v create mode 100644 control_lib/wb_regfile_2clock.v create mode 100644 control_lib/wb_semaphore.v create mode 100644 control_lib/wb_sim.v (limited to 'control_lib') diff --git a/control_lib/CRC16_D16.v b/control_lib/CRC16_D16.v new file mode 100644 index 000000000..7e2816af1 --- /dev/null +++ b/control_lib/CRC16_D16.v @@ -0,0 +1,89 @@ +/////////////////////////////////////////////////////////////////////// +// File: CRC16_D16.v +// Date: Sun Jun 17 06:42:55 2007 +// +// Copyright (C) 1999-2003 Easics NV. +// This source file may be used and distributed without restriction +// provided that this copyright statement is not removed from the file +// and that any derivative work contains the original copyright notice +// and the associated disclaimer. +// +// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS +// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Purpose: Verilog module containing a synthesizable CRC function +// * polynomial: (0 5 12 16) +// * data width: 16 +// +// Info: tools@easics.be +// http://www.easics.com +/////////////////////////////////////////////////////////////////////// + + +module CRC16_D16 + (input [15:0] Data, + input [15:0] CRC, + output [15:0] NewCRC); + + assign NewCRC = nextCRC16_D16(Data,CRC); + + // polynomial: (0 5 12 16) + // data width: 16 + // convention: the first serial data bit is D[15] + function [15:0] nextCRC16_D16; + + input [15:0] Data; + input [15:0] CRC; + + reg [15:0] D; + reg [15:0] C; + reg [15:0] NewCRC; + + begin + + D = Data; + C = CRC; + + NewCRC[0] = D[12] ^ D[11] ^ D[8] ^ D[4] ^ D[0] ^ C[0] ^ C[4] ^ + C[8] ^ C[11] ^ C[12]; + NewCRC[1] = D[13] ^ D[12] ^ D[9] ^ D[5] ^ D[1] ^ C[1] ^ C[5] ^ + C[9] ^ C[12] ^ C[13]; + NewCRC[2] = D[14] ^ D[13] ^ D[10] ^ D[6] ^ D[2] ^ C[2] ^ C[6] ^ + C[10] ^ C[13] ^ C[14]; + NewCRC[3] = D[15] ^ D[14] ^ D[11] ^ D[7] ^ D[3] ^ C[3] ^ C[7] ^ + C[11] ^ C[14] ^ C[15]; + NewCRC[4] = D[15] ^ D[12] ^ D[8] ^ D[4] ^ C[4] ^ C[8] ^ C[12] ^ + C[15]; + NewCRC[5] = D[13] ^ D[12] ^ D[11] ^ D[9] ^ D[8] ^ D[5] ^ D[4] ^ + D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[8] ^ C[9] ^ C[11] ^ C[12] ^ + C[13]; + NewCRC[6] = D[14] ^ D[13] ^ D[12] ^ D[10] ^ D[9] ^ D[6] ^ D[5] ^ + D[1] ^ C[1] ^ C[5] ^ C[6] ^ C[9] ^ C[10] ^ C[12] ^ + C[13] ^ C[14]; + NewCRC[7] = D[15] ^ D[14] ^ D[13] ^ D[11] ^ D[10] ^ D[7] ^ D[6] ^ + D[2] ^ C[2] ^ C[6] ^ C[7] ^ C[10] ^ C[11] ^ C[13] ^ + C[14] ^ C[15]; + NewCRC[8] = D[15] ^ D[14] ^ D[12] ^ D[11] ^ D[8] ^ D[7] ^ D[3] ^ + C[3] ^ C[7] ^ C[8] ^ C[11] ^ C[12] ^ C[14] ^ C[15]; + NewCRC[9] = D[15] ^ D[13] ^ D[12] ^ D[9] ^ D[8] ^ D[4] ^ C[4] ^ + C[8] ^ C[9] ^ C[12] ^ C[13] ^ C[15]; + NewCRC[10] = D[14] ^ D[13] ^ D[10] ^ D[9] ^ D[5] ^ C[5] ^ C[9] ^ + C[10] ^ C[13] ^ C[14]; + NewCRC[11] = D[15] ^ D[14] ^ D[11] ^ D[10] ^ D[6] ^ C[6] ^ C[10] ^ + C[11] ^ C[14] ^ C[15]; + NewCRC[12] = D[15] ^ D[8] ^ D[7] ^ D[4] ^ D[0] ^ C[0] ^ C[4] ^ C[7] ^ + C[8] ^ C[15]; + NewCRC[13] = D[9] ^ D[8] ^ D[5] ^ D[1] ^ C[1] ^ C[5] ^ C[8] ^ C[9]; + NewCRC[14] = D[10] ^ D[9] ^ D[6] ^ D[2] ^ C[2] ^ C[6] ^ C[9] ^ C[10]; + NewCRC[15] = D[11] ^ D[10] ^ D[7] ^ D[3] ^ C[3] ^ C[7] ^ C[10] ^ + C[11]; + + nextCRC16_D16 = NewCRC; + + end + + endfunction + +endmodule + diff --git a/control_lib/SYSCTRL.sav b/control_lib/SYSCTRL.sav new file mode 100644 index 000000000..43bfef10e --- /dev/null +++ b/control_lib/SYSCTRL.sav @@ -0,0 +1,24 @@ +[size] 1400 971 +[pos] -1 -1 +*-11.026821 2450 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +@28 +system_control_tb.aux_clk +@29 +system_control_tb.clk_fpga +@28 +system_control_tb.dsp_clk +system_control_tb.dsp_rst +system_control_tb.proc_rst +system_control_tb.rl_done +system_control_tb.rl_rst +system_control_tb.wb_clk +system_control_tb.wb_rst +system_control_tb.system_control.POR +@22 +system_control_tb.system_control.POR_ctr[3:0] +@28 +system_control_tb.clock_ready +system_control_tb.system_control.half_clk +system_control_tb.system_control.fin_ret_half +system_control_tb.system_control.fin_ret_aux +system_control_tb.system_control.gate_dsp_clk diff --git a/control_lib/WB_SIM.sav b/control_lib/WB_SIM.sav new file mode 100644 index 000000000..467cd35ef --- /dev/null +++ b/control_lib/WB_SIM.sav @@ -0,0 +1,47 @@ +[size] 1400 971 +[pos] -1 -1 +*-6.099828 350 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +@28 +wb_sim.wb_rst +wb_sim.wb_clk +@23 +wb_sim.rom_data[47:0] +@22 +wb_sim.rom_addr[15:0] +@28 +wb_sim.start +wb_sim.wb_ack +@22 +wb_sim.wb_adr[15:0] +@28 +wb_sim.wb_cyc +@22 +wb_sim.wb_dat[31:0] +wb_sim.wb_sel[3:0] +@28 +wb_sim.wb_stb +wb_sim.wb_we +@22 +wb_sim.port_output[31:0] +@28 +wb_sim.system_control.POR +wb_sim.system_control.aux_clk +wb_sim.system_control.clk_fpga +@29 +wb_sim.system_control.done +@28 +wb_sim.system_control.dsp_clk +wb_sim.system_control.fin_del1 +wb_sim.system_control.fin_del2 +wb_sim.system_control.fin_del3 +wb_sim.system_control.fin_ret_aux +@29 +wb_sim.system_control.fin_ret_fpga +@28 +wb_sim.system_control.finished +wb_sim.system_control.reset_out +wb_sim.system_control.start +wb_sim.system_control.started +wb_sim.system_control.wb_clk_o +wb_sim.system_control.wb_rst_o +wb_sim.system_control.wb_rst_o_alt diff --git a/control_lib/atr_controller.v b/control_lib/atr_controller.v new file mode 100644 index 000000000..fed2791f9 --- /dev/null +++ b/control_lib/atr_controller.v @@ -0,0 +1,57 @@ + +// Automatic transmit/receive switching of control pins to daughterboards +// Store everything in registers for now, but could use a RAM for more +// complex state machines in the future + +module atr_controller + (input clk_i, input rst_i, + input [5:0] adr_i, input [3:0] sel_i, input [31:0] dat_i, output reg [31:0] dat_o, + input we_i, input stb_i, input cyc_i, output reg ack_o, + input run_rx, input run_tx, input [31:0] master_time, + output [31:0] ctrl_lines); + + reg [3:0] state; + reg [31:0] atr_ram [0:15]; // DP distributed RAM + + // WB Interface + always @(posedge clk_i) + if(we_i & stb_i & cyc_i) + begin + if(sel_i[3]) + atr_ram[adr_i[5:2]][31:24] <= dat_i[31:24]; + if(sel_i[2]) + atr_ram[adr_i[5:2]][23:16] <= dat_i[23:16]; + if(sel_i[1]) + atr_ram[adr_i[5:2]][15:8] <= dat_i[15:8]; + if(sel_i[0]) + atr_ram[adr_i[5:2]][7:0] <= dat_i[7:0]; + end // if (we_i & stb_i & cyc_i) + + always @(posedge clk_i) + dat_o <= atr_ram[adr_i[5:2]]; + + always @(posedge clk_i) + ack_o <= stb_i & cyc_i & ~ack_o; + + // Control side of DP RAM + assign ctrl_lines = atr_ram[state]; + + // Put a more complex state machine with time delays and multiple states here + // if daughterboard requires more complex sequencing + localparam ATR_IDLE = 4'd0; + localparam ATR_TX = 4'd1; + localparam ATR_RX = 4'd2; + localparam ATR_FULL_DUPLEX = 4'd3; + + always @(posedge clk_i) + if(rst_i) + state <= ATR_IDLE; + else + case ({run_rx,run_tx}) + 2'b00 : state <= ATR_IDLE; + 2'b01 : state <= ATR_TX; + 2'b10 : state <= ATR_RX; + 2'b11 : state <= ATR_FULL_DUPLEX; + endcase // case({run_rx,run_tx}) + +endmodule // atr_controller diff --git a/control_lib/bin2gray.v b/control_lib/bin2gray.v new file mode 100644 index 000000000..513402163 --- /dev/null +++ b/control_lib/bin2gray.v @@ -0,0 +1,10 @@ + + +module bin2gray + #(parameter WIDTH=8) + (input [WIDTH-1:0] bin, + output [WIDTH-1:0] gray); + + assign gray = (bin >> 1) ^ bin; + +endmodule // bin2gray diff --git a/control_lib/bootrom.mem b/control_lib/bootrom.mem new file mode 100644 index 000000000..d688b4342 --- /dev/null +++ b/control_lib/bootrom.mem @@ -0,0 +1,26 @@ +00000C000F03 +101400000000 + // SPI: Set Divider to div by 2 +// Both clk sel choose ext ref (0), both are enabled (1), turn off SERDES, ADCs, turn on leds +1018_0000_0001 // SPI: Choose AD9510 +1010_0000_3418 // SPI: Auto-slave select, interrupt when done, TX_NEG, 24-bit word +1000_0000_0010 // SPI: AD9510 A:0 D:10 Set up AD9510 SPI +1010_0000_3518 // SPI: SEND IT Auto-slave select, interrupt when done, TX_NEG, 24-bit word +ffff_ffff_ffff // terminate +#// First 16 bits are address, last 32 are data +#// First 4 bits of address select which slave +// 6'd01 : addr_data = {13'h45,8'h00}; // CLK2 drives distribution, everything on +// 6'd02 : addr_data = {13'h3D,8'h80}; // Turn on output 1, normal levels +// 6'd03 : addr_data = {13'h4B,8'h80}; // Bypass divider 1 (div by 1) +// 6'd04 : addr_data = {13'h08,8'h47}; // POS PFD, Dig LK Det, Charge Pump normal +// 6'd05 : addr_data = {13'h09,8'h70}; // Max Charge Pump current +// 6'd06 : addr_data = {13'h0A,8'h04}; // Normal operation, Prescalar Div by 2, PLL On +// 6'd07 : addr_data = {13'h0B,8'h00}; // RDIV MSB (6 bits) +// 6'd08 : addr_data = {13'h0C,8'h01}; // RDIV LSB (8 bits), Div by 1 +// 6'd09 : addr_data = {13'h0D,8'h00}; // Everything normal, Dig Lock Det +// 6'd10 : addr_data = {13'h07,8'h00}; // Disable LOR detect - LOR causes failure... +// 6'd11 : addr_data = {13'h04,8'h00}; // A Counter = Don't Care +// 6'd12 : addr_data = {13'h05,8'h00}; // B Counter MSB = 0 +// 6'd13 : addr_data = {13'h06,8'h05}; // B Counter LSB = 5 + // default : addr_data = {13'h5A,8'h01}; // Register Update +// @ 55 // Jump to new address 8'h55 diff --git a/control_lib/buffer_int.v b/control_lib/buffer_int.v new file mode 100644 index 000000000..e362d93f2 --- /dev/null +++ b/control_lib/buffer_int.v @@ -0,0 +1,191 @@ + +// FIFO Interface to the 2K buffer RAMs +// Read port is read-acknowledge +// FIXME do we want to be able to interleave reads and writes? + +module buffer_int + #(parameter BUFF_NUM = 0) + (// Control Interface + input clk, + input rst, + input [31:0] ctrl_word, + input go, + output done, + output error, + output idle, + + // Buffer Interface + output en_o, + output we_o, + output reg [8:0] addr_o, + output [31:0] dat_to_buf, + input [31:0] dat_from_buf, + + // Write FIFO Interface + input [31:0] wr_dat_i, + input wr_write_i, + input wr_done_i, + input wr_error_i, + output reg wr_ready_o, + output reg wr_full_o, + + // Read FIFO Interface + output [31:0] rd_dat_o, + input rd_read_i, + input rd_done_i, + input rd_error_i, + output reg rd_sop_o, + output reg rd_eop_o + ); + + reg [31:0] ctrl_reg; + reg go_reg; + + always @(posedge clk) + go_reg <= go; + + always @(posedge clk) + if(rst) + ctrl_reg <= 0; + else + if(go & (ctrl_word[31:28] == BUFF_NUM)) + ctrl_reg <= ctrl_word; + + wire [8:0] firstline = ctrl_reg[8:0]; + wire [8:0] lastline = ctrl_reg[17:9]; + wire [3:0] step = ctrl_reg[21:18]; + wire read = ctrl_reg[22]; + wire write = ctrl_reg[23]; + wire clear = ctrl_reg[24]; + //wire [2:0] port = ctrl_reg[27:25]; // Ignored in this block + //wire [3:0] buff_num = ctrl_reg[31:28]; // Ignored here ? + + assign dat_to_buf = wr_dat_i; + assign rd_dat_o = dat_from_buf; + + localparam IDLE = 3'd0; + localparam PRE_READ = 3'd1; + localparam READING = 3'd2; + localparam WRITING = 3'd3; + localparam ERROR = 3'd4; + localparam DONE = 3'd5; + + reg [2:0] state; + + always @(posedge clk) + if(rst) + begin + state <= IDLE; + rd_sop_o <= 0; + rd_eop_o <= 0; + wr_ready_o <= 0; + wr_full_o <= 0; + end + else + if(clear) + begin + state <= IDLE; + rd_sop_o <= 0; + rd_eop_o <= 0; + wr_ready_o <= 0; + wr_full_o <= 0; + end + else + case(state) + IDLE : + if(go_reg & read) + begin + addr_o <= firstline; + state <= PRE_READ; + end + else if(go_reg & write) + begin + addr_o <= firstline; + state <= WRITING; + wr_ready_o <= 1; + end + + PRE_READ : + begin + state <= READING; + addr_o <= addr_o + 1; + rd_sop_o <= 1; + end + + READING : + if(rd_error_i) + state <= ERROR; + else if(rd_done_i) + state <= DONE; + else if(rd_read_i) + begin + rd_sop_o <= 0; + addr_o <= addr_o + 1; + if(addr_o == lastline) + rd_eop_o <= 1; + else + rd_eop_o <= 0; + if(rd_eop_o) + state <= DONE; + end + + WRITING : + begin + if(wr_error_i) + begin + state <= ERROR; + wr_ready_o <= 0; + end + else + begin + if(wr_write_i) + begin + wr_ready_o <= 0; + addr_o <= addr_o + 1; + if(addr_o == (lastline-1)) + wr_full_o <= 1; + if(addr_o == lastline) + state <= DONE; + end + if(wr_done_i) + begin + state <= DONE; + wr_ready_o <= 0; + end + end // else: !if(wr_error_i) + end // case: WRITING + + DONE : + begin + rd_eop_o <= 0; + rd_sop_o <= 0; + wr_ready_o <= 0; + wr_full_o <= 0; + end + + endcase // case(state) + + // FIXME ignores step for now + + assign we_o = (state == WRITING) && wr_write_i; // FIXME potential critical path + // IF this is a timing problem, we could always write when in this state + assign en_o = ~((state==READING)& ~rd_read_i); // FIXME potential critical path + + assign done = (state == DONE); + assign error = (state == ERROR); + assign idle = (state == IDLE); +endmodule // buffer_int + +// Unused old code + //assign rd_empty_o = (state != READING); // && (state != PRE_READ); + //assign rd_empty_o = rd_empty_reg; // timing fix? + //assign rd_ready_o = (state == READING); + //assign rd_ready_o = ~rd_empty_reg; // timing fix? + + //wire rd_en = (state == PRE_READ) || ((state == READING) && rd_read_i); + //wire wr_en = (state == WRITING) && wr_write_i; // IF this is a timing problem, we could always enable when in this state + //assign en_o = rd_en | wr_en; + + // assign wr_full_o = (state != WRITING); + // assign wr_ready_o = (state == WRITING); + diff --git a/control_lib/buffer_int_tb.v b/control_lib/buffer_int_tb.v new file mode 100644 index 000000000..4fb5c6710 --- /dev/null +++ b/control_lib/buffer_int_tb.v @@ -0,0 +1,447 @@ + +module buffer_int_tb (); + + reg clk = 0; + reg rst = 1; + + initial #100 rst = 0; + always #5 clk = ~clk; + + wire en, we; + wire [8:0] addr; + wire [31:0] fifo2buf, buf2fifo; + + wire [31:0] rd_dat_o; + wire rd_sop_o, rd_eop_o; + reg rd_done_i = 0, rd_error_i = 0, rd_read_i = 0; + + reg [31:0] wr_dat_i = 0; + reg wr_write_i=0, wr_done_i = 0, wr_error_i = 0; + wire wr_ready_o, wr_full_o; + + reg clear = 0, write = 0, read = 0; + reg [8:0] firstline = 0, lastline = 0; + wire [3:0] step = 1; + wire [31:0] ctrl_word = {4'b0,3'b0,clear,write,read,step,lastline,firstline}; + reg go = 0; + wire done, error; + + buffer_int buffer_int + (.clk(clk),.rst(rst), + .ctrl_word(ctrl_word),.go(go), + .done(done),.error(error), + + // Buffer Interface + .en_o(en),.we_o(we),.addr_o(addr), + .dat_to_buf(fifo2buf),.dat_from_buf(buf2fifo), + + // Write FIFO Interface + .wr_dat_i(wr_dat_i), .wr_write_i(wr_write_i), .wr_done_i(wr_done_i), .wr_error_i(wr_error_i), + .wr_ready_o(wr_ready_o), .wr_full_o(wr_full_o), + + // Read FIFO Interface + .rd_dat_o(rd_dat_o), .rd_read_i(rd_read_i), .rd_done_i(rd_done_i), .rd_error_i(rd_error_i), + .rd_sop_o(rd_sop_o), .rd_eop_o(rd_eop_o) + ); + + reg ram_en = 0, ram_we = 0; + reg [8:0] ram_addr = 0; + reg [31:0] ram_data = 0; + + ram_2port #(.DWIDTH(32),.AWIDTH(9)) ram_2port + (.clka(clk), .ena(ram_en), .wea(ram_we), .addra(ram_addr), .dia(ram_data), .doa(), + .clkb(clk), .enb(en), .web(we), .addrb(addr), .dib(fifo2buf), .dob(buf2fifo) ); + + initial + begin + @(negedge rst); + @(posedge clk); + FillRAM; + + ResetBuffer; + SetBufferRead(5,10); + $display("Testing full read, no wait states."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(6,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(5,10); + $display("Testing full read, 2 wait states."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(6,2); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(5,10); + $display("Testing full read, done ON the last."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(5,2); + rd_done_i <= 1; + ReadALine; + rd_done_i <= 0; + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(5,10); + $display("Testing partial read, 0 wait states, then nothing after last."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(3,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(5,10); + $display("Testing partial read, 0 wait states, then done after last."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(3,0); + rd_done_i <= 1; + @(posedge clk); + rd_done_i <= 0; + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(5,10); + $display("Testing partial read, 0 wait states, then done at same time as last."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(2,0); + rd_done_i <= 1; + ReadALine; + rd_done_i <= 0; + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(5,10); + $display("Testing partial read, 3 wait states, then error at same time as last."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(2,3); + rd_error_i <= 1; + ReadALine; + rd_error_i <= 0; + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(5,10); + $display("Testing Reading too much, 3 wait states."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(9,3); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(500,511); + $display("Testing full read, to the end of the buffer."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(12,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(0,511); + $display("Testing full read, start to end of the buffer."); + while(!rd_sop_o) + @(posedge clk); + ReadLines(512,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(505,3); + $display("Testing full read, wraparound"); + while(!rd_sop_o) + @(posedge clk); + ReadLines(11,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(10,15); + $display("Testing Full Write, no wait states"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(6,0,72); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(18,23); + $display("Testing Full Write, 1 wait states"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(6,0,101); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(27,40); + $display("Testing Partial Write, 0 wait states"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(6,0,201); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(35,200); + $display("Testing Partial Write, 0 wait states, then done"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(6,0,301); + wr_done_i <= 1; + @(posedge clk); + wr_done_i <= 0; + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(45,200); + $display("Testing Partial Write, 0 wait states, then done and write simultaneously"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(6,0,301); + wr_done_i <= 1; + WriteALine(400); + wr_done_i <= 0; + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(55,200); + $display("Testing Partial Write, 0 wait states, then error"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(6,0,501); + wr_error_i <= 1; + @(posedge clk); + wr_error_i <= 0; + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(0,82); + $display("Testing read after all the writes"); + while(!rd_sop_o) + @(posedge clk); + ReadLines(83,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(508,4); + $display("Testing wraparound write"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(9,0,601); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(506,10); + $display("Reading wraparound write"); + while(!rd_sop_o) + @(posedge clk); + ReadLines(17,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(0,511); + $display("Testing Whole Buffer write"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(512,0,1000); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(0,511); + $display("Reading Whole Buffer write"); + while(!rd_sop_o) + @(posedge clk); + ReadLines(512,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(5,10); + $display("Testing Write Too Many"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(12,0,2000); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(0,15); + $display("Reading back Write Too Many"); + while(!rd_sop_o) + @(posedge clk); + ReadLines(16,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferWrite(15,20); + $display("Testing Write One Less Than Full"); + while(!wr_ready_o) + @(posedge clk); + WriteLines(5,0,2000); + repeat (10) + @(posedge clk); + + ResetBuffer; + SetBufferRead(13,22); + $display("Reading back Write One Less Than Full"); + while(!rd_sop_o) + @(posedge clk); + ReadLines(10,0); + repeat (10) + @(posedge clk); + + ResetBuffer; + repeat(100) + @(posedge clk); + $finish; + end + + always @(posedge clk) + if(rd_read_i == 1'd1) + $display("READ Buffer %d, rd_sop_o %d, rd_eop_o %d", rd_dat_o, rd_sop_o, rd_eop_o); + + always @(posedge clk) + if(wr_write_i == 1'd1) + $display("WRITE Buffer %d, wr_ready_o %d, wr_full_o %d", wr_dat_i, wr_ready_o, wr_full_o); + + initial begin + $dumpfile("buffer_int_tb.vcd"); + $dumpvars(0,buffer_int_tb); + end + + task FillRAM; + begin + ram_addr <= 0; + ram_data <= 0; + @(posedge clk); + ram_en <= 1; + ram_we <= 1; + @(posedge clk); + repeat (511) + begin + ram_addr <= ram_addr + 1; + ram_data <= ram_data + 1; + ram_en <= 1; + ram_we <= 1; + @(posedge clk); + end + ram_en <= 0; + ram_we <= 0; + @(posedge clk); + $display("Filled the RAM"); + end + endtask // FillRAM + + task ResetBuffer; + begin + clear <= 1; read <= 0; write <= 0; + go <= 1; + @(posedge clk); + go <= 0; + @(posedge clk); + $display("Buffer Reset"); + end + endtask // ClearBuffer + + task SetBufferWrite; + input [8:0] start; + input [8:0] stop; + begin + clear <= 0; read <= 0; write <= 1; + firstline <= start; + lastline <= stop; + go <= 1; + @(posedge clk); + go <= 0; + @(posedge clk); + $display("Buffer Set for Write"); + end + endtask // SetBufferWrite + + task SetBufferRead; + input [8:0] start; + input [8:0] stop; + begin + clear <= 0; read <= 1; write <= 0; + firstline <= start; + lastline <= stop; + go <= 1; + @(posedge clk); + go <= 0; + @(posedge clk); + $display("Buffer Set for Read"); + end + endtask // SetBufferRead + + task ReadALine; + begin + #1 rd_read_i <= 1; + @(posedge clk); + rd_read_i <= 0; + end + endtask // ReadALine + + task ReadLines; + input [9:0] lines; + input [7:0] wait_states; + begin + $display("Read Lines: Number %d, Wait States %d",lines,wait_states); + repeat (lines) + begin + ReadALine; + repeat (wait_states) + @(posedge clk); + end + end + endtask // ReadLines + + task WriteALine; + input [31:0] value; + begin + #1 wr_write_i <= 1; + wr_dat_i <= value; + @(posedge clk); + wr_write_i <= 0; + end + endtask // WriteALine + + task WriteLines; + input [9:0] lines; + input [7:0] wait_states; + input [31:0] value; + begin + $display("Write Lines: Number %d, Wait States %d",lines,wait_states); + repeat(lines) + begin + value <= value + 1; + WriteALine(value); + repeat(wait_states) + @(posedge clk); + end + end + endtask // WriteLines + +endmodule // buffer_int_tb diff --git a/control_lib/buffer_pool.v b/control_lib/buffer_pool.v new file mode 100644 index 000000000..969296230 --- /dev/null +++ b/control_lib/buffer_pool.v @@ -0,0 +1,323 @@ + +// Buffer pool. Contains 8 buffers, each 2K (512 by 32). Each buffer +// is a dual-ported RAM. Port A on each of them is indirectly connected +// to the wishbone bus by a bridge. Port B may be connected any one of the +// 8 (4 rd, 4 wr) FIFO-like streaming interaces, or disconnected. The wishbone bus +// provides access to all 8 buffers, and also controls the connections +// between the ports and the buffers, allocating them as needed. + +// wb_adr is 16 bits -- +// bits 13:11 select which buffer +// bits 10:2 select line in buffer +// bits 1:0 are unused (32-bit access only) + +module buffer_pool + (input wb_clk_i, + input wb_rst_i, + input wb_we_i, + input wb_stb_i, + input [15:0] wb_adr_i, + input [31:0] wb_dat_i, + output [31:0] wb_dat_o, + output reg wb_ack_o, + output wb_err_o, + output wb_rty_o, + + input stream_clk, + input stream_rst, + + input set_stb, input [7:0] set_addr, input [31:0] set_data, + output [31:0] status, + output sys_int_o, + + output [31:0] s0, output [31:0] s1, output [31:0] s2, output [31:0] s3, + output [31:0] s4, output [31:0] s5, output [31:0] s6, output [31:0] s7, + + // Write Interfaces + input [31:0] wr0_dat_i, input wr0_write_i, input wr0_done_i, input wr0_error_i, output wr0_ready_o, output wr0_full_o, + input [31:0] wr1_dat_i, input wr1_write_i, input wr1_done_i, input wr1_error_i, output wr1_ready_o, output wr1_full_o, + input [31:0] wr2_dat_i, input wr2_write_i, input wr2_done_i, input wr2_error_i, output wr2_ready_o, output wr2_full_o, + input [31:0] wr3_dat_i, input wr3_write_i, input wr3_done_i, input wr3_error_i, output wr3_ready_o, output wr3_full_o, + + // Read Interfaces + output [31:0] rd0_dat_o, input rd0_read_i, input rd0_done_i, input rd0_error_i, output rd0_sop_o, output rd0_eop_o, + output [31:0] rd1_dat_o, input rd1_read_i, input rd1_done_i, input rd1_error_i, output rd1_sop_o, output rd1_eop_o, + output [31:0] rd2_dat_o, input rd2_read_i, input rd2_done_i, input rd2_error_i, output rd2_sop_o, output rd2_eop_o, + output [31:0] rd3_dat_o, input rd3_read_i, input rd3_done_i, input rd3_error_i, output rd3_sop_o, output rd3_eop_o + ); + + wire [7:0] sel_a; + + wire [2:0] which_buf = wb_adr_i[13:11]; // address 15:14 selects the buffer pool + wire [8:0] buf_addra = wb_adr_i[10:2]; // ignore address 1:0, 32-bit access only + + decoder_3_8 dec(.sel(which_buf),.res(sel_a)); + + genvar i; + + wire go; + + reg [2:0] port[0:7]; + reg [3:0] read_src[0:3]; + reg [3:0] write_src[0:3]; + + wire [7:0] done; + wire [7:0] error; + wire [7:0] idle; + + wire [31:0] buf_doa[0:7]; + + wire [7:0] buf_enb; + wire [7:0] buf_web; + wire [8:0] buf_addrb[0:7]; + wire [31:0] buf_dib[0:7]; + wire [31:0] buf_dob[0:7]; + + wire [31:0] wr_dat_i[0:7]; + wire [7:0] wr_write_i; + wire [7:0] wr_done_i; + wire [7:0] wr_error_i; + wire [7:0] wr_ready_o; + wire [7:0] wr_full_o; + + wire [31:0] rd_dat_o[0:7]; + wire [7:0] rd_read_i; + wire [7:0] rd_done_i; + wire [7:0] rd_error_i; + wire [7:0] rd_sop_o; + wire [7:0] rd_eop_o; + + assign status = {8'd0,idle[7:0],error[7:0],done[7:0]}; + + assign s0 = {23'd0,buf_addrb[0]}; + assign s1 = {23'd0,buf_addrb[1]}; + assign s2 = {23'd0,buf_addrb[2]}; + assign s3 = {23'd0,buf_addrb[3]}; + assign s4 = {23'd0,buf_addrb[4]}; + assign s5 = {23'd0,buf_addrb[5]}; + assign s6 = {23'd0,buf_addrb[6]}; + assign s7 = {23'd0,buf_addrb[7]}; + + wire [31:0] fifo_ctrl; + setting_reg #(.my_addr(64)) + sreg(.clk(stream_clk),.rst(stream_rst),.strobe(set_stb),.addr(set_addr),.in(set_data), + .out(fifo_ctrl),.changed(go)); + + integer k; + always @(posedge stream_clk) + if(stream_rst) + for(k=0;k<8;k=k+1) + port[k] <= 4; // disabled + else + for(k=0;k<8;k=k+1) + if(go & (fifo_ctrl[31:28]==k)) + port[k] <= fifo_ctrl[27:25]; + + always @(posedge stream_clk) + if(stream_rst) + for(k=0;k<4;k=k+1) + read_src[k] <= 8; // disabled + else + for(k=0;k<4;k=k+1) + if(go & fifo_ctrl[22] & (fifo_ctrl[27:25]==k)) + read_src[k] <= fifo_ctrl[31:28]; + + always @(posedge stream_clk) + if(stream_rst) + for(k=0;k<4;k=k+1) + write_src[k] <= 8; // disabled + else + for(k=0;k<4;k=k+1) + if(go & fifo_ctrl[23] & (fifo_ctrl[27:25]==k)) + write_src[k] <= fifo_ctrl[31:28]; + + generate + for(i=0;i<8;i=i+1) + begin : gen_buffer + RAMB16_S36_S36 dpram + (.DOA(buf_doa[i]),.ADDRA(buf_addra),.CLKA(wb_clk_i),.DIA(wb_dat_i),.DIPA(4'h0), + .ENA(wb_stb_i & sel_a[i]),.SSRA(0),.WEA(wb_we_i), + .DOB(buf_dob[i]),.ADDRB(buf_addrb[i]),.CLKB(stream_clk),.DIB(buf_dib[i]),.DIPB(4'h0), + .ENB(buf_enb[i]),.SSRB(0),.WEB(buf_web[i]) ); + + /* ram_2port #(.DWIDTH(32),.AWIDTH(9)) buffer + (.clka(wb_clk_i),.ena(wb_stb_i & sel_a[i]),.wea(wb_we_i), + .addra(buf_addra),.dia(wb_dat_i),.doa(buf_doa[i]), + .clkb(stream_clk),.enb(buf_enb[i]),.web(buf_web[i]), + .addrb(buf_addrb[i]),.dib(buf_dib[i]),.dob(buf_dob[i])); */ + + buffer_int #(.BUFF_NUM(i)) fifo_int + (.clk(stream_clk),.rst(stream_rst), + .ctrl_word(fifo_ctrl),.go(go & (fifo_ctrl[31:28]==i)), + .done(done[i]),.error(error[i]),.idle(idle[i]), + .en_o(buf_enb[i]), + .we_o(buf_web[i]), + .addr_o(buf_addrb[i]), + .dat_to_buf(buf_dib[i]), + .dat_from_buf(buf_dob[i]), + .wr_dat_i(wr_dat_i[i]), + .wr_write_i(wr_write_i[i]), + .wr_done_i(wr_done_i[i]), + .wr_error_i(wr_error_i[i]), + .wr_ready_o(wr_ready_o[i]), + .wr_full_o(wr_full_o[i]), + .rd_dat_o(rd_dat_o[i]), + .rd_read_i(rd_read_i[i]), + .rd_done_i(rd_done_i[i]), + .rd_error_i(rd_error_i[i]), + .rd_sop_o(rd_sop_o[i]), + .rd_eop_o(rd_eop_o[i]) + ); + + // FIXME -- if it is a problem, maybe we don't need enables on these muxes + mux4 #(.WIDTH(32)) + mux4_dat_i (.en(~port[i][2]),.sel(port[i][1:0]),.i0(wr0_dat_i),.i1(wr1_dat_i), + .i2(wr2_dat_i),.i3(wr3_dat_i),.o(wr_dat_i[i])); + mux4 #(.WIDTH(1)) + mux4_write_i (.en(~port[i][2]),.sel(port[i][1:0]),.i0(wr0_write_i),.i1(wr1_write_i), + .i2(wr2_write_i),.i3(wr3_write_i),.o(wr_write_i[i])); + mux4 #(.WIDTH(1)) + mux4_wrdone_i (.en(~port[i][2]),.sel(port[i][1:0]),.i0(wr0_done_i),.i1(wr1_done_i), + .i2(wr2_done_i),.i3(wr3_done_i),.o(wr_done_i[i])); + mux4 #(.WIDTH(1)) + mux4_wrerror_i (.en(~port[i][2]),.sel(port[i][1:0]),.i0(wr0_error_i),.i1(wr1_error_i), + .i2(wr2_error_i),.i3(wr3_error_i),.o(wr_error_i[i])); + mux4 #(.WIDTH(1)) + mux4_read_i (.en(~port[i][2]),.sel(port[i][1:0]),.i0(rd0_read_i),.i1(rd1_read_i), + .i2(rd2_read_i),.i3(rd3_read_i),.o(rd_read_i[i])); + mux4 #(.WIDTH(1)) + mux4_rddone_i (.en(~port[i][2]),.sel(port[i][1:0]),.i0(rd0_done_i),.i1(rd1_done_i), + .i2(rd2_done_i),.i3(rd3_done_i),.o(rd_done_i[i])); + mux4 #(.WIDTH(1)) + mux4_rderror_i (.en(~port[i][2]),.sel(port[i][1:0]),.i0(rd0_error_i),.i1(rd1_error_i), + .i2(rd2_error_i),.i3(rd3_error_i),.o(rd_error_i[i])); + end // block: gen_buffer + endgenerate + + //---------------------------------------------------------------------- + // Wishbone Outputs + + // Use the following lines if ram output and mux can be made fast enough + + assign wb_err_o = 1'b0; // Unused for now + assign wb_rty_o = 1'b0; // Unused for now + + always @(posedge wb_clk_i) + wb_ack_o <= wb_stb_i & ~wb_ack_o; + assign wb_dat_o = buf_doa[which_buf]; + + // Use this if we can't make the RAM+MUX fast enough + // reg [31:0] wb_dat_o_reg; + // reg stb_d1; + + // always @(posedge wb_clk_i) + // begin + // wb_dat_o_reg <= buf_doa[which_buf]; + // stb_d1 <= wb_stb_i; + // wb_ack_o <= (stb_d1 & ~wb_ack_o) | (wb_we_i & wb_stb_i); + // end + //assign wb_dat_o = wb_dat_o_reg; + + mux8 #(.WIDTH(1)) + mux8_wr_ready0(.en(~write_src[0][3]),.sel(write_src[0][2:0]), .i0(wr_ready_o[0]), .i1(wr_ready_o[1]), + .i2(wr_ready_o[2]), .i3(wr_ready_o[3]), .i4(wr_ready_o[4]), + .i5(wr_ready_o[5]), .i6(wr_ready_o[6]), .i7(wr_ready_o[7]),.o(wr0_ready_o)); + + mux8 #(.WIDTH(1)) + mux8_wr_full0(.en(~write_src[0][3]),.sel(write_src[0][2:0]), .i0(wr_full_o[0]), .i1(wr_full_o[1]), + .i2(wr_full_o[2]), .i3(wr_full_o[3]), .i4(wr_full_o[4]), + .i5(wr_full_o[5]), .i6(wr_full_o[6]), .i7(wr_full_o[7]),.o(wr0_full_o)); + + mux8 #(.WIDTH(1)) + mux8_wr_ready1(.en(~write_src[1][3]),.sel(write_src[1][2:0]), .i0(wr_ready_o[0]), .i1(wr_ready_o[1]), + .i2(wr_ready_o[2]), .i3(wr_ready_o[3]), .i4(wr_ready_o[4]), + .i5(wr_ready_o[5]), .i6(wr_ready_o[6]), .i7(wr_ready_o[7]),.o(wr1_ready_o)); + + mux8 #(.WIDTH(1)) + mux8_wr_full1(.en(~write_src[1][3]),.sel(write_src[1][2:0]), .i0(wr_full_o[0]), .i1(wr_full_o[1]), + .i2(wr_full_o[2]), .i3(wr_full_o[3]), .i4(wr_full_o[4]), + .i5(wr_full_o[5]), .i6(wr_full_o[6]), .i7(wr_full_o[7]),.o(wr1_full_o)); + + mux8 #(.WIDTH(1)) + mux8_wr_ready2(.en(~write_src[2][3]),.sel(write_src[2][2:0]), .i0(wr_ready_o[0]), .i1(wr_ready_o[1]), + .i2(wr_ready_o[2]), .i3(wr_ready_o[3]), .i4(wr_ready_o[4]), + .i5(wr_ready_o[5]), .i6(wr_ready_o[6]), .i7(wr_ready_o[7]),.o(wr2_ready_o)); + + mux8 #(.WIDTH(1)) + mux8_wr_full2(.en(~write_src[2][3]),.sel(write_src[2][2:0]), .i0(wr_full_o[0]), .i1(wr_full_o[1]), + .i2(wr_full_o[2]), .i3(wr_full_o[3]), .i4(wr_full_o[4]), + .i5(wr_full_o[5]), .i6(wr_full_o[6]), .i7(wr_full_o[7]),.o(wr2_full_o)); + + mux8 #(.WIDTH(1)) + mux8_wr_ready3(.en(~write_src[3][3]),.sel(write_src[3][2:0]), .i0(wr_ready_o[0]), .i1(wr_ready_o[1]), + .i2(wr_ready_o[2]), .i3(wr_ready_o[3]), .i4(wr_ready_o[4]), + .i5(wr_ready_o[5]), .i6(wr_ready_o[6]), .i7(wr_ready_o[7]),.o(wr3_ready_o)); + + mux8 #(.WIDTH(1)) + mux8_wr_full3(.en(~write_src[3][3]),.sel(write_src[3][2:0]), .i0(wr_full_o[0]), .i1(wr_full_o[1]), + .i2(wr_full_o[2]), .i3(wr_full_o[3]), .i4(wr_full_o[4]), + .i5(wr_full_o[5]), .i6(wr_full_o[6]), .i7(wr_full_o[7]),.o(wr3_full_o)); + + mux8 #(.WIDTH(1)) + mux8_rd_sop0(.en(~read_src[0][3]),.sel(read_src[0][2:0]), .i0(rd_sop_o[0]), .i1(rd_sop_o[1]), + .i2(rd_sop_o[2]), .i3(rd_sop_o[3]), .i4(rd_sop_o[4]), + .i5(rd_sop_o[5]), .i6(rd_sop_o[6]), .i7(rd_sop_o[7]),.o(rd0_sop_o)); + + mux8 #(.WIDTH(1)) + mux8_rd_eop0(.en(~read_src[0][3]),.sel(read_src[0][2:0]), .i0(rd_eop_o[0]), .i1(rd_eop_o[1]), + .i2(rd_eop_o[2]), .i3(rd_eop_o[3]), .i4(rd_eop_o[4]), + .i5(rd_eop_o[5]), .i6(rd_eop_o[6]), .i7(rd_eop_o[7]),.o(rd0_eop_o)); + + mux8 #(.WIDTH(32)) + mux8_rd_dat_0 (.en(~read_src[0][3]),.sel(read_src[0][2:0]), .i0(rd_dat_o[0]), .i1(rd_dat_o[1]), + .i2(rd_dat_o[2]), .i3(rd_dat_o[3]), .i4(rd_dat_o[4]), + .i5(rd_dat_o[5]), .i6(rd_dat_o[6]), .i7(rd_dat_o[7]),.o(rd0_dat_o)); + + mux8 #(.WIDTH(1)) + mux8_rd_sop1(.en(~read_src[1][3]),.sel(read_src[1][2:0]), .i0(rd_sop_o[0]), .i1(rd_sop_o[1]), + .i2(rd_sop_o[2]), .i3(rd_sop_o[3]), .i4(rd_sop_o[4]), + .i5(rd_sop_o[5]), .i6(rd_sop_o[6]), .i7(rd_sop_o[7]),.o(rd1_sop_o)); + + mux8 #(.WIDTH(1)) + mux8_rd_eop1(.en(~read_src[1][3]),.sel(read_src[1][2:0]), .i0(rd_eop_o[0]), .i1(rd_eop_o[1]), + .i2(rd_eop_o[2]), .i3(rd_eop_o[3]), .i4(rd_eop_o[4]), + .i5(rd_eop_o[5]), .i6(rd_eop_o[6]), .i7(rd_eop_o[7]),.o(rd1_eop_o)); + + mux8 #(.WIDTH(32)) + mux8_rd_dat_1 (.en(~read_src[1][3]),.sel(read_src[1][2:0]), .i0(rd_dat_o[0]), .i1(rd_dat_o[1]), + .i2(rd_dat_o[2]), .i3(rd_dat_o[3]), .i4(rd_dat_o[4]), + .i5(rd_dat_o[5]), .i6(rd_dat_o[6]), .i7(rd_dat_o[7]),.o(rd1_dat_o)); + + mux8 #(.WIDTH(1)) + mux8_rd_sop2(.en(~read_src[2][3]),.sel(read_src[2][2:0]), .i0(rd_sop_o[0]), .i1(rd_sop_o[1]), + .i2(rd_sop_o[2]), .i3(rd_sop_o[3]), .i4(rd_sop_o[4]), + .i5(rd_sop_o[5]), .i6(rd_sop_o[6]), .i7(rd_sop_o[7]),.o(rd2_sop_o)); + + mux8 #(.WIDTH(1)) + mux8_rd_eop2(.en(~read_src[2][3]),.sel(read_src[2][2:0]), .i0(rd_eop_o[0]), .i1(rd_eop_o[1]), + .i2(rd_eop_o[2]), .i3(rd_eop_o[3]), .i4(rd_eop_o[4]), + .i5(rd_eop_o[5]), .i6(rd_eop_o[6]), .i7(rd_eop_o[7]),.o(rd2_eop_o)); + + mux8 #(.WIDTH(32)) + mux8_rd_dat_2 (.en(~read_src[2][3]),.sel(read_src[2][2:0]), .i0(rd_dat_o[0]), .i1(rd_dat_o[1]), + .i2(rd_dat_o[2]), .i3(rd_dat_o[3]), .i4(rd_dat_o[4]), + .i5(rd_dat_o[5]), .i6(rd_dat_o[6]), .i7(rd_dat_o[7]),.o(rd2_dat_o)); + + mux8 #(.WIDTH(1)) + mux8_rd_sop3(.en(~read_src[3][3]),.sel(read_src[3][2:0]), .i0(rd_sop_o[0]), .i1(rd_sop_o[1]), + .i2(rd_sop_o[2]), .i3(rd_sop_o[3]), .i4(rd_sop_o[4]), + .i5(rd_sop_o[5]), .i6(rd_sop_o[6]), .i7(rd_sop_o[7]),.o(rd3_sop_o)); + + mux8 #(.WIDTH(1)) + mux8_rd_eop3(.en(~read_src[3][3]),.sel(read_src[3][2:0]), .i0(rd_eop_o[0]), .i1(rd_eop_o[1]), + .i2(rd_eop_o[2]), .i3(rd_eop_o[3]), .i4(rd_eop_o[4]), + .i5(rd_eop_o[5]), .i6(rd_eop_o[6]), .i7(rd_eop_o[7]),.o(rd3_eop_o)); + + mux8 #(.WIDTH(32)) + mux8_rd_dat_3 (.en(~read_src[3][3]),.sel(read_src[3][2:0]), .i0(rd_dat_o[0]), .i1(rd_dat_o[1]), + .i2(rd_dat_o[2]), .i3(rd_dat_o[3]), .i4(rd_dat_o[4]), + .i5(rd_dat_o[5]), .i6(rd_dat_o[6]), .i7(rd_dat_o[7]),.o(rd3_dat_o)); + + assign sys_int_o = (|error) | (|done); + +endmodule // buffer_pool diff --git a/control_lib/buffer_pool_tb.v b/control_lib/buffer_pool_tb.v new file mode 100644 index 000000000..16741438e --- /dev/null +++ b/control_lib/buffer_pool_tb.v @@ -0,0 +1,50 @@ + +module buffer_pool_tb(); + + wire wb_clk_i; + wire wb_rst_i; + wire wb_we_i; + wire wb_stb_i; + wire [15:0] wb_adr_i; + wire [31:0] wb_dat_i; + wire [31:0] wb_dat_o; + wire wb_ack_o; + wire wb_err_o; + wire wb_rty_o; + + wire stream_clk, stream_rst; + + wire set_stb; + wire [7:0] set_addr; + wire [31:0] set_data; + + wire [31:0] wr0_dat_i; + buffer_pool dut + (.wb_clk_i(wb_clk_i), + .wb_rst_i(wb_rst_i), + .wb_we_i(wb_we_i), + .wb_stb_i(wb_stb_i), + .wb_adr_i(wb_adr_i), + .wb_dat_i(wb_dat_i), + .wb_dat_o(wb_dat_o), + .wb_ack_o(wb_ack_o), + .wb_err_o(wb_err_o), + .wb_rty_o(wb_rty_o), + + .stream_clk(stream_clk), + .stream_rst(stream_rst), + + .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + + .wr0_dat_i(wr0_dat_i), .wr0_write_i(), .wr0_done_i(), .wr0_error_i(), .wr0_ready_o(), .wr0_full_o(), + .wr1_dat_i(), .wr1_write_i(), .wr1_done_i(), .wr1_error_i(), .wr1_ready_o(), .wr1_full_o(), + .wr2_dat_i(), .wr2_write_i(), .wr2_done_i(), .wr2_error_i(), .wr2_ready_o(), .wr2_full_o(), + .wr3_dat_i(), .wr3_write_i(), .wr3_done_i(), .wr3_error_i(), .wr3_ready_o(), .wr3_full_o(), + + .rd0_dat_o(), .rd0_read_i(), .rd0_done_i(), .rd0_error_i(), .rd0_ready_o(), .rd0_empty_o(), + .rd1_dat_o(), .rd1_read_i(), .rd1_done_i(), .rd1_error_i(), .rd1_ready_o(), .rd1_empty_o(), + .rd2_dat_o(), .rd2_read_i(), .rd2_done_i(), .rd2_error_i(), .rd2_ready_o(), .rd2_empty_o(), + .rd3_dat_o(), .rd3_read_i(), .rd3_done_i(), .rd3_error_i(), .rd3_ready_o(), .rd3_empty_o() + ); + +endmodule // buffer_pool_tb diff --git a/control_lib/cascadefifo.v b/control_lib/cascadefifo.v new file mode 100644 index 000000000..c1a4ab335 --- /dev/null +++ b/control_lib/cascadefifo.v @@ -0,0 +1,50 @@ + + +// This FIFO exists to provide an intermediate point for the data on its +// long trek from one RAM (in the buffer pool) to another (in the longfifo) +// The shortfifo is more flexible in its placement since it is based on +// distributed RAM +// This one should only be used on transmit side applications. I.e. tx_mac, tx_dsp, etc. +// Spartan 3's have slow routing.... +// If we REALLY need to, we could also do this on the output side, +// with for the receive side stuff + +module cascadefifo + #(parameter WIDTH=32, SIZE=9) + (input clk, input rst, + input [WIDTH-1:0] datain, + output [WIDTH-1:0] dataout, + input read, + input write, + input clear, + output full, + output empty, + output [15:0] space, + output [15:0] occupied); + + wire [WIDTH-1:0] data_int; + wire empty_int, full_int, transfer; + wire [4:0] short_space, short_occupied; + wire [15:0] long_space, long_occupied; + + shortfifo #(.WIDTH(WIDTH)) shortfifo + (.clk(clk),.rst(rst),.clear(clear), + .datain(datain), .write(write), .full(full), + .dataout(data_int), .read(transfer), .empty(empty_int), + .space(short_space),.occupied(short_occupied) ); + + longfifo #(.WIDTH(WIDTH),.SIZE(SIZE)) longfifo + (.clk(clk),.rst(rst),.clear(clear), + .datain(data_int), .write(transfer), .full(full_int), + .dataout(dataout), .read(read), .empty(empty), + .space(long_space),.occupied(long_occupied) ); + + assign transfer = ~empty_int & ~full_int; + + assign space = {11'b0,short_space} + long_space; + assign occupied = {11'b0,short_occupied} + long_occupied; + +endmodule // cascadefifo + + + diff --git a/control_lib/cascadefifo2.v b/control_lib/cascadefifo2.v new file mode 100644 index 000000000..984cc46e6 --- /dev/null +++ b/control_lib/cascadefifo2.v @@ -0,0 +1,56 @@ + + +// This FIFO exists to provide an intermediate point for the data on its +// long trek from one RAM (in the buffer pool) to another (in the longfifo) +// The shortfifo is more flexible in its placement since it is based on +// distributed RAM + +// This one has the shortfifo on both the in and out sides. +module cascadefifo2 + #(parameter WIDTH=32, SIZE=9) + (input clk, input rst, + input [WIDTH-1:0] datain, + output [WIDTH-1:0] dataout, + input read, + input write, + input clear, + output full, + output empty, + output [15:0] space, + output [15:0] occupied); + + wire [WIDTH-1:0] data_int, data_int2; + wire empty_int, full_int, transfer; + wire empty_int2, full_int2, transfer2; + wire [4:0] s1_space, s1_occupied, s2_space, s2_occupied; + wire [15:0] l_space, l_occupied; + + shortfifo #(.WIDTH(WIDTH)) shortfifo + (.clk(clk),.rst(rst),.clear(clear), + .datain(datain), .write(write), .full(full), + .dataout(data_int), .read(transfer), .empty(empty_int), + .space(s1_space),.occupied(s1_occupied) ); + + longfifo #(.WIDTH(WIDTH),.SIZE(SIZE)) longfifo + (.clk(clk),.rst(rst),.clear(clear), + .datain(data_int), .write(transfer), .full(full_int), + .dataout(data_int2), .read(transfer2), .empty(empty_int2), + .space(l_space),.occupied(l_occupied) ); + + shortfifo #(.WIDTH(WIDTH)) shortfifo2 + (.clk(clk),.rst(rst),.clear(clear), + .datain(data_int2), .write(transfer2), .full(full_int2), + .dataout(dataout), .read(read), .empty(empty), + .space(s2_space),.occupied(s2_occupied) ); + + assign transfer = ~empty_int & ~full_int; + assign transfer2 = ~empty_int2 & ~full_int2; + + assign space = {11'b0,s1_space} + {11'b0,s2_space} + l_space; + assign occupied = {11'b0,s1_occupied} + {11'b0,s2_occupied} + l_occupied; + +endmodule // cascadefifo2 + + + + diff --git a/control_lib/clock_bootstrap_rom.v b/control_lib/clock_bootstrap_rom.v new file mode 100644 index 000000000..46563db65 --- /dev/null +++ b/control_lib/clock_bootstrap_rom.v @@ -0,0 +1,34 @@ + + +module clock_bootstrap_rom(input [15:0] addr, output [47:0] data); + + reg [47:0] rom [0:15]; + + //initial + // $readmemh("bootrom.mem", rom); + + assign data = rom[addr]; + + initial + begin + // First 16 bits are address, last 32 are data + // First 4 bits of address select which slave + rom[0] = 48'h0000_0C00_0F03; // Both clk sel choose ext ref (0), both are enabled (1), turn off SERDES, ADCs, turn on leds + rom[1] = 48'h1014_0000_0000; // SPI: Set Divider to div by 2 + rom[2] = 48'h1018_0000_0001; // SPI: Choose AD9510 + rom[3] = 48'h1010_0000_3418; // SPI: Auto-slave select, interrupt when done, TX_NEG, 24-bit word + rom[4] = 48'h1000_0000_0010; // SPI: AD9510 A:0 D:10 Set up AD9510 SPI + rom[5] = 48'h1010_0000_3518; // SPI: SEND IT Auto-slave select, interrupt when done, TX_NEG, 24-bit word + rom[6] = 48'hffff_ffff_ffff; // terminate + rom[7] = 48'hffff_ffff_ffff; // terminate + rom[8] = 48'hffff_ffff_ffff; // terminate + rom[9] = 48'hffff_ffff_ffff; // terminate + rom[10] = 48'hffff_ffff_ffff; // terminate + rom[11] = 48'hffff_ffff_ffff; // terminate + rom[12] = 48'hffff_ffff_ffff; // terminate + rom[13] = 48'hffff_ffff_ffff; // terminate + rom[14] = 48'hffff_ffff_ffff; // terminate + rom[15] = 48'hffff_ffff_ffff; // terminate + end // initial begin + +endmodule // clock_bootstrap_rom diff --git a/control_lib/clock_control.v b/control_lib/clock_control.v new file mode 100644 index 000000000..1bbe6bd75 --- /dev/null +++ b/control_lib/clock_control.v @@ -0,0 +1,115 @@ + + +// AD9510 Register Map (from datasheet Rev. A) + +/* INSTRUCTION word format (16 bits) + * 15 Read = 1, Write = 0 + * 14:13 W1/W0, Number of bytes 00 - 1, 01 - 2, 10 - 3, 11 - stream + * 12:0 Address + */ + +/* ADDR Contents Value (hex) + * 00 Serial Config Port 10 (def) -- MSB first, SDI/SDO separate + * 04 A Counter + * 05-06 B Counter + * 07-0A PLL Control + * 0B-0C R Divider + * 0D PLL Control + * 34-3A Fine Delay + * 3C-3F LVPECL Outs + * 40-43 LVDS/CMOS Outs + * 45 Clock select, power down + * 48-57 Dividers + * 58 Func and Sync + * 5A Update regs + */ + + +module clock_control + (input reset, + input aux_clk, // 25MHz, for before fpga clock is active + input clk_fpga, // real 100 MHz FPGA clock + output [1:0] clk_en, // controls source of reference clock + output [1:0] clk_sel, // controls source of reference clock + input clk_func, // FIXME needs to be some kind of out SYNC or reset to 9510 + input clk_status, // Monitor PLL or SYNC status + + output sen, // Enable for the AD9510 + output sclk, // FIXME these need to be shared + input sdi, + output sdo + ); + + wire read = 1'b0; // Always write for now + wire [1:0] w = 2'b00; // Always send 1 byte at a time + + assign clk_sel = 2'b00; // Both outputs from External Ref (SMA) + assign clk_en = 2'b11; // Both outputs enabled + + reg [20:0] addr_data; + + reg [5:0] entry; + reg start; + reg [7:0] counter; + reg [23:0] command; + + always @* + case(entry) + 6'd00 : addr_data = {13'h00,8'h10}; // Serial setup + 6'd01 : addr_data = {13'h45,8'h00}; // CLK2 drives distribution, everything on + 6'd02 : addr_data = {13'h3D,8'h80}; // Turn on output 1, normal levels + 6'd03 : addr_data = {13'h4B,8'h80}; // Bypass divider 1 (div by 1) + 6'd04 : addr_data = {13'h08,8'h47}; // POS PFD, Dig LK Det, Charge Pump normal + 6'd05 : addr_data = {13'h09,8'h70}; // Max Charge Pump current + 6'd06 : addr_data = {13'h0A,8'h04}; // Normal operation, Prescalar Div by 2, PLL On + 6'd07 : addr_data = {13'h0B,8'h00}; // RDIV MSB (6 bits) + 6'd08 : addr_data = {13'h0C,8'h01}; // RDIV LSB (8 bits), Div by 1 + 6'd09 : addr_data = {13'h0D,8'h00}; // Everything normal, Dig Lock Det + 6'd10 : addr_data = {13'h07,8'h00}; // Disable LOR detect - LOR causes failure... + 6'd11 : addr_data = {13'h04,8'h00}; // A Counter = Don't Care + 6'd12 : addr_data = {13'h05,8'h00}; // B Counter MSB = 0 + 6'd13 : addr_data = {13'h06,8'h05}; // B Counter LSB = 5 + default : addr_data = {13'h5A,8'h01}; // Register Update + endcase // case(entry) + + wire [5:0] lastentry = 6'd15; + wire done = (counter == 8'd49); + + always @(posedge aux_clk) + if(reset) + begin + entry <= #1 6'd0; + start <= #1 1'b1; + end + else if(start) + start <= #1 1'b0; + else if(done && (entry + // reg [7:0] ram3 [0:(1<<(AWIDTH-2))-1]; + + // Port 1 + always @(posedge clk) + if(en1_i) dat1_o[31:24] <= ram3[adr1_i[AWIDTH-1:2]]; + always @(posedge clk) + if(en1_i) dat1_o[23:16] <= ram2[adr1_i[AWIDTH-1:2]]; + always @(posedge clk) + if(en1_i) dat1_o[15:8] <= ram1[adr1_i[AWIDTH-1:2]]; + always @(posedge clk) + if(en1_i) dat1_o[7:0] <= ram0[adr1_i[AWIDTH-1:2]]; + + always @(posedge clk) + if(we1_i & en1_i & sel1_i[3]) + ram3[adr1_i[AWIDTH-1:2]] <= dat1_i[31:24]; + always @(posedge clk) + if(we1_i & en1_i & sel1_i[2]) + ram2[adr1_i[AWIDTH-1:2]] <= dat1_i[23:16]; + always @(posedge clk) + if(we1_i & en1_i & sel1_i[1]) + ram1[adr1_i[AWIDTH-1:2]] <= dat1_i[15:8]; + always @(posedge clk) + if(we1_i & en1_i & sel1_i[0]) + ram0[adr1_i[AWIDTH-1:2]] <= dat1_i[7:0]; + + // Port 2 + always @(posedge clk) + if(en2_i) dat2_o[31:24] <= ram3[adr2_i[AWIDTH-1:2]]; + always @(posedge clk) + if(en2_i) dat2_o[23:16] <= ram2[adr2_i[AWIDTH-1:2]]; + always @(posedge clk) + if(en2_i) dat2_o[15:8] <= ram1[adr2_i[AWIDTH-1:2]]; + always @(posedge clk) + if(en2_i) dat2_o[7:0] <= ram0[adr2_i[AWIDTH-1:2]]; + + always @(posedge clk) + if(we2_i & en2_i & sel2_i[3]) + ram3[adr2_i[AWIDTH-1:2]] <= dat2_i[31:24]; + always @(posedge clk) + if(we2_i & en2_i & sel2_i[2]) + ram2[adr2_i[AWIDTH-1:2]] <= dat2_i[23:16]; + always @(posedge clk) + if(we2_i & en2_i & sel2_i[1]) + ram1[adr2_i[AWIDTH-1:2]] <= dat2_i[15:8]; + always @(posedge clk) + if(we2_i & en2_i & sel2_i[0]) + ram0[adr2_i[AWIDTH-1:2]] <= dat2_i[7:0]; + +endmodule // dpram32 + + diff --git a/control_lib/extram_interface.v b/control_lib/extram_interface.v new file mode 100644 index 000000000..7554592ba --- /dev/null +++ b/control_lib/extram_interface.v @@ -0,0 +1,53 @@ + +// Temporary buffer pool storage, mostly useful for pre-generated data streams or +// for making more space to juggle packets in case of eth frames coming out of order + +module extram_interface + (input clk, input rst, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + // Buffer pool interfaces + input [31:0] rd_dat_i, output rd_read_o, output rd_done_o, output rd_error_o, + input rd_sop_i, input rd_eop_i, + output [31:0] wr_dat_o, output wr_write_o, output wr_done_o, output wr_error_o, + input wr_ready_i, input wr_full_i, + + // RAM Interface + inout [17:0] RAM_D, + output [18:0] RAM_A, + output RAM_CE1n, + output RAM_CENn, + input RAM_CLK, + output RAM_WEn, + output RAM_OEn, + output RAM_LDn ); + + // Command format -- + // Read/_Write , start address[17:0] + wire [18:0] cmd_in; + wire cmd_stb, store_wr_cmd, store_rd_cmd, read_wr_cmd, read_rd_cmd; + wire empty_wr_cmd, empty_rd_cmd, full_wr_cmd, full_rd_cmd; + + // Dummy logic + assign RAM_OEn = 1; + + setting_reg #(.my_addr(0)) + sr_ram_cmd (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(cmd_in),.changed(cmd_stb)); + + reg cmd_stb_d1; + always @(posedge clk) cmd_stb_d1 <= cmd_stb; + assign store_wr_cmd = ~cmd_in[18] & cmd_stb & ~cmd_stb_d1; + assign store_rd_cmd = cmd_in[18] & cmd_stb & ~cmd_stb_d1; + + shortfifo #(.WIDTH(19)) wr_cmd_fifo + (.clk(clk),.rst(rst),.clear(1'b0), + .datain(cmd_in), .write(store_wr_cmd), .full(full_wr_cmd), + .dataout(), .read(read_wr_cmd), .empty(empty_wr_cmd) ); + + shortfifo #(.WIDTH(19)) rd_cmd_fifo + (.clk(clk),.rst(rst),.clear(1'b0), + .datain(cmd_in), .write(store_rd_cmd), .full(full_rd_cmd), + .dataout(), .read(read_rd_cmd), .empty(empty_rd_cmd) ); + +endmodule // extram_interface diff --git a/control_lib/fifo_2clock.v b/control_lib/fifo_2clock.v new file mode 100644 index 000000000..6b1eb607e --- /dev/null +++ b/control_lib/fifo_2clock.v @@ -0,0 +1,66 @@ + +module fifo_2clock + #(parameter DWIDTH=32, AWIDTH=9) + (input wclk, input [DWIDTH-1:0] datain, input write, output full, output reg [AWIDTH-1:0] level_wclk, + input rclk, output [DWIDTH-1:0] dataout, input read, output empty, output reg [AWIDTH-1:0] level_rclk, + input arst); + + reg [AWIDTH-1:0] wr_addr, rd_addr; + wire [AWIDTH-1:0] wr_addr_rclk, rd_addr_wclk; + wire [AWIDTH-1:0] next_rd_addr; + wire enb_read; + + // Write side management + wire [AWIDTH-1:0] next_wr_addr = wr_addr + 1; + always @(posedge wclk or posedge arst) + if(arst) + wr_addr <= 0; + else if(write) + wr_addr <= next_wr_addr; + assign full = (next_wr_addr == rd_addr_wclk); + + // RAM for data storage. Data out is registered, complicating the + // read side logic + ram_2port #(.DWIDTH(DWIDTH),.AWIDTH(AWIDTH)) mac_rx_ff_ram + (.clka(wclk),.ena(1'b1),.wea(write),.addra(wr_addr),.dia(datain),.doa(), + .clkb(rclk),.enb(enb_read),.web(1'b0),.addrb(next_rd_addr),.dib(0),.dob(dataout) ); + + // Read side management + reg data_valid; + assign empty = ~data_valid; + assign next_rd_addr = rd_addr + data_valid; + assign enb_read = read | ~data_valid; + + always @(posedge rclk or posedge arst) + if(arst) + rd_addr <= 0; + else if(read) + rd_addr <= rd_addr + 1; + + always @(posedge rclk or posedge arst) + if(arst) + data_valid <= 0; + else + if(read & (next_rd_addr == wr_addr_rclk)) + data_valid <= 0; + else if(next_rd_addr != wr_addr_rclk) + data_valid <= 1; + + // Send pointers across clock domains via gray code + gray_send #(.WIDTH(AWIDTH)) send_wr_addr + (.clk_in(wclk),.addr_in(wr_addr), + .clk_out(rclk),.addr_out(wr_addr_rclk) ); + + gray_send #(.WIDTH(AWIDTH)) send_rd_addr + (.clk_in(rclk),.addr_in(rd_addr), + .clk_out(wclk),.addr_out(rd_addr_wclk) ); + + // Generate fullness info, these are approximate and may be delayed + // and are only for higher-level flow control. + // Only full and empty are guaranteed exact. + always @(posedge wclk) + level_wclk <= wr_addr - rd_addr_wclk; + always @(posedge rclk) + level_rclk <= wr_addr_rclk - rd_addr; + +endmodule // fifo_2clock diff --git a/control_lib/fifo_2clock_casc.v b/control_lib/fifo_2clock_casc.v new file mode 100644 index 000000000..e9b0cfc25 --- /dev/null +++ b/control_lib/fifo_2clock_casc.v @@ -0,0 +1,31 @@ + +module fifo_2clock_casc + #(parameter DWIDTH=32, AWIDTH=9) + (input wclk, input [DWIDTH-1:0] datain, input write, output full, output [AWIDTH-1:0] level_wclk, + input rclk, output [DWIDTH-1:0] dataout, input read, output empty, output [AWIDTH-1:0] level_rclk, + input arst); + + wire full_int, empty_int, full_int2, empty_int2, transfer, transfer2; + wire [DWIDTH-1:0] data_int, data_int2; + + shortfifo #(.WIDTH(DWIDTH)) shortfifo + (.clk(wclk), .rst(arst), .clear(0), + .datain(datain), .write(write), .full(full), + .dataout(data_int), .read(transfer), .empty(empty_int) ); + + assign transfer = ~full_int & ~empty_int; + + fifo_2clock #(.DWIDTH(DWIDTH),.AWIDTH(AWIDTH)) fifo_2clock + (.wclk(wclk), .datain(data_int), .write(transfer), .full(full_int), .level_wclk(level_wclk), + .rclk(rclk), .dataout(data_int2), .read(transfer2), .empty(empty_int2), .level_rclk(level_rclk), + .arst(arst) ); + + assign transfer2 = ~full_int2 & ~empty_int2; + + shortfifo #(.WIDTH(DWIDTH)) shortfifo2 + (.clk(rclk), .rst(arst), .clear(0), + .datain(data_int2), .write(transfer2), .full(full_int2), + .dataout(dataout), .read(read), .empty(empty) ); + +endmodule // fifo_2clock_casc + diff --git a/control_lib/fifo_reader.v b/control_lib/fifo_reader.v new file mode 100644 index 000000000..49d05b1a6 --- /dev/null +++ b/control_lib/fifo_reader.v @@ -0,0 +1,28 @@ + +module fifo_reader + #(parameter rate=4) + (input clk, + input [31:0] data_in, + output read_o + input ready_i, + input done_i + ); + + reg [7:0] state = 0; + + always @(posedge clk) + if(ready) + if(state == rate) + state <= 0; + else + state <= state + 1; + else + state <= 0; + + assign read = (state == rate); + + initial $monitor(data_in); + +endmodule // fifo_reader + + diff --git a/control_lib/fifo_tb.v b/control_lib/fifo_tb.v new file mode 100644 index 000000000..136ed011e --- /dev/null +++ b/control_lib/fifo_tb.v @@ -0,0 +1,153 @@ +module fifo_tb(); + + reg clk, rst; + wire short_full, short_empty, long_full, long_empty; + wire casc_full, casc_empty, casc2_full, casc2_empty; + reg read, write; + + wire [7:0] short_do, long_do; + wire [7:0] casc_do, casc2_do; + reg [7:0] di; + + reg clear = 0; + + shortfifo #(.WIDTH(8)) shortfifo + (.clk(clk),.rst(rst),.datain(di),.dataout(short_do),.clear(clear), + .read(read),.write(write),.full(short_full),.empty(short_empty)); + + longfifo #(.WIDTH(8), .SIZE(4)) longfifo + (.clk(clk),.rst(rst),.datain(di),.dataout(long_do),.clear(clear), + .read(read),.write(write),.full(long_full),.empty(long_empty)); + + cascadefifo #(.WIDTH(8), .SIZE(4)) cascadefifo + (.clk(clk),.rst(rst),.datain(di),.dataout(casc_do),.clear(clear), + .read(read),.write(write),.full(casc_full),.empty(casc_empty)); + + cascadefifo2 #(.WIDTH(8), .SIZE(4)) cascadefifo2 + (.clk(clk),.rst(rst),.datain(di),.dataout(casc2_do),.clear(clear), + .read(read),.write(write),.full(casc2_full),.empty(casc2_empty)); + + initial rst = 1; + initial #1000 rst = 0; + initial clk = 0; + always #50 clk = ~clk; + + initial di = 8'hAE; + initial read = 0; + initial write = 0; + + always @(posedge clk) + if(write) + di <= di + 1; + + always @(posedge clk) + begin + if(short_full != long_full) + $display("Error: FULL mismatch"); + if(short_empty != long_empty) + $display("Note: EMPTY mismatch, usually not a problem (longfifo has 2 cycle latency)"); + if(read & (short_do != long_do)) + $display("Error: DATA mismatch"); + end + + initial $dumpfile("fifo_tb.vcd"); + initial $dumpvars(0,fifo_tb); + + initial + begin + @(negedge rst); + @(posedge clk); + repeat (10) + @(posedge clk); + write <= 1; + @(posedge clk); + write <= 0; + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + read <= 1; + @(posedge clk); + read <= 0; + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + + repeat(10) + begin + write <= 1; + @(posedge clk); + write <= 0; + @(posedge clk); + @(posedge clk); + @(posedge clk); + read <= 1; + @(posedge clk); + read <= 0; + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + @(posedge clk); + end // repeat (10) + + write <= 1; + repeat (4) + @(posedge clk); + write <= 0; + @(posedge clk); + read <= 1; + repeat (4) + @(posedge clk); + read <= 0; + @(posedge clk); + + + write <= 1; + repeat (4) + @(posedge clk); + write <= 0; + @(posedge clk); + repeat (4) + begin + read <= 1; + @(posedge clk); + read <= 0; + @(posedge clk); + end + + write <= 1; + @(posedge clk); + @(posedge clk); + read <= 1; + repeat (5) + @(posedge clk); + write <= 0; + @(posedge clk); + @(posedge clk); + read <= 0; + @(posedge clk); + + write <= 1; + repeat (16) + @(posedge clk); + write <= 0; + @(posedge clk); + + read <= 1; + repeat (16) + @(posedge clk); + read <= 0; + @(posedge clk); + + repeat (10) + @(posedge clk); + $finish; + end +endmodule // longfifo_tb diff --git a/control_lib/fifo_writer.v b/control_lib/fifo_writer.v new file mode 100644 index 000000000..064ad3cb9 --- /dev/null +++ b/control_lib/fifo_writer.v @@ -0,0 +1,31 @@ + +module fifo_writer + #(parameter rate=4) + (input clk, + output [31:0] data_out, + output write_o, + input ready_i, + input done_i + ); + + reg [7:0] state = 0; + + + // FIXME change this to write + always @(posedge clk) + if(ready) + if(state == rate) + state <= 0; + else + state <= state + 1; + else + state <= 0; + + assign read = (state == rate); + + initial $monitor(data_in); + +endmodule // fifo_writer + + + diff --git a/control_lib/gray2bin.v b/control_lib/gray2bin.v new file mode 100644 index 000000000..5df40bd52 --- /dev/null +++ b/control_lib/gray2bin.v @@ -0,0 +1,13 @@ + + +module gray2bin + #(parameter WIDTH=8) + (input [WIDTH-1:0] gray, + output reg [WIDTH-1:0] bin); + + integer i; + always @(gray) + for(i = 0;i>i); + +endmodule // gray2bin diff --git a/control_lib/gray_send.v b/control_lib/gray_send.v new file mode 100644 index 000000000..7fc07d40c --- /dev/null +++ b/control_lib/gray_send.v @@ -0,0 +1,29 @@ + + + +module gray_send + #(parameter WIDTH = 8) + (input clk_in, input [WIDTH-1:0] addr_in, + input clk_out, output reg [WIDTH-1:0] addr_out); + + reg [WIDTH-1:0] gray_clkin, gray_clkout, gray_clkout_d1; + wire [WIDTH-1:0] gray, bin; + + bin2gray #(.WIDTH(WIDTH)) b2g (.bin(addr_in), .gray(gray) ); + + always @(posedge clk_in) + gray_clkin <= gray; + + always @(posedge clk_out) + gray_clkout <= gray_clkin; + + always @(posedge clk_out) + gray_clkout_d1 <= gray_clkout; + + gray2bin #(.WIDTH(WIDTH)) g2b (.gray(gray_clkout_d1), .bin(bin) ); + + // FIXME we may not need the next register, but it may help timing + always @(posedge clk_out) + addr_out <= bin; + +endmodule // gray_send diff --git a/control_lib/icache.v b/control_lib/icache.v new file mode 100644 index 000000000..dd93c88ed --- /dev/null +++ b/control_lib/icache.v @@ -0,0 +1,134 @@ + +module icache + #(parameter AWIDTH=14, + parameter CWIDTH=6) + + (input wb_clk_i, + input wb_rst_i, + input [AWIDTH-1:0] iwb_adr_i, + input iwb_stb_i, + output [31:0] iwb_dat_o, + output iwb_ack_o, + input [31:0] iram_dat_i, + output [AWIDTH-1:0] iram_adr_o, + output iram_en_o ); + + localparam TAGWIDTH = AWIDTH-CWIDTH-2; + reg stb_d1, ack_d1, miss_d1; + reg [AWIDTH-1:0] held_addr; + reg [31:0] idata [0:(1<>1)); + wire latch_dat = (clk_ctr == (clk_div - 8'd2)); + wire send_clk_lo = (clk_ctr == (clk_div - 8'd1)); + + wire send_bit = (bit_ready && (bit_ctr != 0)); + assign ready = (bit_ctr == 0); + + always @(posedge clk) + if(rst) + clk_ctr <= 0; + else if(bit_done) + clk_ctr <= 0; + else if(bit_busy) + clk_ctr <= clk_ctr + 1; + else if(send_bit) + clk_ctr <= 1; + + always @(posedge clk) + if(rst) + sd_clk <= 0; + else if(send_clk_hi) + sd_clk <= 1; + else if(send_clk_lo) + sd_clk <= 0; + + always @(posedge clk) + if(rst) + bit_ctr <= 0; + else if(bit_done) + if(bit_ctr == 4'd8) + bit_ctr <= 0; + else + bit_ctr <= bit_ctr + 1; + else if(bit_ready & go) + bit_ctr <= 1; + + reg [7:0] shift_reg; + always @(posedge clk) + if(go) + shift_reg <= send_dat; + else if(latch_dat) + shift_reg <= {shift_reg[6:0],sd_miso}; + + assign sd_mosi = shift_reg[7]; + assign rcv_dat = shift_reg; + +endmodule // sd_spi diff --git a/control_lib/sd_spi_tb.v b/control_lib/sd_spi_tb.v new file mode 100644 index 000000000..e30a5bdf6 --- /dev/null +++ b/control_lib/sd_spi_tb.v @@ -0,0 +1,40 @@ + + +module sd_spi_tb; + + reg clk = 0; + always #5 clk = ~clk; + reg rst = 1; + initial #32 rst = 0; + + wire sd_clk, sd_mosi, sd_miso; + wire [7:0] clk_div = 12; + wire [7:0] send_dat = 23; + wire [7:0] rcv_dat; + + wire ready; + reg go = 0; + initial + begin + repeat (100) + @(posedge clk); + go <= 1; + @(posedge clk); + go <= 0; + end + + sd_spi dut(.clk(clk),.rst(rst), + .sd_clk(sd_clk),.sd_mosi(sd_mosi),.sd_miso(sd_miso), + .clk_div(clk_div),.send_dat(send_dat),.rcv_dat(rcv_dat), + .go(go),.ready(ready) ); + + initial + begin + $dumpfile("sd_spi_tb.vcd"); + $dumpvars(0,sd_spi_tb); + end + + initial + #10000 $finish(); + +endmodule // sd_spi_tb diff --git a/control_lib/sd_spi_wb.v b/control_lib/sd_spi_wb.v new file mode 100644 index 000000000..53036d363 --- /dev/null +++ b/control_lib/sd_spi_wb.v @@ -0,0 +1,66 @@ + +// Wishbone module for spi communications with an SD Card +// The programming interface is simple -- +// Write the desired clock divider to address 1 (should be 1 or higher) +// Status is in address 0. A 1 indicates the last transaction is done and it is safe to +// send another +// Writing a byte to address 2 sends that byte over SPI. When it is done, +// status (addr 0) goes high again, and the received byte can be read from address 3. + +module sd_spi_wb + (input clk, + input rst, + + // SD Card interface + output sd_clk, + output sd_csn, + output sd_mosi, + input sd_miso, + + input wb_cyc_i, + input wb_stb_i, + input wb_we_i, + input [1:0] wb_adr_i, + input [7:0] wb_dat_i, + output reg [7:0] wb_dat_o, + output reg wb_ack_o); + + localparam ADDR_STATUS = 0; + localparam ADDR_CLKDIV = 1; + localparam ADDR_WRITE = 2; + localparam ADDR_READ = 3; + + wire [7:0] status, rcv_dat; + reg [7:0] clkdiv; + wire ready; + reg ack_d1; + always @(posedge clk) + if(rst) ack_d1 <= 0; + else ack_d1 <= wb_ack_o; + + always @(posedge clk) + if(rst) wb_ack_o <= 0; + else wb_ack_o <= wb_cyc_i & wb_stb_i & ~ack_d1; + + always @(posedge clk) + case(wb_adr_i) + ADDR_STATUS : wb_dat_o <= {7'd0,ready}; + ADDR_CLKDIV : wb_dat_o <= clkdiv; + ADDR_READ : wb_dat_o <= rcv_dat; + default : wb_dat_o <= 0; + endcase // case(wb_adr_i) + + always @(posedge clk) + if(wb_we_i & wb_stb_i & wb_cyc_i & wb_ack_o) + case(wb_adr_i) + ADDR_CLKDIV : clkdiv <= wb_dat_i; + endcase // case(wb_adr_i) + + wire go = wb_we_i & wb_stb_i & wb_cyc_i & wb_ack_o & (wb_adr_i == ADDR_WRITE); + + sd_spi sd_spi(.clk(clk),.rst(rst), + .sd_clk(sd_clk),.sd_mosi(sd_mosi),.sd_miso(sd_miso), + .clk_div(clkdiv),.send_dat(wb_dat_i),.rcv_dat(rcv_dat), + .go(go),.ready(ready) ); + +endmodule // sd_spi_wb diff --git a/control_lib/setting_reg.v b/control_lib/setting_reg.v new file mode 100644 index 000000000..ccbaa3d2e --- /dev/null +++ b/control_lib/setting_reg.v @@ -0,0 +1,23 @@ + + +module setting_reg + #(parameter my_addr = 0) + (input clk, input rst, input strobe, input wire [7:0] addr, + input wire [31:0] in, output reg [31:0] out, output reg changed); + + always @(posedge clk) + if(rst) + begin + out <= 32'd0; + changed <= 1'b0; + end + else + if(strobe & (my_addr==addr)) + begin + out <= in; + changed <= 1'b1; + end + else + changed <= 1'b0; + +endmodule // setting_reg diff --git a/control_lib/settings_bus.v b/control_lib/settings_bus.v new file mode 100644 index 000000000..d01a30ab4 --- /dev/null +++ b/control_lib/settings_bus.v @@ -0,0 +1,49 @@ + +// Grab settings off the wishbone bus, send them out to our simpler bus on the fast clock + +module settings_bus + #(parameter AWIDTH=16, parameter DWIDTH=32) + (input wb_clk, + input wb_rst, + input [AWIDTH-1:0] wb_adr_i, + input [DWIDTH-1:0] wb_dat_i, + input wb_stb_i, + input wb_we_i, + output reg wb_ack_o, + input sys_clk, + output strobe, + output reg [7:0] addr, + output reg [31:0] data); + + reg stb_int, stb_int_d1; + + always @(posedge wb_clk) + if(wb_rst) + begin + stb_int <= 1'b0; + addr <= 8'd0; + data <= 32'd0; + end + else if(wb_we_i & wb_stb_i) + begin + stb_int <= 1'b1; + addr <= wb_adr_i[9:2]; + data <= wb_dat_i; + end + else + stb_int <= 1'b0; + + always @(posedge wb_clk) + if(wb_rst) + wb_ack_o <= 0; + else + wb_ack_o <= wb_stb_i & ~wb_ack_o; + + always @(posedge wb_clk) + stb_int_d1 <= stb_int; + + //assign strobe = stb_int & ~stb_int_d1; + assign strobe = stb_int & wb_ack_o; + +endmodule // settings_bus + diff --git a/control_lib/shortfifo.v b/control_lib/shortfifo.v new file mode 100644 index 000000000..83d2c1980 --- /dev/null +++ b/control_lib/shortfifo.v @@ -0,0 +1,63 @@ + +module shortfifo + #(parameter WIDTH=32) + (input clk, input rst, + input [WIDTH-1:0] datain, + output [WIDTH-1:0] dataout, + input read, + input write, + input clear, + output reg full, + output reg empty, + output [4:0] space, + output [4:0] occupied); + + reg [3:0] a; + genvar i; + + generate + for (i=0;i>1); + wire stop_now = (bit_ctr == 10) && shift_now; + wire go_now = (bit_ctr == 0) && neg_trans; + + always @(posedge clk) + if(rst) + sr <= 0; + else if(shift_now) + sr <= {rx_d2,sr[7:1]}; + + always @(posedge clk) + if(rst) + baud_ctr <= 0; + else + if(go_now) + baud_ctr <= 1; + else if(stop_now) + baud_ctr <= 0; + else if(baud_ctr >= clkdiv) + baud_ctr <= 1; + else if(baud_ctr != 0) + baud_ctr <= baud_ctr + 1; + + always @(posedge clk) + if(rst) + bit_ctr <= 0; + else + if(go_now) + bit_ctr <= 1; + else if(stop_now) + bit_ctr <= 0; + else if(baud_ctr == clkdiv) + bit_ctr <= bit_ctr + 1; + + wire full; + wire write = ~full & rx_d2 & stop_now; + + medfifo #(.WIDTH(8),.DEPTH(DEPTH)) fifo + (.clk(clk),.rst(rst), + .datain(sr),.write(write),.full(full), + .dataout(fifo_out),.read(fifo_read),.empty(fifo_empty), + .clear(0),.space(),.occupied(fifo_level) ); + +endmodule // simple_uart_rx diff --git a/control_lib/simple_uart_tx.v b/control_lib/simple_uart_tx.v new file mode 100644 index 000000000..e11a347ed --- /dev/null +++ b/control_lib/simple_uart_tx.v @@ -0,0 +1,60 @@ + +module simple_uart_tx + #(parameter DEPTH=0) + (input clk, input rst, + input [7:0] fifo_in, input fifo_write, output [7:0] fifo_level, output fifo_full, + input [15:0] clkdiv, output baudclk, output reg tx); + + reg [15:0] baud_ctr; + reg [3:0] bit_ctr; + + wire read, empty; + wire [7:0] char_to_send; + + medfifo #(.WIDTH(8),.DEPTH(DEPTH)) fifo + (.clk(clk),.rst(rst), + .datain(fifo_in),.write(fifo_write),.full(fifo_full), + .dataout(char_to_send),.read(read),.empty(empty), + .clear(0),.space(fifo_level),.occupied() ); + + always @(posedge clk) + if(rst) + baud_ctr <= 0; + else if (baud_ctr >= clkdiv) + baud_ctr <= 0; + else + baud_ctr <= baud_ctr + 1; + + always @(posedge clk) + if(rst) + bit_ctr <= 0; + else if(baud_ctr == clkdiv) + if(bit_ctr == 9) + bit_ctr <= 0; + else if(bit_ctr != 0) + bit_ctr <= bit_ctr + 1; + else if(~empty) + bit_ctr <= 1; + + always @(posedge clk) + if(rst) + tx <= 1; + else + case(bit_ctr) + 0 : tx <= 1; + 1 : tx <= 0; + 2 : tx <= char_to_send[0]; + 3 : tx <= char_to_send[1]; + 4 : tx <= char_to_send[2]; + 5 : tx <= char_to_send[3]; + 6 : tx <= char_to_send[4]; + 7 : tx <= char_to_send[5]; + 8 : tx <= char_to_send[6]; + 9 : tx <= char_to_send[7]; + default : tx <= 1; + endcase // case(bit_ctr) + + assign read = (bit_ctr == 9) && (baud_ctr == clkdiv); + assign baudclk = (baud_ctr == 1); // Only for debug purposes + +endmodule // simple_uart_tx diff --git a/control_lib/spi.v b/control_lib/spi.v new file mode 100644 index 000000000..a80c488e9 --- /dev/null +++ b/control_lib/spi.v @@ -0,0 +1,84 @@ + + +// AD9510 Register Map (from datasheet Rev. A) + +/* INSTRUCTION word format (16 bits) + * 15 Read = 1, Write = 0 + * 14:13 W1/W0, Number of bytes 00 - 1, 01 - 2, 10 - 3, 11 - stream + * 12:0 Address + */ + +/* ADDR Contents Value (hex) + * 00 Serial Config Port 10 (def) -- MSB first, SDI/SDO separate + * 04 A Counter + * 05-06 B Counter + * 07-0A PLL Control + * 0B-0C R Divider + * 0D PLL Control + * 34-3A Fine Delay + * 3C-3F LVPECL Outs + * 40-43 LVDS/CMOS Outs + * 45 Clock select, power down + * 48-57 Dividers + * 58 Func and Sync + * 5A Update regs + */ + + +module spi + (input reset, + input clk, + + // SPI signals + output sen, + output sclk, + input sdi, + output sdo, + + // Interfaces + input read_1, + input write_1, + input [15:0] command_1, + input [15:0] wdata_1, + output [15:0] rdata_1, + output reg done_1, + input msb_first_1, + input [5:0] command_width_1, + input [5:0] data_width_1, + input [7:0] clkdiv_1 + + ); + + reg [15:0] command, wdata, rdata; + reg done; + + always @(posedge clk) + if(reset) + done_1 <= #1 1'b0; + + always @(posedge clk) + if(reset) + begin + counter <= #1 7'd0; + command <= #1 20'd0; + end + else if(start) + begin + counter <= #1 7'd1; + command <= #1 {read,w,addr_data}; + end + else if( |counter && ~done ) + begin + counter <= #1 counter + 7'd1; + if(~counter[0]) + command <= {command[22:0],1'b0}; + end + + wire done = (counter == 8'd49); + + assign sen = (done | counter == 8'd0); // CSB is high when we're not doing anything + assign sclk = ~counter[0]; + assign sdo = command[23]; + + +endmodule // clock_control diff --git a/control_lib/srl.v b/control_lib/srl.v new file mode 100644 index 000000000..fa28c7669 --- /dev/null +++ b/control_lib/srl.v @@ -0,0 +1,21 @@ + +module srl + #(parameter WIDTH=18) + (input clk, + input write, + input [WIDTH-1:0] in, + input [3:0] addr, + output [WIDTH-1:0] out); + + genvar i; + generate + for (i=0;i 5) + clock_present <= 1; + else + ; + else + if(abs_diff<3) + clock_present <= 0; + else + rd_counter <= rd_counter + 1; + +endmodule // ss_rcvr diff --git a/control_lib/system_control.v b/control_lib/system_control.v new file mode 100644 index 000000000..5d89f13db --- /dev/null +++ b/control_lib/system_control.v @@ -0,0 +1,47 @@ +// System bootup order: +// 0 - Internal POR to reset this block. Maybe control it from CPLD in the future? +// 1 - Everything in reset +// 2 - Take RAM Loader out of reset +// 3 - When RAM Loader done, take processor and wishbone out of reset + +module system_control + (input wb_clk_i, + output reg ram_loader_rst_o, + output reg wb_rst_o, + input ram_loader_done_i + ); + + reg POR = 1'b1; + reg [3:0] POR_ctr; + + initial POR_ctr = 4'd0; + always @(posedge wb_clk_i) + if(POR_ctr == 4'd15) + POR <= 1'b0; + else + POR_ctr <= POR_ctr + 4'd1; + + always @(posedge POR or posedge wb_clk_i) + if(POR) + ram_loader_rst_o <= 1'b1; + else + ram_loader_rst_o <= #1 1'b0; + + // Main system reset + reg delayed_rst; + + always @(posedge POR or posedge wb_clk_i) + if(POR) + begin + wb_rst_o <= 1'b1; + delayed_rst <= 1'b1; + end + else if(ram_loader_done_i) + begin + delayed_rst <= 1'b0; + wb_rst_o <= delayed_rst; + end + +endmodule // system_control + + diff --git a/control_lib/system_control_tb.v b/control_lib/system_control_tb.v new file mode 100644 index 000000000..a8eff4811 --- /dev/null +++ b/control_lib/system_control_tb.v @@ -0,0 +1,57 @@ + + +module system_control_tb(); + + reg aux_clk, clk_fpga; + wire wb_clk, dsp_clk; + wire wb_rst, dsp_rst, rl_rst, proc_rst; + + reg rl_done, clock_ready; + + initial aux_clk = 1'b0; + always #25 aux_clk = ~aux_clk; + + initial clk_fpga = 1'b0; + + initial clock_ready = 1'b0; + initial + begin + @(negedge proc_rst); + #1003 clock_ready <= 1'b1; + end + + always #7 clk_fpga = ~clk_fpga; + + initial begin + $dumpfile("system_control_tb.vcd"); + $dumpvars(0,system_control_tb); + end + + initial #10000 $finish; + + initial + begin + @(negedge rl_rst); + rl_done <= 1'b0; + #1325 rl_done <= 1'b1; + end + + initial + begin + @(negedge proc_rst); + clock_ready <= 1'b0; + #327 clock_ready <= 1'b1; + end + + system_control + system_control(.aux_clk_i(aux_clk),.clk_fpga_i(clk_fpga), + .dsp_clk_o(dsp_clk),.wb_clk_o(wb_clk), + .ram_loader_rst_o(rl_rst), + .processor_rst_o(proc_rst), + .wb_rst_o(wb_rst), + .dsp_rst_o(dsp_rst), + .ram_loader_done_i(rl_done), + .clock_ready_i(clock_ready), + .debug_o()); + +endmodule // system_control_tb diff --git a/control_lib/traffic_cop.v b/control_lib/traffic_cop.v new file mode 100644 index 000000000..e7579656a --- /dev/null +++ b/control_lib/traffic_cop.v @@ -0,0 +1,25 @@ + +module traffic_cop(); + + +endmodule // traffic_cop + + + +/* + + Traffic Cop to control buffer pool + + Inputs + + Commands + + Basic Operations + + Outputs + + + + + + */ diff --git a/control_lib/wb_1master.v b/control_lib/wb_1master.v new file mode 100644 index 000000000..e56ba1fb2 --- /dev/null +++ b/control_lib/wb_1master.v @@ -0,0 +1,430 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE Connection Bus Top Level //// +//// //// +//// //// +//// Original Author: Johny Chi //// +//// chisuhua@yahoo.com.cn //// +//// Modified By Matt Ettus, matt@ettus.com //// +//// //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2000, 2007 Authors and OPENCORES.ORG //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source 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 Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +////////////////////////////////////////////////////////////////////// +// +// Up to 8 slaves share a Wishbone Bus connection to 1 master + + module wb_1master + #(parameter s0_addr_w = 4, // slave 0 address decode width + parameter s0_addr = 4'h0, // slave 0 address + parameter s1_addr_w = 4 , // slave 1 address decode width + parameter s1_addr = 4'h1, // slave 1 address + parameter s215_addr_w = 8 , // slave 2 to slave 7 address decode width + parameter s2_addr = 8'h92, // slave 2 address + parameter s3_addr = 8'h93, // slave 3 address + parameter s4_addr = 8'h94, // slave 4 address + parameter s5_addr = 8'h95, // slave 5 address + parameter s6_addr = 8'h96, // slave 6 address + parameter s7_addr = 8'h97, // slave 7 address + parameter s8_addr = 8'h98, // slave 7 address + parameter s9_addr = 8'h99, // slave 7 address + parameter s10_addr = 8'h9a, // slave 7 address + parameter s11_addr = 8'h9b, // slave 7 address + parameter s12_addr = 8'h9c, // slave 7 address + parameter s13_addr = 8'h9d, // slave 7 address + parameter s14_addr = 8'h9e, // slave 7 address + parameter s15_addr = 8'h9f, // slave 7 address + + parameter dw = 32, // Data bus Width + parameter aw = 32, // Address bus Width + parameter sw = 4) // Number of Select Lines + + (input clk_i, + input rst_i, + + // Master Interface + input [dw-1:0] m0_dat_i, + output [dw-1:0] m0_dat_o, + input [aw-1:0] m0_adr_i, + input [sw-1:0] m0_sel_i, + input m0_we_i, + input m0_cyc_i, + input m0_stb_i, + output m0_ack_o, + output m0_err_o, + output m0_rty_o, + + // Slave Interfaces + input [dw-1:0] s0_dat_i, + output [dw-1:0] s0_dat_o, + output [aw-1:0] s0_adr_o, + output [sw-1:0] s0_sel_o, + output s0_we_o, + output s0_cyc_o, + output s0_stb_o, + input s0_ack_i, + input s0_err_i, + input s0_rty_i, + + input [dw-1:0] s1_dat_i, + output [dw-1:0] s1_dat_o, + output [aw-1:0] s1_adr_o, + output [sw-1:0] s1_sel_o, + output s1_we_o, + output s1_cyc_o, + output s1_stb_o, + input s1_ack_i, + input s1_err_i, + input s1_rty_i, + + input [dw-1:0] s2_dat_i, + output [dw-1:0] s2_dat_o, + output [aw-1:0] s2_adr_o, + output [sw-1:0] s2_sel_o, + output s2_we_o, + output s2_cyc_o, + output s2_stb_o, + input s2_ack_i, + input s2_err_i, + input s2_rty_i, + + input [dw-1:0] s3_dat_i, + output [dw-1:0] s3_dat_o, + output [aw-1:0] s3_adr_o, + output [sw-1:0] s3_sel_o, + output s3_we_o, + output s3_cyc_o, + output s3_stb_o, + input s3_ack_i, + input s3_err_i, + input s3_rty_i, + + input [dw-1:0] s4_dat_i, + output [dw-1:0] s4_dat_o, + output [aw-1:0] s4_adr_o, + output [sw-1:0] s4_sel_o, + output s4_we_o, + output s4_cyc_o, + output s4_stb_o, + input s4_ack_i, + input s4_err_i, + input s4_rty_i, + + input [dw-1:0] s5_dat_i, + output [dw-1:0] s5_dat_o, + output [aw-1:0] s5_adr_o, + output [sw-1:0] s5_sel_o, + output s5_we_o, + output s5_cyc_o, + output s5_stb_o, + input s5_ack_i, + input s5_err_i, + input s5_rty_i, + + input [dw-1:0] s6_dat_i, + output [dw-1:0] s6_dat_o, + output [aw-1:0] s6_adr_o, + output [sw-1:0] s6_sel_o, + output s6_we_o, + output s6_cyc_o, + output s6_stb_o, + input s6_ack_i, + input s6_err_i, + input s6_rty_i, + + input [dw-1:0] s7_dat_i, + output [dw-1:0] s7_dat_o, + output [aw-1:0] s7_adr_o, + output [sw-1:0] s7_sel_o, + output s7_we_o, + output s7_cyc_o, + output s7_stb_o, + input s7_ack_i, + input s7_err_i, + input s7_rty_i, + + input [dw-1:0] s8_dat_i, + output [dw-1:0] s8_dat_o, + output [aw-1:0] s8_adr_o, + output [sw-1:0] s8_sel_o, + output s8_we_o, + output s8_cyc_o, + output s8_stb_o, + input s8_ack_i, + input s8_err_i, + input s8_rty_i, + + input [dw-1:0] s9_dat_i, + output [dw-1:0] s9_dat_o, + output [aw-1:0] s9_adr_o, + output [sw-1:0] s9_sel_o, + output s9_we_o, + output s9_cyc_o, + output s9_stb_o, + input s9_ack_i, + input s9_err_i, + input s9_rty_i, + + input [dw-1:0] s10_dat_i, + output [dw-1:0] s10_dat_o, + output [aw-1:0] s10_adr_o, + output [sw-1:0] s10_sel_o, + output s10_we_o, + output s10_cyc_o, + output s10_stb_o, + input s10_ack_i, + input s10_err_i, + input s10_rty_i, + + input [dw-1:0] s11_dat_i, + output [dw-1:0] s11_dat_o, + output [aw-1:0] s11_adr_o, + output [sw-1:0] s11_sel_o, + output s11_we_o, + output s11_cyc_o, + output s11_stb_o, + input s11_ack_i, + input s11_err_i, + input s11_rty_i, + + input [dw-1:0] s12_dat_i, + output [dw-1:0] s12_dat_o, + output [aw-1:0] s12_adr_o, + output [sw-1:0] s12_sel_o, + output s12_we_o, + output s12_cyc_o, + output s12_stb_o, + input s12_ack_i, + input s12_err_i, + input s12_rty_i, + + input [dw-1:0] s13_dat_i, + output [dw-1:0] s13_dat_o, + output [aw-1:0] s13_adr_o, + output [sw-1:0] s13_sel_o, + output s13_we_o, + output s13_cyc_o, + output s13_stb_o, + input s13_ack_i, + input s13_err_i, + input s13_rty_i, + + input [dw-1:0] s14_dat_i, + output [dw-1:0] s14_dat_o, + output [aw-1:0] s14_adr_o, + output [sw-1:0] s14_sel_o, + output s14_we_o, + output s14_cyc_o, + output s14_stb_o, + input s14_ack_i, + input s14_err_i, + input s14_rty_i, + + input [dw-1:0] s15_dat_i, + output [dw-1:0] s15_dat_o, + output [aw-1:0] s15_adr_o, + output [sw-1:0] s15_sel_o, + output s15_we_o, + output s15_cyc_o, + output s15_stb_o, + input s15_ack_i, + input s15_err_i, + input s15_rty_i + ); + + // //////////////////////////////////////////////////////////////// + // + // Local wires + // + + wire [15:0] ssel_dec; + reg [dw-1:0] i_dat_s; // internal share bus , slave data to master + + // Master output Interface + assign m0_dat_o = i_dat_s; + + always @* + case(ssel_dec) + 1 : i_dat_s <= s0_dat_i; + 2 : i_dat_s <= s1_dat_i; + 4 : i_dat_s <= s2_dat_i; + 8 : i_dat_s <= s3_dat_i; + 16 : i_dat_s <= s4_dat_i; + 32 : i_dat_s <= s5_dat_i; + 64 : i_dat_s <= s6_dat_i; + 128 : i_dat_s <= s7_dat_i; + 256 : i_dat_s <= s8_dat_i; + 512 : i_dat_s <= s9_dat_i; + 1024 : i_dat_s <= s10_dat_i; + 2048 : i_dat_s <= s11_dat_i; + 4096 : i_dat_s <= s12_dat_i; + 8192 : i_dat_s <= s13_dat_i; + 16384 : i_dat_s <= s14_dat_i; + 32768 : i_dat_s <= s15_dat_i; + default : i_dat_s <= s0_dat_i; + endcase // case(ssel_dec) + + assign {m0_ack_o, m0_err_o, m0_rty_o} + = {s0_ack_i | s1_ack_i | s2_ack_i | s3_ack_i | s4_ack_i | s5_ack_i | s6_ack_i | s7_ack_i | + s8_ack_i | s9_ack_i | s10_ack_i | s11_ack_i | s12_ack_i | s13_ack_i | s14_ack_i | s15_ack_i , + s0_err_i | s1_err_i | s2_err_i | s3_err_i | s4_err_i | s5_err_i | s6_err_i | s7_err_i | + s8_err_i | s9_err_i | s10_err_i | s11_err_i | s12_err_i | s13_err_i | s14_err_i | s15_err_i , + s0_rty_i | s1_rty_i | s2_rty_i | s3_rty_i | s4_rty_i | s5_rty_i | s6_rty_i | s7_rty_i | + s8_rty_i | s9_rty_i | s10_rty_i | s11_rty_i | s12_rty_i | s13_rty_i | s14_rty_i | s15_rty_i }; + + // Slave output interfaces + assign s0_adr_o = m0_adr_i; + assign s0_sel_o = m0_sel_i; + assign s0_dat_o = m0_dat_i; + assign s0_we_o = m0_we_i; + assign s0_cyc_o = m0_cyc_i; + assign s0_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[0]; + + assign s1_adr_o = m0_adr_i; + assign s1_sel_o = m0_sel_i; + assign s1_dat_o = m0_dat_i; + assign s1_we_o = m0_we_i; + assign s1_cyc_o = m0_cyc_i; + assign s1_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[1]; + + assign s2_adr_o = m0_adr_i; + assign s2_sel_o = m0_sel_i; + assign s2_dat_o = m0_dat_i; + assign s2_we_o = m0_we_i; + assign s2_cyc_o = m0_cyc_i; + assign s2_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[2]; + + assign s3_adr_o = m0_adr_i; + assign s3_sel_o = m0_sel_i; + assign s3_dat_o = m0_dat_i; + assign s3_we_o = m0_we_i; + assign s3_cyc_o = m0_cyc_i; + assign s3_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[3]; + + assign s4_adr_o = m0_adr_i; + assign s4_sel_o = m0_sel_i; + assign s4_dat_o = m0_dat_i; + assign s4_we_o = m0_we_i; + assign s4_cyc_o = m0_cyc_i; + assign s4_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[4]; + + assign s5_adr_o = m0_adr_i; + assign s5_sel_o = m0_sel_i; + assign s5_dat_o = m0_dat_i; + assign s5_we_o = m0_we_i; + assign s5_cyc_o = m0_cyc_i; + assign s5_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[5]; + + assign s6_adr_o = m0_adr_i; + assign s6_sel_o = m0_sel_i; + assign s6_dat_o = m0_dat_i; + assign s6_we_o = m0_we_i; + assign s6_cyc_o = m0_cyc_i; + assign s6_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[6]; + + assign s7_adr_o = m0_adr_i; + assign s7_sel_o = m0_sel_i; + assign s7_dat_o = m0_dat_i; + assign s7_we_o = m0_we_i; + assign s7_cyc_o = m0_cyc_i; + assign s7_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[7]; + + assign s8_adr_o = m0_adr_i; + assign s8_sel_o = m0_sel_i; + assign s8_dat_o = m0_dat_i; + assign s8_we_o = m0_we_i; + assign s8_cyc_o = m0_cyc_i; + assign s8_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[8]; + + assign s9_adr_o = m0_adr_i; + assign s9_sel_o = m0_sel_i; + assign s9_dat_o = m0_dat_i; + assign s9_we_o = m0_we_i; + assign s9_cyc_o = m0_cyc_i; + assign s9_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[9]; + + assign s10_adr_o = m0_adr_i; + assign s10_sel_o = m0_sel_i; + assign s10_dat_o = m0_dat_i; + assign s10_we_o = m0_we_i; + assign s10_cyc_o = m0_cyc_i; + assign s10_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[10]; + + assign s11_adr_o = m0_adr_i; + assign s11_sel_o = m0_sel_i; + assign s11_dat_o = m0_dat_i; + assign s11_we_o = m0_we_i; + assign s11_cyc_o = m0_cyc_i; + assign s11_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[11]; + + assign s12_adr_o = m0_adr_i; + assign s12_sel_o = m0_sel_i; + assign s12_dat_o = m0_dat_i; + assign s12_we_o = m0_we_i; + assign s12_cyc_o = m0_cyc_i; + assign s12_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[12]; + + assign s13_adr_o = m0_adr_i; + assign s13_sel_o = m0_sel_i; + assign s13_dat_o = m0_dat_i; + assign s13_we_o = m0_we_i; + assign s13_cyc_o = m0_cyc_i; + assign s13_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[13]; + + assign s14_adr_o = m0_adr_i; + assign s14_sel_o = m0_sel_i; + assign s14_dat_o = m0_dat_i; + assign s14_we_o = m0_we_i; + assign s14_cyc_o = m0_cyc_i; + assign s14_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[14]; + + assign s15_adr_o = m0_adr_i; + assign s15_sel_o = m0_sel_i; + assign s15_dat_o = m0_dat_i; + assign s15_we_o = m0_we_i; + assign s15_cyc_o = m0_cyc_i; + assign s15_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[15]; + + // Address decode logic + // WARNING -- must make sure these are mutually exclusive! + assign ssel_dec[0] = (m0_adr_i[aw -1 : aw - s0_addr_w ] == s0_addr); + assign ssel_dec[1] = (m0_adr_i[aw -1 : aw - s1_addr_w ] == s1_addr); + assign ssel_dec[2] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s2_addr); + assign ssel_dec[3] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s3_addr); + assign ssel_dec[4] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s4_addr); + assign ssel_dec[5] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s5_addr); + assign ssel_dec[6] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s6_addr); + assign ssel_dec[7] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s7_addr); + assign ssel_dec[8] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s8_addr); + assign ssel_dec[9] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s9_addr); + assign ssel_dec[10] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s10_addr); + assign ssel_dec[11] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s11_addr); + assign ssel_dec[12] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s12_addr); + assign ssel_dec[13] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s13_addr); + assign ssel_dec[14] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s14_addr); + assign ssel_dec[15] = (m0_adr_i[aw -1 : aw - s215_addr_w ] == s15_addr); + +endmodule // wb_1master diff --git a/control_lib/wb_bus_writer.v b/control_lib/wb_bus_writer.v new file mode 100644 index 000000000..fc148a0ff --- /dev/null +++ b/control_lib/wb_bus_writer.v @@ -0,0 +1,57 @@ + +// wb_bus_writer +// +// WB Bus Master device to send a sequence of single-word transactions +// based on a list in a RAM or ROM (FASM interface) +// ROM data format is {WB_ADDR[15:0],WB_DATA[31:0]} +// continues until it gets an all-1s entry + +module wb_bus_writer (input start, + output done, + output reg [15:0] rom_addr, + input [47:0] rom_data, + // WB Master Interface, don't need wb_dat_i + input wb_clk_i, + input wb_rst_i, + output [31:0] wb_dat_o, + input wb_ack_i, + output [15:0] wb_adr_o, + output wb_cyc_o, + output [3:0] wb_sel_o, + output wb_stb_o, + output wb_we_o + ); + +`define IDLE 0 +`define READ 1 + + reg [3:0] state; + + assign done = (state != `IDLE) && (&rom_data); // Done when we see all 1s + + always @(posedge wb_clk_i) + if(wb_rst_i) + begin + rom_addr <= #1 0; + state <= #1 0; + end + else if(start) + begin + rom_addr <= #1 0; + state <= #1 `READ; + end + else if((state == `READ) && wb_ack_i) + if(done) + state <= #1 `IDLE; + else + rom_addr <= #1 rom_addr + 1; + + assign wb_dat_o = rom_data[31:0]; + assign wb_adr_o = rom_data[47:32]; + assign wb_sel_o = 4'b1111; // All writes are the full 32 bits + + assign wb_cyc_o = !done & (state != `IDLE); + assign wb_stb_o = !done & (state != `IDLE); + assign wb_we_o = !done & (state != `IDLE); + +endmodule // wb_bus_writer diff --git a/control_lib/wb_output_pins32.v b/control_lib/wb_output_pins32.v new file mode 100644 index 000000000..1517f2066 --- /dev/null +++ b/control_lib/wb_output_pins32.v @@ -0,0 +1,49 @@ + + +// Simple 32-bit Wishbone compatible slave output port +// with 8-bit granularity, modeled after the one in the spec +// Allows for readback +// Assumes a 32-bit wishbone bus +// Lowest order bits get sel[0] +// + +module wb_output_pins32 + (wb_rst_i, wb_clk_i, wb_dat_i, wb_dat_o, + wb_we_i, wb_sel_i, wb_stb_i, wb_ack_o, wb_cyc_i, + port_output); + + input wb_rst_i; + input wb_clk_i; + input wire [31:0] wb_dat_i; + output wire [31:0] wb_dat_o; + input wb_we_i; + input wire [3:0] wb_sel_i; + input wb_stb_i; + output wb_ack_o; + input wb_cyc_i; + + output wire [31:0] port_output; + + reg [31:0] internal_reg; + + always @(posedge wb_clk_i) + if(wb_rst_i) + internal_reg <= #1 32'b0; + else + begin + if(wb_stb_i & wb_we_i & wb_sel_i[0]) + internal_reg[7:0] <= #1 wb_dat_i[7:0]; + if(wb_stb_i & wb_we_i & wb_sel_i[1]) + internal_reg[15:8] <= #1 wb_dat_i[15:8]; + if(wb_stb_i & wb_we_i & wb_sel_i[2]) + internal_reg[23:16] <= #1 wb_dat_i[23:16]; + if(wb_stb_i & wb_we_i & wb_sel_i[3]) + internal_reg[31:24] <= #1 wb_dat_i[31:24]; + end // else: !if(wb_rst_i) + + assign wb_dat_o = internal_reg; + assign port_output = internal_reg; + assign wb_ack_o = wb_stb_i; + +endmodule // wb_output_pins32 + diff --git a/control_lib/wb_ram_block.v b/control_lib/wb_ram_block.v new file mode 100644 index 000000000..044d34ca4 --- /dev/null +++ b/control_lib/wb_ram_block.v @@ -0,0 +1,36 @@ + + +// Since this is a block ram, there are no byte-selects and there is a 1-cycle read latency +// These have to be a multiple of 512 lines (2K) long + +module wb_ram_block + #(parameter AWIDTH=9) + (input clk_i, + input stb_i, + input we_i, + input [AWIDTH-1:0] adr_i, + input [31:0] dat_i, + output reg [31:0] dat_o, + output ack_o); + + reg [31:0] distram [0:1<<(AWIDTH-1)]; + + always @(posedge clk_i) + begin + if(stb_i & we_i) + distram[adr_i] <= dat_i; + dat_o <= distram[adr_i]; + end + + reg stb_d1, ack_d1; + always @(posedge clk_i) + stb_d1 <= stb_i; + + always @(posedge clk_i) + ack_d1 <= ack_o; + + assign ack_o = stb_i & (we_i | (stb_d1 & ~ack_d1)); +endmodule // wb_ram_block + + + diff --git a/control_lib/wb_ram_dist.v b/control_lib/wb_ram_dist.v new file mode 100644 index 000000000..cffc2f423 --- /dev/null +++ b/control_lib/wb_ram_dist.v @@ -0,0 +1,33 @@ + + +module wb_ram_dist + #(parameter AWIDTH=8) + (input clk_i, + input stb_i, + input we_i, + input [AWIDTH-1:0] adr_i, + input [31:0] dat_i, + input [3:0] sel_i, + output [31:0] dat_o, + output ack_o); + + reg [31:0] distram [0:1<<(AWIDTH-1)]; + + always @(posedge clk_i) + begin + if(stb_i & we_i & sel_i[3]) + distram[adr_i][31:24] <= dat_i[31:24]; + if(stb_i & we_i & sel_i[2]) + distram[adr_i][24:16] <= dat_i[24:16]; + if(stb_i & we_i & sel_i[1]) + distram[adr_i][15:8] <= dat_i[15:8]; + if(stb_i & we_i & sel_i[0]) + distram[adr_i][7:0] <= dat_i[7:0]; + end // always @ (posedge clk_i) + + assign dat_o = distram[adr_i]; + assign ack_o = stb_i; + +endmodule // wb_ram_dist + + diff --git a/control_lib/wb_readback_mux.v b/control_lib/wb_readback_mux.v new file mode 100644 index 000000000..3922b03e3 --- /dev/null +++ b/control_lib/wb_readback_mux.v @@ -0,0 +1,60 @@ + + +// Note -- clocks must be synchronous (derived from the same source) +// Assumes alt_clk is running at a multiple of wb_clk + +module wb_readback_mux + (input wb_clk_i, + input wb_rst_i, + input wb_stb_i, + input [15:0] wb_adr_i, + output reg [31:0] wb_dat_o, + output reg wb_ack_o, + + input [31:0] word00, + input [31:0] word01, + input [31:0] word02, + input [31:0] word03, + input [31:0] word04, + input [31:0] word05, + input [31:0] word06, + input [31:0] word07, + input [31:0] word08, + input [31:0] word09, + input [31:0] word10, + input [31:0] word11, + input [31:0] word12, + input [31:0] word13, + input [31:0] word14, + input [31:0] word15 + ); + + always @(posedge wb_clk_i) + if(wb_rst_i) + wb_ack_o <= 0; + else + wb_ack_o <= wb_stb_i & ~wb_ack_o; + + always @(posedge wb_clk_i) + case(wb_adr_i[5:2]) + 0 : wb_dat_o <= word00; + 1 : wb_dat_o <= word01; + 2 : wb_dat_o <= word02; + 3 : wb_dat_o <= word03; + 4 : wb_dat_o <= word04; + 5 : wb_dat_o <= word05; + 6 : wb_dat_o <= word06; + 7 : wb_dat_o <= word07; + 8 : wb_dat_o <= word08; + 9 : wb_dat_o <= word09; + 10: wb_dat_o <= word10; + 11: wb_dat_o <= word11; + 12: wb_dat_o <= word12; + 13: wb_dat_o <= word13; + 14: wb_dat_o <= word14; + 15: wb_dat_o <= word15; + endcase // case(addr_reg[3:0]) + +endmodule // wb_readback_mux + + diff --git a/control_lib/wb_regfile_2clock.v b/control_lib/wb_regfile_2clock.v new file mode 100644 index 000000000..e248e5161 --- /dev/null +++ b/control_lib/wb_regfile_2clock.v @@ -0,0 +1,107 @@ + +module wb_regfile_2clock + (input wb_clk_i, + input wb_rst_i, + input wb_stb_i, + input wb_we_i, + input [15:0] wb_adr_i, + input [3:0] wb_sel_i, + input [31:0] wb_dat_i, + output [31:0] wb_dat_o, + output wb_ack_o, + input alt_clk, + input alt_rst, + + output reg [31:0] reg00, + output reg [31:0] reg01, + output reg [31:0] reg02, + output reg [31:0] reg03, + output reg [31:0] reg04, + output reg [31:0] reg05, + output reg [31:0] reg06, + output reg [31:0] reg07 + ); + + reg [15:0] addr_reg; + reg [3:0] sel_reg; + reg [31:0] dat_reg; + reg wr_ret1, wr_ret2, we_reg, stb_reg; + + always @(posedge wb_clk_i) + if(wb_rst_i) + begin + addr_reg <= 0; + sel_reg <= 0; + dat_reg <= 0; + end + else if(wb_stb_i & wb_we_i) + begin + addr_reg <= wb_adr_i; + sel_reg <= wb_sel_i; + dat_reg <= wb_dat_i; + end + + always @(posedge wb_clk_i) + if(wb_rst_i) + {we_reg,stb_reg} <= 2'b0; + else + {we_reg,stb_reg} <= {wb_we_i,wb_stb_i}; + + assign wb_ack_o = stb_reg; + + always @(posedge alt_clk) + if(alt_rst) + {wr_ret2, wr_ret1} <= 2'b0; + else + {wr_ret2, wr_ret1} <= {wr_ret1, we_reg & stb_reg}; + + always @(posedge alt_clk) + if(alt_rst) + begin + reg00 <= 0; + reg01 <= 0; + reg02 <= 0; + reg03 <= 0; + reg04 <= 0; + reg05 <= 0; + reg06 <= 0; + reg07 <= 0; + end // if (alt_rst) + else if(wr_ret2) + case(addr_reg[4:2]) + 3'd0: reg00 <= { {sel_reg[3] ? dat_reg[31:24] : reg00[31:24]}, + {sel_reg[2] ? dat_reg[23:16] : reg00[23:16]}, + {sel_reg[1] ? dat_reg[15:8] : reg00[15:8]}, + {sel_reg[0] ? dat_reg[7:0] : reg00[7:0]}}; + 3'd1: reg01 <= { {sel_reg[3] ? dat_reg[31:24] : reg01[31:24]}, + {sel_reg[2] ? dat_reg[23:16] : reg01[23:16]}, + {sel_reg[1] ? dat_reg[15:8] : reg01[15:8]}, + {sel_reg[0] ? dat_reg[7:0] : reg01[7:0]}}; + 3'd2: reg02 <= { {sel_reg[3] ? dat_reg[31:24] : reg02[31:24]}, + {sel_reg[2] ? dat_reg[23:16] : reg02[23:16]}, + {sel_reg[1] ? dat_reg[15:8] : reg02[15:8]}, + {sel_reg[0] ? dat_reg[7:0] : reg02[7:0]}}; + 3'd3: reg03 <= { {sel_reg[3] ? dat_reg[31:24] : reg03[31:24]}, + {sel_reg[2] ? dat_reg[23:16] : reg03[23:16]}, + {sel_reg[1] ? dat_reg[15:8] : reg03[15:8]}, + {sel_reg[0] ? dat_reg[7:0] : reg03[7:0]}}; + 3'd4: reg04 <= { {sel_reg[3] ? dat_reg[31:24] : reg04[31:24]}, + {sel_reg[2] ? dat_reg[23:16] : reg04[23:16]}, + {sel_reg[1] ? dat_reg[15:8] : reg04[15:8]}, + {sel_reg[0] ? dat_reg[7:0] : reg04[7:0]}}; + 3'd5: reg05 <= { {sel_reg[3] ? dat_reg[31:24] : reg05[31:24]}, + {sel_reg[2] ? dat_reg[23:16] : reg05[23:16]}, + {sel_reg[1] ? dat_reg[15:8] : reg05[15:8]}, + {sel_reg[0] ? dat_reg[7:0] : reg05[7:0]}}; + 3'd6: reg06 <= { {sel_reg[3] ? dat_reg[31:24] : reg06[31:24]}, + {sel_reg[2] ? dat_reg[23:16] : reg06[23:16]}, + {sel_reg[1] ? dat_reg[15:8] : reg06[15:8]}, + {sel_reg[0] ? dat_reg[7:0] : reg06[7:0]}}; + 3'd7: reg07 <= { {sel_reg[3] ? dat_reg[31:24] : reg07[31:24]}, + {sel_reg[2] ? dat_reg[23:16] : reg07[23:16]}, + {sel_reg[1] ? dat_reg[15:8] : reg07[15:8]}, + {sel_reg[0] ? dat_reg[7:0] : reg07[7:0]}}; + endcase // case(addr_reg[2:0]) + +endmodule // wb_regfile_2clock + diff --git a/control_lib/wb_semaphore.v b/control_lib/wb_semaphore.v new file mode 100644 index 000000000..a9208e6a1 --- /dev/null +++ b/control_lib/wb_semaphore.v @@ -0,0 +1,42 @@ + +// up to 8 semaphores + +// After a read operation, the semaphore is always locked +// If it was already locked before the read (meaning someone else holds the lock) +// then a 1 is returned +// If it was not already locked (meaning the reader now holds the lock) +// then a 0 is returned + +// A write operation clears the lock + +module wb_semaphore + #(parameter count=8, DBUS_WIDTH=32) + (input wb_clk_i, + input wb_rst_i, + input [DBUS_WIDTH-1:0] wb_dat_i, + input [2:0] wb_adr_i, + input wb_cyc_i, + input wb_stb_i, + input wb_we_i, + output wb_ack_o, + output [DBUS_WIDTH-1:0] wb_dat_o); + + reg [count-1:0] locked; + + always @(posedge clock) + if(wb_rst_i) + locked <= {count{1'b0}}; + else if(wb_stb_i) + if(wb_we_i) + locked[adr_i] <= 1'b0; + else + locked[adr_i] <= 1'b1; + + assign wb_dat_o[DBUS_WIDTH-1:1] = {(DBUS_WIDTH-1){1'b0}}; + assign wb_dat_o[0] = locked[adr_i]; + assign wb_ack_o = wb_stb_i; + + +endmodule // wb_semaphore + + diff --git a/control_lib/wb_sim.v b/control_lib/wb_sim.v new file mode 100644 index 000000000..b324e1457 --- /dev/null +++ b/control_lib/wb_sim.v @@ -0,0 +1,79 @@ + + +module wb_sim(); + + wire wb_clk, wb_rst; + wire start; + + reg POR, aux_clk, clk_fpga; + + initial POR = 1'b1; + initial #103 POR = 1'b0; + + initial aux_clk = 1'b0; + always #25 aux_clk = ~aux_clk; + + initial clk_fpga = 1'bx; + initial #3007 clk_fpga = 1'b0; + always #7 clk_fpga = ~clk_fpga; + + initial begin + $dumpfile("wb_sim.vcd"); + $dumpvars(0,wb_sim); + end + + initial #10000 $finish; + + wire [15:0] rom_addr; + wire [47:0] rom_data; + wire [31:0] wb_dat; + wire [15:0] wb_adr; + wire wb_cyc,wb_stb,wb_we,wb_ack; + wire [3:0] wb_sel; + + wire [31:0] port_output; + + + system_control system_control(.dsp_clk(dsp_clk), + .reset_out(reset_out), + .wb_clk_o(wb_clk), + .wb_rst_o(wb_rst), + .wb_rst_o_alt(wb_rst_o_alt), + .start (start), + .aux_clk(aux_clk), + .clk_fpga(clk_fpga), + .POR (POR), + .done (done)); + + clock_bootstrap_rom cbrom(.addr(rom_addr),.data(rom_data)); + + wb_bus_writer bus_writer(.rom_addr (rom_addr[15:0]), + .wb_dat_o (wb_dat[31:0]), + .wb_adr_o (wb_adr[15:0]), + .wb_cyc_o (wb_cyc), + .wb_sel_o (wb_sel[3:0]), + .wb_stb_o (wb_stb), + .wb_we_o (wb_we), + .start (start), + .done (done), + .rom_data (rom_data[47:0]), + .wb_clk_i (wb_clk), + .wb_rst_i (wb_rst), + .wb_ack_i (wb_ack)); + + wb_output_pins32 output_pins(.wb_dat_o(), + .wb_ack_o(wb_ack), + .port_output(port_output[31:0]), + .wb_rst_i(wb_rst), + .wb_clk_i(wb_clk), + .wb_dat_i(wb_dat[31:0]), + .wb_we_i(wb_we), + .wb_sel_i(wb_sel[3:0]), + .wb_stb_i(wb_stb), + .wb_cyc_i(wb_cyc)); + + + + +endmodule // wb_sim + -- cgit v1.2.3