dakies/OSS_Verilog huggingface dataset:
module rx_chain_dual
  (input clock,
   input clock_2x,
   input reset,
   input enable,
   input wire [7:0] decim_rate,
   input sample_strobe,
   input decimator_strobe,
   input wire [31:0] freq0,
   input wire [15:0] i_in0,
   input wire [15:0] q_in0,
   output wire [15:0] i_out0,
   output wire [15:0] q_out0,
   input wire [31:0] freq1,
   input wire [15:0] i_in1,
   input wire [15:0] q_in1,
   output wire [15:0] i_out1,
   output wire [15:0] q_out1
   );

   wire [15:0] phase;
   wire [15:0] bb_i, bb_q;
   wire [15:0] i_in, q_in;
   
   wire [31:0] phase0;
   wire [31:0] phase1;
   reg [15:0] bb_i0, bb_q0;
   reg [15:0] bb_i1, bb_q1;

   // We want to time-share the CORDIC by double-clocking it
   
   phase_acc rx_phase_acc_0
     (.clk(clock),.reset(reset),.enable(enable),
      .strobe(sample_strobe),.freq(freq0),.phase(phase0) );

   phase_acc rx_phase_acc_1
     (.clk(clock),.reset(reset),.enable(enable),
      .strobe(sample_strobe),.freq(freq1),.phase(phase1) );
   
   assign phase = clock ? phase0[31:16] : phase1[31:16];
   assign i_in = clock ? i_in0 : i_in1;
   assign q_in = clock ? q_in0 : q_in1;

// This appears reversed because of the number of CORDIC stages
   always @(posedge clock_2x)
     if(clock)
       begin
	  bb_i1 <= #1 bb_i;
	  bb_q1 <= #1 bb_q;
       end
     else
       begin
	  bb_i0 <= #1 bb_i;
	  bb_q0 <= #1 bb_q;
       end
	
   cordic rx_cordic
     ( .clock(clock_2x),.reset(reset),.enable(enable), 
       .xi(i_in),.yi(q_in),.zi(phase),
       .xo(bb_i),.yo(bb_q),.zo() );
   
   cic_decim cic_decim_i_0
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(decim_rate),.strobe_in(sample_strobe),.strobe_out(decimator_strobe),
       .signal_in(bb_i0),.signal_out(i_out0) );

   cic_decim cic_decim_q_0
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(decim_rate),.strobe_in(sample_strobe),.strobe_out(decimator_strobe),
       .signal_in(bb_q0),.signal_out(q_out0) );

   cic_decim cic_decim_i_1
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(decim_rate),.strobe_in(sample_strobe),.strobe_out(decimator_strobe),
       .signal_in(bb_i1),.signal_out(i_out1) );

   cic_decim cic_decim_q_1
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(decim_rate),.strobe_in(sample_strobe),.strobe_out(decimator_strobe),
       .signal_in(bb_q1),.signal_out(q_out1) );

endmodule // rx_chain
module phase_acc (clk,reset,enable,strobe,serial_addr,serial_data,serial_strobe,phase);   
   parameter FREQADDR = 0;
   parameter PHASEADDR = 0;
   parameter resolution = 32;
   
   input     clk, reset, enable, strobe;
   input [6:0] serial_addr;
   input [31:0] serial_data;
   input 	serial_strobe;
   
   output reg [resolution-1:0] phase;
   wire [resolution-1:0] freq;

   setting_reg #(FREQADDR) sr_rxfreq0(.clock(clk),.reset(1'b0),.strobe(serial_strobe),.addr(serial_addr),.in(serial_data),.out(freq));

   always @(posedge clk)
     if(reset)
       phase <= #1 32'b0;
     else if(serial_strobe & (serial_addr == PHASEADDR))
       phase <= #1 serial_data;
     else if(enable & strobe)
       phase <= #1 phase + freq;

endmodule // phase_acc
module setting_reg
  ( input clock, input reset, input strobe, input wire [6:0] addr,
    input wire [31:0] in, output reg [31:0] out, output reg changed);
   parameter my_addr = 0;
   
   always @(posedge clock)
     if(reset)
       begin
	  out <= #1 32'd0;
	  changed <= #1 1'b0;
       end
     else
       if(strobe & (my_addr==addr))
	 begin
	    out <= #1 in;
	    changed <= #1 1'b1;
	 end
       else
	 changed <= #1 1'b0;
   
endmodule // setting_reg
module cic_decim
  ( clock,reset,enable,rate,strobe_in,strobe_out,signal_in,signal_out);
   parameter bw = 16;
   parameter N = 4;
   parameter log2_of_max_rate = 7;
   parameter maxbitgain = N * log2_of_max_rate;
   
   input clock;
   input reset;
   input enable;
   input [7:0] rate;
   input strobe_in,strobe_out;	
   input [bw-1:0] signal_in;
   output [bw-1:0] signal_out;
   reg [bw-1:0] signal_out;
   wire [bw-1:0] signal_out_unreg;
   
   wire [bw+maxbitgain-1:0] signal_in_ext;
   reg [bw+maxbitgain-1:0]  integrator [0:N-1];
   reg [bw+maxbitgain-1:0] differentiator [0:N-1];
   reg [bw+maxbitgain-1:0] pipeline [0:N-1];
   reg [bw+maxbitgain-1:0] sampler;
   
   integer i;
   
   sign_extend #(bw,bw+maxbitgain) 
      ext_input (.in(signal_in),.out(signal_in_ext));
   
   always @(posedge clock)
     if(reset)
       for(i=0;i<N;i=i+1)
	 integrator[i] <= #1 0;
     else if (enable && strobe_in)
       begin
	  integrator[0] <= #1 integrator[0] + signal_in_ext;
	  for(i=1;i<N;i=i+1)
	    integrator[i] <= #1 integrator[i] + integrator[i-1];
       end	
   
   always @(posedge clock)
     if(reset)
       begin
	  sampler <= #1 0;
	  for(i=0;i<N;i=i+1)
	    begin
	       pipeline[i] <= #1 0;
	       differentiator[i] <= #1 0;
	    end
       end
     else if (enable && strobe_out)
       begin
	  sampler <= #1 integrator[N-1];
	  differentiator[0] <= #1 sampler;
	  pipeline[0] <= #1 sampler - differentiator[0];
	  for(i=1;i<N;i=i+1)
	    begin
	       differentiator[i] <= #1 pipeline[i-1];
	       pipeline[i] <= #1 pipeline[i-1] - differentiator[i];
	    end
       end // if (enable && strobe_out)
      
   wire [bw+maxbitgain-1:0] signal_out_unnorm = pipeline[N-1];

   cic_dec_shifter #(bw)
	cic_dec_shifter(rate,signal_out_unnorm,signal_out_unreg);

   always @(posedge clock)
     signal_out <= #1 signal_out_unreg;
   
endmodule // cic_decim
module clk_divider(input reset, input wire in_clk,output reg out_clk, input [7:0] ratio);
   reg [7:0] counter;
   
   // FIXME maybe should use PLL or switch to double edge version	
	
   always @(posedge in_clk or posedge reset)
     if(reset)
       counter <= #1 8'd0;
     else if(counter == 0)
       counter <= #1 ratio[7:1] + (ratio[0] & out_clk) - 8'b1;
     else
       counter <= #1 counter-8'd1;
   
   always @(posedge in_clk or posedge reset)
     if(reset)
       out_clk <= #1 1'b0;
     else if(counter == 0)
       out_clk <= #1 ~out_clk;
   
