dakies/OSS_Verilog huggingface dataset:
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;

   reg 	      cs_reg;
   assign     sd_csn = ~cs_reg;  // FIXME
   
   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(rst)
       begin
	  clkdiv <= 200;
	  cs_reg <= 0;
       end
     else if(wb_we_i & wb_stb_i & wb_cyc_i & wb_ack_o)
       case(wb_adr_i)
	 ADDR_STATUS : cs_reg <= wb_dat_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
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
module wb_bridge_16_32
  #(parameter AWIDTH=16)
    (input wb_clk, input wb_rst,
     input A_cyc_i, input A_stb_i, input A_we_i, input [3:0] A_sel_i,
     input [AWIDTH-1:0] A_adr_i, input [31:0] A_dat_i, output [31:0] A_dat_o, output A_ack_o,
     output B_cyc_o, output B_stb_o, output B_we_o, output [1:0] B_sel_o,
     output [AWIDTH-1:0] B_adr_o, output [15:0] B_dat_o, input [15:0] B_dat_i, input B_ack_i
     );

   reg [15:0] 		 holding;
   reg 			 phase;
   
   assign 		 B_adr_o = {A_adr_i[AWIDTH-1:2],phase,1'b0};
   assign 		 B_cyc_o = A_cyc_i;
   assign 		 B_stb_o = A_stb_i;
   assign 		 B_we_o = A_we_i;

   assign 		 B_dat_o = ~phase ? A_dat_i[15:0] : A_dat_i[31:16];
   assign 		 B_sel_o = ~phase ? A_sel_i[1:0] : A_sel_i[3:2];

   assign 		 A_dat_o = {B_dat_i,holding};
   assign 		 A_ack_o = phase & B_ack_i;

   always @(posedge wb_clk)
     if(wb_rst)
       phase <= 0;
     else if(B_ack_i)
       phase <= ~phase;

   always @(posedge wb_clk)
     if(~phase & B_ack_i)
       holding <= B_dat_i;
   
endmodule // wb_bridge_16_32
module quad_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 [4:0] adr_i, input [31:0] dat_i, output reg [31:0] dat_o,
     output [3:0] rx_int_o, output [3:0] tx_int_o, 
     output [3:0] tx_o, input [3:0] rx_i, output [3:0] 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[0:3];
   wire [7:0] rx_char[0:3];
   wire  [3:0] tx_fifo_full, rx_fifo_empty;   
   wire [7:0] tx_fifo_level[0:3], rx_fifo_level[0:3];

   always @(posedge clk_i)
     if (rst_i)
       ack_o 			    <= 1'b0;
     else
       ack_o 			    <= wb_acc & ~ack_o;

   integer    i;
   always @(posedge clk_i)
     if (rst_i)
       for(i=0;i<4;i=i+1)
	 clkdiv[i] <= 0;
     else if (wb_wr)
       case(adr_i[2:0])
	 SUART_CLKDIV : clkdiv[adr_i[4:3]] <= dat_i[15:0];
       endcase // case(adr_i)
   
   always @(posedge clk_i)
     case (adr_i[2:0])
       SUART_TXLEVEL : dat_o <= tx_fifo_level[adr_i[4:3]];
       SUART_RXLEVEL : dat_o <= rx_fifo_level[adr_i[4:3]];
       SUART_RXCHAR : dat_o <= rx_char[adr_i[4:3]];
     endcase // case(adr_i)

   genvar     j;
   generate
      for(j=0;j<4;j=j+1)
	begin : gen_uarts
	   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[2:0] == SUART_TXCHAR) && (adr_i[4:3]==j)),
	     .fifo_level(tx_fifo_level[j]),.fifo_full(tx_fifo_full[j]),
	     .clkdiv(clkdiv[j]),.baudclk(baud_o[j]),.tx(tx_o[j]));
	   
	   simple_uart_rx #(.DEPTH(RXDEPTH)) simple_uart_rx
	     (.clk(clk_i),.rst(rst_i),
	      .fifo_out(rx_char[j]),.fifo_read(ack_o && ~wb_wr && (adr_i[2:0] == SUART_RXCHAR) && (adr_i[4:3]==j)),
	      .fifo_level(rx_fifo_level[j]),.fifo_empty(rx_fifo_empty[j]),
	      .clkdiv(clkdiv[j]),.rx(rx_i[j]));
	end // block: gen_uarts
   endgenerate
   
   assign     tx_int_o 	= ~tx_fifo_full;  // Interrupt for those that have space
   assign     rx_int_o 	= ~rx_fifo_empty; // Interrupt for those that have data
   
