aboutsummaryrefslogtreecommitdiff
/*
 * This module transforms a Wishbone pipelined MASTER interface with 32-bit
 * data port and 8-bit granularity into one with 16-bit data port and 16-bit
 * granularity. It's just a wrapper, it is not considered a Wishbone SLAVE nor
 * MASTER by itself (although it could be presented that way). See Wishbone
 * datasheets of data interfaces in stack_machine.v and wrapped_stack_machine.v.
 */

`default_nettype none

module interface_wrapper
  (
   input wire 	      CLK_I,
   input wire 	      RST_I,

   output wire 	      RAW_ACK_I,
   output wire 	      RAW_ERR_I, /* We'll start using it soon */
   input wire [20:0]  RAW_ADR_O,
   output wire [31:0] RAW_DAT_I,
   input wire [31:0]  RAW_DAT_O,
   input wire [3:0]   RAW_SEL_O,
   input wire 	      RAW_STB_O,
   input wire 	      RAW_CYC_O,
   input wire 	      RAW_WE_O,
   output wire 	      RAW_STALL_I,

   input wire 	      WRAPPED_ACK_I,
   output wire [19:0] WRAPPED_ADR_O,
   input wire [15:0]  WRAPPED_DAT_I,
   output wire [15:0] WRAPPED_DAT_O,
   output wire 	      WRAPPED_STB_O,
   output wire 	      WRAPPED_CYC_O,
   output wire 	      WRAPPED_WE_O,
   input wire 	      WRAPPED_STALL_I
   );

   wire 	      raw_request_wanted;
   wire 	      raw_request_completes;
   wire 	      wrapped_request_sent;
   wire 	      wrapped_request_completes;
   assign raw_request_wanted = RAW_CYC_O && RAW_STB_O;
   assign raw_request_completes = RAW_CYC_O && RAW_ACK_I;
   assign wrapped_request_sent = WRAPPED_CYC_O && WRAPPED_STB_O &&
				 !WRAPPED_STALL_I;
   assign wrapped_request_completes = WRAPPED_CYC_O && WRAPPED_ACK_I;

   /* "Parsing" raw command */
   wire 	      nothing_selected;
   wire [1:0] 	      highest_selected_byte;
   wire [1:0] 	      transfers_needed;
   wire 	      start_with_read;
   assign nothing_selected = RAW_SEL_O == 4'b0;
   assign highest_selected_byte = RAW_SEL_O[3] ? 3 :
				  RAW_SEL_O[2] ? 2 :
				  RAW_SEL_O[1] ? 1 : 0;
   assign transfers_needed = nothing_selected ? 1 :
			     (RAW_ADR_O[0] + highest_selected_byte + 2) / 2;
   assign start_with_read = !RAW_WE_O || RAW_ADR_O[0] ||
			    RAW_SEL_O[0] != RAW_SEL_O[1] ||
			    RAW_SEL_O[2] != RAW_SEL_O[3] ||
			    nothing_selected;

   /* Sending commands */
   reg [1:0] 	      left_to_send;
   reg [19:0] 	      ADR;
   reg 		      WE;
   reg 		      STB;
   reg [47:0] 	      write_data;

   /* Receiving responses */
   reg [31:0] 	      received_data_part;
   reg [1:0] 	      acks_waited_for;
   reg [20:0] 	      saved_ADR;
   reg [1:0] 	      writes_back_needed;
   reg [4:0] 	      write_mask;

   wire [47:0] 	      received_data;
   wire 	      command_sequence_finishes;
   wire 	      can_accept_raw_command;
   assign received_data = {received_data_part, WRAPPED_DAT_I};
   assign command_sequence_finishes = acks_waited_for == 1 && WRAPPED_ACK_I;
   assign can_accept_raw_command = acks_waited_for == 0 ||
				   (writes_back_needed == 0 &&
				    command_sequence_finishes);

   assign RAW_ACK_I = writes_back_needed == 0 && command_sequence_finishes;
   assign RAW_DAT_I = saved_ADR[0] ? received_data >> 8 : received_data;
   assign RAW_STALL_I = !can_accept_raw_command;

   assign WRAPPED_CYC_O = RAW_CYC_O;
   assign WRAPPED_ADR_O = ADR;
   assign WRAPPED_WE_O = WE;
   assign WRAPPED_STB_O = STB;
   assign WRAPPED_DAT_O = write_data[15:0];

   always @ (posedge CLK_I) begin
      if (wrapped_request_sent) begin
	 /* Variable assignments here are overridden further down */

	 left_to_send <= left_to_send - 1;

	 if (WE)
	   ADR <= ADR + 1;
	 else
	   ADR <= ADR - 1;

	 if (left_to_send == 1)
	   STB <= 0;

	 if (WE)
	   write_data <= {16'bx, write_data[47:16]};
      end // if (wrapped_request_sent)

      if (wrapped_request_completes) begin
	 received_data_part <= {received_data_part[15:0], WRAPPED_DAT_I};
	 acks_waited_for <= acks_waited_for - 1; /* might get overridden */
      end

      if (writes_back_needed != 0 && command_sequence_finishes) begin
	 /* Write data back */
	 left_to_send <= writes_back_needed;
	 ADR <= saved_ADR[20:1];
	 WE <= 1;
	 STB <= 1;

	 write_data[47:40] <= received_data[47:40];
	 if (!write_mask[4])
	   write_data[39:32] <= received_data[39:32];
	 if (!write_mask[3])
	   write_data[31:24] <= received_data[31:24];
	 if (!write_mask[2])
	   write_data[23:16] <= received_data[23:16];
	 if (!write_mask[1])
	   write_data[15:8] <= received_data[15:8];
	 if (!write_mask[0])
	   write_data[7:0] <= received_data[7:0];

	 acks_waited_for <= writes_back_needed;
	 writes_back_needed <= 0;
      end // if (writes_back_needed != 0 && command_sequence_finishes)

      if (raw_request_wanted && can_accept_raw_command) begin
	 /* Setting up for sending commands */
	 left_to_send <= transfers_needed;

	 if (start_with_read)
	   ADR <= RAW_ADR_O[20:1] + transfers_needed - 1;
	 else
	   ADR <= RAW_ADR_O[20:1];

	 WE <= !start_with_read;
	 STB <= 1;

	 if (RAW_ADR_O[0])
	   write_data <= {8'bx, RAW_DAT_O, 8'bx};
	 else
	   write_data <= {16'bx, RAW_DAT_O};

	 /* Setting up for receiving responses */
	 acks_waited_for <= transfers_needed;
	 saved_ADR <= RAW_ADR_O;

	 if (RAW_WE_O && start_with_read && !nothing_selected)
	   writes_back_needed <= transfers_needed;
	 else
	   writes_back_needed <= 0;

	 if (RAW_ADR_O[0])
	   write_mask <= {RAW_SEL_O, 1'b0};
	 else
	   write_mask <= {1'b0, RAW_SEL_O};
      end // if (raw_request_wanted && can_accept_raw_command)

      /* Override what's needed */
      if (RST_I) begin
	 left_to_send <= 0;
 	 STB <= 0;
 	 acks_waited_for <= 0;
 	 writes_back_needed <= 0;
      end
   end // always @ (posedge CLK_I)

`ifdef SIMULATION
   /* Avoid undefined values */
   initial begin
      left_to_send <= 0;
      STB <= 0;
      acks_waited_for <= 0;
      writes_back_needed <= 0;
   end
`endif
endmodule // interface_wrapper