endmodule // clk_divider
module serial_io
  ( input master_clk,
    input serial_clock,
    input serial_data_in,
    input enable,
    input reset,
    inout wire serial_data_out,
    output reg [6:0] serial_addr,
    output reg [31:0] serial_data,
    output wire serial_strobe,
    input wire [31:0] readback_0,
    input wire [31:0] readback_1,
    input wire [31:0] readback_2,
    input wire [31:0] readback_3,
    input wire [31:0] readback_4,
    input wire [31:0] readback_5,
    input wire [31:0] readback_6,
    input wire [31:0] readback_7
    );
       
   reg 	      is_read;
   reg [7:0]  ser_ctr;
   reg 	      write_done;

   assign serial_data_out = is_read ? serial_data[31] : 1'bz;

   always @(posedge serial_clock, posedge reset, negedge enable)
     if(reset)
       ser_ctr <= #1 8'd0;
     else if(~enable)
       ser_ctr <= #1 8'd0;
     else if(ser_ctr == 39)
       ser_ctr <= #1 8'd0;
     else
       ser_ctr <= #1 ser_ctr + 8'd1;

   always @(posedge serial_clock, posedge reset, negedge enable)
     if(reset)
       is_read <= #1 1'b0;
     else if(~enable)
       is_read <= #1 1'b0;
     else if((ser_ctr == 7)&&(serial_addr[6]==1))
       is_read <= #1 1'b1;
   
   always @(posedge serial_clock, posedge reset)
     if(reset)
       begin
	  serial_addr <= #1 7'b0;
	  serial_data <= #1 32'b0;
	  write_done <= #1 1'b0;
       end
     else if(~enable)
       begin
	  //serial_addr <= #1 7'b0;
	  //serial_data <= #1 32'b0;
	  write_done <= #1 1'b0;
       end
     else 
       begin
	  if(~is_read && (ser_ctr == 39))
	    write_done <= #1 1'b1;
	  else
	    write_done <= #1 1'b0;
	  if(is_read & (ser_ctr==8))
	    case (serial_addr)
	      7'd1: serial_data <= #1 readback_0;
	      7'd2: serial_data <= #1 readback_1;
	      7'd3: serial_data <= #1 readback_2;
	      7'd4: serial_data <= #1 readback_3;
	      7'd5: serial_data <= #1 readback_4;
	      7'd6: serial_data <= #1 readback_5;
	      7'd7: serial_data <= #1 readback_6;
	      7'd8: serial_data <= #1 readback_7;
	      default: serial_data <= #1 32'd0;
	    endcase // case(serial_addr)
	  else if(ser_ctr >= 8)
	    serial_data <= #1 {serial_data[30:0],serial_data_in};
	  else if(ser_ctr < 8)
	    serial_addr <= #1 {serial_addr[5:0],serial_data_in};
       end // else: !if(~enable)

   reg enable_d1, enable_d2;
   always @(posedge master_clk)
     begin
	enable_d1 <= #1 enable;
	enable_d2 <= #1 enable_d1;
     end

   assign serial_strobe = enable_d2 & ~enable_d1;
   
endmodule // serial_io
module tx_chain_hb
  (input clock,
   input reset,
   input enable,
   input wire [7:0] interp_rate,
   input sample_strobe,
   input interpolator_strobe,
   input hb_strobe,
   input wire [31:0] freq,
   input wire [15:0] i_in,
   input wire [15:0] q_in,
   output wire [15:0] i_out,
   output wire [15:0] q_out,
output wire [15:0] debug, output [15:0] hb_i_out
   );
assign debug[15:13] = {sample_strobe,hb_strobe,interpolator_strobe};

   wire [15:0] bb_i, bb_q;
   wire [15:0] hb_i_out, hb_q_out;
   
   halfband_interp hb
     (.clock(clock),.reset(reset),.enable(enable),
      .strobe_in(interpolator_strobe),.strobe_out(hb_strobe),
      .signal_in_i(i_in),.signal_in_q(q_in),
      .signal_out_i(hb_i_out),.signal_out_q(hb_q_out),
	.debug(debug[12:0]));
      
   cic_interp cic_interp_i
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(interp_rate),.strobe_in(hb_strobe),.strobe_out(sample_strobe),
       .signal_in(hb_i_out),.signal_out(bb_i) );

   cic_interp cic_interp_q
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(interp_rate),.strobe_in(hb_strobe),.strobe_out(sample_strobe),
       .signal_in(hb_q_out),.signal_out(bb_q) );
   
`define NOCORDIC_TX
`ifdef NOCORDIC_TX
   assign      i_out = bb_i;
   assign      q_out = bb_q;
`else
   wire [31:0] phase;

   phase_acc phase_acc_tx
     (.clk(clock),.reset(reset),.enable(enable),
      .strobe(sample_strobe),.freq(freq),.phase(phase) );
   
   cordic tx_cordic_0
     ( .clock(clock),.reset(reset),.enable(sample_strobe), 
       .xi(bb_i),.yi(bb_q),.zi(phase[31:16]),
       .xo(i_out),.yo(q_out),.zo() );
`endif

endmodule // tx_chain
module strobe_gen 
  ( input clock,
    input reset,
    input enable,
    input [7:0] rate, // Rate should be 1 LESS THAN your desired divide ratio
    input strobe_in,
    output wire strobe );
   
//   parameter width = 8;
   
   reg [7:0] counter;
   assign strobe = ~|counter && enable && strobe_in;
   
   always @(posedge clock)
     if(reset | ~enable)
       counter <= #1 8'd0;
     else if(strobe_in)
       if(counter == 0)
	 counter <= #1 rate;
       else 
	 counter <= #1 counter - 8'd1;
   
endmodule // strobe_gen
module fifo (reset,data,write,wrclk,wr_used,q,read_ack,rdclk,rd_used);
   parameter width=32;
   parameter depth=10;

   input reset;  // Asynchronous
   input [width-1:0] data;
   input write;
   input wrclk;
   output [depth-1:0] wr_used;
   output [width-1:0] q;
   input read_ack;
   input rdclk;
   output [depth-1:0] rd_used;

   reg [depth-1:0] read_addr, write_addr, 
		   read_addr_gray, read_addr_gray_sync,
		   write_addr_gray, write_addr_gray_sync;

   // Pseudo-dual-port RAM
   dpram #(.depth(10),.width(width),.size(1024))
         fifo_ram (.wclk(wrclk),.wdata(data),.waddr(write_addr),.wen(write),
		   .rclk(rdclk), .rdata(q),.raddr(read_addr) );

   wire [depth-1:0] wag,rag;

   // Keep track of own side's pointer
   always @(posedge wrclk or posedge reset)
     if(reset) write_addr <= #1 0;
     else if(write) write_addr <= #1 write_addr + 1;

   always @(posedge rdclk or posedge reset)
     if(reset) read_addr <= #1 0;
     else if(read_ack) read_addr <= #1 read_addr + 1;

   // Convert own side pointer to gray
   bin2gray #(depth) write_b2g (write_addr,wag);
   bin2gray #(depth) read_b2g (read_addr,rag);

   // Latch it
   always @(posedge wrclk or posedge reset)
     if(reset) write_addr_gray <= #1 0;
     else write_addr_gray <= #1 wag;

   always @(posedge rdclk or posedge reset)
     if(reset) read_addr_gray <= #1 0;
     else read_addr_gray <= #1 rag;

   // Send it to other side and latch
   always @(posedge wrclk or posedge reset)
     if(reset) read_addr_gray_sync <= #1 0;
     else read_addr_gray_sync <= #1 read_addr_gray;

   always @(posedge rdclk or posedge reset)
     if(reset) write_addr_gray_sync <= #1 0;
     else write_addr_gray_sync <= #1 write_addr_gray;

   wire [depth-1:0] write_addr_sync, read_addr_sync;
   
   // Convert back to binary
   gray2bin #(depth) write_g2b (write_addr_gray_sync, write_addr_sync);
   gray2bin #(depth) read_g2b (read_addr_gray_sync, read_addr_sync);
 
   assign rd_used = write_addr_sync - read_addr;
   assign wr_used = write_addr - read_addr_sync;
   		  
