diff options
Diffstat (limited to 'control_lib')
64 files changed, 4898 insertions, 0 deletions
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<lastentry)) +       begin +	  entry <= #1 entry + 6'd1; +	  start <= #1 1'b1; +       end +    +   always @(posedge aux_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 +    +    +   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/clock_control_tb.sav b/control_lib/clock_control_tb.sav new file mode 100644 index 000000000..be4001dc5 --- /dev/null +++ b/control_lib/clock_control_tb.sav @@ -0,0 +1,28 @@ +[size] 1400 971 +[pos] -1 -1 +*-7.848898 -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 -1 +@28 +clock_control_tb.aux_clk +clock_control_tb.reset +clock_control_tb.sclk +clock_control_tb.sdi +clock_control_tb.sdo +clock_control_tb.sen +@22 +clock_control_tb.clock_control.counter[7:0] +@28 +clock_control_tb.clock_control.done +@22 +clock_control_tb.clock_control.entry[5:0] +@28 +clock_control_tb.clock_control.read +clock_control_tb.clock_control.reset +clock_control_tb.clock_control.sclk +clock_control_tb.clock_control.w[1:0] +clock_control_tb.sen +clock_control_tb.sdo +clock_control_tb.sclk +clock_control_tb.clock_control.done +clock_control_tb.clock_control.start +@22 +clock_control_tb.clock_control.addr_data[20:0] diff --git a/control_lib/clock_control_tb.v b/control_lib/clock_control_tb.v new file mode 100644 index 000000000..4e705cf23 --- /dev/null +++ b/control_lib/clock_control_tb.v @@ -0,0 +1,35 @@ + + +module clock_control_tb(); +    +  clock_control clock_control +    (.reset(reset), +     .aux_clk(aux_clk),   +     .clk_fpga(clk_fpga), +     .clk_en(clk_en),     +     .clk_sel(clk_sel),   +     .clk_func(clk_func),  +     .clk_status(clk_status), +      +     .sen(sen),    +     .sclk(sclk),  +     .sdi(sdi), +     .sdo(sdo) +     ); + +   reg reset, aux_clk; +    +   wire [1:0] clk_sel, clk_en; +    +   initial reset = 1'b1; +   initial #1000 reset = 1'b0; +    +   initial aux_clk = 1'b0; +   always #10 aux_clk = ~aux_clk; +    +   initial $dumpfile("clock_control_tb.vcd"); +   initial $dumpvars(0,clock_control_tb); +    +   initial #10000 $finish; +    +endmodule // clock_control_tb diff --git a/control_lib/cmdfile b/control_lib/cmdfile new file mode 100644 index 000000000..cb3756cfc --- /dev/null +++ b/control_lib/cmdfile @@ -0,0 +1,18 @@ +# My stuff +-y . +-y ../u2_basic +-y ../control_lib +-y ../sdr_lib + +# Models +-y ../models + +# Open Cores +-y ../opencores/spi/rtl/verilog ++incdir+../opencores/spi/rtl/verilog +-y ../opencores/wb_conbus/rtl/verilog ++incdir+../opencores/wb_conbus/rtl/verilog +-y ../opencores/i2c/rtl/verilog ++incdir+../opencores/i2c/rtl/verilog +-y ../opencores/aemb/rtl/verilog +-y ../opencores/simple_gpio/rtl diff --git a/control_lib/dcache.v b/control_lib/dcache.v new file mode 100644 index 000000000..9063bf02a --- /dev/null +++ b/control_lib/dcache.v @@ -0,0 +1,165 @@ + +module dcache +  #(parameter AWIDTH=14, +    parameter CWIDTH=6) +    (input wb_clk_i, +     input wb_rst_i, +      +     input [AWIDTH-1:0] dwb_adr_i, +     input dwb_stb_i, +     input dwb_we_i, +     input [3:0] dwb_sel_i, +     input [31:0] dwb_dat_i, +     output [31:0] dwb_dat_o, +     output dwb_ack_o, +      +     input [31:0] dram_dat_i, +     output [31:0] dram_dat_o, +     output [AWIDTH-1:0] dram_adr_o, +     output dram_we_o, +     output dram_en_o, +     output [3:0] dram_sel_o ); + +   localparam TAGWIDTH = AWIDTH-CWIDTH-2; +   reg 	      stb_d1, ack_d1, miss_d1; +   reg [AWIDTH-1:0] held_addr; +   reg [31:0] 	    ddata [0:(1<<CWIDTH)-1]; +   reg [TAGWIDTH-1:0] dtags [0:(1<<CWIDTH)-1]; +   reg 		      dvalid [0:(1<<CWIDTH)-1]; +    +   wire [CWIDTH-1:0]  rd_line, wr_line; +   wire [TAGWIDTH-1:0] wr_tags; +   wire 	       cache_write, invalidate; +   wire [31:0] 	       wr_data; +    +   // ///////////////////////////////////// +   // Write into cache +   integer 	      i; +   always @(posedge wb_clk_i) +     if(wb_rst_i) +       for(i=0;i<(1<<CWIDTH);i=i+1) +	 dvalid[i] <= 0; +     else +       if(invalidate) +	 dvalid[wr_line] <= 1'b0; +       else if(cache_write) +	 dvalid[wr_line] <= 1'b1; +    +   always @(posedge wb_clk_i) +     if(cache_write) +       begin +	  ddata[wr_line] <= wr_data; +	  dtags[wr_line] <= wr_tags; +       end +    +   // ////////////////////////////////////// +   // Read from Cache +   wire [TAGWIDTH-1:0] tag_out = dtags[rd_line]; +   wire 	       valid_out = dvalid[rd_line]; +   wire [31:0] 	       data_out	= ddata[rd_line]; +   wire 	       cache_hit = valid_out & (tag_out == dwb_adr_i[AWIDTH-1:CWIDTH+2]); +   wire 	       cache_miss = ~cache_hit; + +   // ////////////////////////////////////// +   // Handle 1-cycle delay of Block-RAM +   always @(posedge wb_clk_i) +     if(wb_rst_i) +       stb_d1 <= 0; +     else +       stb_d1 <= dwb_stb_i; +    +   always @(posedge wb_clk_i) +     if(wb_rst_i) +       held_addr <= 0; +     else +       held_addr <= dwb_adr_i; +    +   always @(posedge wb_clk_i)  +     if(wb_rst_i) +       ack_d1 <= 1'b0; +     else  +       ack_d1 <= dwb_ack_o; + +   always @(posedge wb_clk_i)  +     if(wb_rst_i) +       miss_d1 <= 0; +     else  +       miss_d1 <= cache_miss; + +`define DC_NOCACHE +//`define DC_BASIC +//`define DC_FORWARDING_DP +//`define DC_FORWARDING_SP +//`define DC_PREFETCH + +`ifdef DC_NOCACHE +   assign 	       dwb_dat_o = dram_dat_i; +   assign 	       dwb_ack_o = dwb_stb_i & (dwb_we_i | (stb_d1 & ~ack_d1)); +   assign 	       dram_adr_o = dwb_adr_i; +   assign 	       dram_en_o = dwb_stb_i; +   assign 	       dram_dat_o = dwb_dat_i; +   assign 	       dram_we_o = dwb_we_i; +   assign 	       dram_sel_o = dwb_sel_i;	        +   assign 	       rd_line = 0; +   assign 	       wr_line = 0; +   assign 	       wr_tags = 0; +   assign 	       wr_data = 0; +   assign 	       cache_write = 0; +   assign 	       invalidate = 0; 	        +`endif +    +`ifdef DC_BASIC    // Very basic, no forwarding, 2 wait states on miss +   assign 	       dwb_dat_o = data_out; +   assign 	       dwb_ack_o = dwb_stb_i & cache_hit; +   assign 	       dram_adr_o = dwb_adr_i; +   assign 	       dram_en_o = dwb_stb_i; +   assign 	       dram_dat_o = dwb_dat_i; +   assign 	       dram_we_o = dwb_we_i; +   assign 	       dram_sel_o = dwb_sel_i;	        +   assign 	       rd_line = dwb_adr_i[CWIDTH+1:2]; +   assign 	       wr_line = rd_line; +   assign 	       wr_tags = dwb_adr_i[AWIDTH-1:CWIDTH+2]; +   assign 	       wr_data = dwb_we_i ? dwb_dat_i : dram_dat_i; +   assign 	       cache_write = dwb_stb_i & (dwb_we_i | (stb_d1 & miss_d1)); +   assign 	       invalidate = dwb_we_i & ~(&dwb_sel_i); +`endif +    +`ifdef DC_FORWARDING_DP   // Simple forwarding, 1 wait state on miss, dual-port ram +   assign 	       dwb_dat_o = cache_hit ? data_out : dram_dat_i; +   assign 	       dwb_ack_o = dwb_stb_i & (cache_hit | (stb_d1 & ~ack_d1)); +   assign 	       dram_adr_o = dwb_adr_i; +   assign 	       dram_en_o = 1'b1; +   assign 	       dram_dat_o = dwb_dat_i; +   assign 	       dram_we_o = dwb_we_i; +   assign 	       dram_sel_o = dwb_sel_i;	        +   assign 	       rd_line = dwb_adr_i[CWIDTH+1:2]; +   assign 	       wr_line = held_addr[CWIDTH+1:2]; +   assign 	       wr_tags = held_addr[AWIDTH-1:CWIDTH+2];	        +   assign 	       wr_data = dram_dat_i; +   assign 	       cache_write = dwb_stb_i & stb_d1 & miss_d1 & ~ack_d1; +   assign 	       invalidate = 0; 	        +`endif + +`ifdef DC_FORWARDING_SP   // Simple forwarding, 1 wait state on miss, single-port ram +   assign 	       dwb_dat_o = cache_hit ? data_out : dram_dat_i; +   assign 	       dwb_ack_o = dwb_stb_i & (cache_hit | (stb_d1 & ~ack_d1)); +   assign 	       dram_adr_o = dwb_adr_i; +   assign 	       dram_en_o = 1'b1; +   assign 	       dram_dat_o = dwb_dat_i; +   assign 	       dram_we_o = dwb_we_i; +   assign 	       dram_sel_o = dwb_sel_i;	        +   assign 	       rd_line = dwb_adr_i[CWIDTH+1:2]; +   assign 	       wr_line = rd_line; +   assign 	       wr_tags = dwb_adr_i[AWIDTH-1:CWIDTH+2]; +   assign 	       wr_data = dram_dat_i; +   assign 	       cache_write = dwb_stb_i & stb_d1 & miss_d1 & ~ack_d1; +   assign 	       invalidate = 0; 	        +`endif + +`ifdef DC_PREFETCH   // Forwarding plus prefetch + +`endif +    +    +endmodule // dcache + diff --git a/control_lib/decoder_3_8.v b/control_lib/decoder_3_8.v new file mode 100644 index 000000000..729b45d18 --- /dev/null +++ b/control_lib/decoder_3_8.v @@ -0,0 +1,21 @@ + +module decoder_3_8  +  (input [2:0] sel,  +   output reg [7:0] res); + +   always @(sel or res) +     begin +        case (sel) +          3'b000 : res = 8'b00000001; +          3'b001 : res = 8'b00000010; +          3'b010 : res = 8'b00000100; +          3'b011 : res = 8'b00001000; +          3'b100 : res = 8'b00010000; +          3'b101 : res = 8'b00100000; +          3'b110 : res = 8'b01000000; +          default : res = 8'b10000000; +        endcase // case(sel) +     end // always @ (sel or res) + +endmodule // decoder_3_8 + diff --git a/control_lib/dpram32.v b/control_lib/dpram32.v new file mode 100644 index 000000000..4da621823 --- /dev/null +++ b/control_lib/dpram32.v @@ -0,0 +1,82 @@ + +// Dual ported RAM +//    Addresses are byte-oriented, so botton 2 address bits are ignored. +//    AWIDTH of 13 allows you to address 8K bytes.   +//    For Spartan 3, if the total RAM size is not a multiple of 8K then BRAM space is wasted +// RAM_SIZE parameter allows odd-sized RAMs, like 24K + +module dpram32 #(parameter AWIDTH=15,  +		 parameter RAM_SIZE=16384) +  (input clk, +    +   input [AWIDTH-1:0] adr1_i, +   input [31:0] dat1_i, +   output reg [31:0] dat1_o, +   input we1_i, +   input en1_i, +   input [3:0] sel1_i, + +   input [AWIDTH-1:0] adr2_i, +   input [31:0] dat2_i, +   output reg [31:0] dat2_o, +   input we2_i, +   input en2_i, +   input [3:0] sel2_i ); +    +   reg [7:0]   ram0 [0:(RAM_SIZE/4)-1]; +   reg [7:0]   ram1 [0:(RAM_SIZE/4)-1]; +   reg [7:0]   ram2 [0:(RAM_SIZE/4)-1]; +   reg [7:0]   ram3 [0:(RAM_SIZE/4)-1]; + +   //  This is how we used to size the RAM -->   +   //      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<WIDTH;i=i+1) +	  bin[i] = ^(gray>>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<<CWIDTH)-1]; +   reg [TAGWIDTH-1:0] itags [0:(1<<CWIDTH)-1]; +   reg 		      ivalid [0:(1<<CWIDTH)-1]; +    +   wire [CWIDTH-1:0]  rd_line, wr_line; +   wire [TAGWIDTH-1:0] wr_tags; +   wire 	       store_in_cache; + +   // ///////////////////////////////////// +   // Write into cache +   integer 	      i; +   always @(posedge wb_clk_i) +     if(wb_rst_i) +       for(i=0;i<(1<<CWIDTH);i=i+1) +	 ivalid[i] <= 0; +     else +       if(store_in_cache) +	 ivalid[wr_line] <= 1'b1; +    +   always @(posedge wb_clk_i) +     if(store_in_cache) +       begin +	  idata[wr_line] <= iram_dat_i; +	  itags[wr_line] <= wr_tags; +       end +    +   // ////////////////////////////////////// +   // Read from Cache +   wire [TAGWIDTH-1:0] tag_out = itags[rd_line]; +   wire 	       valid_out = ivalid[rd_line]; +   wire [31:0] 	       data_out	= idata[rd_line]; +   wire 	       cache_hit = valid_out & (tag_out == iwb_adr_i[AWIDTH-1:CWIDTH+2]); +   wire 	       cache_miss = ~cache_hit; + +   // ////////////////////////////////////// +   // Handle 1-cycle delay of Block-RAM +   always @(posedge wb_clk_i) +     if(wb_rst_i) +       stb_d1 <= 0; +     else +       stb_d1 <= iwb_stb_i; +    +   always @(posedge wb_clk_i) +     if(wb_rst_i) +       held_addr <= 0; +     else +       held_addr <= iwb_adr_i; +    +   always @(posedge wb_clk_i)  +     if(wb_rst_i) +       ack_d1 <= 1'b0; +     else  +       ack_d1 <= iwb_ack_o; + +   always @(posedge wb_clk_i)  +     if(wb_rst_i) +       miss_d1 <= 0; +     else  +       miss_d1 <= cache_miss; + +//`define IC_NOCACHE +//`define IC_BASIC +//`define IC_FORWARDING_DP +`define IC_FORWARDING_SP +//`define IC_PREFETCH + +`ifdef IC_NOCACHE +   assign 	       iwb_dat_o = iram_dat_i; +   assign 	       iwb_ack_o = iwb_stb_i & (stb_d1 & ~ack_d1); +   assign 	       iram_adr_o = iwb_adr_i; +   assign 	       iram_en_o = 1'b1; +   assign 	       rd_line = 0; +   assign 	       wr_line = 0; +   assign 	       wr_tags = 0; +   assign 	       store_in_cache = 0; +`endif +    +`ifdef IC_BASIC    // Very basic, no forwarding, 2 wait states on miss +   assign 	       iwb_dat_o = data_out; +   assign 	       iwb_ack_o = iwb_stb_i & cache_hit; +   assign 	       iram_adr_o = iwb_adr_i; +   assign 	       iram_en_o = 1'b1; +   assign 	       rd_line = iwb_adr_i[CWIDTH+1:2]; +   assign 	       wr_line = rd_line; +   assign 	       wr_tags = iwb_adr_i[AWIDTH-1:CWIDTH+2]; +   assign 	       store_in_cache = stb_d1 & miss_d1; +`endif +    +`ifdef IC_FORWARDING_DP   // Simple forwarding, 1 wait state on miss, dual-port ram +   assign 	       iwb_dat_o = cache_hit ? data_out : iram_dat_i; +   assign 	       iwb_ack_o = iwb_stb_i & (cache_hit | (stb_d1 & ~ack_d1)); +   assign 	       iram_adr_o = iwb_adr_i; +   assign 	       iram_en_o = 1'b1; +   assign 	       rd_line = iwb_adr_i[CWIDTH+1:2]; +   assign 	       wr_line = held_addr[CWIDTH+1:2]; +   assign 	       wr_tags = held_addr[AWIDTH-1:CWIDTH+2];	        +   assign 	       store_in_cache = iwb_stb_i & stb_d1 & miss_d1 & ~ack_d1; +`endif + +`ifdef IC_FORWARDING_SP   // Simple forwarding, 1 wait state on miss, single-port ram +   assign 	       iwb_dat_o = cache_hit ? data_out : iram_dat_i; +   assign 	       iwb_ack_o = iwb_stb_i & (cache_hit | (stb_d1 & ~ack_d1)); +   assign 	       iram_adr_o = iwb_adr_i; +   assign 	       iram_en_o = 1'b1; +   assign 	       rd_line = iwb_adr_i[CWIDTH+1:2]; +   assign 	       wr_line = rd_line; +   assign 	       wr_tags = iwb_adr_i[AWIDTH-1:CWIDTH+2]; +   assign 	       store_in_cache = iwb_stb_i & stb_d1 & miss_d1 & ~ack_d1; +`endif + +`ifdef IC_PREFETCH   // Forwarding plus prefetch + +`endif +    +    +endmodule // icache diff --git a/control_lib/longfifo.v b/control_lib/longfifo.v new file mode 100644 index 000000000..c73cc76f8 --- /dev/null +++ b/control_lib/longfifo.v @@ -0,0 +1,122 @@ + +// FIFO intended to be interchangeable with shortfifo, but +//  based on block ram instead of SRL16's +//  only one clock domain + +// Port A is write port, Port B is read port + +module longfifo +  #(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); + +   // Read side states +   localparam 	  EMPTY = 0; +   localparam 	  PRE_READ = 1; +   localparam 	  READING = 2; + +   reg [SIZE-1:0] wr_addr, rd_addr; +   reg [1:0] 	  read_state; + +   wire [SIZE-1:0] fullness = wr_addr - rd_addr;  // Approximate, for simulation only +   assign occupied = {{16-SIZE{1'b0}},fullness}; + +   wire [SIZE-1:0] free_space = rd_addr - wr_addr - 2;  // Approximate, for SERDES flow control +   assign space = {{16-SIZE{1'b0}},free_space}; +	   +   reg 	  empty_reg, full_reg; +   always @(posedge clk) +     if(rst) +       wr_addr <= 0; +     else if(clear) +       wr_addr <= 0; +     else if(write) +       wr_addr <= wr_addr + 1; + +   ram_2port #(.DWIDTH(WIDTH),.AWIDTH(SIZE)) +     ram (.clka(clk), +	  .ena(1), +	  .wea(write), +	  .addra(wr_addr), +	  .dia(datain), +	  .doa(), + +	  .clkb(clk), +	  .enb((read_state==PRE_READ)|read), +	  .web(0), +	  .addrb(rd_addr), +	  .dib(0), +	  .dob(dataout)); + +   always @(posedge clk) +     if(rst) +       begin +	  read_state <= EMPTY; +	  rd_addr <= 0; +	  empty_reg <= 1; +       end +     else +       if(clear) +	 begin +	    read_state <= EMPTY; +	    rd_addr <= 0; +	    empty_reg <= 1; +	 end +       else  +	 case(read_state) +	   EMPTY : +	     if(write) +	       begin +		  //rd_addr <= wr_addr; +		  read_state <= PRE_READ; +	       end +	   PRE_READ : +	     begin +		read_state <= READING; +		empty_reg <= 0; +		rd_addr <= rd_addr + 1; +	     end +	    +	   READING : +	     if(read) +	       if(rd_addr == wr_addr) +		 begin +		    empty_reg <= 1; +		    if(write) +		      read_state <= PRE_READ; +		    else +		      read_state <= EMPTY; +		 end +	       else +		 rd_addr <= rd_addr + 1; +	 endcase // case(read_state) + +   wire [SIZE-1:0] dont_write_past_me = rd_addr - 3; +   wire 	   becoming_full = wr_addr == dont_write_past_me; +      +   always @(posedge clk) +     if(rst) +       full_reg <= 0; +     else if(clear) +       full_reg <= 0; +     else if(read & ~write) +       full_reg <= 0; +     //else if(write & ~read & (wr_addr == (rd_addr-3))) +     else if(write & ~read & becoming_full) +       full_reg <= 1; + +   //assign empty = (read_state != READING); +   assign empty = empty_reg; + +   // assign full = ((rd_addr - 1) == wr_addr); +   assign full = full_reg; +    +endmodule // longfifo diff --git a/control_lib/medfifo.v b/control_lib/medfifo.v new file mode 100644 index 000000000..5a77e8c16 --- /dev/null +++ b/control_lib/medfifo.v @@ -0,0 +1,49 @@ + +module medfifo +  #(parameter WIDTH=32, +    parameter DEPTH=1) +    (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 [7:0] space, +     output [7:0] occupied); + +   localparam 		NUM_FIFOS = (1<<DEPTH); +    +   wire [WIDTH-1:0] 	dout [0:NUM_FIFOS-1]; +   wire [0:NUM_FIFOS-1] full_x; +   wire [0:NUM_FIFOS-1] empty_x; + +   shortfifo #(.WIDTH(WIDTH)) +     head (.clk(clk),.rst(rst), +	   .datain(datain),.write(write),.full(full), +	   .dataout(dout[0]),.read(~empty_x[0] & ~full_x[1]),.empty(empty_x[0]), +	   .clear(clear),.space(space[4:0]),.occupied() ); +    +   shortfifo #(.WIDTH(WIDTH)) +     tail (.clk(clk),.rst(rst), +	   .datain(dout[NUM_FIFOS-2]),.write(~empty_x[NUM_FIFOS-2] & ~full_x[NUM_FIFOS-1]),.full(full_x[NUM_FIFOS-1]), +	   .dataout(dataout),.read(read),.empty(empty), +	   .clear(clear),.space(),.occupied(occupied[4:0]) ); + +   genvar 		i; +   generate +      for(i = 1; i < NUM_FIFOS-1 ; i = i + 1) +	begin : gen_depth +	   shortfifo #(.WIDTH(WIDTH)) +	     shortfifo (.clk(clk),.rst(rst), +			.datain(dout[i-1]),.write(~full_x[i] & ~empty_x[i-1]),.full(full_x[i]), +			.dataout(dout[i]),.read(~full_x[i+1] & ~empty_x[i]),.empty(empty_x[i]), +			.clear(clear),.space(),.occupied() ); +	end +   endgenerate + +   assign space[7:5] = 0; +   assign occupied[7:5] = 0; +    +endmodule // medfifo diff --git a/control_lib/mux4.v b/control_lib/mux4.v new file mode 100644 index 000000000..31c85c832 --- /dev/null +++ b/control_lib/mux4.v @@ -0,0 +1,16 @@ + + +module mux4 +  #(parameter WIDTH=32, parameter DISABLED=0) +    (input en, +     input [1:0] sel, +     input [WIDTH-1:0] i0, +     input [WIDTH-1:0] i1, +     input [WIDTH-1:0] i2, +     input [WIDTH-1:0] i3, +     output [WIDTH-1:0] o); + +   assign 		o = en ? (sel[1] ? (sel[0] ? i3 : i2) : (sel[0] ? i1 : i0)) : +			DISABLED; +    +endmodule // mux4 diff --git a/control_lib/mux8.v b/control_lib/mux8.v new file mode 100644 index 000000000..9db96a60f --- /dev/null +++ b/control_lib/mux8.v @@ -0,0 +1,21 @@ + + +module mux8 +  #(parameter WIDTH=32, parameter DISABLED=0) +    (input en, +     input [2:0] sel, +     input [WIDTH-1:0] i0, +     input [WIDTH-1:0] i1, +     input [WIDTH-1:0] i2, +     input [WIDTH-1:0] i3, +     input [WIDTH-1:0] i4, +     input [WIDTH-1:0] i5, +     input [WIDTH-1:0] i6, +     input [WIDTH-1:0] i7, +     output [WIDTH-1:0] o); + +   assign 		o = en ? (sel[2] ? (sel[1] ? (sel[0] ? i7 : i6) : (sel[0] ? i5 : i4)) : +				  (sel[1] ? (sel[0] ? i3 : i2) : (sel[0] ? i1 : i0))) : +			DISABLED; +    +endmodule // mux8 diff --git a/control_lib/mux_32_4.v b/control_lib/mux_32_4.v new file mode 100644 index 000000000..fef5812e9 --- /dev/null +++ b/control_lib/mux_32_4.v @@ -0,0 +1,13 @@ + + +module mux_32_4 +  (input [1:0] sel, +   input [31:0] in0, +   input [31:0] in1, +   input [31:0] in2, +   input [31:0] in3, +   output [31:0] out); + +   assign 	 out = sel[1] ? (sel[0] ? in3 : in2) : (sel[0] ? in1 : in0); + +endmodule // mux_32_4 diff --git a/control_lib/nsgpio.v b/control_lib/nsgpio.v new file mode 100644 index 000000000..937ea7020 --- /dev/null +++ b/control_lib/nsgpio.v @@ -0,0 +1,107 @@ +// Modified from code originally by Richard Herveille, his copyright is below + +///////////////////////////////////////////////////////////////////// +////                                                             //// +////  OpenCores Simple General Purpose IO core                   //// +////                                                             //// +////  Author: Richard Herveille                                  //// +////          richard@asics.ws                                   //// +////          www.asics.ws                                       //// +////                                                             //// +///////////////////////////////////////////////////////////////////// +////                                                             //// +//// Copyright (C) 2002 Richard Herveille                        //// +////                    richard@asics.ws                         //// +////                                                             //// +//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     //// +//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   //// +//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   //// +//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      //// +//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         //// +//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    //// +//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   //// +//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        //// +//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  //// +//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  //// +//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  //// +//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         //// +//// POSSIBILITY OF SUCH DAMAGE.                                 //// +////                                                             //// +///////////////////////////////////////////////////////////////////// + + +module nsgpio +  (input clk_i, input rst_i,  +   input cyc_i, input stb_i, input [3:0] adr_i, input we_i, input [31:0] dat_i,  +   output reg [31:0] dat_o, output reg ack_o, +   input [31:0] atr, input [31:0] debug_0, input [31:0] debug_1,  +   inout [31:0] gpio +   ); + +   reg [63:0] 	ctrl; +   reg [31:0] 	line; +   reg [31:0] 	lgpio;               // LatchedGPIO pins +   reg [31:0] 	ddr; +    +   wire 	wb_acc = cyc_i & stb_i;            // WISHBONE access +   wire 	wb_wr  = wb_acc & we_i;            // WISHBONE write access + +   always @(posedge clk_i or posedge rst_i) +     if (rst_i) +       begin +          ctrl <= 64'h0; +          line <= 0; +       end +     else if (wb_wr) +       case( adr_i[3:2] ) +	 2'b00 :  +           line <= dat_i; +	 2'b01 : +	   ddr[31:0] <= dat_i; +	 2'b10 : +	   ctrl[63:32] <= dat_i; +	 2'b11 : +	   ctrl[31:0] <= dat_i; +       endcase // case( adr_i[3:2] ) +    +   always @(posedge clk_i) +     case (adr_i[3:2]) +       2'b00 : +	 dat_o <= lgpio; +       2'b01 : +	 dat_o <= ddr; +       2'b10 : +	 dat_o <= ctrl[63:32]; +       2'b11 : +	 dat_o <= ctrl[31:0]; +     endcase // case(adr_i[3:2]) +    +   always @(posedge clk_i or posedge rst_i) +     if (rst_i) +       ack_o <= 1'b0; +     else +       ack_o <= wb_acc & !ack_o; +    +   // latch GPIO input pins +   always @(posedge clk_i) +     lgpio <= gpio; +    +   // assign GPIO outputs +   integer   n; +   reg [31:0] igpio; // temporary internal signal +    +   always @(ctrl or line or debug_1 or debug_0 or atr) +     for(n=0;n<32;n=n+1) +       igpio[n] <= ddr[n] ? (ctrl[2*n+1] ? (ctrl[2*n] ? debug_1[n] : debug_0[n]) :  +			     (ctrl[2*n] ?  atr[n] : line[n]) ) +	 : 1'bz; +    +   assign     gpio = igpio; +    +endmodule + diff --git a/control_lib/oneshot_2clk.v b/control_lib/oneshot_2clk.v new file mode 100644 index 000000000..72f16a4b3 --- /dev/null +++ b/control_lib/oneshot_2clk.v @@ -0,0 +1,35 @@ + +// Retime a single bit from one clock domain to another +// Guarantees that no matter what the relative clock rates, if the in signal is high for at least +//   one clock cycle in the clk_in domain, then the out signal will be high for at least one +//   clock cycle in the clk_out domain.  If the in signal goes high again before the process is done +//   the behavior is undefined.  No other guarantees.  Designed for passing reset into a new +//   clock domain. + +module oneshot_2clk +  (input clk_in, +   input in, +   input clk_out, +   output reg out); + +   reg 	  del_in = 0; +   reg 	  sendit = 0, gotit = 0; +   reg 	  sendit_d = 0, gotit_d = 0; +    +   always @(posedge clk_in) del_in <= in; + +   always @(posedge clk_in) +     if(in & ~del_in)  // we have a positive edge +       sendit <= 1; +     else if(gotit) +       sendit <= 0; + +   always @(posedge clk_out) sendit_d <= sendit; +   always @(posedge clk_out) out <= sendit_d; + +   always @(posedge clk_in) gotit_d <= out; +   always @(posedge clk_in) gotit <= gotit_d; + +endmodule // oneshot_2clk + +   diff --git a/control_lib/ram_2port.v b/control_lib/ram_2port.v new file mode 100644 index 000000000..6c8332b9c --- /dev/null +++ b/control_lib/ram_2port.v @@ -0,0 +1,42 @@ + + +module ram_2port +  #(parameter DWIDTH=32, +    parameter AWIDTH=9) +    (input clka, +     input ena, +     input wea, +     input [AWIDTH-1:0] addra, +     input [DWIDTH-1:0] dia, +     output reg [DWIDTH-1:0] doa, +      +     input clkb, +     input enb, +     input web, +     input [AWIDTH-1:0] addrb, +     input [DWIDTH-1:0] dib, +     output reg [DWIDTH-1:0] dob); +    +   reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0]; +   integer 	    i; +   initial +     for(i=0;i<(1<<AWIDTH);i=i+1) +       ram[i] <= {AWIDTH{1'b0}}; +    +   always @(posedge clka) begin +      if (ena) +        begin +           if (wea) +             ram[addra] <= dia; +           doa <= ram[addra]; +        end +   end +   always @(posedge clkb) begin +      if (enb) +        begin +           if (web) +             ram[addrb] <= dib; +           dob <= ram[addrb]; +        end +   end +endmodule // ram_2port diff --git a/control_lib/ram_harv_cache.v b/control_lib/ram_harv_cache.v new file mode 100644 index 000000000..933f9ba1a --- /dev/null +++ b/control_lib/ram_harv_cache.v @@ -0,0 +1,72 @@ + + +// Dual ported, Harvard architecture, cached ram + +module ram_harv_cache +  #(parameter AWIDTH=15,parameter RAM_SIZE=16384,parameter ICWIDTH=6,parameter DCWIDTH=6) +    (input wb_clk_i, input wb_rst_i, +      +     input [AWIDTH-1:0] ram_loader_adr_i, +     input [31:0] ram_loader_dat_i, +     input ram_loader_stb_i, +     input [3:0] ram_loader_sel_i, +     input ram_loader_we_i, +     output ram_loader_ack_o, +     input ram_loader_done_i, +      +     input [AWIDTH-1:0] iwb_adr_i, +     input iwb_stb_i, +     output [31:0] iwb_dat_o, +     output iwb_ack_o, +      +     input [AWIDTH-1:0] dwb_adr_i, +     input [31:0] dwb_dat_i,  +     output [31:0] dwb_dat_o, +     input dwb_we_i, +     output dwb_ack_o, +     input dwb_stb_i, +     input [3:0] dwb_sel_i ); + +   wire [31:0] 	 iram_dat, dram_dat_i, dram_dat_o; +   wire [AWIDTH-1:0] iram_adr, dram_adr; +   wire 	     iram_en, dram_en, dram_we; +   wire [3:0] 	     dram_sel; +    +   dpram32 #(.AWIDTH(AWIDTH),.RAM_SIZE(RAM_SIZE)) sys_ram +     (.clk(wb_clk_i), + +      .adr1_i(ram_loader_done_i ? iram_adr : ram_loader_adr_i), +      .dat1_i(ram_loader_dat_i), +      .dat1_o(iram_dat), +      .we1_i(ram_loader_done_i ? 1'b0 : ram_loader_we_i), +      .en1_i(ram_loader_done_i ? iram_en : ram_loader_stb_i), +      .sel1_i(ram_loader_done_i ? 4'hF : ram_loader_sel_i), + +      .adr2_i(dram_adr),.dat2_i(dram_dat_i),.dat2_o(dram_dat_o), +      .we2_i(dram_we),.en2_i(dram_en),.sel2_i(dram_sel) ); + +   // Data bus side +   dcache #(.AWIDTH(AWIDTH),.CWIDTH(DCWIDTH)) +     dcache(.wb_clk_i(wb_clk_i),.wb_rst_i(wb_rst_i), +	    .dwb_adr_i(dwb_adr_i),.dwb_stb_i(dwb_stb_i), +	    .dwb_we_i(dwb_we_i),.dwb_sel_i(dwb_sel_i), +	    .dwb_dat_i(dwb_dat_i),.dwb_dat_o(dwb_dat_o), +	    .dwb_ack_o(dwb_ack_o), +	    .dram_dat_i(dram_dat_o),.dram_dat_o(dram_dat_i),.dram_adr_o(dram_adr), +	    .dram_we_o(dram_we),.dram_en_o(dram_en), .dram_sel_o(dram_sel) ); +	     +   // Instruction bus side +   icache #(.AWIDTH(AWIDTH),.CWIDTH(ICWIDTH)) +     icache(.wb_clk_i(wb_clk_i),.wb_rst_i(wb_rst_i), +	    .iwb_adr_i(iwb_adr_i),.iwb_stb_i(iwb_stb_i), +	    .iwb_dat_o(iwb_dat_o),.iwb_ack_o(iwb_ack_o), +	    .iram_dat_i(iram_dat),.iram_adr_o(iram_adr),.iram_en_o(iram_en) ); + +   // RAM loader +   assign 	 ram_loader_ack_o = ram_loader_stb_i; + +   // Performance Monitoring +   wire 	 i_wait = iwb_stb_i & ~iwb_ack_o; +   wire 	 d_wait = dwb_stb_i & ~dwb_ack_o; +    +endmodule // ram_harv_cache diff --git a/control_lib/ram_loader.v b/control_lib/ram_loader.v new file mode 100644 index 000000000..cb67de739 --- /dev/null +++ b/control_lib/ram_loader.v @@ -0,0 +1,225 @@ + +// Adapted from VHDL code in spi_boot by Arnim Legauer +//  Added a full wishbone master interface (32-bit) + +module ram_loader #(parameter AWIDTH=16, RAM_SIZE=16384) +  (input clk_i, input rst_i, +   // CPLD Interface +   input cfg_clk_i, input cfg_data_i, +   output start_o, output mode_o, output done_o, +   input detached_i, +   // Wishbone interface +   output wire [31:0] wb_dat_o, +   output reg [AWIDTH-1:0] wb_adr_o, +   output wb_stb_o, +   output wb_cyc_o, +   output reg [3:0] wb_sel_o, +   output reg wb_we_o, +   input wb_ack_i, +   output ram_loader_done_o); +    +   //  FSM to control start signal, clocked on main clock +   localparam FSM1_WAIT_DETACH = 2'b00; +   localparam FSM1_CHECK_NO_DONE = 2'b01; +   localparam FSM1_WAIT_DONE = 2'b10; +    +   reg [1:0]  start_fsm_q, start_fsm_s; +   reg 	      start_q, enable_q, start_s, enable_s; +   reg 	      done_q, done_s; +    +   always @(posedge clk_i or posedge rst_i) +     if(rst_i) +       begin +	  start_fsm_q <= FSM1_WAIT_DETACH; +	  start_q <= 1'b0; +	  enable_q <= 1'b0; +       end +     else +       begin +	  start_fsm_q <= start_fsm_s; +	  enable_q <= enable_s; +	  start_q <= start_s; +       end // else: !if(rst_i) +    +   always @* +     case(start_fsm_q) +       FSM1_WAIT_DETACH: +	 if(detached_i == 1'b1) +	   begin +	      start_fsm_s <= FSM1_CHECK_NO_DONE; +	      enable_s <= 1'b1; +	      start_s <= 1'b1; +	   end +	 else +	   begin +	      start_fsm_s <= FSM1_WAIT_DETACH; +	      enable_s <= enable_q; +	      start_s <= start_q; +	   end // else: !if(detached_i == 1'b1) +       FSM1_CHECK_NO_DONE: +	 if(~done_q) +	   begin +	      start_fsm_s  <= FSM1_WAIT_DONE; +	      enable_s <= enable_q; +	      start_s <= start_q; +	   end +	 else +	   begin +	      start_fsm_s  <= FSM1_CHECK_NO_DONE; +	      enable_s <= enable_q; +	      start_s <= start_q; +	   end // else: !if(~done_q) +       FSM1_WAIT_DONE: +	 if(done_q) +	   begin +	      start_fsm_s  <= FSM1_WAIT_DETACH; +	      enable_s <= 1'b0; +	      start_s <= 1'b0; +	   end +	 else +	   begin +	      start_fsm_s  <= FSM1_WAIT_DONE; +	      enable_s <= enable_q; +	      start_s <= start_q; +	   end // else: !if(done_q) +       default: +	 begin +	    start_fsm_s  <= FSM1_WAIT_DETACH; +	    enable_s <= enable_q; +	    start_s <= start_q; +	 end // else: !if(done_q) +     endcase // case(start_fsm_q) +    +   //  FSM running on data clock + +   localparam FSM2_IDLE = 3'b000; +   localparam FSM2_WE_ON = 3'b001; +   localparam FSM2_WE_OFF = 3'b010; +   localparam FSM2_INC_ADDR1 = 3'b011; +   localparam FSM2_INC_ADDR2 = 3'b100; +   localparam FSM2_FINISHED = 3'b101; +    +   reg [AWIDTH-1:0] addr_q; +   reg [7:0] 	    shift_dat_q, ser_dat_q; +   reg [2:0] 	    bit_q, fsm_q, fsm_s; +   reg 		    bit_ovfl_q, ram_we_s, ram_we_q, mode_q, mode_s, inc_addr_s; +    +   always @(posedge cfg_clk_i or posedge rst_i) +     if(rst_i) +       begin +	  addr_q <= 0; +	  shift_dat_q <= 8'd0; +	  ser_dat_q <= 8'd0; +	  bit_q <= 3'd0; +	  bit_ovfl_q <= 1'b0; +	  fsm_q <= FSM2_IDLE; +	  ram_we_q <= 1'b0; +	  done_q <= 1'b0; +	  mode_q <= 1'b0; +       end +     else +       begin +	  if(inc_addr_s) +	    addr_q <= addr_q + 1; +	  if(enable_q) +	    begin +	       bit_q <= bit_q + 1; +	       bit_ovfl_q <= (bit_q == 3'd7); +	       shift_dat_q[0] <= cfg_data_i; +	       shift_dat_q[7:1] <= shift_dat_q[6:0]; +	    end +	  if(bit_ovfl_q) +	    ser_dat_q <= shift_dat_q; + +	  fsm_q <= fsm_s; + +	  ram_we_q <= ram_we_s; + +	  if(done_s) +	    done_q <= 1'b1; +	  mode_q <= mode_s; +       end // else: !if(rst_i) + +   always @* +     begin +	inc_addr_s <= 1'b0; +	ram_we_s <= 1'b0; +	done_s <= 1'b0; +	fsm_s <= FSM2_IDLE; +	mode_s <= 1'b0; + +	case(fsm_q) +	  FSM2_IDLE : +	    if(start_q) +	      if(bit_ovfl_q) +		fsm_s <= FSM2_WE_ON; +	  FSM2_WE_ON: +	    begin +	       ram_we_s <= 1'b1; +	       fsm_s <= FSM2_WE_OFF; +	    end +	  FSM2_WE_OFF: +	    begin +	       ram_we_s <= 1'b1; +	       fsm_s <= FSM2_INC_ADDR1; +	    end +	  FSM2_INC_ADDR1: +	    fsm_s <= FSM2_INC_ADDR2; +	  FSM2_INC_ADDR2: +	    if(addr_q == (RAM_SIZE-1)) +	    //if(&addr_q) +	      begin +		 fsm_s <= FSM2_FINISHED; +		 done_s <= 1'b1; +		 mode_s <= 1'b1; +	      end +	    else +	      begin +		 inc_addr_s <= 1'b1; +		 fsm_s <= FSM2_IDLE; +	      end // else: !if(&addr_q) +	  FSM2_FINISHED: +	    begin +	       fsm_s <= FSM2_FINISHED; +	       mode_s <= 1'b1; +	    end +	endcase // case(fsm_q) +     end // always @ * +    +   assign start_o = start_q; +   assign mode_o = mode_q; +   assign done_o = start_q ? done_q : 1'b1; +   wire [AWIDTH-1:0] ram_addr = addr_q; +   wire [7:0] ram_data = ser_dat_q; +   assign ram_loader_done_o = (fsm_q == FSM2_FINISHED); +    +   // wishbone master, only writes +   reg [7:0] dat_holder; +   assign    wb_dat_o = {4{dat_holder}}; +   assign    wb_stb_o = wb_we_o; +   assign    wb_cyc_o = wb_we_o; +    +   always @(posedge clk_i or posedge rst_i) +     if(rst_i) +       begin +	  dat_holder <= 8'd0; +	  wb_adr_o <= 0; +	  wb_sel_o <= 4'b0000; +	  wb_we_o <= 1'b0; +       end +     else if(ram_we_q) +       begin +	  dat_holder <= ram_data; +	  wb_adr_o <= ram_addr; +	  wb_we_o <= 1'b1; +	  case(ram_addr[1:0])   // Big Endian +	    2'b00 : wb_sel_o <= 4'b1000; +	    2'b01 : wb_sel_o <= 4'b0100; +	    2'b10 : wb_sel_o <= 4'b0010; +	    2'b11 : wb_sel_o <= 4'b0001; +	  endcase // case(ram_addr[1:0]) +       end // if (ram_we_q) +     else if(wb_ack_i) +       wb_we_o <= 1'b0; +       +endmodule // ram_loader diff --git a/control_lib/ram_wb_harvard.v b/control_lib/ram_wb_harvard.v new file mode 100644 index 000000000..c3efc12e0 --- /dev/null +++ b/control_lib/ram_wb_harvard.v @@ -0,0 +1,86 @@ + +// Dual ported RAM for Harvard architecture processors +//    Does no forwarding +//    Addresses are byte-oriented, so botton 2 address bits are ignored.  FIXME +//    AWIDTH of 13 gives 8K bytes.  For Spartan 3, if the total RAM size is not a +//    multiple of 8K then BRAM space is wasted + +module ram_wb_harvard #(parameter AWIDTH=13) +  (input wb_clk_i, +   input wb_rst_i, +    +   input [AWIDTH-1:0] iwb_adr_i, +   input [31:0] iwb_dat_i, +   output reg [31:0] iwb_dat_o, +   input iwb_we_i, +   output reg iwb_ack_o, +   input iwb_stb_i, +   input [3:0] iwb_sel_i, +    +   input [AWIDTH-1:0] dwb_adr_i, +   input [31:0] dwb_dat_i, +   output reg [31:0] dwb_dat_o, +   input dwb_we_i, +   output reg dwb_ack_o, +   input dwb_stb_i, +   input [3:0] dwb_sel_i); +    +   reg [7:0] 	 ram0 [0:(1<<(AWIDTH-2))-1]; +   reg [7:0] 	 ram1 [0:(1<<(AWIDTH-2))-1]; +   reg [7:0] 	 ram2 [0:(1<<(AWIDTH-2))-1]; +   reg [7:0] 	 ram3 [0:(1<<(AWIDTH-2))-1]; +    +   // Instruction Read Port +   always @(posedge wb_clk_i) +     iwb_ack_o <= iwb_stb_i & ~iwb_ack_o; +    +   always @(posedge wb_clk_i) +     iwb_dat_o[31:24] <= ram3[iwb_adr_i[AWIDTH-1:2]]; +   always @(posedge wb_clk_i) +     iwb_dat_o[23:16] <= ram2[iwb_adr_i[AWIDTH-1:2]]; +   always @(posedge wb_clk_i) +     iwb_dat_o[15:8] <= ram1[iwb_adr_i[AWIDTH-1:2]]; +   always @(posedge wb_clk_i) +     iwb_dat_o[7:0] <= ram0[iwb_adr_i[AWIDTH-1:2]]; +    +   always @(posedge wb_clk_i) +     if(iwb_we_i & iwb_stb_i & iwb_sel_i[3]) +       ram3[iwb_adr_i[AWIDTH-1:2]] <= iwb_dat_i[31:24]; +   always @(posedge wb_clk_i) +     if(iwb_we_i & iwb_stb_i & iwb_sel_i[2]) +       ram2[iwb_adr_i[AWIDTH-1:2]] <= iwb_dat_i[23:16]; +   always @(posedge wb_clk_i) +     if(iwb_we_i & iwb_stb_i & iwb_sel_i[1]) +       ram1[iwb_adr_i[AWIDTH-1:2]] <= iwb_dat_i[15:8]; +   always @(posedge wb_clk_i) +     if(iwb_we_i & iwb_stb_i & iwb_sel_i[0]) +       ram0[iwb_adr_i[AWIDTH-1:2]] <= iwb_dat_i[7:0]; +    +   // Data Port +   always @(posedge wb_clk_i) +     dwb_ack_o <= dwb_stb_i & ~dwb_ack_o; +    +   always @(posedge wb_clk_i) +     dwb_dat_o[31:24] <= ram3[dwb_adr_i[AWIDTH-1:2]]; +   always @(posedge wb_clk_i) +     dwb_dat_o[23:16] <= ram2[dwb_adr_i[AWIDTH-1:2]]; +   always @(posedge wb_clk_i) +     dwb_dat_o[15:8] <= ram1[dwb_adr_i[AWIDTH-1:2]]; +   always @(posedge wb_clk_i) +     dwb_dat_o[7:0]  <= ram0[dwb_adr_i[AWIDTH-1:2]]; +    +   always @(posedge wb_clk_i) +     if(dwb_we_i & dwb_stb_i & dwb_sel_i[3]) +       ram3[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[31:24]; +   always @(posedge wb_clk_i) +     if(dwb_we_i & dwb_stb_i & dwb_sel_i[2]) +       ram2[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[23:16]; +   always @(posedge wb_clk_i) +     if(dwb_we_i & dwb_stb_i & dwb_sel_i[1]) +       ram1[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[15:8]; +   always @(posedge wb_clk_i) +     if(dwb_we_i & dwb_stb_i & dwb_sel_i[0]) +       ram0[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[7:0]; +    +endmodule // ram_wb_harvard + diff --git a/control_lib/sd_spi.v b/control_lib/sd_spi.v new file mode 100644 index 000000000..3f4d7f46a --- /dev/null +++ b/control_lib/sd_spi.v @@ -0,0 +1,70 @@ +module sd_spi +  (input clk, +   input rst, +    +   // SD Card interface +   output reg sd_clk, +   output sd_mosi, +   input sd_miso, +    +   // Controls +   input [7:0] clk_div, +   input [7:0] send_dat, +   output [7:0] rcv_dat, +   input go, +   output ready); + +   reg [7:0] clk_ctr;    +   reg [3:0] bit_ctr; + +   wire      bit_ready = (clk_ctr == 8'd0); +   wire      bit_busy = (clk_ctr != 8'd0); +   wire      bit_done = (clk_ctr == clk_div); + +   wire      send_clk_hi = (clk_ctr == (clk_div>>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<WIDTH;i=i+1) +	begin : gen_srl16 +	   SRL16E +	     srl16e(.Q(dataout[i]), +		    .A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]), +		    .CE(write),.CLK(clk),.D(datain[i])); +	end +   endgenerate +    +   always @(posedge clk) +     if(rst) +       begin +	  a <= 0; +	  empty <= 1; +	  full <= 0; +       end +     else if(clear) +       begin +	  a <= 0; +	  empty <= 1; +	  full<= 0; +       end +     else if(read & ~write) +       begin +	  full <= 0; +	  if(a==0) +	    empty <= 1; +	  else +	    a <= a - 1; +       end +     else if(write & ~read) +       begin +	  empty <= 0; +	  if(~empty) +	    a <= a + 1; +	  if(a == 14) +	    full <= 1; +       end + +   // NOTE will fail if you write into a full fifo or read from an empty one + +   assign space = full ? 0 : empty ? 16 : 15-a; +   assign occupied = empty ? 0 : full ? 16 : a+1; +    +endmodule // shortfifo diff --git a/control_lib/simple_uart.v b/control_lib/simple_uart.v new file mode 100644 index 000000000..22f0e70a2 --- /dev/null +++ b/control_lib/simple_uart.v @@ -0,0 +1,61 @@ + +module simple_uart +  #(parameter TXDEPTH = 1, +    parameter RXDEPTH = 1) +    (input clk_i, input rst_i, +     input we_i, input stb_i, input cyc_i, output reg ack_o, +     input [2:0] adr_i, input [31:0] dat_i, output reg [31:0] dat_o, +     output rx_int_o, output tx_int_o, output tx_o, input rx_i, output baud_o); +    +   // Register Map +   localparam SUART_CLKDIV = 0; +   localparam SUART_TXLEVEL = 1; +   localparam SUART_RXLEVEL = 2; +   localparam SUART_TXCHAR = 3; +   localparam SUART_RXCHAR = 4; +    +   wire       wb_acc = cyc_i & stb_i;            // WISHBONE access +   wire       wb_wr  = wb_acc & we_i;            // WISHBONE write access +    +   reg [15:0] clkdiv; +   wire [7:0] rx_char; +   wire       tx_fifo_full, rx_fifo_empty;    +   wire [7:0] tx_fifo_level, rx_fifo_level; +    +   always @(posedge clk_i) +     if (rst_i) +       ack_o <= 1'b0; +     else +       ack_o <= wb_acc & ~ack_o; +    +   always @(posedge clk_i) +     if (rst_i) +       clkdiv <= 0; +     else if (wb_wr) +       case(adr_i) +	 SUART_CLKDIV : clkdiv <= dat_i[15:0]; +       endcase // case(adr_i) +    +   always @(posedge clk_i) +     case (adr_i) +       SUART_TXLEVEL : dat_o <= tx_fifo_level; +       SUART_RXLEVEL : dat_o <= rx_fifo_level; +       SUART_RXCHAR : dat_o <= rx_char; +     endcase // case(adr_i) +    +   simple_uart_tx #(.DEPTH(TXDEPTH)) simple_uart_tx +     (.clk(clk_i),.rst(rst_i), +      .fifo_in(dat_i[7:0]),.fifo_write(ack_o && wb_wr && (adr_i == SUART_TXCHAR)), +      .fifo_level(tx_fifo_level),.fifo_full(tx_fifo_full), +      .clkdiv(clkdiv),.baudclk(baud_o),.tx(tx_o)); +    +   simple_uart_rx #(.DEPTH(RXDEPTH)) simple_uart_rx +     (.clk(clk_i),.rst(rst_i), +      .fifo_out(rx_char),.fifo_read(ack_o && ~wb_wr && (adr_i == SUART_RXCHAR)), +      .fifo_level(rx_fifo_level),.fifo_empty(rx_fifo_empty), +      .clkdiv(clkdiv),.rx(rx_i)); +    +   assign     tx_int_o = ~tx_fifo_full; +   assign     rx_int_o = ~rx_fifo_empty; +    +endmodule // simple_uart diff --git a/control_lib/simple_uart_rx.v b/control_lib/simple_uart_rx.v new file mode 100644 index 000000000..debdd618b --- /dev/null +++ b/control_lib/simple_uart_rx.v @@ -0,0 +1,64 @@ + + +module simple_uart_rx +  #(parameter DEPTH=0) +    (input clk, input rst,  +     output [7:0] fifo_out, input fifo_read, output [7:0] fifo_level, output fifo_empty,  +     input [15:0] clkdiv, input rx); + +   reg 		  rx_d1, rx_d2; +   always @(posedge clk) +     if(rst) +       {rx_d2,rx_d1} <= 0; +     else +       {rx_d2,rx_d1} <= {rx_d1,rx}; +    +   reg [15:0] 	  baud_ctr; +   reg [3:0] 	  bit_ctr; +   reg [7:0] 	  sr; + +   wire 	  neg_trans = rx_d2 & ~rx_d1; +   wire 	  shift_now = baud_ctr == (clkdiv>>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<WIDTH;i=i+1) +	begin : gen_srl +	   SRL16E +	     srl16e(.Q(out[i]), +		    .A0(addr[0]),.A1(addr[1]),.A2(addr[2]),.A3(addr[3]), +		    .CE(write),.CLK(clk),.D(in[i])); +	end +   endgenerate + +endmodule // srl diff --git a/control_lib/ss_rcvr.v b/control_lib/ss_rcvr.v new file mode 100644 index 000000000..8e650d21b --- /dev/null +++ b/control_lib/ss_rcvr.v @@ -0,0 +1,81 @@ + + +// Source-synchronous receiver +// Assumes both clocks are at the same rate +// Relative clock phase is +//    unknown +//    variable +//    bounded +// The output will come several cycles later than the input + +// This should synthesize efficiently in Xilinx distributed ram cells, +//   which is why we use a buffer depth of 16 + +// FIXME Async reset on rxclk side? + +module ss_rcvr +  #(parameter WIDTH=16) +    (input rxclk, +     input sysclk, +     input rst, +      +     input [WIDTH-1:0] data_in, +     output [WIDTH-1:0] data_out, +     output reg clock_present); +    +   wire [3:0] rd_addr, wr_addr; + +   // Distributed RAM +   reg [WIDTH-1:0] buffer [0:15]; +   always @(posedge rxclk) +     buffer[wr_addr] <= data_in; +    +   assign 	   data_out = buffer[rd_addr]; +    +   // Write address generation +   reg [3:0] 	   wr_counter; +   always @(posedge rxclk or posedge rst) +     if (rst) +       wr_counter <= 0; +     else +       wr_counter <= wr_counter + 1; +    +   assign 	   wr_addr = {wr_counter[3], ^wr_counter[3:2], ^wr_counter[2:1], ^wr_counter[1:0]}; +    +   // Read Address generation +   wire [3:0] 	   wr_ctr_sys, diff, abs_diff; +   reg [3:0] 	   wr_addr_sys_d1, wr_addr_sys_d2; +   reg [3:0] 	   rd_counter; +    +   assign 	   rd_addr = {rd_counter[3], ^rd_counter[3:2], ^rd_counter[2:1], ^rd_counter[1:0]}; +    +   always @(posedge sysclk) +     wr_addr_sys_d1 <= wr_addr; +    +   always @(posedge sysclk) +     wr_addr_sys_d2 <= wr_addr_sys_d1; +    +   assign 	   wr_ctr_sys = {wr_addr_sys_d2[3],^wr_addr_sys_d2[3:2],^wr_addr_sys_d2[3:1],^wr_addr_sys_d2[3:0]}; +    +   assign 	   diff = wr_ctr_sys - rd_counter; +   assign 	   abs_diff = diff[3] ? (~diff+1) : diff; +    +   always @(posedge sysclk) +     if(rst) +       begin +	  clock_present <= 0; +	  rd_counter <= 0; +       end +     else  +       if(~clock_present) +	 if(abs_diff > 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 +  | 
