/*
* JR-IDE Project
* - (c) 2017 Alan Hightower
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
`define VERSION_MAJOR 8'd1
`define VERSION_MINOR 8'd8
module bridge_top
(
// embedded function block interface
inout cfg_SCL, // Config only I2C clock line
inout cfg_SDA, // Config only I2C data line
// IDE interface
inout [15:0] ide_D, // Data bus
input [2:0] ide_A, // Address bus
input [1:0] ide_CSn, // Chip selects
input ide_RDn, // Read strobe
input ide_WRn, // Write strobe
input ide_RSTn, // Reset
output ide_IRQen, // IRQ enable
output ide_IRQout, // IRQ level
output ide_DASP, // Disk activity
output ide_OEn, // data bus enable
output ide_DIR, // data bus direction
// Raspberry PI
input pi_RX, // BCM15 : console receive
output pi_TX, // BCM14 : console transmit
input spi_CSn, // BCM8
input spi_CLK, // BCM11
input spi_MOSI, // BCM10
output spi_MISO, // BCM9
output pi_IRQn, // BCM24 (gpio read 5)
// FTDI serial cable
output debug_TX, //
input debug_RX
);
// Use internal RC for IDE timing
localparam RC_CLOCK = 38000000;
wire ide_CLK;
defparam OSCH_inst.NOM_FREQ = "38.00";
OSCH OSCH_inst (.OSC(ide_CLK), .SEDSTDBY(), .STDBY(1'b0));
// Connect clock and I2C lines to EFB (work around silicon bug)
efb EFB
(
.wb_clk_i (ide_CLK),
.wb_rst_i (),
.wb_cyc_i (1'b0),
.wb_stb_i (1'b0),
.wb_we_i (1'b0),
.wb_adr_i (8'h00),
.wb_dat_i (8'h00),
.wb_dat_o (),
.wb_ack_o (),
.i2c1_scl (cfg_SCL),
.i2c1_sda (cfg_SDA),
.i2c1_irqo (),
.wbc_ufm_irq ()
);
// Synchronize control strobes from IDE bus
reg ide_RD;
reg ide_WR;
reg ide_CSA;
reg ide_CSB;
reg ide_CS;
always @(posedge ide_CLK)
begin
ide_RD <= ~ide_RDn;
ide_WR <= ~ide_WRn;
ide_CSA <= ~ide_CSn[0];
ide_CSB <= ~ide_CSn[1];
ide_CS <= ~ide_CSn[0] | ~ide_CSn[1];
end
/*
* Serial data from the Pi console gets directly
* connected to the debug output pin. It is also
* connected to a UART/RX block which feeds a FIFO
* to the Pi. This is so a console utility can
* service the port on the connected IDE host.
*/
assign debug_TX = pi_RX;
wire [7:0] stojr_in; // data UART to FIFO
wire [7:0] stojr_out; // data FIFO to IDE data
wire stojr_wr; // data UART to FIFO strobe
wire stojr_empty; // FIFO empty flag
wire stojr_full; // FIFO full flag
uart_rx #(
.CLK_FREQ (RC_CLOCK),
.BAUD_RATE (115200)
) UART_STOJR (
.clk (ide_CLK),
.pad (pi_RX),
.data (stojr_in),
.strobe (stojr_wr)
);
/*
* The console access data register is at IDE chip
* select B at at address 0 while an incoming status
* register (below) is placed at IDE chip select B
* at address 2. These are both reserved in the ATA
* spec, but should be safe.
*/
wire [7:0] ireg_UART = { 6'b000000, stojr_full, ~stojr_empty };
/*
* The serial input on the debug header is also conneted
* to a UART/RX block which feeds a FIFO along with a
* IDE writes to the CSB/address 0 serial data register.
* There is an opportunity that if both have a character
* ready on the same IDE clock, one could get dropped.
* But the use cases for both ports should be exclusive.
*/
wire [7:0] stopi_in; // data debug to FIFO
wire [7:0] stopi_out; // data FIFO to Pi UART/TX
wire stopi_wr; // data UART to FIFO strobe
wire stopi_empty;
wire stopi_ready;
uart_rx #(
.CLK_FREQ (RC_CLOCK),
.BAUD_RATE (115200)
) UART_STOPI_RX (
.clk (ide_CLK),
.pad (debug_RX),
.data (stopi_in),
.strobe (stopi_wr)
);
/*
* The following state machine services the FIFO going
* to the Pi console via a UART/TX block below. It
* simply reads when there is data present and forwards
* it to the TX block below.
*/
`define serial_IDLE 2'b00
`define serial_FETCH 2'b01
`define serial_WRITE 2'b10
reg [1:0] serial_state = `serial_IDLE;
always @(posedge ide_CLK)
begin
case (serial_state)
`serial_IDLE :
begin
if (~stopi_empty & stopi_ready)
serial_state <= `serial_FETCH;
end
`serial_FETCH:
serial_state <= `serial_WRITE;
`serial_WRITE:
serial_state <= `serial_IDLE;
endcase
end
uart_tx #(
.CLK_FREQ (RC_CLOCK),
.BAUD_RATE (115200)
) UART_STOPI_TX (
.clk (ide_CLK),
.data (stopi_out),
.strobe (serial_state == `serial_WRITE),
.pad (pi_TX),
.ready (stopi_ready)
);
// ********* ATAPI REGISTER FILE *********
/*
* Historcally the IDE register file came from the Western
* Digital WD1010 Hard Drive Controller ASIC. Refer to it's
* data sheet if you want a trip down memory lane on how we
* arrived here.
*/
/* CS0:1 - [R] Error register
* - bit 7: BBK - Set if bad block detected
* - bit 6: UNC - Set if uncorrectable CRC error
* - bit 5: MC - Set if media changed
* - bit 4: IDNF - Sector not found
* - bit 3: MCR - Media changed requested (hit eject button)
* - bit 2: ABRT - Aborted command
* - bit 1: TK0NF - Track 0 not found
* - bit 0: AMNF - Address mark not found
*/
reg ireg_IDNF = 1'b0; // CS0:A1:b4
reg ireg_ABRT = 1'b0; // CS0:A1:b2
wire [7:0] ireg_ERR = { 3'b000, ireg_IDNF, 1'b0, ireg_ABRT, 2'b00 };
// CS0:1 - [W] Feature register (command argument)
// Historically - write precompensation cylinder / 4
reg [7:0] ireg_FEAT = 8'h00;
// CS0:2 - [R/W] Number of sectors to be transfered (zero = 256)
reg [7:0] ireg_SECZ = 8'h00;
// CS0:3 - [R/W] Starting sector number (LBA byte 0)
reg [7:0] ireg_SECN = 8'h01;
// CS0:4 - [R/W] Cylinder number low (or LBA byte 1)
reg [7:0] ireg_CYLL = 8'h00;
// CS0:5 - [R/W] Cylinder number high (or LBA byte 2)
reg [7:0] ireg_CYLH = 8'h00;
/* CS0:6 - [R/W] Drive/head register
* - bit 7: EXT (obsolete - always 1) Extension bit
* When 0, append CRC data to sector data
* - bit 6: 1 = LBA mode, 0 = CHS mode
* - bit 5: (obsolete - always 1) Sector size
* Combination w/ bit 6: 128, 256, (512), 1024
* - bit 4: 0 = master, 1 = slave
* - bit 3: HS3 head bit 3 (or LBA bit 27)
* - bit 2: HS2 head bit 2 (or LBA bit 26)
* - bit 1: HS1 head bit 1 (or LBA bit 25)
* - bit 0: HS0 head bit 0 (or LBA bit 24)
*/
reg ireg_LBA = 1'b0; // CS0:A6:b6
reg ireg_SLAVE = 1'b0; // CS0:A6:b4
reg [3:0] ireg_HEAD = 4'b0000; // CS0:A6:b3-0
wire [7:0] ireg_DRVH = { 1'b1, ireg_LBA, 1'b1, ireg_SLAVE, ireg_HEAD };
/* CS0:7 - [R] Status register
* - bit 7: BSY - Busy
* - bit 6: DRDY - Drive ready
* - bit 5: DF - Drive fault
* - bit 4: DSC - Drive seek complete
* - bit 3: DRQ - Data Request
* - bit 2: CORR - Correctable read error occured
* - bit 1: IDX - Index mark under read head
* - bit 0: ERR - If any bit in error register is set
*/
reg ireg_BSY = 1'b0; // CS0:A7:b7
reg ireg_DRDY = 1'b0; // CS0:A7:b6
reg ireg_DF = 1'b0; // CS0:A7:b5
reg ireg_DSC = 1'b0; // CS0:A7:b4
wire ireg_DRQ; // CS0:A7:b3
wire [7:0] ireg_STS = { ireg_BSY, ireg_DRDY, ireg_DF, ireg_DSC,
ireg_DRQ, 2'b00, ireg_IDNF | ireg_ABRT };
// CS0:7 - [W] Command register
reg [7:0] ireg_CMD = 8'h00;
/* CS1:6 - [W] Device control register
* - bit 7: HOB - High order byte (48-bit LBA)
* - bit 6: reserved
* - bit 5: reserved
* - bit 4: reserved
* - bit 3: reserved
* - bit 2: SRST - Host software reset
* - bit 1: IENn - Interrupt enable
* - bit 0: zero
*/
reg ireg_SRST = 1'b0; // CS1:A6:b2
reg ireg_IENn = 1'b1; // CS1:A6:b1
wire [7:0] ireg_DCTL = { 5'b00000, ireg_SRST, ireg_IENn, 1'b0 };
// ********* SUPPORT REGISTER FILE *********
reg [7:0] ireg_SECR = 8'h00; // Byte remainder of transfer size
reg ireg_IRQACT = 1'b0; // Wether the IRQ driver is enabled atm
reg ireg_IRQOUT = 1'b0; // Input state of the IRQ driver
reg ireg_IRQPIn = 1'b0; // IRQ to RPi - pending
reg ireg_SRSTP = 1'b1; // Reset pending
reg ireg_EMUX = 1'b0; // Error reg mux control
reg ireg_FRST = 1'b0; // FIFO reset stobe
`define DRQ_MODE_OFF 2'b00 // Static value 0
`define DRQ_MODE_ON 2'b01 // Static value 1
`define DRQ_MODE_READSEC 2'b10 // IFIFO >= 256 words
`define DRQ_MODE_WRITESEC 2'b11 // OFIFO >= 256 words
reg [1:0] ireg_DRQm = `DRQ_MODE_OFF; // Data request mux mode
reg [11:0] ififo_CNT = 12'h000; // Total words in PI->CPLD FIFO
reg [11:0] ofifo_CNT = 12'h400; // Total words available in CPLD->PI FIFO
wire [15:0] ififo_OUT; // Forward dec for IFIFO output (unreg)
wire [15:0] ofifo_OUT; // Forward dec for OFIFO output (unreg)
/*
* Change the behaviour of the DRQ signal to the host
* based on a) the transfer mode we are currently in, and
* b) the level of the FIFOs.
*/
assign ireg_DRQ = (ireg_DRQm == `DRQ_MODE_ON) ? 1'b1 :
(ireg_DRQm == `DRQ_MODE_READSEC) ? |ififo_CNT :
(ireg_DRQm == `DRQ_MODE_WRITESEC) ? |ofifo_CNT :
1'b0;
/*
* I am not using the normal Lattice FIFO E/F/AE/AF flags as
* they do not propagate at controllable atomic points.
* For example, a 'real' IDE device will add 256 words to the
* read data availability when a block is transfered in from
* storage and ready to move out the data register. Once
* the first word is available, all words are available. It
* has IORDY to help. We don't here.
*
* If a SPI transfer started filling the FIFO, ~E or ~AE
* could be affected before we have enough of the 256 words
* a host could transfer before looking at the DRQ line again.
* The Lattice FIFO has controllable high and low water marks,
* however they are static and I'd rather have finer control
* over how thresholds are managed going forward. During
* a register transfer in, an adjustment value is applied by
* the PI giving it complete control over how and how much the
* flags are affected at any given time.
*
* Using the high and low watermark feature of Lattice FIFO
* flags could be an option. However there has to be more
* state glue logic added and the continuous presence of a
* stable clock on both sides - not possible with SPI.
* Keeping control on the PI is just simpler and works better.
*/
// ********* OUT-GOING REGISTER DATA FORMAT TO THE PI *********
wire [111:0] spi_REGSOUT =
{
// 16-bit flags - LE byte 0
ireg_DRDY, // 7: STS: Drive ready
ireg_DF, // 6: STS: Drive fault
ireg_DSC, // 5: STS: Drive seek complete
ireg_DRQm, // 4-3: STS: Data request mux mode
ireg_EMUX, // 2: Error mux control
ireg_LBA, // 1: LBA mode
ireg_SLAVE, // 0: Master/slave
// 16-bit flags - LE byte 1
ireg_SRST, // 15: Soft reset request
ireg_IENn, // 14: Host interrupt enable
ireg_IRQACT, // 13: Host interrupt active
ireg_IRQPIn, // 12: Output pending to RPi
ireg_SRSTP, // 11: Reset pending
ireg_IDNF, // 10: ERR: Sector not found
ireg_ABRT, // 9: ERR: Aborted command
ireg_BSY, // 8: STS: Busy
// 16-bit command and feature arguement
ireg_CMD,
ireg_FEAT,
// 16-bit transfer size
ireg_SECR, // Byte remainder for packet formats
ireg_SECZ, // Number of 512 byte transfers (sectors)
// 32-bit LE logical block address - LE
ireg_SECN, // LBA0: Start sector number
ireg_CYLL, // LBA1: Lower cylinder number
ireg_CYLH, // LBA2: Upper cylinder number
4'b0000, // Upper nibble pad
ireg_HEAD, // LBA3: Head number
// Current FIFO levels
ififo_CNT[7:0], // Input FIFO level
4'b000,
ififo_CNT[11:8],
ofifo_CNT[7:0], // Output FIFO free level
4'b000,
ofifo_CNT[11:8]
};
// ********* SPI PROTOCOL ENGINE *********
/*
* Many SPI peripheral implementations will use an independent
* internal clock to over-sample the transitions on the SPI
* lines. This makes the world easy in that you never have to
* cross a clock domain. However it limits the total speed of
* the SPI clock to a subset of the sampling clock.
*
* I didn't want to do that here opting to direct drive the
* SPI flip-flops using the SPI clock and rising edge of CS
* and use FIFOs and transfer logic to move data and status
* to the IDE state machine.
*
* The SPI data format follows (8-bit word size):
*
*
*
* Read data commands require an extra dummy byte before the start
* of data to be read to allow advance latching. Both read and
* write data commands require the byte count to be present as a
* 16-bit LE value in ARG1/ARG2. Nearly all commands need some
* trailing clocks to drive completion logic in the state machine.
*/
`define state_SPI_CMD 3'b0_00
`define state_SPI_IGNORE 3'b0_01
`define state_SPI_FIFO_READ 3'b1_00
`define state_SPI_FIFO_WRITE 3'b1_01
`define state_SPI_REG_READ 3'b1_10
`define state_SPI_REG_WRITE 3'b1_11
reg [2:0] spi_state = `state_SPI_CMD;
reg [15:0] spi_count = 16'h0000;
reg [23:0] spi_arg = 24'h000000;
reg [111:0] spi_shifti = 112'h0000000000000000000000000000;
reg [111:0] spi_datain = 112'h0000000000000000000000000000;
reg [111:0] spi_shifto = { 8'h00, `VERSION_MAJOR, `VERSION_MINOR, 96'h0000000000000000000000 };
reg ififo_xfer = 1'b0; // FIFO transfer in strobe
reg ofifo_xfer = 1'b0; // FIFO transfer out strobe
wire [111:0] spi_shift = { spi_shifti[110:0], spi_MOSI };
always @(posedge spi_CLK or posedge spi_CSn)
begin
if (spi_CSn)
begin
spi_state <= `state_SPI_CMD;
spi_count <= 16'h0000;
// During CMD dword and first FIFO read byte, clock 0's
spi_shifto[111:72] <= { 8'h00, `VERSION_MAJOR, `VERSION_MINOR, 16'h0000 };
end
else
begin
spi_shifti <= spi_shift;
spi_shifto <= { spi_shifto[110:0], 1'b0 };
spi_count <= spi_count + 1;
ififo_xfer <= spi_count[3:0] == 4'b1111;
ofifo_xfer <= spi_count[3:0] == 4'b0101;
case (spi_state)
`state_SPI_CMD :
begin
if (spi_count == 16'd31)
begin
// Lower 3 bits of first (upper) byte of command word
spi_state <= spi_shift[26:24];
spi_arg <= spi_shift[23:0];
spi_count <= 16'h0000;
spi_shifto <= spi_REGSOUT;
// override/squash strobe on this word boundary
ififo_xfer <= 1'b0;
end
end
`state_SPI_REG_WRITE :
begin
if (spi_count == 16'd111)
begin
spi_state <= `state_SPI_IGNORE;
spi_datain <= spi_shift;
end
end
`state_SPI_REG_READ :
begin
if (spi_count == 16'd111)
spi_state <= `state_SPI_IGNORE;
end
`state_SPI_IGNORE :
spi_count <= 16'd0;
`state_SPI_FIFO_READ :
begin
// (word count * 16 bits) + 4
if (spi_count == { spi_arg[11:0], 4'b0100 })
spi_state <= `state_SPI_IGNORE;
if (spi_count[3:0] == 4'b0111)
spi_shifto[111:96] <= ofifo_OUT;
end
`state_SPI_FIFO_WRITE :
begin
// (word count * 16 bits) + 4
if (spi_count == { spi_arg[11:0], 4'b0100 })
spi_state <= `state_SPI_IGNORE;
end
endcase
end
end
assign spi_MISO = spi_shifto[111];
// ********* ATAPI FINITE STATE MACHINE *********
/*
* Transfer a single bit across clock domains (SPI -> IDE)
* to indicate a SPI register write is complete so the
* latched datain values above can be processed by the
* IDE state machine.
*
* There is no state progression in the IDE FSM that can
* last as long as the time it takes for a subsequent
* SPI transaction from the PI + the time it takes to
* actually cross latch the data from the SPI datain
* holding register to the IDE registers. So the data
* should remain stable till that point. This does
* assume the IDE sys clock is fast enough to process
* a single cycle transfer state between bus accesses
* as bus accesses always have priority.
*/
wire spi_reg_write = (spi_state == `state_SPI_REG_WRITE);
reg spi_reg_write_d1;
reg spi_reg_write_d2;
reg spi_reg_pending = 1'b0;
/*
*
*/
`define state_IO_IDLE 4'b0_000
`define state_IO_RESET 4'b0_001
`define state_IO_RESET_DELAY 4'b0_010
`define state_IO_XFER_REGS 4'b0_011
`define state_IO_WRITE_REG 4'b1_000
`define state_IO_WRITE_DATA 4'b1_001
`define state_IO_WRITE_WAIT 4'b1_010
`define state_IO_READ_REG 4'b1_100
`define state_IO_READ_FETCH 4'b1_101
`define state_IO_READ_DATA 4'b1_110
`define state_IO_READ_WAIT 4'b1_111
`define state_IO_READ_SFETCH 4'b0_100
`define state_IO_READ_SDATA 4'b0_101
`define state_IO_WRITE_SDATA 4'b0_111
reg [3:0] state = `state_IO_IDLE;
reg data_dir = 1'b0;
reg data_en = 1'b0;
reg [15:0] ide_DAT;
always @(posedge ide_CLK)
begin
// Synchronize cross latch of SPI data
spi_reg_write_d2 <= spi_reg_write_d1;
spi_reg_write_d1 <= spi_reg_write;
if (spi_reg_write_d2 & ~spi_reg_write_d1) // falling edge
spi_reg_pending <= 1'b1;
// Finite State Machine for IDE I/O interface
case (state)
`state_IO_IDLE :
begin
// Reminder: listed in reverse priority order
if (~ide_RSTn | ireg_SRST)
state <= `state_IO_RESET;
if (spi_reg_pending)
state <= `state_IO_XFER_REGS;
if (ide_CS & ide_RD)
begin
if (ide_CSA && (ide_A[2:0] == 3'b000))
state <= `state_IO_READ_FETCH;
else if (ide_CSB && (ide_A[2:0] == 3'b001))
state <= `state_IO_READ_SFETCH;
else
state <= `state_IO_READ_REG;
data_dir <= 1'b1;
// data_en <= 1'b1;
end
if (ide_CS & ide_WR)
begin
if (ide_CSA && (ide_A[2:0] == 3'b000))
state <= `state_IO_WRITE_DATA;
else if (ide_CSB && (ide_A[2:0] == 3'b001))
state <= `state_IO_WRITE_SDATA;
else
state <= `state_IO_WRITE_REG;
data_dir <= 1'b0;
data_en <= 1'b1;
end
end
`state_IO_RESET :
begin
state <= `state_IO_RESET_DELAY;
// immediate register actions - wait on PI for rest
ireg_ABRT <= 1'b1; // current command aborted
ireg_BSY <= 1'b1; // drive busy
ireg_DRDY <= 1'b0; // drive not ready
ireg_DRQm <= `DRQ_MODE_OFF;
ireg_IRQACT <= 1'b0; // de-assert any host IRQ
ireg_IRQPIn <= 1'b1; // de-assert any Pi IRQ
ireg_SRSTP <= 1'b1; // software reset pending
ireg_EMUX <= 1'b0; // error mux control
ireg_FRST <= 1'b1; // Reset FIFOs
ififo_CNT <= 12'h000; // Reset FIFO levels to empty
ofifo_CNT <= 12'h400;
end
`state_IO_RESET_DELAY :
begin
state <= `state_IO_IDLE;
ireg_IRQPIn <= 1'b0; // assert Pi IRQ
ireg_FRST <= 1'b0; // FIFOs ready on next clock
end
`state_IO_XFER_REGS :
begin
state <= `state_IO_IDLE;
ireg_DRDY <= spi_datain[111];
ireg_DF <= spi_datain[110];
ireg_DSC <= spi_datain[109];
ireg_DRQm <= spi_datain[108:107];
ireg_EMUX <= spi_datain[106];
ireg_LBA <= spi_datain[105];
ireg_SLAVE <= spi_datain[104];
ireg_SRST <= spi_datain[103];
ireg_IENn <= spi_datain[102];
ireg_IRQACT <= spi_datain[101];
ireg_IRQPIn <= spi_datain[100];
ireg_SRSTP <= spi_datain[99];
ireg_IDNF <= spi_datain[98];
ireg_ABRT <= spi_datain[97];
ireg_BSY <= spi_datain[96];
ireg_CMD <= spi_datain[95:88];
ireg_FEAT <= spi_datain[87:80];
ireg_SECR <= spi_datain[79:72];
ireg_SECZ <= spi_datain[71:64];
ireg_SECN <= spi_datain[63:56];
ireg_CYLL <= spi_datain[55:48];
ireg_CYLH <= spi_datain[47:40];
ireg_HEAD <= spi_datain[35:32];
// bits 36-39 ignored (upper 4 bits of LBA/head)
ififo_CNT <= ififo_CNT + { spi_datain[19:16], spi_datain[31:24] };
ofifo_CNT <= ofifo_CNT + { spi_datain[3:0], spi_datain[15:8] };
// bits 20-23 ignored (upper 4 bits of upper ififo_ADJ byte)
// bits 4-7 ignored (upped 4 bits of upper ofifo_ADJ byte)
spi_reg_pending <= 1'b0;
end
`state_IO_READ_REG :
begin
state <= `state_IO_READ_WAIT;
data_en <= |ide_A;
ide_DAT[15:8] <= 8'h00;
ide_DAT[7:0] <=
(ide_CSA && (ide_A[2:0] == 3'b001)) ? ireg_EMUX ? ireg_FEAT : ireg_ERR :
(ide_CSA && (ide_A[2:0] == 3'b010)) ? ireg_SECZ :
(ide_CSA && (ide_A[2:0] == 3'b011)) ? ireg_SECN :
(ide_CSA && (ide_A[2:0] == 3'b100)) ? ireg_CYLL :
(ide_CSA && (ide_A[2:0] == 3'b101)) ? ireg_CYLH :
(ide_CSA && (ide_A[2:0] == 3'b110)) ? ireg_DRVH :
(ide_CSA && (ide_A[2:0] == 3'b111)) ? ireg_STS :
(ide_CSB && (ide_A[2:0] == 3'b010)) ? ireg_UART :
(ide_CSB && (ide_A[2:0] == 3'b011)) ? ireg_SECR :
(ide_CSB && (ide_A[2:0] == 3'b110)) ? ireg_STS :
8'h00;
end
`state_IO_READ_FETCH :
begin
state <= `state_IO_READ_DATA;
end
`state_IO_READ_DATA :
begin
state <= `state_IO_READ_WAIT;
data_en <= 1'b1;
if (|ififo_CNT)
begin
ide_DAT <= { ififo_OUT[7:0], ififo_OUT[15:8] };
ififo_CNT <= ififo_CNT - 1;
end
else
ide_DAT <= 16'h0000;
end
`state_IO_READ_SFETCH :
begin
state <= `state_IO_READ_SDATA;
end
`state_IO_READ_SDATA :
begin
state <= `state_IO_READ_WAIT;
data_en <= 1'b1;
ide_DAT <= { 8'h00, stojr_out };
end
`state_IO_READ_WAIT :
begin
if (~ide_RD)
begin
state <= `state_IO_IDLE;
// data_en <= 1'b0;
end
end
`state_IO_WRITE_REG :
begin
state <= `state_IO_WRITE_WAIT;
if (ide_CSA)
begin
case (ide_A[2:0])
3'b001 : ireg_FEAT <= ide_D[7:0];
3'b010 : ireg_SECZ <= ide_D[7:0];
3'b011 : ireg_SECN <= ide_D[7:0];
3'b100 : ireg_CYLL <= ide_D[7:0];
3'b101 : ireg_CYLH <= ide_D[7:0];
3'b110 :
begin
ireg_LBA <= ide_D[6];
ireg_SLAVE <= ide_D[4];
ireg_HEAD <= ide_D[3:0];
end
3'b111 : // Command register - trigger IRQ to PI
begin
ireg_CMD <= ide_D[7:0];
ireg_IDNF <= 1'b0; // clear error bits
ireg_ABRT <= 1'b0;
ireg_BSY <= 1'b1; // busy
ireg_IRQPIn <= 1'b0; // active
ireg_DRQm <= `DRQ_MODE_OFF;
ireg_EMUX <= 1'b0;
// Reset FIFOs on every command
ireg_FRST <= 1'b1;
ififo_CNT <= 12'h000;
ofifo_CNT <= 12'h400;
end
endcase
end
if (ide_CSB)
begin
case (ide_A[2:0])
3'b011 : ireg_SECR <= ide_D[7:0];
3'b110 :
begin
ireg_SRST <= ide_D[2];
ireg_IENn <= ide_D[1];
end
endcase
end
end
`state_IO_WRITE_DATA :
begin
state <= `state_IO_WRITE_WAIT;
if (|ofifo_CNT)
ofifo_CNT <= ofifo_CNT - 1;
end
`state_IO_WRITE_SDATA :
begin
state <= `state_IO_WRITE_WAIT;
end
`state_IO_WRITE_WAIT :
begin
ireg_FRST <= 1'b0;
if (~ide_WR)
begin
state <= `state_IO_IDLE;
data_en <= 1'b0;
end
end
endcase
end
assign ide_D = (data_en && data_dir) ? ide_DAT : 16'hzzzz;
// RPI -> CPLD data input FIFO
datafifo FIFO_IN
(
.Reset (ireg_FRST),
.RPReset (ireg_FRST),
.WrClock (spi_CLK),
.WrEn ((spi_state == `state_SPI_FIFO_WRITE) && ififo_xfer),
.Data (spi_shifti[15:0]),
.RdClock (ide_CLK),
.RdEn (state == `state_IO_READ_FETCH),
.Q (ififo_OUT)
);
// CPLD -> RPI data output FIFO
datafifo FIFO_OUT
(
.Reset (ireg_FRST),
.RPReset (ireg_FRST),
.WrClock (ide_CLK),
.WrEn (state == `state_IO_WRITE_DATA),
.Data ({ide_D[7:0], ide_D[15:8]}),
.RdClock (spi_CLK),
.RdEn ((spi_state == `state_SPI_FIFO_READ) && ofifo_xfer),
.Q (ofifo_OUT)
);
// PI -> JR serial FIFO
serialfifo2k FIFO_STOJR
(
.Reset (~ide_RSTn),
.RPReset (~ide_RSTn),
.WrClock (ide_CLK),
.WrEn (stojr_wr),
.Data (stojr_in),
.RdClock (ide_CLK),
.RdEn (state == `state_IO_READ_SFETCH),
.Q (stojr_out),
.Empty (stojr_empty),
.Full (stojr_full)
);
// JR/Debug -> PI serial FIFO
serialfifo1k FIFO_STOPI
(
.Reset (~ide_RSTn),
.RPReset (~ide_RSTn),
.WrClock (ide_CLK),
.WrEn (stopi_wr | (state == `state_IO_WRITE_SDATA)),
.Data (stopi_wr ? stopi_in : ide_D[7:0]),
.RdClock (ide_CLK),
.RdEn (serial_state == `serial_FETCH),
.Q (stopi_out),
.Empty (stopi_empty)
);
// Conditions that illuminate the drive activity LED
wire [2:0] ide_ACTIVE =
{
ireg_BSY, // Command servicing active
(ififo_CNT != 12'h000), // In-bound data transfer (R)
(ofifo_CNT != 12'h400) // Out-bound data transfer (W)
};
assign ide_DASP = |ide_ACTIVE; // to external open drain nFET
// Static output assignments from registered logic
assign pi_IRQn = ireg_IRQPIn; // GPIO.5 / BCM24
assign ide_DIR = data_dir;
assign ide_OEn = ~data_en;
assign ide_IRQen = ireg_IRQACT;
assign ide_IRQout = ireg_IRQOUT;
endmodule