endmodule // fifo
module bin2gray(bin_val,gray_val);
   parameter width = 8;
   input [width-1:0] bin_val;
   output reg [width-1:0] gray_val;
   
   integer i;

   always @*
     begin
	gray_val[width-1] = bin_val[width-1];
	for(i=0;i<width-1;i=i+1)
	  gray_val[i] = bin_val[i] ^ bin_val[i+1];
     end
endmodule // bin2gray
module gray2bin(gray_val,bin_val);
   parameter width = 8;
   input [width-1:0] gray_val;
   output reg [width-1:0] bin_val;

   integer i;
   
   always @*
     begin
	bin_val[width-1] = gray_val[width-1];
	for(i=width-2;i>=0;i=i-1)
	  bin_val[i] = bin_val[i+1] ^ gray_val[i];
     end
endmodule // gray2bin
module tx_chain
  (input clock,
   input reset,
   input enable,
   input wire [7:0] interp_rate,
   input sample_strobe,
   input interpolator_strobe,
   input wire [31:0] freq,
   input wire [15:0] i_in,
   input wire [15:0] q_in,
   output wire [15:0] i_out,
   output wire [15:0] q_out
   );

   wire [15:0] bb_i, bb_q;

   cic_interp cic_interp_i
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(interp_rate),.strobe_in(interpolator_strobe),.strobe_out(sample_strobe),
       .signal_in(i_in),.signal_out(bb_i) );

   cic_interp cic_interp_q
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(interp_rate),.strobe_in(interpolator_strobe),.strobe_out(sample_strobe),
       .signal_in(q_in),.signal_out(bb_q) );
   
`define NOCORDIC_TX
`ifdef NOCORDIC_TX
   assign      i_out = bb_i;
   assign      q_out = bb_q;
`else
   wire [31:0] phase;

   phase_acc phase_acc_tx
     (.clk(clock),.reset(reset),.enable(enable),
      .strobe(sample_strobe),.freq(freq),.phase(phase) );
   
   cordic tx_cordic_0
     ( .clock(clock),.reset(reset),.enable(sample_strobe), 
       .xi(bb_i),.yi(bb_q),.zi(phase[31:16]),
       .xo(i_out),.yo(q_out),.zo() );
`endif

endmodule // tx_chain
module io_pins
  ( inout wire [15:0] io_0, inout wire [15:0] io_1, inout wire [15:0] io_2, inout wire [15:0] io_3,
    input wire [15:0] reg_0, input wire [15:0] reg_1, input wire [15:0] reg_2, input wire [15:0] reg_3,
    input clock, input rx_reset, input tx_reset,
    input [6:0] serial_addr, input [31:0] serial_data, input serial_strobe);
   
   reg [15:0] io_0_oe,io_1_oe,io_2_oe,io_3_oe;
   
   bidir_reg bidir_reg_0 (.tristate(io_0),.oe(io_0_oe),.reg_val(reg_0));
   bidir_reg bidir_reg_1 (.tristate(io_1),.oe(io_1_oe),.reg_val(reg_1));
   bidir_reg bidir_reg_2 (.tristate(io_2),.oe(io_2_oe),.reg_val(reg_2));
   bidir_reg bidir_reg_3 (.tristate(io_3),.oe(io_3_oe),.reg_val(reg_3));
   
   // Upper 16 bits are mask for lower 16
   always @(posedge clock)
     if(serial_strobe)
       case(serial_addr)
	 `FR_OE_0 : io_0_oe
	   <= #1 (io_0_oe & ~serial_data[31:16]) | (serial_data[15:0] & serial_data[31:16] );
	 `FR_OE_1 : io_1_oe
	   <= #1 (io_1_oe & ~serial_data[31:16]) | (serial_data[15:0] & serial_data[31:16] );
	 `FR_OE_2 : io_2_oe
	   <= #1 (io_2_oe & ~serial_data[31:16]) | (serial_data[15:0] & serial_data[31:16] );
	 `FR_OE_3 : io_3_oe
	   <= #1 (io_3_oe & ~serial_data[31:16]) | (serial_data[15:0] & serial_data[31:16] );
       endcase // case(serial_addr)

endmodule // io_pins
module ram32 (input clock, input write, 
	      input [4:0] wr_addr, input [15:0] wr_data,
	      input [4:0] rd_addr, output reg [15:0] rd_data);

   reg [15:0] 		ram_array [0:31];

   always @(posedge clock)
     rd_data <= #1 ram_array[rd_addr];

   always @(posedge clock)
     if(write)
       ram_array[wr_addr] <= #1 wr_data;

endmodule // ram32
module rx_chain
  (input clock,
   input reset,
   input enable,
   input wire [7:0] decim_rate,
   input sample_strobe,
   input decimator_strobe,
   output wire hb_strobe,
   input [6:0] serial_addr, input [31:0] serial_data, input serial_strobe,
   input wire [15:0] i_in,
   input wire [15:0] q_in,
   output wire [15:0] i_out,
   output wire [15:0] q_out,
   output wire [15:0] debugdata,output wire [15:0] debugctrl
   );

   parameter FREQADDR = 0;
   parameter PHASEADDR = 0;
   
   wire [31:0] phase;
   wire [15:0] bb_i, bb_q;
   wire [15:0] hb_in_i, hb_in_q;
   
   assign      debugdata = hb_in_i;

`ifdef RX_NCO_ON
    phase_acc #(FREQADDR,PHASEADDR,32) rx_phase_acc
     (.clk(clock),.reset(reset),.enable(enable),
      .serial_addr(serial_addr),.serial_data(serial_data),.serial_strobe(serial_strobe),
      .strobe(sample_strobe),.phase(phase) );

   cordic rx_cordic
     ( .clock(clock),.reset(reset),.enable(enable), 
       .xi(i_in),.yi(q_in),.zi(phase[31:16]),
       .xo(bb_i),.yo(bb_q),.zo() );
`else
   assign bb_i = i_in;
   assign bb_q = q_in;
   assign sample_strobe = 1;
`endif // !`ifdef RX_NCO_ON
   
`ifdef RX_CIC_ON
   cic_decim cic_decim_i_0
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(decim_rate),.strobe_in(sample_strobe),.strobe_out(decimator_strobe),
       .signal_in(bb_i),.signal_out(hb_in_i) );
`else
   assign hb_in_i = bb_i;
   assign decimator_strobe = sample_strobe;
`endif
   
`ifdef RX_HB_ON
   halfband_decim hbd_i_0
     ( .clock(clock),.reset(reset),.enable(enable),
       .strobe_in(decimator_strobe),.strobe_out(hb_strobe),
       .data_in(hb_in_i),.data_out(i_out),.debugctrl(debugctrl) );
`else
   assign i_out = hb_in_i;
   assign hb_strobe = decimator_strobe;
`endif
   
`ifdef RX_CIC_ON
   cic_decim cic_decim_q_0
     ( .clock(clock),.reset(reset),.enable(enable),
       .rate(decim_rate),.strobe_in(sample_strobe),.strobe_out(decimator_strobe),
       .signal_in(bb_q),.signal_out(hb_in_q) );
`else
   assign hb_in_q = bb_q;
`endif

`ifdef RX_HB_ON
   halfband_decim hbd_q_0
     ( .clock(clock),.reset(reset),.enable(enable),
       .strobe_in(decimator_strobe),.strobe_out(),
       .data_in(hb_in_q),.data_out(q_out) );   
`else
   assign q_out = hb_in_q;
`endif


endmodule // rx_chain
module ram64 (input clock, input write, 
	      input [5:0] wr_addr, input [15:0] wr_data,
	      input [5:0] rd_addr, output reg [15:0] rd_data);

   reg [15:0] 		ram_array [0:63];

   always @(posedge clock)
     rd_data <= #1 ram_array[rd_addr];

   always @(posedge clock)
     if(write)
       ram_array[wr_addr] <= #1 wr_data;