endmodule // quad_uart
module gpio_atr
  #(parameter BASE = 0,
    parameter WIDTH = 32)
   (input clk, input reset,
    input set_stb, input [7:0] set_addr, input [31:0] set_data,
    input rx, input tx,
    inout [WIDTH-1:0] gpio,
    output reg [31:0] gpio_readback
    );
   
   wire [WIDTH-1:0]   ddr, in_idle, in_tx, in_rx, in_fdx;
   reg [WIDTH-1:0]    rgpio, igpio;
   
   setting_reg #(.my_addr(BASE+0), .width(WIDTH)) reg_idle
     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
      .out(in_idle),.changed());

   setting_reg #(.my_addr(BASE+1), .width(WIDTH)) reg_rx
     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
      .out(in_rx),.changed());

   setting_reg #(.my_addr(BASE+2), .width(WIDTH)) reg_tx
     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
      .out(in_tx),.changed());

   setting_reg #(.my_addr(BASE+3), .width(WIDTH)) reg_fdx
     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
      .out(in_fdx),.changed());

   setting_reg #(.my_addr(BASE+4), .width(WIDTH)) reg_ddr
     (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
      .out(ddr),.changed());

   always @(posedge clk)
     case({tx,rx})
       2'b00: rgpio <= in_idle;
       2'b01: rgpio <= in_rx;
       2'b10: rgpio <= in_tx;
       2'b11: rgpio <= in_fdx;
     endcase // case ({tx,rx})
   
   integer 	      n;
   always @*
     for(n=0;n<WIDTH;n=n+1)
       igpio[n] <= ddr[n] ? rgpio[n] : 1'bz;

   assign     gpio = igpio;

   always @(posedge clk)
     gpio_readback <= gpio;
   
