/* * 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