endmodule // ram64
module gen_sync
  ( input clock,
    input reset,
    input enable,
    input [7:0] rate,
    output wire sync );
   
//   parameter width = 8;
   
   reg [7:0] counter;
   assign sync = |(((rate+1)>>1)& counter);
      
   always @(posedge clock)
     if(reset || ~enable)
       counter <= #1 0;
     else if(counter == rate)
       counter <= #1 0;
     else 
       counter <= #1 counter + 8'd1;
   
endmodule // gen_sync
module cic_dec_shifter(rate,signal_in,signal_out);
   parameter bw = 16;
   parameter maxbitgain = 28;
   
   input [7:0] rate;
   input       wire [bw+maxbitgain-1:0] signal_in;
   output      reg [bw-1:0] signal_out;

   function [4:0] bitgain;
      input [7:0] rate;
      case(rate)
	// Exact Cases -- N*log2(rate)
	8'd4 : bitgain = 8;
	8'd8 : bitgain = 12;
	8'd16 : bitgain = 16;
	8'd32 : bitgain = 20;
	8'd64 : bitgain = 24;
	8'd128 : bitgain = 28;
	
	// Nearest without overflow -- ceil(N*log2(rate))
	8'd5 : bitgain = 10;
	8'd6 : bitgain = 11;
	8'd7 : bitgain = 12;
	8'd9 : bitgain = 13;
	8'd10,8'd11 : bitgain = 14;
	8'd12,8'd13 : bitgain = 15;
	8'd14,8'd15 : bitgain = 16;
	8'd17,8'd18,8'd19 : bitgain = 17;
	8'd20,8'd21,8'd22 : bitgain = 18;
	8'd23,8'd24,8'd25,8'd26 : bitgain = 19;
	8'd27,8'd28,8'd29,8'd30,8'd31 : bitgain = 20;
	8'd33,8'd34,8'd35,8'd36,8'd37,8'd38 : bitgain = 21;
	8'd39,8'd40,8'd41,8'd42,8'd43,8'd44,8'd45 : bitgain = 22;
	8'd46,8'd47,8'd48,8'd49,8'd50,8'd51,8'd52,8'd53 : bitgain = 23;
	8'd54,8'd55,8'd56,8'd57,8'd58,8'd59,8'd60,8'd61,8'd62,8'd63 : bitgain = 24;
	8'd65,8'd66,8'd67,8'd68,8'd69,8'd70,8'd71,8'd72,8'd73,8'd74,8'd75,8'd76 : bitgain = 25;
	8'd77,8'd78,8'd79,8'd80,8'd81,8'd82,8'd83,8'd84,8'd85,8'd86,8'd87,8'd88,8'd89,8'd90 : bitgain = 26;
	8'd91,8'd92,8'd93,8'd94,8'd95,8'd96,8'd97,8'd98,8'd99,8'd100,8'd101,8'd102,8'd103,8'd104,8'd105,8'd106,8'd107 : bitgain = 27;
	default : bitgain = 28;
      endcase // case(rate)
   endfunction // bitgain
   
   wire [4:0] 	  shift = bitgain(rate+1);
   
   // We should be able to do this, but can't ....
   // assign 	  signal_out = signal_in[shift+bw-1:shift];
   
   always @*
     case(shift)
       5'd8  : signal_out = signal_in[8+bw-1:8];
       5'd10 : signal_out = signal_in[10+bw-1:10];
       5'd11 : signal_out = signal_in[11+bw-1:11];
       5'd12 : signal_out = signal_in[12+bw-1:12];
       5'd13 : signal_out = signal_in[13+bw-1:13];
       5'd14 : signal_out = signal_in[14+bw-1:14];
       5'd15 : signal_out = signal_in[15+bw-1:15];
       5'd16 : signal_out = signal_in[16+bw-1:16];
       5'd17 : signal_out = signal_in[17+bw-1:17];
       5'd18 : signal_out = signal_in[18+bw-1:18];
       5'd19 : signal_out = signal_in[19+bw-1:19];
       5'd20 : signal_out = signal_in[20+bw-1:20];
       5'd21 : signal_out = signal_in[21+bw-1:21];
       5'd22 : signal_out = signal_in[22+bw-1:22];
       5'd23 : signal_out = signal_in[23+bw-1:23];
       5'd24 : signal_out = signal_in[24+bw-1:24];
       5'd25 : signal_out = signal_in[25+bw-1:25];
       5'd26 : signal_out = signal_in[26+bw-1:26];
       5'd27 : signal_out = signal_in[27+bw-1:27];
       5'd28 : signal_out = signal_in[28+bw-1:28];
       
       default : signal_out = signal_in[28+bw-1:28];
     endcase // case(shift)

endmodule // cic_dec_shifter
module dpram(wclk,wdata,waddr,wen,rclk,rdata,raddr);
   parameter depth = 4;
   parameter width = 16;
   parameter size = 16;
   
   input wclk;
   input [width-1:0] wdata;
   input [depth-1:0] waddr;
   input 	     wen;

   input rclk;
   output reg [width-1:0] rdata;
   input [depth-1:0]  raddr;
   
   reg [width-1:0]    ram [0:size-1];
   
   always @(posedge wclk)
     if(wen)
       ram[waddr] <= #1 wdata;
   
   always @(posedge rclk)
     rdata <= #1 ram[raddr];
   
endmodule // dpram
module cic_interp(clock,reset,enable,rate,strobe_in,strobe_out,signal_in,signal_out);
   parameter bw = 16;
   parameter N = 4;
   parameter log2_of_max_rate = 7;
   parameter maxbitgain = (N-1)*log2_of_max_rate;
   
   input clock;
   input reset;
   input enable;
   input [7:0] rate;
   input strobe_in,strobe_out;	
   input [bw-1:0] signal_in;
   wire [bw-1:0] 	signal_in;
   output [bw-1:0] signal_out;
   wire [bw-1:0]   signal_out;

   wire [bw+maxbitgain-1:0] signal_in_ext;
   reg [bw+maxbitgain-1:0] integrator [0:N-1];
   reg [bw+maxbitgain-1:0] differentiator [0:N-1];
   reg [bw+maxbitgain-1:0] pipeline [0:N-1];

   integer i;

   sign_extend #(bw,bw+maxbitgain) 
      ext_input (.in(signal_in),.out(signal_in_ext));

   wire    clear_me = reset | ~enable;
   //FIXME Note that this section has pipe and diff reversed
   // It still works, but is confusing
   always @(posedge clock)
     if(clear_me)
       for(i=0;i<N;i=i+1)
	 integrator[i] <= #1 0;
     else if (enable & strobe_out)
       begin
	  if(strobe_in)
	    integrator[0] <= #1 integrator[0] + pipeline[N-1];
	  for(i=1;i<N;i=i+1)
	    integrator[i] <= #1 integrator[i] + integrator[i-1];
       end
   
   always @(posedge clock)
     if(clear_me)
       begin
	  for(i=0;i<N;i=i+1)
	    begin
	       differentiator[i] <= #1 0;
	       pipeline[i] <= #1 0;
 	    end
       end
     else if (enable && strobe_in)
       begin
	  differentiator[0] <= #1 signal_in_ext;
	  pipeline[0] <= #1 signal_in_ext - differentiator[0];
	  for(i=1;i<N;i=i+1)
	    begin
	       differentiator[i] <= #1 pipeline[i-1];
	       pipeline[i] <= #1 pipeline[i-1] - differentiator[i];
	    end
       end
   
   wire [bw+maxbitgain-1:0] signal_out_unnorm = integrator[N-1];

   cic_int_shifter #(bw)
	cic_int_shifter(rate,signal_out_unnorm,signal_out);
   
endmodule // cic_interp
module fifo_4k
  (  input [15:0] data,
     input 	wrreq,
     input 	rdreq,
     input 	rdclk,
     input 	wrclk,
     input 	aclr,
     output [15:0] q,
     output 	 rdfull,
     output 	 rdempty,
     output [11:0] rdusedw,
     output 	 wrfull,
     output 	 wrempty,
     output [11:0]  wrusedw
     );

