mor1kx-bemicrocv/ip/altera/ddr3/altera_avalon_packets_to_ma...

1241 lines
50 KiB
Verilog

// (C) 2001-2015 Altera Corporation. All rights reserved.
// Your use of Altera Corporation's design tools, logic functions and other
// software and tools, and its AMPP partner logic functions, and any output
// files any of the foregoing (including device programming or simulation
// files), and any associated documentation or information are expressly subject
// to the terms and conditions of the Altera Program License Subscription
// Agreement, Altera MegaCore Function License Agreement, or other applicable
// license agreement, including, without limitation, that your use is for the
// sole purpose of programming logic devices manufactured by Altera and sold by
// Altera or its authorized distributors. Please refer to the applicable
// agreement for further details.
// --------------------------------------------------------------------------------
//| Avalon ST Packets to MM Master Transaction Component
// --------------------------------------------------------------------------------
`timescale 1ns / 100ps
// --------------------------------------------------------------------------------
//| Fast Transaction Master
// --------------------------------------------------------------------------------
module altera_avalon_packets_to_master (
// Interface: clk
input wire clk,
input wire reset_n,
// Interface: ST in
output wire in_ready,
input wire in_valid,
input wire [ 7: 0] in_data,
input wire in_startofpacket,
input wire in_endofpacket,
// Interface: ST out
input wire out_ready,
output wire out_valid,
output wire [ 7: 0] out_data,
output wire out_startofpacket,
output wire out_endofpacket,
// Interface: MM out
output wire [31: 0] address,
input wire [31: 0] readdata,
output wire read,
output wire write,
output wire [ 3: 0] byteenable,
output wire [31: 0] writedata,
input wire waitrequest,
input wire readdatavalid
);
wire [ 35: 0] fifo_readdata;
wire fifo_read;
wire fifo_empty;
wire [ 35: 0] fifo_writedata;
wire fifo_write;
wire fifo_write_waitrequest;
// ---------------------------------------------------------------------
//| Parameter Declarations
// ---------------------------------------------------------------------
parameter EXPORT_MASTER_SIGNALS = 0;
parameter FIFO_DEPTHS = 2;
parameter FIFO_WIDTHU = 1;
parameter FAST_VER = 0;
generate
if (FAST_VER) begin
packets_to_fifo p2f (
.clk (clk),
.reset_n (reset_n),
.in_ready (in_ready),
.in_valid (in_valid),
.in_data (in_data),
.in_startofpacket (in_startofpacket),
.in_endofpacket (in_endofpacket),
.address (address),
.readdata (readdata),
.read (read),
.write (write),
.byteenable (byteenable),
.writedata (writedata),
.waitrequest (waitrequest),
.readdatavalid (readdatavalid),
.fifo_writedata (fifo_writedata),
.fifo_write (fifo_write),
.fifo_write_waitrequest (fifo_write_waitrequest)
);
fifo_to_packet f2p (
.clk (clk),
.reset_n (reset_n),
.out_ready (out_ready),
.out_valid (out_valid),
.out_data (out_data),
.out_startofpacket (out_startofpacket),
.out_endofpacket (out_endofpacket),
.fifo_readdata (fifo_readdata),
.fifo_read (fifo_read),
.fifo_empty (fifo_empty)
);
fifo_buffer #(
.FIFO_DEPTHS(FIFO_DEPTHS),
.FIFO_WIDTHU(FIFO_WIDTHU)
) fb (
.wrclock (clk),
.reset_n (reset_n),
.avalonmm_write_slave_writedata (fifo_writedata),
.avalonmm_write_slave_write (fifo_write),
.avalonmm_write_slave_waitrequest (fifo_write_waitrequest),
.avalonmm_read_slave_readdata (fifo_readdata),
.avalonmm_read_slave_read (fifo_read),
.avalonmm_read_slave_waitrequest (fifo_empty)
);
end else begin
packets_to_master p2m (
.clk (clk),
.reset_n (reset_n),
.in_ready (in_ready),
.in_valid (in_valid),
.in_data (in_data),
.in_startofpacket (in_startofpacket),
.in_endofpacket (in_endofpacket),
.address (address),
.readdata (readdata),
.read (read),
.write (write),
.byteenable (byteenable),
.writedata (writedata),
.waitrequest (waitrequest),
.readdatavalid (readdatavalid),
.out_ready (out_ready),
.out_valid (out_valid),
.out_data (out_data),
.out_startofpacket (out_startofpacket),
.out_endofpacket (out_endofpacket)
);
end
endgenerate
endmodule
module packets_to_fifo (
// Interface: clk
input clk,
input reset_n,
// Interface: ST in
output reg in_ready,
input in_valid,
input [ 7: 0] in_data,
input in_startofpacket,
input in_endofpacket,
// Interface: MM out
output reg [31: 0] address,
input [31: 0] readdata,
output reg read,
output reg write,
output reg [ 3: 0] byteenable,
output reg [31: 0] writedata,
input waitrequest,
input readdatavalid,
// Interface: FIFO
// FIFO data format:
// | sop, eop, [1:0]valid, [31:0]data |
output reg [ 35: 0] fifo_writedata,
output reg fifo_write,
input wire fifo_write_waitrequest
);
// ---------------------------------------------------------------------
//| Command Declarations
// ---------------------------------------------------------------------
localparam CMD_WRITE_NON_INCR = 8'h00;
localparam CMD_WRITE_INCR = 8'h04;
localparam CMD_READ_NON_INCR = 8'h10;
localparam CMD_READ_INCR = 8'h14;
// ---------------------------------------------------------------------
//| Signal Declarations
// ---------------------------------------------------------------------
reg [ 3: 0] state;
reg [ 7: 0] command;
reg [ 1: 0] current_byte, byte_avail;
reg [ 15: 0] counter;
reg [ 31: 0] read_data_buffer;
reg [ 31: 0] fifo_data_buffer;
reg in_ready_0;
reg first_trans, last_trans, fifo_sop;
reg [ 3: 0] unshifted_byteenable;
wire enable;
localparam READY = 4'b0000,
GET_EXTRA = 4'b0001,
GET_SIZE1 = 4'b0010,
GET_SIZE2 = 4'b0011,
GET_ADDR1 = 4'b0100,
GET_ADDR2 = 4'b0101,
GET_ADDR3 = 4'b0110,
GET_ADDR4 = 4'b0111,
GET_WRITE_DATA = 4'b1000,
WRITE_WAIT = 4'b1001,
READ_ASSERT = 4'b1010,
READ_CMD_WAIT = 4'b1011,
READ_DATA_WAIT = 4'b1100,
PUSH_FIFO = 4'b1101,
PUSH_FIFO_WAIT = 4'b1110,
FIFO_CMD_WAIT = 4'b1111;
// ---------------------------------------------------------------------
//| Thingofamagick
// ---------------------------------------------------------------------
assign enable = (in_ready & in_valid);
always @* begin
in_ready = in_ready_0;
end
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
in_ready_0 <= 1'b0;
fifo_writedata <= 'b0;
fifo_write <= 1'b0;
fifo_sop <= 1'b0;
read <= 1'b0;
write <= 1'b0;
byteenable <= 'b0;
writedata <= 'b0;
address <= 'b0;
counter <= 'b0;
command <= 'b0;
first_trans <= 1'b0;
last_trans <= 1'b0;
state <= 'b0;
current_byte <= 'b0;
read_data_buffer <= 'b0;
unshifted_byteenable <= 'b0;
byte_avail <= 'b0;
fifo_data_buffer <= 'b0;
end else begin
address[1:0] <= 'b0;
in_ready_0 <= 1'b0;
if (counter > 3) unshifted_byteenable <= 4'b1111;
else if (counter == 3) unshifted_byteenable <= 4'b0111;
else if (counter == 2) unshifted_byteenable <= 4'b0011;
else if (counter == 1) unshifted_byteenable <= 4'b0001;
case (state)
READY : begin
in_ready_0 <= !fifo_write_waitrequest;
fifo_write <= 1'b0;
end
GET_EXTRA : begin
in_ready_0 <= 1'b1;
byteenable <= 'b0;
if (enable) state <= GET_SIZE1;
end
GET_SIZE1 : begin
in_ready_0 <= 1'b1;
//load counter on reads only
counter[15:8] <= command[4]?in_data:8'b0;
if (enable) state <= GET_SIZE2;
end
GET_SIZE2 : begin
in_ready_0 <= 1'b1;
//load counter on reads only
counter[7:0] <= command[4]?in_data:8'b0;
if (enable) state <= GET_ADDR1;
end
GET_ADDR1 : begin
in_ready_0 <= 1'b1;
first_trans <= 1'b1;
last_trans <= 1'b0;
address[31:24] <= in_data;
if (enable) state <= GET_ADDR2;
end
GET_ADDR2 : begin
in_ready_0 <= 1'b1;
address[23:16] <= in_data;
if (enable) state <= GET_ADDR3;
end
GET_ADDR3 : begin
in_ready_0 <= 1'b1;
address[15:8] <= in_data;
if (enable) state <= GET_ADDR4;
end
GET_ADDR4 : begin
in_ready_0 <= 1'b1;
address[7:2] <= in_data[7:2];
current_byte <= in_data[1:0];
if (enable) begin
if (command == CMD_WRITE_NON_INCR | command == CMD_WRITE_INCR) begin
state <= GET_WRITE_DATA; //writes
in_ready_0 <= 1'b1;
end
else if (command == CMD_READ_NON_INCR | command == CMD_READ_INCR) begin
state <= READ_ASSERT; //reads
in_ready_0 <= 1'b0;
end
else begin
//nops
//treat all unrecognized commands as nops as well
in_ready_0 <= 1'b0;
state <= FIFO_CMD_WAIT;
//| sop, eop, [1:0]valid, [31:0]data |
//| 1 , 1 , 2'b11 ,{counter,reserved_byte}|
fifo_writedata[7:0] <= (8'h80 | command);
fifo_writedata[35:8]<= {4'b1111,counter[7:0],counter[15:8],8'b0};
fifo_write <= 1'b1;
counter <= 0;
end
end
end
GET_WRITE_DATA : begin
in_ready_0 <= 1'b1;
if (enable) begin
counter <= counter + 1'b1;
//2 bit, should wrap by itself
current_byte <= current_byte + 1'b1;
if (in_endofpacket || current_byte == 3)
begin
in_ready_0 <= 1'b0;
write <= 1'b1;
state <= WRITE_WAIT;
end
end
if (in_endofpacket) begin
last_trans <= 1'b1;
end
// handle byte writes properly
// drive data pins based on addresses
case (current_byte)
0: begin
writedata[7:0] <= in_data;
byteenable[0] <= 1'b1;
end
1: begin
writedata[15:8] <= in_data;
byteenable[1] <= 1'b1;
end
2: begin
writedata[23:16] <= in_data;
byteenable[2] <= 1'b1;
end
3: begin
writedata[31:24] <= in_data;
byteenable[3] <= 1'b1;
end
endcase
end
WRITE_WAIT : begin
in_ready_0 <= 1'b0;
write <= 1'b1;
if (~waitrequest) begin
write <= 1'b0;
state <= GET_WRITE_DATA;
in_ready_0 <= 1'b1;
byteenable <= 'b0;
if (command[2] == 1'b1) begin
//increment address, but word-align it
address[31:2] <= (address[31:2] + 1'b1);
end
if (last_trans) begin
in_ready_0 <= 1'b0;
state <= FIFO_CMD_WAIT;
//| sop, eop, [1:0]valid, [31:0]data |
//| 1 , 1 , 2'b11 ,{counter,reserved_byte}|
fifo_writedata[7:0] <= (8'h80 | command);
fifo_writedata[35:8]<= {4'b1111,counter[7:0],counter[15:8],8'b0};
fifo_write <= 1'b1;
counter <= 0;
end
end
end
READ_ASSERT : begin
if (current_byte == 3) byteenable <= unshifted_byteenable << 3;
if (current_byte == 2) byteenable <= unshifted_byteenable << 2;
if (current_byte == 1) byteenable <= unshifted_byteenable << 1;
if (current_byte == 0) byteenable <= unshifted_byteenable;
read <= 1'b1;
fifo_write <= 1'b0;
state <= READ_CMD_WAIT;
end
READ_CMD_WAIT : begin
// number of valid byte
case (byteenable)
4'b0000 : byte_avail <= 1'b0;
4'b0001 : byte_avail <= 1'b0;
4'b0010 : byte_avail <= 1'b0;
4'b0100 : byte_avail <= 1'b0;
4'b1000 : byte_avail <= 1'b0;
4'b0011 : byte_avail <= 1'b1;
4'b0110 : byte_avail <= 1'b1;
4'b1100 : byte_avail <= 1'b1;
4'b0111 : byte_avail <= 2'h2;
4'b1110 : byte_avail <= 2'h2;
default : byte_avail <= 2'h3;
endcase
read_data_buffer <= readdata;
read <= 1;
// if readdatavalid, take the data and
// go directly to READ_SEND_ISSUE. This is for fixed
// latency slaves. Ignore waitrequest in this case,
// since this master does not issue pipelined reads.
//
// For variable latency slaves, once waitrequest is low
// the read command is accepted, so deassert read and
// go to READ_DATA_WAIT to wait for readdatavalid
if (readdatavalid) begin
state <= PUSH_FIFO;
read <= 0;
end else begin
if (~waitrequest) begin
state <= READ_DATA_WAIT;
read <= 0;
end
end
end
READ_DATA_WAIT : begin
read_data_buffer <= readdata;
if (readdatavalid) begin
state <= PUSH_FIFO;
end
end
PUSH_FIFO : begin
fifo_write <= 1'b0;
fifo_sop <= 1'b0;
if (first_trans) begin
first_trans <= 1'b0;
fifo_sop <= 1'b1;
end
case (current_byte)
3 : begin
fifo_data_buffer <= read_data_buffer >> 24;
counter <= counter - 1'b1;
end
2 : begin
fifo_data_buffer <= read_data_buffer >> 16;
if (counter == 1) counter <= 0;
else counter <= counter - 2'h2;
end
1 : begin
fifo_data_buffer <= read_data_buffer >> 8;
if (counter < 3) counter <= 0;
else counter <= counter - 2'h3;
end
default : begin
fifo_data_buffer <= read_data_buffer;
if (counter < 4) counter <= 0;
else counter <= counter - 3'h4;
end
endcase
current_byte <= 0;
state <= PUSH_FIFO_WAIT;
end
PUSH_FIFO_WAIT : begin
// pushd return packet with data
fifo_write <= 1'b1;
fifo_writedata <= {fifo_sop,(counter == 0)?1'b1:1'b0,byte_avail,fifo_data_buffer};
// count down on the number of bytes to read
// shift current byte location within word
// if increment address, add it, so the next read
// can use it, if more reads are required
// no more bytes to send - go to READY state
if (counter == 0) begin
state <= FIFO_CMD_WAIT;
end else if (command[2]== 1'b1) begin
//increment address, but word-align it
state <= FIFO_CMD_WAIT;
address[31:2] <= (address[31:2] + 1'b1);
end
end
FIFO_CMD_WAIT : begin
// back pressure if fifo_write_waitrequest
if (!fifo_write_waitrequest) begin
if (counter == 0) begin
state <= READY;
end else begin
state <= READ_ASSERT;
end
fifo_write <= 1'b0;
end
end
endcase
if (enable & in_startofpacket) begin
state <= GET_EXTRA;
command <= in_data;
in_ready_0 <= !fifo_write_waitrequest;
end
end // end else
end // end always block
endmodule
// --------------------------------------------------------------------------------
// FIFO buffer
// --------------------------------------------------------------------------------
// turn off superfluous verilog processor warnings
// altera message_level Level1
// altera message_off 10034 10035 10036 10037 10230 10240 10030
module fifo_buffer_single_clock_fifo (
// inputs:
aclr,
clock,
data,
rdreq,
wrreq,
// outputs:
empty,
full,
q
)
;
parameter FIFO_DEPTHS = 2;
parameter FIFO_WIDTHU = 1;
output empty;
output full;
output [ 35: 0] q;
input aclr;
input clock;
input [ 35: 0] data;
input rdreq;
input wrreq;
wire empty;
wire full;
wire [ 35: 0] q;
scfifo single_clock_fifo
(
.aclr (aclr),
.clock (clock),
.data (data),
.empty (empty),
.full (full),
.q (q),
.rdreq (rdreq),
.wrreq (wrreq)
);
defparam single_clock_fifo.add_ram_output_register = "OFF",
single_clock_fifo.lpm_numwords = FIFO_DEPTHS,
single_clock_fifo.lpm_showahead = "OFF",
single_clock_fifo.lpm_type = "scfifo",
single_clock_fifo.lpm_width = 36,
single_clock_fifo.lpm_widthu = FIFO_WIDTHU,
single_clock_fifo.overflow_checking = "ON",
single_clock_fifo.underflow_checking = "ON",
single_clock_fifo.use_eab = "OFF";
endmodule
// turn off superfluous verilog processor warnings
// altera message_level Level1
// altera message_off 10034 10035 10036 10037 10230 10240 10030
module fifo_buffer_scfifo_with_controls (
// inputs:
clock,
data,
rdreq,
reset_n,
wrreq,
// outputs:
empty,
full,
q
)
;
parameter FIFO_DEPTHS = 2;
parameter FIFO_WIDTHU = 1;
output empty;
output full;
output [ 35: 0] q;
input clock;
input [ 35: 0] data;
input rdreq;
input reset_n;
input wrreq;
wire empty;
wire full;
wire [ 35: 0] q;
wire wrreq_valid;
//the_scfifo, which is an e_instance
fifo_buffer_single_clock_fifo #(
.FIFO_DEPTHS(FIFO_DEPTHS),
.FIFO_WIDTHU(FIFO_WIDTHU)
) the_scfifo (
.aclr (~reset_n),
.clock (clock),
.data (data),
.empty (empty),
.full (full),
.q (q),
.rdreq (rdreq),
.wrreq (wrreq_valid)
);
assign wrreq_valid = wrreq & ~full;
endmodule
// turn off superfluous verilog processor warnings
// altera message_level Level1
// altera message_off 10034 10035 10036 10037 10230 10240 10030
module fifo_buffer (
// inputs:
avalonmm_read_slave_read,
avalonmm_write_slave_write,
avalonmm_write_slave_writedata,
reset_n,
wrclock,
// outputs:
avalonmm_read_slave_readdata,
avalonmm_read_slave_waitrequest,
avalonmm_write_slave_waitrequest
)
;
parameter FIFO_DEPTHS = 2;
parameter FIFO_WIDTHU = 1;
output [ 35: 0] avalonmm_read_slave_readdata;
output avalonmm_read_slave_waitrequest;
output avalonmm_write_slave_waitrequest;
input avalonmm_read_slave_read;
input avalonmm_write_slave_write;
input [ 35: 0] avalonmm_write_slave_writedata;
input reset_n;
input wrclock;
wire [ 35: 0] avalonmm_read_slave_readdata;
wire avalonmm_read_slave_waitrequest;
wire avalonmm_write_slave_waitrequest;
wire clock;
wire [ 35: 0] data;
wire empty;
wire full;
wire [ 35: 0] q;
wire rdreq;
wire wrreq;
//the_scfifo_with_controls, which is an e_instance
fifo_buffer_scfifo_with_controls #(
.FIFO_DEPTHS(FIFO_DEPTHS),
.FIFO_WIDTHU(FIFO_WIDTHU)
) the_scfifo_with_controls
(
.clock (clock),
.data (data),
.empty (empty),
.full (full),
.q (q),
.rdreq (rdreq),
.reset_n (reset_n),
.wrreq (wrreq)
);
//in, which is an e_avalon_slave
//out, which is an e_avalon_slave
assign data = avalonmm_write_slave_writedata;
assign wrreq = avalonmm_write_slave_write;
assign avalonmm_read_slave_readdata = q;
assign rdreq = avalonmm_read_slave_read;
assign clock = wrclock;
assign avalonmm_write_slave_waitrequest = full;
assign avalonmm_read_slave_waitrequest = empty;
endmodule
// --------------------------------------------------------------------------------
// fifo_buffer to Avalon-ST interface
// --------------------------------------------------------------------------------
module fifo_to_packet (
// Interface: clk
input clk,
input reset_n,
// Interface: ST out
input out_ready,
output reg out_valid,
output reg [ 7: 0] out_data,
output reg out_startofpacket,
output reg out_endofpacket,
// Interface: FIFO in
input [ 35: 0] fifo_readdata,
output reg fifo_read,
input fifo_empty
);
reg [ 1: 0] state;
reg enable, sent_all;
reg [ 1: 0] current_byte, byte_end;
reg first_trans, last_trans;
reg [ 23:0] fifo_data_buffer;
localparam POP_FIFO = 2'b00,
POP_FIFO_WAIT = 2'b01,
FIFO_DATA_WAIT = 2'b10,
READ_SEND_ISSUE = 2'b11;
always @* begin
enable = (!fifo_empty & sent_all);
end
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
fifo_data_buffer <= 'b0;
out_startofpacket <= 1'b0;
out_endofpacket <= 1'b0;
out_valid <= 1'b0;
out_data <= 'b0;
state <= 'b0;
fifo_read <= 1'b0;
current_byte <= 'b0;
byte_end <= 'b0;
first_trans <= 1'b0;
last_trans <= 1'b0;
sent_all <= 1'b1;
end else begin
if (out_ready) begin
out_startofpacket <= 1'b0;
out_endofpacket <= 1'b0;
end
case (state)
POP_FIFO : begin
if (out_ready) begin
out_startofpacket <= 1'b0;
out_endofpacket <= 1'b0;
out_valid <= 1'b0;
first_trans <= 1'b0;
last_trans <= 1'b0;
byte_end <= 'b0;
fifo_read <= 1'b0;
sent_all <= 1'b1;
end
// start poping fifo after all data sent and data available
if (enable) begin
fifo_read <= 1'b1;
out_valid <= 1'b0;
state <= POP_FIFO_WAIT;
end
end
POP_FIFO_WAIT : begin
//fifo latency of 1
fifo_read <= 1'b0;
state <= FIFO_DATA_WAIT;
end
FIFO_DATA_WAIT : begin
sent_all <= 1'b0;
first_trans <= fifo_readdata[35];
last_trans <= fifo_readdata[34];
out_data <= fifo_readdata[7:0];
fifo_data_buffer <= fifo_readdata[31:8];
byte_end <= fifo_readdata[33:32];
current_byte <= 1'b1;
out_valid <= 1'b1;
// first byte sop eop handling
if (fifo_readdata[35] & fifo_readdata[34] & (fifo_readdata[33:32] == 0)) begin
first_trans <= 1'b0;
last_trans <= 1'b0;
out_startofpacket <= 1'b1;
out_endofpacket <= 1'b1;
state <= POP_FIFO;
end else if (fifo_readdata[35] & (fifo_readdata[33:32] == 0)) begin
first_trans <= 1'b0;
out_startofpacket <= 1'b1;
state <= POP_FIFO;
end else if (fifo_readdata[35]) begin
first_trans <= 1'b0;
out_startofpacket <= 1'b1;
state <= READ_SEND_ISSUE;
end else if (fifo_readdata[34] & (fifo_readdata[33:32] == 0)) begin
last_trans <= 1'b0;
out_endofpacket <= 1'b1;
state <= POP_FIFO;
end else begin
state <= READ_SEND_ISSUE;
end
end
READ_SEND_ISSUE : begin
out_valid <= 1'b1;
sent_all <= 1'b0;
if (out_ready) begin
out_startofpacket <= 1'b0;
// last byte
if (last_trans & (current_byte == byte_end)) begin
last_trans <= 1'b0;
out_endofpacket <= 1'b1;
state <= POP_FIFO;
end
case (current_byte)
3: begin
out_data <= fifo_data_buffer[23:16];
end
2: begin
out_data <= fifo_data_buffer[15:8];
end
1: begin
out_data <= fifo_data_buffer[7:0];
end
default: begin
//out_data <= fifo_readdata[7:0];
end
endcase
current_byte <= current_byte + 1'b1;
if (current_byte == byte_end) begin
state <= POP_FIFO;
end else begin
state <= READ_SEND_ISSUE;
end
end
end
endcase
end
end
endmodule
// --------------------------------------------------------------------------------
//| Economy Transaction Master
// --------------------------------------------------------------------------------
module packets_to_master (
// Interface: clk
input clk,
input reset_n,
// Interface: ST in
output reg in_ready,
input in_valid,
input [ 7: 0] in_data,
input in_startofpacket,
input in_endofpacket,
// Interface: ST out
input out_ready,
output reg out_valid,
output reg [ 7: 0] out_data,
output reg out_startofpacket,
output reg out_endofpacket,
// Interface: MM out
output reg [31: 0] address,
input [31: 0] readdata,
output reg read,
output reg write,
output reg [ 3: 0] byteenable,
output reg [31: 0] writedata,
input waitrequest,
input readdatavalid
);
// ---------------------------------------------------------------------
//| Parameter Declarations
// ---------------------------------------------------------------------
parameter EXPORT_MASTER_SIGNALS = 0;
// ---------------------------------------------------------------------
//| Command Declarations
// ---------------------------------------------------------------------
localparam CMD_WRITE_NON_INCR = 8'h00;
localparam CMD_WRITE_INCR = 8'h04;
localparam CMD_READ_NON_INCR = 8'h10;
localparam CMD_READ_INCR = 8'h14;
// ---------------------------------------------------------------------
//| Signal Declarations
// ---------------------------------------------------------------------
reg [ 3: 0] state;
reg [ 7: 0] command;
reg [ 1: 0] current_byte; //, result_byte;
reg [ 15: 0] counter;
reg [ 23: 0] read_data_buffer;
reg in_ready_0;
reg first_trans, last_trans;
reg [ 3: 0] unshifted_byteenable;
wire enable;
localparam READY = 4'b0000,
GET_EXTRA = 4'b0001,
GET_SIZE1 = 4'b0010,
GET_SIZE2 = 4'b0011,
GET_ADDR1 = 4'b0100,
GET_ADDR2 = 4'b0101,
GET_ADDR3 = 4'b0110,
GET_ADDR4 = 4'b0111,
GET_WRITE_DATA = 4'b1000,
WRITE_WAIT = 4'b1001,
RETURN_PACKET = 4'b1010,
READ_ASSERT = 4'b1011,
READ_CMD_WAIT = 4'b1100,
READ_DATA_WAIT = 4'b1101,
READ_SEND_ISSUE= 4'b1110,
READ_SEND_WAIT = 4'b1111;
// ---------------------------------------------------------------------
//| Thingofamagick
// ---------------------------------------------------------------------
assign enable = (in_ready & in_valid);
always @*
// in_ready = in_ready_0 & out_ready;
in_ready = in_ready_0;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
in_ready_0 <= 1'b0;
out_startofpacket <= 1'b0;
out_endofpacket <= 1'b0;
out_valid <= 1'b0;
out_data <= 'b0;
read <= 1'b0;
write <= 1'b0;
byteenable <= 'b0;
writedata <= 'b0;
address <= 'b0;
counter <= 'b0;
command <= 'b0;
first_trans <= 1'b0;
last_trans <= 1'b0;
state <= 'b0;
current_byte <= 'b0;
// result_byte <= 'b0;
read_data_buffer <= 'b0;
unshifted_byteenable <= 'b0;
end else begin
address[1:0] <= 'b0;
if (out_ready) begin
out_startofpacket <= 1'b0;
out_endofpacket <= 1'b0;
out_valid <= 1'b0;
end
in_ready_0 <= 1'b0;
if (counter >= 3) unshifted_byteenable <= 4'b1111;
else if (counter == 3) unshifted_byteenable <= 4'b0111;
else if (counter == 2) unshifted_byteenable <= 4'b0011;
else if (counter == 1) unshifted_byteenable <= 4'b0001;
case (state)
READY : begin
out_valid <= 1'b0;
in_ready_0 <= 1'b1;
end
GET_EXTRA : begin
in_ready_0 <= 1'b1;
byteenable <= 'b0;
if (enable) state <= GET_SIZE1;
end
GET_SIZE1 : begin
in_ready_0 <= 1'b1;
//load counter on reads only
counter[15:8] <= command[4]?in_data:8'b0;
if (enable) state <= GET_SIZE2;
end
GET_SIZE2 : begin
in_ready_0 <= 1'b1;
//load counter on reads only
counter[7:0] <= command[4]?in_data:8'b0;
if (enable) state <= GET_ADDR1;
end
GET_ADDR1 : begin
in_ready_0 <= 1'b1;
first_trans <= 1'b1;
last_trans <= 1'b0;
address[31:24] <= in_data;
if (enable) state <= GET_ADDR2;
end
GET_ADDR2 : begin
in_ready_0 <= 1'b1;
address[23:16] <= in_data;
if (enable) state <= GET_ADDR3;
end
GET_ADDR3 : begin
in_ready_0 <= 1'b1;
address[15:8] <= in_data;
if (enable) state <= GET_ADDR4;
end
GET_ADDR4 : begin
in_ready_0 <= 1'b1;
address[7:2] <= in_data[7:2];
current_byte <= in_data[1:0];
if (enable) begin
if (command == CMD_WRITE_NON_INCR | command == CMD_WRITE_INCR) begin
state <= GET_WRITE_DATA; //writes
in_ready_0 <= 1'b1;
end
else if (command == CMD_READ_NON_INCR | command == CMD_READ_INCR) begin
state <= READ_ASSERT; //reads
in_ready_0 <= 1'b0;
end
else begin
//nops
//treat all unrecognized commands as nops as well
state <= RETURN_PACKET;
out_startofpacket <= 1'b1;
out_data <= (8'h80 | command);
out_valid <= 1'b1;
current_byte <= 'h0;
in_ready_0 <= 1'b0;
end
end
end
GET_WRITE_DATA : begin
in_ready_0 <= 1;
if (enable) begin
counter <= counter + 1'b1;
//2 bit, should wrap by itself
current_byte <= current_byte + 1'b1;
if (in_endofpacket || current_byte == 3)
begin
in_ready_0 <= 0;
write <= 1'b1;
state <= WRITE_WAIT;
end
end
if (in_endofpacket) begin
last_trans <= 1'b1;
end
// handle byte writes properly
// drive data pins based on addresses
case (current_byte)
0: begin
writedata[7:0] <= in_data;
byteenable[0] <= 1;
end
1: begin
writedata[15:8] <= in_data;
byteenable[1] <= 1;
end
2: begin
writedata[23:16] <= in_data;
byteenable[2] <= 1;
end
3: begin
writedata[31:24] <= in_data;
byteenable[3] <= 1;
end
endcase
end
WRITE_WAIT : begin
in_ready_0 <= 0;
write <= 1'b1;
if (~waitrequest) begin
write <= 1'b0;
state <= GET_WRITE_DATA;
in_ready_0 <= 1;
byteenable <= 'b0;
if (command[2] == 1'b1) begin
//increment address, but word-align it
address[31:2] <= (address[31:2] + 1'b1);
end
if (last_trans) begin
state <= RETURN_PACKET;
out_startofpacket <= 1'b1;
out_data <= (8'h80 | command);
out_valid <= 1'b1;
current_byte <= 'h0;
in_ready_0 <= 1'b0;
end
end
end
RETURN_PACKET : begin
out_valid <= 1'b1;
if (out_ready) begin
case (current_byte)
// 0: begin
// out_startofpacket <= 1'b1;
// out_data <= (8'h80 | command);
// end
0: begin
out_data <= 8'b0;
end
1: begin
out_data <= counter[15:8];
end
2: begin
out_endofpacket <= 1'b1;
out_data <= counter[7:0];
end
default: begin
// out_data <= 8'b0;
// out_startofpacket <= 1'b0;
// out_endofpacket <= 1'b0;
end
endcase
current_byte <= current_byte + 1'b1;
if (current_byte == 3) begin
state <= READY;
out_valid <= 1'b0;
end
else state <= RETURN_PACKET;
end
end
READ_ASSERT : begin
if (current_byte == 3) byteenable <= unshifted_byteenable << 3;
if (current_byte == 2) byteenable <= unshifted_byteenable << 2;
if (current_byte == 1) byteenable <= unshifted_byteenable << 1;
if (current_byte == 0) byteenable <= unshifted_byteenable;
// byteenable <= unshifted_byteenable << current_byte;
read <= 1;
state <= READ_CMD_WAIT;
end
READ_CMD_WAIT : begin
read_data_buffer <= readdata[31:8];
out_data <= readdata[7:0];
read <= 1;
// if readdatavalid, take the data and
// go directly to READ_SEND_ISSUE. This is for fixed
// latency slaves. Ignore waitrequest in this case,
// since this master does not issue pipelined reads.
//
// For variable latency slaves, once waitrequest is low
// the read command is accepted, so deassert read and
// go to READ_DATA_WAIT to wait for readdatavalid
if (readdatavalid) begin
state <= READ_SEND_ISSUE;
read <= 0;
end else begin
if (~waitrequest) begin
state <= READ_DATA_WAIT;
read <= 0;
end
end
end
READ_DATA_WAIT : begin
read_data_buffer <= readdata[31:8];
out_data <= readdata[7:0];
if (readdatavalid) begin
state <= READ_SEND_ISSUE;
end
end
READ_SEND_ISSUE : begin
out_valid <= 1'b1;
out_startofpacket <= 'h0;
out_endofpacket <= 'h0;
if (counter == 1) begin
out_endofpacket <= 1'b1;
end
if (first_trans) begin
first_trans <= 1'b0;
out_startofpacket <= 1'b1;
end
case (current_byte)
3: begin
out_data <= read_data_buffer[23:16];
end
2: begin
out_data <= read_data_buffer[15:8];
end
1: begin
out_data <= read_data_buffer[7:0];
end
default: begin
out_data <= out_data;
end
endcase
state <= READ_SEND_WAIT;
end
READ_SEND_WAIT : begin
out_valid <= 1'b1;
if (out_ready) begin
counter <= counter - 1'b1;
current_byte <= current_byte + 1'b1;
out_valid <= 1'b0;
// count down on the number of bytes to read
// shift current byte location within word
// if increment address, add it, so the next read
// can use it, if more reads are required
// no more bytes to send - go to READY state
if (counter == 1) begin
state <= READY;
// end of current word, but we have more bytes to
// read - go back to READ_ASSERT
end else if (current_byte == 3) begin
if (command[2] == 1'b1) begin
//increment address, but word-align it
address[31:2] <= (address[31:2] + 1'b1);
end
state <= READ_ASSERT;
// continue sending current word
end else begin
state <= READ_SEND_ISSUE;
end
//maybe add in_ready_0 here so we are ready to go
//right away
end
end
endcase
if (enable & in_startofpacket) begin
state <= GET_EXTRA;
command <= in_data;
in_ready_0 <= 1'b1;
end
end // end else
end // end always block
endmodule