`default_nettype none
// Read-Only Memory Adapter
//
// This core is used to interface an SPI Flash ROM to the
// TileLink TL/UL interconnect.
//
// This core is not in any way, shape, or form intended to be a particularly
// fast core. EVERY memory access to the ROM will result in a 96 clock cycle
// latency, for will always fetch a complete 64-bit word. The lowest 3 bits
// of the address provided on the A-channel are ignored and assumed to be
// 3'b000. Thus, byte, half-word, word, and double-word accesses are all
// equally accommodated without any need for decoding a_mask and a_size
// fields.
`include "tilelink.vh"
module roma(
i_clk,
i_reset,
// Slave Link
//
// Channel A
i_a_opcode,
i_a_address,
i_a_source,
i_a_valid,
o_a_ready,
// Channel D
o_d_opcode,
o_d_data,
o_d_size,
o_d_source,
o_d_valid,
i_d_ready,
// SPI Link
o_spi_mosi,
i_spi_miso,
o_spi_clk,
o_spi_cs
);
input i_clk;
input i_reset;
input [2:0] i_a_opcode;
input [20:0] i_a_address;
input [1:0] i_a_source;
input i_a_valid;
output o_a_ready;
output reg [2:0] o_d_opcode;
output [63:0] o_d_data;
output [1:0] o_d_size;
output reg [1:0] o_d_source;
output reg o_d_valid;
input i_d_ready;
output o_spi_mosi;
input i_spi_miso;
output o_spi_clk;
output reg o_spi_cs;
reg [32:0] send_message;
reg [6:0] bits_so_far;
reg getting_data;
wire is_read_request = (i_a_valid && o_a_ready && (i_a_opcode === `A_OPC_GET));
wire can_start_receiving_data = (bits_so_far == 7'd32);
wire finished_receiving_data = (bits_so_far == 7'd96);
wire d_channel_handoff = (o_d_valid && i_d_ready);
assign o_a_ready = (bits_so_far == 7'd97);
assign o_d_size = `D_SIZ_DWORD;
assign o_spi_clk = i_clk & o_spi_cs;
always @(posedge i_clk) begin
o_d_valid <= o_d_valid;
o_d_opcode <= o_d_opcode;
o_d_source <= o_d_source;
if(i_reset) begin
o_d_valid <= 0;
o_d_opcode <= 0;
end
else if(finished_receiving_data) begin
o_d_valid <= 1;
o_d_opcode <= `D_OPC_GET_DATA;
o_d_source <= i_a_source;
end
else if(d_channel_handoff) begin
o_d_valid <= 0;
o_d_opcode <= 0;
end
end
always @(posedge i_clk) begin
o_spi_cs <= o_spi_cs;
if(i_reset) begin
o_spi_cs <= 0;
end
else if(is_read_request) begin
o_spi_cs <= 1;
end
else if(finished_receiving_data) begin
o_spi_cs <= 0;
end
end
always @(posedge i_clk) begin
send_message <= {send_message[31:0], 1'b0};
if(is_read_request) begin
send_message <= {1'b0, 8'h03, 3'h0, i_a_address[20:3], 3'b000};
end
end
assign o_spi_mosi = send_message[32];
always @(posedge i_clk) begin
bits_so_far <= bits_so_far;
getting_data <= getting_data;
if(i_reset) begin
bits_so_far <= 97;
getting_data <= 0;
end
else if(is_read_request) begin
bits_so_far <= 0;
getting_data <= 0;
end
else if(o_spi_cs) begin
// -1 bias because of up-counter action below.
if(can_start_receiving_data) begin
getting_data <= 1;
end
else if(finished_receiving_data) begin
getting_data <= 0;
end
bits_so_far <= bits_so_far + 1;
end
end
reg [63:0] rxd;
always @(posedge i_clk) begin
rxd <= rxd;
if(getting_data) begin
rxd <= {rxd[62:0], i_spi_miso};
end
end
assign o_d_data = {
rxd[7:0], rxd[15:8], rxd[23:16], rxd[31:24],
rxd[39:32], rxd[47:40], rxd[55:48], rxd[63:56]
};
`ifdef FORMAL
initial begin
bits_so_far <= 97;
o_d_valid <= 0;
end
`include "properties.vf"
`endif
endmodule