fifo #(.width(16),.depth(4096),.addr_bits(12)) fifo_4k 
  ( data, wrreq, rdreq, rdclk, wrclk, aclr, q,
    rdfull, rdempty, rdusedw, wrfull, wrempty, wrusedw);
   
endmodule // fifo_1k
module fifo_2k
  (  input [15:0] data,
     input 	wrreq,
     input 	rdreq,
     input 	rdclk,
     input 	wrclk,
     input 	aclr,
     output [15:0] q,
     output 	 rdfull,
     output 	 rdempty,
     output [10:0] rdusedw,
     output 	 wrfull,
     output 	 wrempty,
     output [10:0]  wrusedw
     );

fifo #(.width(16),.depth(2048),.addr_bits(11)) fifo_2k 
  ( data, wrreq, rdreq, rdclk, wrclk, aclr, q,
    rdfull, rdempty, rdusedw, wrfull, wrempty, wrusedw);
   
endmodule // fifo_1k
module fifo_1k
  (  input [15:0] data,
     input 	wrreq,
     input 	rdreq,
     input 	rdclk,
     input 	wrclk,
     input 	aclr,
     output [15:0] q,
     output 	 rdfull,
     output 	 rdempty,
     output [9:0] rdusedw,
     output 	 wrfull,
     output 	 wrempty,
     output [9:0]  wrusedw
     );

fifo #(.width(16),.depth(1024),.addr_bits(10)) fifo_1k 
  ( data, wrreq, rdreq, rdclk, wrclk, aclr, q,
    rdfull, rdempty, rdusedw, wrfull, wrempty, wrusedw);
   
endmodule // fifo_1k
module fifo( data, wrreq, rdreq, rdclk, wrclk, aclr, q,
		    rdfull, rdempty, rdusedw, wrfull, wrempty, wrusedw);
   
   parameter width = 16;
   parameter depth = 1024;
   parameter addr_bits = 10;
   
   //`define rd_req 0;  // Set this to 0 for rd_ack, 1 for rd_req
   
   input [width-1:0] data;
   input 	     wrreq;
   input 	     rdreq;
   input 	     rdclk;
   input 	     wrclk;
   input 	     aclr;
   output [width-1:0] q;
   output 	      rdfull;
   output 	      rdempty;
   output reg [addr_bits-1:0]  rdusedw;
   output wrfull;
   output wrempty;
   output reg [addr_bits-1:0]  wrusedw;
   
   reg [width-1:0] mem [0:depth-1];
   reg [addr_bits-1:0] 	      rdptr;
   reg [addr_bits-1:0] 	      wrptr;
   
`ifdef rd_req
   reg [width-1:0]    q;
`else
   wire [width-1:0]   q;
`endif
   
   integer 	      i;
   
   always @( aclr)
     begin
	wrptr <= #1 0;
	rdptr <= #1 0;
	for(i=0;i<depth;i=i+1)
	  mem[i] <= #1 0;
     end
   
   always @(posedge wrclk)
     if(wrreq)
       begin
	  wrptr <= #1 wrptr+1;
	  mem[wrptr] <= #1 data;
       end
   
   always @(posedge rdclk)
     if(rdreq)
       begin
   	  rdptr <= #1 rdptr+1;
`ifdef rd_req
	  q <= #1 mem[rdptr];
`endif
       end
   
`ifdef rd_req
`else
   assign q = mem[rdptr];
`endif
   
   // Fix these
   always @(posedge wrclk)
     wrusedw <= #1 wrptr - rdptr;
   
   always @(posedge rdclk)
     rdusedw <= #1 wrptr - rdptr;
   
   assign wrempty = (wrusedw == 0);
   assign wrfull = (wrusedw == depth-1);
   
   assign rdempty = (rdusedw == 0);
   assign rdfull = (rdusedw == depth-1);
   
endmodule // fifo
module fifo_1c_2k ( data, wrreq, rdreq, rdclk, wrclk, aclr, q,
		    rdfull, rdempty, rdusedw, wrfull, wrempty, wrusedw);

   parameter width = 32;
   parameter depth = 2048;
   //`define rd_req 0;  // Set this to 0 for rd_ack, 1 for rd_req
      
   input [31:0] data;
   input 	wrreq;
   input 	rdreq;
   input 	rdclk;
   input 	wrclk;
   input 	aclr;
   output [31:0] q;
   output 	 rdfull;
   output 	 rdempty;
   output [10:0]  rdusedw;
   output 	 wrfull;
   output 	 wrempty;
   output [10:0]  wrusedw;
   
   reg [width-1:0] mem [0:depth-1];
   reg [7:0] 	   rdptr;
   reg [7:0] 	   wrptr;
   
`ifdef rd_req
   reg [width-1:0] q;
`else
   wire [width-1:0] q;
`endif
   
   reg [10:0] 	    rdusedw;
   reg [10:0] 	    wrusedw;
   
   integer 	    i;

   always @( aclr)
     begin
	wrptr <= #1 0;
	rdptr <= #1 0;
	for(i=0;i<depth;i=i+1)
	  mem[i] <= #1 0;
     end
   
   always @(posedge wrclk)
     if(wrreq)
       begin
	  wrptr <= #1 wrptr+1;
	  mem[wrptr] <= #1 data;
       end
   
   always @(posedge rdclk)
     if(rdreq)
       begin
   	  rdptr <= #1 rdptr+1;
`ifdef rd_req
	  q <= #1 mem[rdptr];
`endif
       end
   
`ifdef rd_req
`else
   assign q = mem[rdptr];
`endif
   
   // Fix these
   always @(posedge wrclk)
     wrusedw <= #1 wrptr - rdptr;
   
   always @(posedge rdclk)
     rdusedw <= #1 wrptr - rdptr;

   assign wrempty = (wrusedw == 0);
   assign wrfull = (wrusedw == depth-1);
   
   assign rdempty = (rdusedw == 0);
   assign rdfull = (rdusedw == depth-1);
   
endmodule // fifo_1c_2k
module fifo_1c_4k ( data, wrreq, rdreq, rdclk, wrclk, aclr, q,
		    rdfull, rdempty, rdusedw, wrfull, wrempty, wrusedw);

   parameter width = 32;
   parameter depth = 4096;
   //`define rd_req 0;  // Set this to 0 for rd_ack, 1 for rd_req
      
   input [31:0] data;
   input 	wrreq;
   input 	rdreq;
   input 	rdclk;
   input 	wrclk;
   input 	aclr;
   output [31:0] q;
   output 	 rdfull;
   output 	 rdempty;
   output [7:0]  rdusedw;
   output 	 wrfull;
   output 	 wrempty;
   output [7:0]  wrusedw;
   
   reg [width-1:0] mem [0:depth-1];
   reg [7:0] 	   rdptr;
   reg [7:0] 	   wrptr;
   
`ifdef rd_req
   reg [width-1:0] q;
`else
   wire [width-1:0] q;
`endif
   
   reg [7:0] 	    rdusedw;
   reg [7:0] 	    wrusedw;
   
   integer 	    i;

   always @( aclr)
     begin
	wrptr <= #1 0;
	rdptr <= #1 0;
	for(i=0;i<depth;i=i+1)
	  mem[i] <= #1 0;
     end
   
   always @(posedge wrclk)
     if(wrreq)
       begin
	  wrptr <= #1 wrptr+1;
	  mem[wrptr] <= #1 data;
       end
   
   always @(posedge rdclk)
     if(rdreq)
       begin
   	  rdptr <= #1 rdptr+1;
`ifdef rd_req
	  q <= #1 mem[rdptr];