endmodule // gpio_atr
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
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
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
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
module fifo_to_wb_tb();
   
   reg clk = 0;
   reg rst = 1;
   reg clear = 0;
   initial #1000 rst = 0;
   always #50 clk = ~clk;
   
   reg 	       trigger = 0;
   initial #10000 trigger = 1;

   wire        wb_cyc, wb_stb, wb_we, wb_ack;
   wire [15:0] wb_adr;
   wire [15:0] wb_dat_miso, wb_dat_mosi;

   reg 	       cmd_src_rdy;
   wire        cmd_dst_rdy, resp_src_rdy, resp_dst_rdy;
   reg [17:0]  cmd;
   wire [17:0] resp;

   wire [17:0] resp_int;
   wire        resp_src_rdy_int, resp_dst_rdy_int;
   
   fifo_to_wb fifo_to_wb
     (.clk(clk), .reset(rst), .clear(clear),
      .data_i(cmd), .src_rdy_i(cmd_src_rdy), .dst_rdy_o(cmd_dst_rdy),
      .data_o(resp_int), .src_rdy_o(resp_src_rdy_int), .dst_rdy_i(resp_dst_rdy_int),

      .wb_adr_o(wb_adr), .wb_dat_mosi(wb_dat_mosi), .wb_dat_miso(wb_dat_miso),
      .wb_sel_o(), .wb_cyc_o(wb_cyc), .wb_stb_o(wb_stb), 
      .wb_we_o(wb_we), .wb_ack_i(wb_ack),
      .triggers());

   assign wb_dat_miso = {wb_adr[7:0],8'hBF};

   fifo19_pad #(.LENGTH(16)) fifo19_pad
     (.clk(clk), .reset(rst), .clear(clear),
      .data_i(resp_int), .src_rdy_i(resp_src_rdy_int), .dst_rdy_o(resp_dst_rdy_int),
      .data_o(resp), .src_rdy_o(resp_src_rdy), .dst_rdy_i(resp_dst_rdy));
        
   
   // Set up monitors
   always @(posedge clk)
     if(wb_cyc & wb_stb & wb_ack)
       if(wb_we)
	 $display("WB-WRITE  ADDR:%h  DATA:%h",wb_adr, wb_dat_mosi);
       else
	 $display("WB-READ  ADDR:%h  DATA:%h",wb_adr, wb_dat_miso);
   
   always @(posedge clk)
     if(cmd_src_rdy & cmd_dst_rdy)
       $display("CMD-WRITE  SOF:%b EOF:%b DATA:%h",cmd[16],cmd[17],cmd[15:0]);
   
   always @(posedge clk)
     if(resp_src_rdy & resp_dst_rdy)
       $display("RESP-READ  SOF:%b EOF:%b DATA:%h",resp[16],resp[17],resp[15:0]);

   assign wb_ack = wb_stb;
   assign resp_dst_rdy = 1;
   
   task InsertRW;
      input [15:0] data_start;
      input [5:0]  triggers;
      input [7:0]  seqno;
      input [15:0] len;
      input [15:0] addr;
      reg [15:0]   data_val;
      
      begin
	 data_val <= data_start;
	 @(posedge clk);
	 cmd <= {2'b01,2'b11,triggers,seqno};
	 cmd_src_rdy <= 1;
	 @(posedge clk);
	 cmd <= {2'b00,len};
	 @(posedge clk);
	 cmd <= {2'b00,addr};
	 @(posedge clk);
	 cmd <= {2'b00,16'd0};
	 @(posedge clk);
	 repeat (len)
	   begin
	      cmd <= {2'b00,data_val};
	      data_val <= data_val + 1;
	      @(posedge clk);
	   end
	 repeat (12-len-1)
	   begin
	      cmd <= {2'b00,16'hBEEF};
	      @(posedge clk);
	   end
	 cmd <= {2'b10, 16'hDEAD};
	 @(posedge clk);
	 cmd_src_rdy <= 0;
      end
   endtask // InsertRead
      
   initial $dumpfile("fifo_to_wb_tb.vcd");
   initial $dumpvars(0,fifo_to_wb_tb);

   initial
     begin
	@(negedge rst);
	//#10000;
	@(posedge clk);
	@(posedge clk);
	@(posedge clk);
	@(posedge clk);
	InsertRW(16'hF00D, 6'd0, 8'hB5, 16'd7, 16'h1234);
	#20000;
	InsertRW(16'h9876, 6'd0, 8'h43, 16'd8, 16'hBEEF);
	#20000;
	InsertRW(16'h1000, 6'd0, 8'h96, 16'd4, 16'hF00D);
	#20000;
	InsertRW(16'h3000, 6'd0, 8'h12, 16'd10,16'hDEAD);
	#20000 $finish;
     end
   
endmodule // fifo_to_wb_tb
module atr_controller16
  (input clk_i, input rst_i,
   input [5:0] adr_i, input [1:0] sel_i, input [15:0] dat_i, output [15:0] dat_o,
   input we_i, input stb_i, input cyc_i, output reg ack_o,
   input run_rx, input run_tx,
   output [31:0] ctrl_lines);
   
   reg [3:0] state;
   reg [31:0] atr_ram [0:15];  // DP distributed RAM

   wire [3:0] sel_int = { (sel_i[1] & adr_i[1]), (sel_i[0] & adr_i[1]),
			  (sel_i[1] & ~adr_i[1]), (sel_i[0] & ~adr_i[1]) };
   
   // WB Interface
   always @(posedge clk_i)
     if(we_i & stb_i & cyc_i)
       begin
	  if(sel_int[3])
	    atr_ram[adr_i[5:2]][31:24] <= dat_i[15:8];
	  if(sel_int[2])
	    atr_ram[adr_i[5:2]][23:16] <= dat_i[7:0];
	  if(sel_int[1])
	    atr_ram[adr_i[5:2]][15:8] <= dat_i[15:8];
	  if(sel_int[0])
	    atr_ram[adr_i[5:2]][7:0] <= dat_i[7:0];
       end // if (we_i & stb_i & cyc_i)

   // Removing readback allows ram to be synthesized as LUTs instead of regs
   //always @(posedge clk_i)
   //  dat_o <= adr_i[1] ? atr_ram[adr_i[5:2]][31:16] : atr_ram[adr_i[5:2]][15:0];
   assign dat_o = 16'd0;
   
   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_controller16
module reset_sync
  (input clk,
   input reset_in,
   output reg reset_out);

   reg 	      reset_int;

   always @(posedge clk or posedge reset_in)
     if(reset_in)
       {reset_out,reset_int} <= 2'b11;
     else
       {reset_out,reset_int} <= {reset_int,1'b0};
   
endmodule // reset_sync
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
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
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
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,

     input flush_icache );

   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),
	    .flush(flush_icache));

   // 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
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
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
module settings_bus_16LE
  #(parameter AWIDTH=16, RWIDTH=8)
    (input wb_clk, 
     input wb_rst, 
     input [AWIDTH-1:0] wb_adr_i,
     input [15:0] wb_dat_i,
     input wb_stb_i,
     input wb_we_i,
     output reg wb_ack_o,
     output strobe,
     output reg [7:0] addr,
     output reg [31:0] data);

   reg 		       stb_int;
   
   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
	  addr <= wb_adr_i[RWIDTH+1:2];  // Zero pad high bits
	  if(wb_adr_i[1])
	    begin
	       stb_int <= 1'b1;     // We now have both halves
	       data[31:16] <= wb_dat_i;
	    end
	  else
	    begin
	       stb_int <= 1'b0;     // Don't strobe, we need other half
	       data[15:0] <= wb_dat_i;
	    end
       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;

   assign strobe = stb_int & wb_ack_o;
          
endmodule // settings_bus_16LE
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
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
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
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
module buff_sm
  #(parameter PORT_USE_FLAG=0)
   (input clk, input reset, input clear,
    input write_done, input access_done, input access_skip_read, input read_done,
    input [1:0] write_port_state, input [1:0] access_port_state, input [1:0] read_port_state,
    output reg [1:0] buff_state);
   
   localparam BUFF_WRITABLE = 0;
   localparam BUFF_ACCESSIBLE = 1;
   localparam BUFF_READABLE = 2;
   localparam BUFF_ERROR = 3;

   always @(posedge clk)
     if(reset | clear)
       buff_state <= BUFF_WRITABLE;
     else
       case(buff_state)
	 BUFF_WRITABLE :
	   if(write_done & (write_port_state == PORT_USE_FLAG))
	     buff_state <= BUFF_ACCESSIBLE;
	 BUFF_ACCESSIBLE :
	   if(access_done & (access_port_state == PORT_USE_FLAG))
	     if(access_skip_read)
	       buff_state <= BUFF_WRITABLE;
	     else
	       buff_state <= BUFF_READABLE;
	 BUFF_READABLE :
	   if(read_done & (read_port_state == PORT_USE_FLAG))
	     buff_state <= BUFF_WRITABLE;
	 BUFF_ERROR :
	   ;
       endcase
	 
endmodule // buff_sm
module fifo19_rxrealign
  (input clk, input reset, input clear,
   input [18:0] datain, input src_rdy_i, output dst_rdy_o,
   output [18:0] dataout, output src_rdy_o, input dst_rdy_i);
   
   reg 	rxre_state;
   localparam RXRE_DUMMY  = 0;
   localparam RXRE_PKT 	  = 1;
   
   assign dataout[18] 	  = datain[18];
   assign dataout[17] 	  = datain[17];
   assign dataout[16] 	  = (rxre_state==RXRE_DUMMY) | (datain[17] & datain[16]);  // allows for passing error signal
   assign dataout[15:0] = datain[15:0];
   
   always @(posedge clk)
     if(reset | clear)
       rxre_state <= RXRE_DUMMY;
     else if(src_rdy_i & dst_rdy_i)
       case(rxre_state)
	 RXRE_DUMMY :
	   rxre_state <= RXRE_PKT;
	 RXRE_PKT :
	   if(datain[17])   // if eof or error
	     rxre_state <= RXRE_DUMMY;
       endcase // case (rxre_state)

   assign src_rdy_o 	 = src_rdy_i & dst_rdy_i;   // Send anytime both sides are ready
   assign dst_rdy_o = src_rdy_i & dst_rdy_i & (rxre_state == RXRE_PKT);  // Only consume after the dummy
   
endmodule // fifo19_rxrealign
module add_onescomp
  #(parameter WIDTH = 16)
   (input [WIDTH-1:0] A,
    input [WIDTH-1:0] B,
    output [WIDTH-1:0] SUM);

   wire [WIDTH:0] SUM_INT = {1'b0,A} + {1'b0,B};
   assign SUM  = SUM_INT[WIDTH-1:0] + {{WIDTH-1{1'b0}},SUM_INT[WIDTH]};
   
endmodule // add_onescomp
module timer
  (input wb_clk_i, input rst_i,
   input cyc_i, input stb_i, input [2:0] adr_i,
   input we_i, input [31:0] dat_i, output [31:0] dat_o, output ack_o,
   input sys_clk_i, input [31:0] master_time_i,
   output int_o );

   reg [31:0] time_wb;
   always @(posedge wb_clk_i)
     time_wb <= master_time_i;

   assign     ack_o = stb_i;

   reg [31:0] int_time;
   reg 	      int_reg;
   
   always @(posedge sys_clk_i)
     if(rst_i)
       begin
	  int_time <= 0;
	  int_reg <= 0;
       end
     else if(|int_time && (master_time_i == int_time))
       begin
	  int_time <= 0;
	  int_reg <= 1;
       end
     else if(stb_i & we_i)
       begin
	  int_time <= dat_i;
	  int_reg <= 0;
       end

   assign dat_o = time_wb;
   assign int_o = int_reg;
   
endmodule // timer
module time_transfer_tb();

   reg clk = 0, rst = 1;
   always #5 clk = ~clk;
   
   initial 
     begin
	@(negedge clk);
	@(negedge clk);
	rst <= 0;
     end

   initial $dumpfile("time_transfer_tb.vcd");
   initial $dumpvars(0,time_transfer_tb);
   
   initial #100000000 $finish;

   wire exp_time, pps, pps_rcv;
   wire [63:0] vita_time_rcv;
   reg [63:0]  vita_time = 0;
   reg [63:0]  counter = 0;

   localparam  PPS_PERIOD = 439; // PPS_PERIOD % 10 must = 9
   always @(posedge clk)
     if(counter == PPS_PERIOD)
       counter <= 0;
     else
       counter <= counter + 1;
   assign      pps = (counter == (PPS_PERIOD-1));
   
   always @(posedge clk)
     vita_time <= vita_time + 1;
   
   time_sender time_sender
     (.clk(clk),.rst(rst),
      .vita_time(vita_time),
      .send_sync(pps),
      .exp_time_out(exp_time) );

   time_receiver time_receiver
     (.clk(clk),.rst(rst),
      .vita_time(vita_time_rcv),
      .sync_rcvd(pps_rcv),
      .exp_time_in(exp_time) );

   wire [31:0] delta = vita_time - vita_time_rcv;
endmodule // time_transfer_tb
module simple_timer
  #(parameter BASE=0)
   (input clk, input reset,
    input set_stb, input [7:0] set_addr, input [31:0] set_data,
    output reg onetime_int, output reg periodic_int);

   reg [31:0]  onetime_ctr;
   always @(posedge clk)
     if(reset)
       begin
	  onetime_int 	  <= 0;
	  onetime_ctr 	  <= 0;
       end
     else
       if(set_stb & (set_addr == BASE))
	 begin
	    onetime_int   <= 0;
	    onetime_ctr   <= set_data;
	 end
       else 
	 begin
	    if(onetime_ctr == 1)
	      onetime_int <= 1;
	    if(onetime_ctr != 0)
	      onetime_ctr <= onetime_ctr - 1;
	    else
	      onetime_int <= 0;
	 end // else: !if(set_stb & (set_addr == BASE))
   
   reg [31:0]  periodic_ctr, period;
   always @(posedge clk)
     if(reset)
       begin
	  periodic_int 	     <= 0;
	  periodic_ctr 	     <= 0;
	  period 	     <= 0;
       end
     else
       if(set_stb & (set_addr == (BASE+1)))
	 begin
	    periodic_int     <= 0;
	    periodic_ctr     <= set_data;
	    period 	     <= set_data;
	 end
       else 
	 if(periodic_ctr == 1)
	   begin
	      periodic_int   <= 1;
	      periodic_ctr   <= period;
	   end
	 else
	   if(periodic_ctr != 0)
	     begin
		periodic_int <= 0;
		periodic_ctr <= periodic_ctr - 1;
	     end
   
endmodule // simple_timer
module time_compare
  (input [63:0] time_now,
   input [63:0] trigger_time,
   output now,
   output early,
   output late,
   output too_early);

    assign now = time_now == trigger_time;
    assign late = time_now > trigger_time;
    assign early = ~now & ~late;
    assign too_early = 0; //not implemented

endmodule // time_compare
module time_sender
  (input clk, input rst,
   input [63:0] vita_time,
   input send_sync,
   output reg exp_time_out);

   reg [7:0] datain;
   reg 	     k;
   wire [9:0] dataout;
   reg [9:0]  dataout_reg;
   reg 	      disp_reg;
   wire       disp, new_word;
   reg [4:0]  state;
   reg [3:0]  bit_count;
   
   encode_8b10b encode_8b10b 
     (.datain({k,datain}),.dispin(disp_reg),
      .dataout(dataout),.dispout(disp));

   always @(posedge clk)
     if(rst)
       disp_reg <= 0;
     else if(new_word)
       disp_reg <= disp;
   
   always @(posedge clk)
     if(rst)
       dataout_reg <= 0;
     else if(new_word)
       dataout_reg <= dataout;
     else
       dataout_reg <= {1'b0,dataout_reg[9:1]};
   
   always @(posedge clk)
     exp_time_out <= dataout_reg[0];
   
   assign    new_word = (bit_count == 9);
   
   always @(posedge clk)
     if(rst)
       bit_count <= 0;
     else if(new_word | send_sync)
       bit_count <= 0;
     else
       bit_count <= bit_count + 1;

   localparam SEND_IDLE = 0;
   localparam SEND_HEAD = 1;
   localparam SEND_T0 = 2;
   localparam SEND_T1 = 3;
   localparam SEND_T2 = 4;
   localparam SEND_T3 = 5;
   localparam SEND_T4 = 6;
   localparam SEND_T5 = 7;
   localparam SEND_T6 = 8;
   localparam SEND_T7 = 9;
   localparam SEND_TAIL = 10;

   localparam COMMA = 8'hBC;
   localparam HEAD = 8'h3C;
   localparam TAIL = 8'hF7;
   
   reg [63:0] vita_time_reg;
   
   always @(posedge clk)
     if(rst)
       vita_time_reg <= 0;
     else if(send_sync)
       vita_time_reg <= vita_time;
   
   always @(posedge clk)
     if(rst)
       begin
	  {k,datain} <= 0;
	  state <= SEND_IDLE;
       end
     else
       if(send_sync)
	 state <= SEND_HEAD;
       else if(new_word)
	 case(state)
	   SEND_IDLE :
	     {k,datain} <= {1'b1,COMMA};
	   SEND_HEAD :
	     begin
		{k,datain} <= {1'b1, HEAD};
		state <= SEND_T0;
	     end
	   SEND_T0 :
	     begin
		{k,datain} <= {1'b0, vita_time_reg[63:56] };
		state <= SEND_T1;
	     end
	   SEND_T1 :
	     begin
		{k,datain} <= {1'b0, vita_time_reg[55:48]};
		state <= SEND_T2;
	     end
	   SEND_T2 :
	     begin
		{k,datain} <= {1'b0, vita_time_reg[47:40]};
		state <= SEND_T3;
	     end
	   SEND_T3 :
	     begin
		{k,datain} <= {1'b0, vita_time_reg[39:32]};
		state <= SEND_T4;
	     end
	   SEND_T4 :
	     begin
		{k,datain} <= {1'b0, vita_time_reg[31:24]};
		state <= SEND_T5;
	     end
	   SEND_T5 :
	     begin
		{k,datain} <= {1'b0, vita_time_reg[23:16]};
		state <= SEND_T6;
	     end
	   SEND_T6 :
	     begin
		{k,datain} <= {1'b0, vita_time_reg[15:8]};
		state <= SEND_T7;
	     end
	   SEND_T7 :
	     begin
		{k,datain} <= {1'b0, vita_time_reg[7:0]};
		state <= SEND_TAIL;
	     end
	   SEND_TAIL :
	     begin
		{k,datain} <= {1'b1, TAIL};
		state <= SEND_IDLE;
	     end
	   default :
	     state <= SEND_IDLE;
	 endcase // case(state)
   
endmodule // time_sender
module address_filter_promisc
  (input clk,
   input reset,
   input go,
   input [7:0] data,
   output match,
   output done);

   reg [2:0] af_state;

   always @(posedge clk)
     if(reset)
       af_state     <= 0;
     else
       if(go)
	 af_state <= (data[0] == 1'b0) ? 1 : 7;
       else
	 case(af_state)
	   1 : af_state <= 2;
	   2 : af_state <= 3;
	   3 : af_state <= 4;
	   4 : af_state <= 5;
	   5 : af_state <= 6;
	   6, 7 : af_state <= 0;
	 endcase // case (af_state)

   assign match  = (af_state==6);
   assign done 	 = (af_state==6)|(af_state==7);
   
endmodule // address_filter_promisc
module ll8_to_txmac
  (input clk, input reset, input clear,
   input [7:0] ll_data, input ll_sof, input ll_eof, input ll_src_rdy, output ll_dst_rdy,
   output [7:0] tx_data, output tx_valid, output tx_error, input tx_ack );

   reg [2:0] xfer_state;

   localparam XFER_IDLE      = 0;
   localparam XFER_ACTIVE    = 1;
   localparam XFER_WAIT1     = 2;
   localparam XFER_UNDERRUN  = 3;
   localparam XFER_DROP      = 4;
   
   always @(posedge clk)
     if(reset | clear)
       xfer_state 	    <= XFER_IDLE;
     else
       case(xfer_state)
	 XFER_IDLE :
	   if(tx_ack)
	     xfer_state <= XFER_ACTIVE;
	 XFER_ACTIVE :
	   if(~ll_src_rdy)
	     xfer_state <= XFER_UNDERRUN;
	   else if(ll_eof)
	     xfer_state <= XFER_WAIT1;
	 XFER_WAIT1 :
	   xfer_state <= XFER_IDLE;
	 XFER_UNDERRUN :
	   xfer_state <= XFER_DROP;
	 XFER_DROP :
	   if(ll_eof)
	     xfer_state <= XFER_IDLE;
       endcase // case (xfer_state)

   assign ll_dst_rdy 	 = (xfer_state == XFER_ACTIVE) | tx_ack | (xfer_state == XFER_DROP);
   assign tx_valid 	 = (ll_src_rdy & (xfer_state == XFER_IDLE))|(xfer_state == XFER_ACTIVE);
   assign tx_data 	 = ll_data;
   assign tx_error 	 = (xfer_state == XFER_UNDERRUN);
   
endmodule // ll8_to_txmac
module ethrx_realign
   (input clk, input reset, input clear,
    input [35:0] datain, input src_rdy_i, output dst_rdy_o,
    output [35:0] dataout, output src_rdy_o, input dst_rdy_i);

   reg [1:0] 	  state;
   reg [15:0] 	  held;
   reg [1:0] 	  held_occ;
	  
   wire 	  xfer_in = src_rdy_i & dst_rdy_o;
   wire 	  xfer_out = src_rdy_o & dst_rdy_i;

   wire 	  sof_in = datain[32];
   wire 	  eof_in = datain[33];
   wire [1:0] 	  occ_in = datain[35:34];
   wire 	  sof_out, eof_out;
   wire [1:0] 	  occ_out;
      
   always @(posedge clk)
     if(reset | clear)
       begin
	  held <= 0;
	  held_occ <= 0;
       end
     else if(xfer_in)
       begin
	  held <= datain[15:0];
	  held_occ <= datain[35:34];
       end
   
   localparam RE_IDLE = 0;
   localparam RE_HELD = 1;
   localparam RE_DONE = 2;

   always @(posedge clk)
     if(reset | clear)
       state <= RE_IDLE;
     else
       case(state)
	 RE_IDLE :
	   if(src_rdy_i & dst_rdy_i)
	      if(eof_in)
		state <= RE_DONE;
	      else
		state <= RE_HELD;

	 RE_HELD :
	   if(src_rdy_i & dst_rdy_i & eof_in)
	     if((occ_in==0)|(occ_in==3))
	       state <= RE_DONE;
	     else
	       state <= RE_IDLE;

	 RE_DONE :
	   if(dst_rdy_i)
	     state <= RE_IDLE;
	 
       endcase // case (state)
   
   
   assign sof_out = (state == RE_IDLE);
   assign eof_out = (state == RE_DONE) | (occ_in == 1) | (occ_in == 2);
   assign occ_out = (state == RE_DONE) ? ((held_occ == 3) ? 1 : 2) :
		    (occ_in == 1) ? 3 : 0;
   		    
   assign dataout = {occ_out,eof_out,sof_out,held,datain[31:16]};
   assign src_rdy_o = (state == RE_DONE) | src_rdy_i;
   assign dst_rdy_o = dst_rdy_i & ((state == RE_IDLE)|(state == RE_HELD));
endmodule // ethrx_realign
module wb_reg
  #(parameter ADDR=0,
    parameter DEFAULT=0,
    parameter WIDTH=32)
   (input clk, input rst, 
    input [5:0] adr, input wr_acc,
    input [31:0] dat_i, output reg [WIDTH-1:0] dat_o);

   always @(posedge clk)
     if(rst)
       dat_o <= DEFAULT;
     else if(wr_acc & (adr == ADDR))
       dat_o <= dat_i[WIDTH-1:0];
   
endmodule // wb_reg
module ethtx_realign
   (input clk, input reset, input clear,
    input [35:0] datain, input src_rdy_i, output dst_rdy_o,
    output [35:0] dataout, output src_rdy_o, input dst_rdy_i);

   reg [1:0] 	  state;
   reg [15:0] 	  held;
   reg [1:0] 	  held_occ;
   reg 		  held_sof;
   
   wire 	  xfer_in = src_rdy_i & dst_rdy_o;
   wire 	  xfer_out = src_rdy_o & dst_rdy_i;

   wire 	  sof_in = datain[32];
   wire 	  eof_in = datain[33];
   wire [1:0] 	  occ_in = datain[35:34];
   wire 	  occ_low = occ_in[1] ^ occ_in[0]; //occ is 1 or 2

   always @(posedge clk)
     if(reset | clear)
       begin
	  held <= 0;
	  held_occ <= 0;
	  held_sof <= 0;
       end
     else if(xfer_in)
       begin
	  held <= datain[15:0];
	  held_occ <= occ_in;
	  held_sof <= sof_in;
       end
   
   localparam RE_IDLE = 0;
   localparam RE_HELD = 1;
   localparam RE_DONE = 2;

   always @(posedge clk)
     if(reset | clear)
       state <= RE_IDLE;
     else
       case(state)
	 RE_IDLE :
	   if(xfer_in & eof_in)
	     state <= RE_DONE;
	   else if(xfer_in & sof_in)
	     state <= RE_HELD;

	 RE_HELD :
	   if(xfer_in & xfer_out & eof_in)
	     if(occ_low)
	       state <= RE_IDLE;
	     else
	       state <= RE_DONE;

	 RE_DONE :
	   if(xfer_out)
	     state <= RE_IDLE;
	 
       endcase // case (state)

   wire sof_out = held_sof;
   wire eof_out = (state == RE_HELD)? (eof_in & occ_low) : (state == RE_DONE);
   wire [1:0] occ_out = ((state == RE_DONE)? held_occ : occ_in) ^ 2'b10; //(occ + 2)%4

   assign dataout = {occ_out,eof_out,sof_out,held,datain[31:16]};
   assign src_rdy_o = (state == RE_HELD)? src_rdy_i : (state == RE_DONE);
   assign dst_rdy_o = (state == RE_HELD)? dst_rdy_i : (state == RE_IDLE);

endmodule // ethtx_realign
module boot_cpld
  (input CLK_25MHZ,
   output CLK_25MHZ_EN,
   output [2:0] LED,
   output [8:0] DEBUG,
   input 	 POR,
   
   // To SD Card
   output 	 SD_nCS,
   output 	 SD_Din,
   output 	 SD_CLK,
   input 	 SD_Dout,
   input 	 SD_DAT1,  // Unused
   input 	 SD_DAT2,  // Unused
   input         SD_prot,  // Write Protect
   input         SD_det,   // Card Detect
   
   // To FPGA Config Interface
   input 	 CFG_INIT_B,
   output 	 CFG_Din,     // Also used in Data interface
   output 	 CFG_CCLK,
   input 	 CFG_DONE,
   output 	 CFG_PROG_B,
   
   // To FPGA data interface
   output 	 CPLD_CLK,
   input 	 START,
   input 	 MODE,
   input 	 DONE,
   output 	 detached,
   input         CPLD_misc   // Unused for now
   );
   
   assign 	 CLK_25MHZ_EN = 1'b1;
   
   assign 	 LED[0] = ~CFG_DONE;
   assign 	 LED[1] = CFG_INIT_B;
   assign 	 LED[2] = ~CFG_PROG_B;
   			
   wire 	 en_outs;
   wire [3:0] 	 set_sel = 4'd0;
   
   assign 	 CPLD_CLK = CFG_CCLK;
   assign 	 DEBUG[8:0] = { CLK_25MHZ, SD_nCS, SD_CLK, SD_Din, SD_Dout, 
				START, MODE, DONE, CPLD_misc};

   // Handle cutover to FPGA control of SD
   wire 	 fpga_takeover = ~CPLD_misc;
   wire 	 SD_CLK_int, SD_nCS_int, SD_Din_int, CFG_Din_int;

   assign 	 SD_CLK = fpga_takeover ? START : SD_CLK_int;
   assign 	 SD_nCS = fpga_takeover ? MODE : SD_nCS_int;
   assign 	 SD_Din = fpga_takeover ? DONE : SD_Din_int;
   assign 	 CFG_Din = fpga_takeover ? SD_Dout : CFG_Din_int;

   spi_boot #(.width_set_sel_g(4),  // How many sets (16)
	      .width_bit_cnt_g(6),  // Block length (12 is faster, 6 is minimum)
	      .width_img_cnt_g(2),  // How many images per set
	      .num_bits_per_img_g(20), // Image size, 20 = 1MB
	      .sd_init_g(1),           // SD-specific initialization
	      .mmc_compat_clk_div_g(0),// No MMC support
	      .width_mmc_clk_div_g(0), // No MMC support
	      .reset_level_g(0))       // Active low reset
     
     spi_boot(.clk_i(CLK_25MHZ), 
	      .reset_i(POR),
	      
	      // To SD Card
	      .spi_clk_o(SD_CLK_int), 
	      .spi_cs_n_o(SD_nCS_int),
	      .spi_data_in_i(SD_Dout), 
	      .spi_data_out_o(SD_Din_int), 
	      .spi_en_outs_o(en_outs), 
	      
	      // Data Port
	      .start_i(START),
	      .mode_i(MODE), // 0->conf mode, 1->data mode  
	      .detached_o(detached), 
	      .dat_done_i(DONE), 
	      .set_sel_i(set_sel),
	      
	      // To FPGA
	      .config_n_o(CFG_PROG_B), 
	      .cfg_init_n_i(CFG_INIT_B), 
	      .cfg_done_i(CFG_DONE), 
	      .cfg_clk_o(CFG_CCLK), 
	      .cfg_dat_o(CFG_Din_int)
	      );
   
endmodule // boot_cpld
module round_sd_tb();
   
   reg clk, rst;

   initial rst = 1;
   initial #1000 rst = 0;
   initial clk = 0;
   always #5 clk = ~clk;
   
   initial $dumpfile("round_sd_tb.vcd");
   initial $dumpvars(0,round_sd_tb);

   localparam WIDTH_IN = 8;
   localparam WIDTH_OUT = 5;
   
   reg [WIDTH_IN-1:0] adc_in, adc_in_del;
   wire [WIDTH_OUT-1:0] adc_out;

   integer 		factor = 1<<(WIDTH_IN-WIDTH_OUT);
   
   always @(posedge clk)
     if(~rst)
	begin  
	   if(adc_in_del[WIDTH_IN-1])
	     $write("-%d\t",-adc_in_del);
	   else
	     $write("%d\t",adc_in_del);
	   if(adc_out[WIDTH_OUT-1])
	     $write("-%d\t",-adc_out);
	   else
	     $write("%d\t",adc_out);
	   $write("\n");
	   
	   //$write("%f\t",adc_in_del/factor);
	   //$write("%f\n",adc_in_del/factor-adc_out);
	end	
   
   round_sd #(.WIDTH_IN(WIDTH_IN),.WIDTH_OUT(WIDTH_OUT)) 
   round_sd(.clk(clk),.reset(rst), .in(adc_in), .strobe_in(1'b1), .out(adc_out), .strobe_out());

   reg [5:0] counter = 0;
   
   always @(posedge clk)
     counter <= counter+1;
   
   always @(posedge clk)
     adc_in_del <= adc_in;

   always @(posedge clk)
     if(rst)
       adc_in <= 0;
     else if(counter == 63)
       adc_in <= adc_in + 1;
   
   initial #300000 $finish;
   
endmodule // longfifo_tb