`timescale 1ns / 100ps /* SPI to backbus interface for minimigmac * * This layers on top of the spi_slave module. It provides a protocol * which allows to read and write from of 8-bit wide, 6 addr bit bus * which is connected to various modules in the system. * * The basic SPI protocol starts with one byte received by the FPGA, * which is has the format * * RW : Read (0) / Write (1) * AI : Auto-increment * ADDR : Register address * * For writes, all subsequent bytes are directly relevant. For reads, * the next byte after the read command shall be ignored, then subsequent * bytes are relevant. * * The backbus side protocol is: * * - Writes: at clock with strobe high and wr high, data and address * are stable and shall be latched. * - Reads : at clock with strobe high and wr low, address stable, * we latch data immediately. */ module spi_backbus ( /* Clock & Reset */ input sysclk, input reset, /* SPI signals (through to the SPI slave core) */ input sdi, output sdo, input sck, input _scs, /* Backbus interface */ output reg [5:0] bb_addr, output [7:0] bb_wdata, input [7:0] bb_rdata, output reg bb_strobe, output reg bb_wr ); /* SPI slave wires */ wire spi_rx; wire spi_cmd; /* Protocol internals */ reg ainc; reg delayed_ainc; reg write; /* Data read latch */ reg [7:0] data; /* Instanciate SPI slave interface */ spi_slave spi0(.sysclk(sysclk), .reset(reset), ._scs(_scs), .sdi(sdi), .sdo(sdo), .sck(sck), .wdata(data), .rdata(bb_wdata), .rx(spi_rx), .cmd(spi_cmd)); /* Data latch */ always@(posedge sysclk or posedge reset) begin if (reset) begin data <= 0; end else begin /* Latch read data at read strobe */ if (bb_strobe && !bb_wr) data <= bb_rdata; end end /* One state machine to rule them all coz I'm lazy */ always@(posedge sysclk or posedge reset) begin if (reset) begin bb_addr <= 0; end else begin /* Command byte. Establish addr, wr and set strobe on read */ if (spi_rx && spi_cmd) begin bb_addr <= bb_wdata[5:0]; delayed_ainc <= bb_wdata[6]; ainc <= bb_wdata[7] ? 0 : bb_wdata[6]; bb_wr <= bb_wdata[7]; bb_strobe <= ~bb_wdata[7]; end else if (spi_rx) begin /* Subsequent bytes */ ainc <= delayed_ainc; if (ainc) begin bb_addr <= bb_addr + 1; end /* New strobe */ bb_strobe <= 1; end else begin bb_strobe <= 0; end end end endmodule