`endif
       end
   
`ifdef rd_req
`else
   assign q = mem[rdptr];
`endif
   
   // Fix these
   always @(posedge wrclk)
     wrusedw <= #1 wrptr - rdptr;
   
   always @(posedge rdclk)
     rdusedw <= #1 wrptr - rdptr;
   
   
endmodule // fifo_1c_4k
module fifo_4k_18
  (input  [17:0] data,
   input         wrreq,
   input         wrclk,
   output 	 wrfull,
   output 	 wrempty,
   output [11:0] wrusedw,

   output [17:0] q,
   input         rdreq,
   input         rdclk,
   output 	 rdfull,
   output 	 rdempty,
   output [11:0] rdusedw,

   input 	 aclr );

fifo #(.width(18),.depth(4096),.addr_bits(12)) fifo_4k 
  ( data, wrreq, rdreq, rdclk, wrclk, aclr, q,
    rdfull, rdempty, rdusedw, wrfull, wrempty, wrusedw);
   
endmodule // fifo_4k_18
module bustri (data,
	       enabledt,
	       tridata);
   
   input [15:0]  data;
   input 	 enabledt;
   inout [15:0]  tridata;
   
   assign 	 tridata = enabledt ? data :16'bz;
   
endmodule // bustri
module fifo_1c_1k ( data, wrreq, rdreq, rdclk, wrclk, aclr, q,
		    rdfull, rdempty, rdusedw, wrfull, wrempty, wrusedw);

   parameter width = 32;
   parameter depth = 1024;
   //`define rd_req 0;  // Set this to 0 for rd_ack, 1 for rd_req
      
   input [31:0] data;
   input 	wrreq;
   input 	rdreq;
   input 	rdclk;
   input 	wrclk;
   input 	aclr;
   output [31:0] q;
   output 	 rdfull;
   output 	 rdempty;
   output [9:0]  rdusedw;
   output 	 wrfull;
   output 	 wrempty;
   output [9:0]  wrusedw;
   
   reg [width-1:0] mem [0:depth-1];
   reg [7:0] 	   rdptr;
   reg [7:0] 	   wrptr;
   
`ifdef rd_req
   reg [width-1:0] q;
`else
   wire [width-1:0] q;
`endif
   
   reg [9:0] 	    rdusedw;
   reg [9:0] 	    wrusedw;
   
   integer 	    i;

   always @( aclr)
     begin
	wrptr <= #1 0;
	rdptr <= #1 0;
	for(i=0;i<depth;i=i+1)
	  mem[i] <= #1 0;
     end
   
   always @(posedge wrclk)
     if(wrreq)
       begin
	  wrptr <= #1 wrptr+1;
	  mem[wrptr] <= #1 data;
       end
   
   always @(posedge rdclk)
     if(rdreq)
       begin
   	  rdptr <= #1 rdptr+1;
`ifdef rd_req
	  q <= #1 mem[rdptr];
`endif
       end
   
`ifdef rd_req
`else
   assign q = mem[rdptr];
`endif
   
   // Fix these
   always @(posedge wrclk)
     wrusedw <= #1 wrptr - rdptr;
   
   always @(posedge rdclk)
     rdusedw <= #1 wrptr - rdptr;

   assign wrempty = (wrusedw == 0);
   assign wrfull = (wrusedw == depth-1);

   assign rdempty = (rdusedw == 0);
   assign rdfull = (rdusedw == depth-1);
   
endmodule // fifo_1c_1k
module fullchip_tb();

`include "usrp_tasks.v"

fullchip fullchip
  (
   .clk_120mhz(clk_120mhz),
   .reset(reset),
   .enable_rx(enable_rx),
   .enable_tx(enable_tx),
   .SLD(serload),
   .SEN(serenable),
   .clear_status(),
   .SDI(serdata),
   .SCLK(serclk),
	  
   .adc1_data(adc1_data),
   .adc2_data(adc2_data),
   .adc3_data(adc1_data),
   .adc4_data(adc2_data),
   
   .dac1_data(dac1_data),
   .dac2_data(dac2_data),
   .dac3_data(),.dac4_data(),
   
   .adclk0(adclk),.adclk1(),
   
   .adc_oeb(),.adc_otr(4'b0),
   
   .clk_out(clk_out),
   
   .misc_pins(),
   
   // USB interface
   .usbclk(usbclk),.usbctl(usbctl),
   .usbrdy(usbrdy),.usbdata(usbdata)
   );	
	
	reg clk_120mhz;
	reg usbclk;
	reg reset;

	reg [11:0] adc1_data, adc2_data;
	wire [13:0] dac1_data, dac2_data;

	wire [5:0] usbctl;
	wire [5:0] usbrdy;

	wire [15:0] usbdata;

	reg WE, RD, OE;

        assign usbctl[0] = WE;
        assign usbctl[1] = RD;
        assign usbctl[2] = OE;
	assign usbctl[5:3] = 0;

        wire have_packet_rdy = usbrdy[1];
   
	reg tb_oe;
   initial tb_oe=1'b1;
   
	assign usbdata = tb_oe ? usbdatareg : 16'hxxxx;
	reg serload, serenable, serclk, serdata;
	reg enable_tx, enable_rx;
	reg [15:0] usbdatareg;

///////////////////////////////////////////////
//  Simulation Control
initial
begin
	$dumpfile("fullchip_tb.vcd");
	$dumpvars(0, fullchip_tb);
end

//initial #1000000 $finish;

///////////////////////////////////////////////
//  Monitors

//initial $monitor(dac1_data);

///////////////////////////////////////////////
// Clock and reset

initial clk_120mhz = 0;
initial usbclk = 0;
always #24 clk_120mhz = ~clk_120mhz;
always #60 usbclk = ~usbclk;

initial reset = 1'b1;
initial #500 reset = 1'b0;

/////////////////////////////////////////////////
// Run AD input

always @(posedge adclk)	 adc1_data <= #1 12'd1234;
always @(posedge adclk)	 adc2_data <= #1 12'd1234;

/////////////////////////////////////////////////
// USB interface

  initial 
    begin
       initialize_usb;
       #30000 @(posedge usbclk);
       burst_usb_write(257);
       
       #30000 burst_usb_read(256);
       #10000 $finish;
   
//	repeat(30)
//	begin
//		write_from_usb;
//		read_from_usb;
//	end
end

/////////////////////////////////////////////////
// TX and RX enable

initial enable_tx = 1'b0;
initial #40000 enable_tx = 1'b1;
initial enable_rx = 1'b0;
initial #40000 enable_rx = 1'b1;

//////////////////////////////////////////////////
// Set up control bus

initial 
begin
	#1000 send_config_word(`ch1in_freq,32'h0); // 1 MHz on 60 MHz clock
	send_config_word(`ch2in_freq,32'h0);
	send_config_word(`ch3in_freq,32'h0);
	send_config_word(`ch4in_freq,32'h0);
	send_config_word(`ch1out_freq,32'h01234567);
	send_config_word(`ch2out_freq,32'h0);
	send_config_word(`ch3out_freq,32'h0);
	send_config_word(`ch4out_freq,32'h0);
	send_config_word(`misc,32'h0);
	send_config_word(`rates,{8'd2,8'd12,8'h0f,8'h07});
	// adc, ext, interp, decim
end

/////////////////////////////////////////////////////////

endmodule
module cbus_tb;

`define ch1in_freq 0
`define ch2in_freq 1
`define ch3in_freq 2
`define ch4in_freq 3
`define ch1out_freq 4
`define ch2out_freq 5
`define ch3out_freq 6
`define ch4out_freq 7
`define rates 8
`define misc 9
  
   task send_config_word;
      input [7:0] addr;
      input [31:0] data;
      integer i;
      
      begin
	 #10 serenable = 1;
	 for(i=7;i>=0;i=i-1)
	   begin
	      #10 serdata = addr[i];
	      #10 serclk = 0;
	      #10 serclk = 1;
	      #10 serclk = 0;
	   end
	 for(i=31;i>=0;i=i-1)
	   begin
	      #10 serdata = data[i];
	      #10 serclk = 0;
	      #10 serclk = 1;
	      #10 serclk = 0;
	   end
	 #10 serenable = 0;
	 // #10 serclk = 1;
	 // #10 serclk = 0;
      end
   endtask // send_config_word
   
   initial $dumpfile("cbus_tb.vcd");
   initial $dumpvars(0,cbus_tb);

   initial reset = 1;
   initial #500 reset = 0;
      
   reg serclk, serdata, serenable, reset;
   wire SDO;
   
  control_bus control_bus
    ( .serial_clock(serclk),
      .serial_data_in(serdata),
      .enable(serenable),
      .reset(reset),
      .serial_data_out(SDO) );


   initial 
     begin
	#1000 send_config_word(8'd1,32'hDEAD_BEEF);
	#1000 send_config_word(8'd3,32'hDDEE_FF01);
	#1000 send_config_word(8'd19,32'hFFFF_FFFF);
	#1000 send_config_word(8'd23,32'h1234_FEDC);
	#1000 send_config_word(8'h80,32'h0);
	#1000 send_config_word(8'h81,32'h0);
	#1000 send_config_word(8'h82,32'h0);
	#1000 reset = 1;
	#1 $finish;
     end
   
endmodule // cbus_tb
module cic_decim_tb;

cic_decim #(.bitwidth(16),.stages(4))
   decim(clock,reset,enable,strobe_in,strobe_out,signal_in,signal_out);
	
   reg clock;
   reg reset;
   reg enable;
   wire strobe;
   reg [15:0] signal_in;
   wire [15:0] signal_out;

   assign      strobe_in = 1'b1;
   reg 	       strobe_out;

   always @(posedge clock)
     while(1)
       begin
	  @(posedge clock);
	  @(posedge clock);
	  @(posedge clock);
	  @(posedge clock);
	  strobe_out <= 1'b1;
	  @(posedge clock);
	  @(posedge clock);
	  @(posedge clock);
	  @(posedge clock);
	  strobe_out <= 1'b0;
       end
   
   initial clock = 0;
   always #50 clock = ~clock;
   
   initial reset = 1;
   initial #1000 reset = 0;

   initial enable = 0;
   initial #2000 enable = 1;
   
   initial signal_in = 16'h1;
   initial #500000 signal_in = 16'h7fff;
   initial #1000000 signal_in = 16'h8000;
   initial #1500000 signal_in = 16'hffff;

   
   initial $dumpfile("decim.vcd");
   initial $dumpvars(0,cic_decim_tb);

   initial #10000000 $finish;
   
endmodule // cic_decim_tb
module shifter(input wire [33:0] in, output wire [15:0] out, input wire [7:0] shift);
   // Wish we could do  assign out = in[15+shift:shift];

   reg [15:0] quotient, remainder;
   wire [15:0] out_unclipped;
   reg [18:0]  msbs;
   wire        in_range;
   
   always @*
     case(shift)
       0 : quotient = in[15:0];
       1 : quotient = in[16:1];
       2 : quotient = in[17:2];
       3 : quotient = in[18:3];
       4 : quotient = in[19:4];
       5 : quotient = in[20:5];
       6 : quotient = in[21:6];
       7 : quotient = in[22:7];
       8 : quotient = in[23:8];
       9 : quotient = in[24:9];
       10 : quotient = in[25:10];
       11 : quotient = in[26:11];
       12 : quotient = in[27:12];
       13 : quotient = in[28:13];
       14 : quotient = in[29:14];
       15 : quotient = in[30:15];
       16 : quotient = in[31:16];
       17 : quotient = in[32:17];
       18 : quotient = in[33:18];
       default : quotient = in[15:0];
     endcase // case(shift)

   always @*
     case(shift)
       0 : remainder = 16'b0;
       1 : remainder = {in[0],15'b0};
       2 : remainder = {in[1:0],14'b0};
       3 : remainder = {in[2:0],13'b0};
       4 : remainder = {in[3:0],12'b0};
       5 : remainder = {in[4:0],11'b0};
       6 : remainder = {in[5:0],10'b0};
       7 : remainder = {in[6:0],9'b0};
       8 : remainder = {in[7:0],8'b0};
       9 : remainder = {in[8:0],7'b0};
       10 : remainder = {in[9:0],6'b0};
       11 : remainder = {in[10:0],5'b0};
       12 : remainder = {in[11:0],4'b0};
       13 : remainder = {in[12:0],3'b0};
       14 : remainder = {in[13:0],2'b0};
       15 : remainder = {in[14:0],1'b0};
       16 : remainder = in[15:0];
       17 : remainder = in[16:1];
       18 : remainder = in[17:2];
       default : remainder = 16'b0;
     endcase // case(shift)

   always @*
     case(shift)
       0 : msbs = in[33:15];
       1 : msbs = {in[33],in[33:16]};
       2 : msbs = {{2{in[33]}},in[33:17]};
       3 : msbs = {{3{in[33]}},in[33:18]};
       4 : msbs = {{4{in[33]}},in[33:19]};
       5 : msbs = {{5{in[33]}},in[33:20]};
       6 : msbs = {{6{in[33]}},in[33:21]};
       7 : msbs = {{7{in[33]}},in[33:22]};
       8 : msbs = {{8{in[33]}},in[33:23]};
       9 : msbs = {{9{in[33]}},in[33:24]};
       10 : msbs = {{10{in[33]}},in[33:25]};
       11 : msbs = {{11{in[33]}},in[33:26]};
       12 : msbs = {{12{in[33]}},in[33:27]};
       13 : msbs = {{13{in[33]}},in[33:28]};
       14 : msbs = {{14{in[33]}},in[33:29]};
       15 : msbs = {{15{in[33]}},in[33:30]};
       16 : msbs = {{16{in[33]}},in[33:31]};
       17 : msbs = {{17{in[33]}},in[33:32]};
       18 : msbs = {{18{in[33]}},in[33]};
       default : msbs = in[33:15];
     endcase // case(shift)

   assign     in_range = &msbs | ~(|msbs);
   assign     out_unclipped = quotient + (in[33] & |remainder);
   assign     out = in_range ? out_unclipped : {in[33],{15{~in[33]}}};
   
endmodule // shifter
module mrfm_compensator (input clock, input reset, input strobe_in,
			 input serial_strobe, input [6:0] serial_addr, input [31:0] serial_data,
			 input [15:0] i_in, input [15:0] q_in, output reg [15:0] i_out, output reg [15:0] q_out);

   wire [15:0] 			      a11,a12,a21,a22;
   reg [15:0] 			      i_in_reg, q_in_reg;
   wire [30:0] 			      product;
   reg [3:0] 			      phase;
   wire [15:0] 			      data,coeff;
   wire [7:0] 			      shift;
   wire [33:0] 			      accum;
   wire [15:0] 			      scaled_accum;
   wire enable_acc;

   setting_reg #(`FR_MRFM_COMP_A11) sr_a11(.clock(clock),.reset(reset),
					   .strobe(serial_strobe),.addr(serial_addr),.in(serial_data),
					   .out(a11),.changed());
   setting_reg #(`FR_MRFM_COMP_A12) sr_a12(.clock(clock),.reset(reset),
					   .strobe(serial_strobe),.addr(serial_addr),.in(serial_data),
					   .out(a12),.changed());
   setting_reg #(`FR_MRFM_COMP_A21) sr_a21(.clock(clock),.reset(reset),
					   .strobe(serial_strobe),.addr(serial_addr),.in(serial_data),
					   .out(a21),.changed());
   setting_reg #(`FR_MRFM_COMP_A22) sr_a22(.clock(clock),.reset(reset),
					   .strobe(serial_strobe),.addr(serial_addr),.in(serial_data),
					   .out(a22),.changed());
   setting_reg #(`FR_MRFM_COMP_SHIFT) sr_cshift(.clock(clock),.reset(reset),
						.strobe(serial_strobe),.addr(serial_addr),.in(serial_data),
						.out(shift),.changed());
   
   mult mult (.clock(clock),.x(data),.y(coeff),.product(product),.enable_in(1'b1),.enable_out() );
   acc acc (.clock(clock),.reset(reset),.clear(clear_acc),.enable_in(enable_acc),.enable_out(),
	    .addend(product),.sum(accum) );   
   shifter shifter (.in(accum),.out(scaled_accum),.shift(shift));
   
   always @(posedge clock)
     if(reset)
       begin
	  i_in_reg <= #1 16'd0;
	  q_in_reg <= #1 16'd0;
       end
     else if(strobe_in)
       begin
	  i_in_reg <= #1 i_in;
	  q_in_reg <= #1 q_in;
       end	  

   always @(posedge clock)
     if(reset)
       phase <= #1 4'd0;
     else if(strobe_in)
       phase <= #1 4'd1;
     else if(strobe_in != 4'd8)
       phase <= #1 phase + 4'd1;

   assign data = ((phase == 4'd1)||(phase === 4'd4)) ? i_in_reg : 
	  ((phase == 4'd2)||(phase == 4'd5)) ? q_in_reg : 16'd0;

   assign coeff = (phase == 4'd1) ? a11 : (phase == 4'd2) ? a12 : 
	  (phase == 4'd4) ? a21 : (phase == 4'd5) ? a22 : 16'd0;

   assign clear_acc = (phase == 4'd0) || (phase == 4'd1) || (phase == 4'd4) || (phase==4'd8);
   assign enable_acc = ~clear_acc;
   
   always @(posedge clock)
     if(reset)
       i_out <= #1 16'd0;
     else if(phase == 4'd4)
       i_out <= #1 scaled_accum;

   always @(posedge clock)
     if(reset)
       q_out <= #1 16'd0;
     else if(phase == 4'd7)
       q_out <= #1 scaled_accum;
   
       
endmodule // mrfm_compensator
module pipe(
    input clk,
    input reset,
    input WE,
    input isDB_in, Overflow_in,
    input [31:0] Instr_in, pc_in, pc8_in, RegData1_in, RegData2_in, ImmEXT_in, ALUout_in, DM_RD_in, CP0_RD_in,
    input [4:0] RegA3_in, ExcCode_in,
    output reg isDB_out, Overflow_out,
    output reg [31:0] Instr_out, pc_out, pc8_out, RegData1_out, RegData2_out, ImmEXT_out, ALUout_out, DM_RD_out, CP0_RD_out,
    output reg [4:0] RegA3_out, ExcCode_out
);

    initial begin
        Instr_out = 0;
        pc_out = 32'h0000_3000;
        pc8_out = 0;
        RegA3_out = 0;
        RegData1_out = 0;
        RegData2_out = 0;
        ImmEXT_out = 0;
        ALUout_out = 0;
        RegData2_out = 0;
        DM_RD_out = 0;
        CP0_RD_out = 0;
        isDB_out = 0;
        ExcCode_out = 0;
        Overflow_out = 0;
    end

    always @(posedge clk) begin
        if(reset) begin
            Instr_out <= 0;
            pc_out <= 32'h0000_3000;
            pc8_out <= 0;
            RegA3_out <= 0;
            RegData1_out <= 0;
            RegData2_out <= 0;
            ImmEXT_out <= 0;
            ALUout_out <= 0;
            DM_RD_out <= 0;
            CP0_RD_out <= 0;
            isDB_out <= 0;
            ExcCode_out <= 0;
            Overflow_out <= 0;
        end
        else if(WE) begin
            Instr_out <= Instr_in;
            pc_out <= pc_in;
            pc8_out <= pc8_in;
            RegA3_out <= RegA3_in;
            RegData1_out <= RegData1_in;
            RegData2_out <= RegData2_in;
            ImmEXT_out <= ImmEXT_in;
            ALUout_out <= ALUout_in;
            DM_RD_out <= DM_RD_in;
            CP0_RD_out <= CP0_RD_in;
            isDB_out <= isDB_in;
            ExcCode_out <= ExcCode_in;
            Overflow_out <= Overflow_in;
        end
    end 

endmodule // pipe
module grf(
    input clk,
    input reset,
    input WE,
    input [4:0] A1,
    input [4:0] A2,
    input [4:0] A3,
    input [31:0] WD,
    output [31:0] RD1,
    output [31:0] RD2
);

    reg [31:0] register[31:0];
    integer i;

    initial begin
        for(i=0; i<32; i=i+1) begin
            register[i] <= 32'h0000_0000;
        end
    end

    always @(posedge clk) begin
        if(reset) begin
            for(i=0; i<32; i=i+1)
                register[i] <= 32'h0000_0000;
        end
        else if(WE&&A3!=5'd0) begin
            register[A3] <= WD;
        end
    end

    assign RD1 =    (A1==5'd0)      ?   32'h0000_0000 : 
                    (A1==A3)&&WE    ?   WD : 
                                        register[A1];
    assign RD2 =    (A2==5'd0)      ?   32'h0000_0000 : 
                    (A2==A3)&&WE    ?   WD : 
                                        register[A2];

endmodule // grf
module TC(
    input clk,
    input reset,
    input [31:2] Addr,
    input WE,
    input [31:0] Din,
    output [31:0] Dout,
    output IRQ
    );

	reg [1:0] state;
	reg [31:0] mem [2:0];
	
	reg _IRQ;
	assign IRQ = `ctrl[3] & _IRQ;
	
	assign Dout = mem[Addr[3:2]];
	
	wire [31:0] load = Addr[3:2] == 0 ? {28'h0, Din[3:0]} : Din;
	
	integer i;
	always @(posedge clk) begin
		if(reset) begin
			state <= 0; 
			for(i = 0; i < 3; i = i+1) mem[i] <= 0;
			_IRQ <= 0;
		end
		else if(WE) begin
			// $display("%d@: *%h <= %h", $time, {Addr, 2'b00}, load);
			mem[Addr[3:2]] <= load;
		end
		else begin
			case(state)
				`IDLE : if(`ctrl[0]) begin
					state <= `LOAD;
					_IRQ <= 1'b0;
				end
				`LOAD : begin
					`count <= `preset;
					state <= `CNT;
				end
				`CNT  : 
					if(`ctrl[0]) begin
						if(`count > 1) `count <= `count-1;
						else begin
							`count <= 0;
							state <= `INT;
							_IRQ <= 1'b1;
						end
					end
					else state <= `IDLE;
				default : begin
					if(`ctrl[2:1] == 2'b00) `ctrl[0] <= 1'b0;
					else _IRQ <= 1'b0;
					state <= `IDLE;
				end
			endcase
		end
	end

endmodule
module ifetch(
    input clk, reset, WE, flush, epc_WE,
    input [1:0] NPCOp_ID,
    input [31:0] npcValue_ID, epcValue_MEM,
    output [31:0] pcValue_IF, Instr_IF,
    output [4:0] ExcCode_out
);

    wire [31:0] npcValue_IF;
    pc myPC(
        .clk(clk), .reset(reset), .WE(WE | flush),
        .npc(npcValue_IF), .pc(pcValue_IF)
    );
    im myIM(.addr(pcValue_IF), .Instr(Instr_IF));

    assign npcValue_IF =    (epc_WE)            ?   epcValue_MEM        :
                            (flush)             ?   32'h0000_4180       :
                            (NPCOp_ID==2'b00)   ?   pcValue_IF+32'd4    :
                                                    npcValue_ID;
    assign ExcCode_out =    (pcValue_IF[1:0]!=2'b00 || (pcValue_IF[31:12]!=20'h0000_3 && pcValue_IF[31:12]!=20'h0000_4)) ?
                            5'd4 : 5'd0;

endmodule // if