Commit 428626df authored by Andrey Filippov's avatar Andrey Filippov

started fsm for the to ahci module

parent bd53b296
...@@ -35,6 +35,7 @@ module ahci_fis_receive#( ...@@ -35,6 +35,7 @@ module ahci_fis_receive#(
input hba_rst, // @posedge mclk - sync reset input hba_rst, // @posedge mclk - sync reset
input mclk, // for command/status input mclk, // for command/status
// Control Interface // Control Interface
output reg fis_first_vld, // fis_first contains valid FIS header, reset by get_*
// Receiving FIS // Receiving FIS
input get_sig, // update signature input get_sig, // update signature
input get_dsfis, input get_dsfis,
...@@ -44,8 +45,8 @@ module ahci_fis_receive#( ...@@ -44,8 +45,8 @@ module ahci_fis_receive#(
input get_ufis, input get_ufis,
input get_data_fis, input get_data_fis,
input get_ignore, // ignore whatever FIS (use for DMA activate too?) input get_ignore, // ignore whatever FIS (use for DMA activate too?)
output reg get_fis_busy, // busy processing FIS output get_fis_busy, // busy processing FIS
output reg fis_first_vld, // fis_first contains valid FIS header, reset by get_* output reg get_fis_done, // done processing FIS (see fis_ok, fis_err, fis_ferr)
output reg fis_ok, // FIS done, checksum OK reset by starting a new get FIS output reg fis_ok, // FIS done, checksum OK reset by starting a new get FIS
output reg fis_err, // FIS done, checksum ERROR reset by starting a new get FIS output reg fis_err, // FIS done, checksum ERROR reset by starting a new get FIS
output fis_ferr, // FIS done, fatal error - FIS too long output fis_ferr, // FIS done, fatal error - FIS too long
...@@ -169,6 +170,7 @@ localparam DATA_TYPE_ERR = 3; ...@@ -169,6 +170,7 @@ localparam DATA_TYPE_ERR = 3;
reg [15:0] tf_err_sts; reg [15:0] tf_err_sts;
reg update_err_sts_r; reg update_err_sts_r;
reg update_prdbc_r; reg update_prdbc_r;
reg get_fis_busy_r;
// Forward data to DMA (dev->mem) engine // Forward data to DMA (dev->mem) engine
assign dma_in_valid = dma_in_ready && (hba_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err; assign dma_in_valid = dma_in_ready && (hba_data_in_type == DATA_TYPE_DMA) && data_in_ready && !too_long_err;
...@@ -186,7 +188,7 @@ localparam DATA_TYPE_ERR = 3; ...@@ -186,7 +188,7 @@ localparam DATA_TYPE_ERR = 3;
assign tfd_err = tf_err_sts[15:8]; assign tfd_err = tf_err_sts[15:8];
assign xfer_cntr = xfer_cntr_r[31:2]; assign xfer_cntr = xfer_cntr_r[31:2];
assign get_fis_busy = get_fis_busy_r;
always @ (posedge mclk) begin always @ (posedge mclk) begin
if (hba_rst || dma_in_stop) dma_in <= 0; if (hba_rst || dma_in_stop) dma_in <= 0;
...@@ -247,9 +249,11 @@ localparam DATA_TYPE_ERR = 3; ...@@ -247,9 +249,11 @@ localparam DATA_TYPE_ERR = 3;
fis_end_r <= {fis_end_r[0], fis_end_w}; fis_end_r <= {fis_end_r[0], fis_end_w};
if (hba_rst) get_fis_busy <= 0; if (hba_rst) get_fis_busy_r <= 0;
else if (get_fis) get_fis_busy <= 1; else if (get_fis) get_fis_busy_r <= 1;
else if (too_long_err || fis_end_w) get_fis_busy <= 0; else if (too_long_err || fis_end_w) get_fis_busy_r <= 0;
get_fis_done <= get_fis_busy_r && (too_long_err || fis_end_w);
if (hba_rst || get_fis) fis_first_vld <= 0; if (hba_rst || get_fis) fis_first_vld <= 0;
else if (is_FIS_HEAD) fis_first_vld <= 1; else if (is_FIS_HEAD) fis_first_vld <= 1;
......
/*******************************************************************************
* Module: ahci_fsm
* Date:2016-01-10
* Author: andrey
* Description: AHCI host+port0 state machine
*
* Copyright (c) 2016 Elphel, Inc .
* ahci_fsm.v 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.
*
* ahci_fsm.v 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 <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ns/1ps
module ahci_fsm #(
// parameter PREFETCH_ALWAYS = 0,
parameter READ_REG_LATENCY = 2, // 0 if reg_rdata is available with reg_re/reg_addr, 2 with re/regen
// parameter READ_CT_LATENCY = 1, // 0 if ct_rdata is available with reg_re/reg_addr, 2 with re/regen
parameter ADDRESS_BITS = 10 // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle)
)(
input hba_rst, // @posedge mclk
input mclk, // for command/status
// notification from axi_ahci_regs that software has written data to register
input [ADDRESS_BITS-1:0] soft_write_addr, // register address written by software
input [31:0] soft_write_data, // register data written (after applying wstb and type (RO, RW, RWC, RW1)
input soft_write_en, // write enable for data write
// input soft_arst, // reset SATA PHY not relying on SATA clock
// R/W access to AXI/AHCI registers, shared with ahci_fis_receive and ahci_fis_transmit modules
output [ADDRESS_BITS-1:0] regs_addr,
output regs_we,
// output [3:0] regs_wstb, Needed?
output [1:0] regs_re, // [0] - re, [1] - regen
output [31:0] regs_din,
input [31:0] regs_dout,
// direct communication with transposrt, link and phy layers
input phy_ready, // goes up after comreset,cominit, align, ...
// Other signals....
// Communication with ahci_fis_receive (some are unused
input fis_first_vld, // fis_first contains valid FIS header, reset by get_*
// Receiving FIS
output get_sig, // update signature
output get_dsfis,
output get_psfis,
output get_rfis,
output get_sdbfis,
output get_ufis,
output get_data_fis,
output get_ignore, // ignore whatever FIS (use for DMA activate too?)
input get_fis_busy, // busy processing FIS
input get_fis_done, // done processing FIS (see fis_ok, fis_err, fis_ferr)
input fis_ok, // FIS done, checksum OK reset by starting a new get FIS
input fis_err, // FIS done, checksum ERROR reset by starting a new get FIS
input fis_ferr, // FIS done, fatal error - FIS too long
// next commands use register address/data/we for 1 clock cycle - after next to command (commnd - t0, we - t2)
output update_err_sts,// update PxTFD.STS and PxTFD.ERR from the last received regs d2h
output update_prdbc, // update PRDBC in registers
output clear_bsy_drq, // clear PxTFD.STS.BSY and PxTFD.STS.DRQ, update
output set_bsy, // set PxTFD.STS.BSY, update
output set_sts_7f, // set PxTFD.STS = 0x7f, update
output set_sts_80, // set PxTFD.STS = 0x80 (may be combined with set_sts_7f), update
output decr_dwc, // decrement DMA Xfer counter // need pulse to 'update_prdbc' to write to registers
output [11:2] decr_DXC_dw, // decrement value (in DWORDs)
input [7:0] tfd_sts, // Current PxTFD status field (updated after regFIS and SDB - certain fields)
// tfd_sts[7] - BSY, tfd_sts[4] - DRQ, tfd_sts[0] - ERR
input [7:0] tfd_err, // Current PxTFD error field (updated after regFIS and SDB)
input fis_i, // value of "I" field in received regsD2H or SDB FIS
input sdb_n, // value of "N" field in received SDB FIS
input dma_a, // value of "A" field in received DMA Setup FIS
input dma_d, // value of "D" field in received DMA Setup FIS
input pio_i, // value of "I" field in received PIO Setup FIS
input pio_d, // value of "D" field in received PIO Setup FIS
input [7:0] pio_es, // value of PIO E_Status
// Using even word count (will be rounded up), partial DWORD (last) will be handled by PRD length if needed
input [31:2] xfer_cntr, // transfer counter in words for both DMA (31 bit) and PIO (lower 15 bits), updated after decr_dwc
input xfer_cntr_zero,// valid next cycle
// Communication with ahci_fis_transmit
// Command pulses to execute states
output fetch_cmd, // Enter p:FetchCmd, fetch command header (from the register memory, prefetch command FIS)
// wait for either fetch_cmd_busy == 0 or pCmdToIssue ==1 after fetch_cmd
output cfis_xmit, // transmit command (wait for dma_ct_busy == 0)
output dx_transmit, // send FIS header DWORD, (just 0x46), then forward DMA data
// transmit until error, 2048DWords or pDmaXferCnt
output atapi_xmit, // tarsmit ATAPI command FIS
input done,
input busy,
output clearCmdToIssue, // From CFIS:SUCCESS
input pCmdToIssue, // AHCI port variable
// output dmaCntrZero, // DMA counter is zero - would be a duplicate to the one in receive module and dwords_sent output
input fetch_cmd_busy, // does not include prefetching CT
output syncesc_recv, // These two inputs interrupt transmit
output xmit_err, //
input [ 1:0] dx_err, // bit 0 - syncesc_recv, 1 - xmit_err (valid @ xmit_err and later, reset by new command)
input [15:0] ch_prdtl, // Physical region descriptor table length (in entries, 0 is 0)
input ch_c, // Clear busy upon R_OK for this FIS
input ch_b, // Built-in self test command
input ch_r, // reset - may need to send SYNC escape before this command
input ch_p, // prefetchable - only used with non-zero PRDTL or ATAPI bit set
input ch_w, // Write: system memory -> device
input ch_a, // ATAPI: 1 means device should send PIO setup FIS for ATAPI command
input [4:0] ch_cfl, // length of the command FIS in DW, 0 means none. 0 and 1 - illegal,
// maximal is 16 (0x10)
input [11:2] dwords_sent // number of DWORDs transmitted (up to 2048)
);
`include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams
/*
Notes:
Implement sync esc request/ackn in TL (available in LL)
*/
endmodule
...@@ -29,7 +29,11 @@ module ahci_top#( ...@@ -29,7 +29,11 @@ module ahci_top#(
input aclk, // clock - should be buffered input aclk, // clock - should be buffered
input arst, // @aclk sync reset, active high input arst, // @aclk sync reset, active high
input mclk, // SATA system clock (current 75MHz for SATA2) input mclk, // SATA system clock (current 75MHz for SATA2)
input mrst, // reset in mclk clock domain input mrst, // reset in mclk clock domain (after SATA PLL is on)
// async reset for SATA (mrst will be responce to it)
output hba_arst, // hba async reset (currently does ~ the same as port reset)
output port_arst, // port0 async reset by software
input hclk, // AXI HP interface clock for 64-bit DMA (current - 150MHz input hclk, // AXI HP interface clock for 64-bit DMA (current - 150MHz
input hrst, // reset in hclk clock domain input hrst, // reset in hclk clock domain
// MAXIGP1 // MAXIGP1
...@@ -143,17 +147,28 @@ module ahci_top#( ...@@ -143,17 +147,28 @@ module ahci_top#(
wire [ADDRESS_BITS-1:0] soft_write_addr; // register address written by software wire [ADDRESS_BITS-1:0] soft_write_addr; // register address written by software
wire [31:0] soft_write_data; // register data written (after applying wstb and type (RO, RW, RWC, RW1) wire [31:0] soft_write_data; // register data written (after applying wstb and type (RO, RW, RWC, RW1)
wire soft_write_en; // write enable for data write wire soft_write_en; // write enable for data write
wire soft_arst; // reset SATA PHY not relying on SATA clock // wire hba_arst; // hba async reset (currently does ~ the same as port reset)
// TODO: Decode from {bram_addr, ahci_regs_di}, bram_wen_d // wire port_arst; // port0 async reset by software
// 2. HBA R/W registers, use hba clock // 2. HBA R/W registers, use hba clock
wire hba_rst; wire hba_rst;
wire regs_we; wire regs_we_fsm;
wire [1:0] regs_re; // [0] - re, [1] - regen wire [1:0] regs_re_fsm;
wire [31:0] regs_din_from_fsm; // from fsm
wire regs_we_freceive;
wire [1:0] regs_re_ftransmit; // [0] - re, [1] - regen
wire [ADDRESS_BITS-1:0] regs_faddr; // read/write adderss from ahci_fsm
wire [ADDRESS_BITS-1:0] regs_waddr; wire [ADDRESS_BITS-1:0] regs_waddr;
wire [ADDRESS_BITS-1:0] regs_raddr; wire [ADDRESS_BITS-1:0] regs_raddr;
wire [31:0] regs_din; wire [31:0] regs_din_from_freceive;
wire [31:0] regs_dout; wire [31:0] regs_dout;
wire [ADDRESS_BITS-1:0] regs_addr = ({ADDRESS_BITS{regs_we}} & regs_waddr) | ({ADDRESS_BITS{regs_re[0]}} & regs_raddr); wire [ADDRESS_BITS-1:0] regs_addr = ({ADDRESS_BITS{regs_we}} & regs_waddr) |
({ADDRESS_BITS{regs_re[0]}} & regs_raddr) |
({ADDRESS_BITS{regs_re_fsm[0] | regs_we_fsm}} & regs_faddr);
wire [31:0] regs_din = ({32{regs_we_freceive}} & regs_din_from_freceive) |
({32{regs_we_fsm}} & regs_din_from_fsm);
wire [1:0] regs_re = regs_re_ftransmit | regs_re_fsm; // [0] - re, [1] - regen
wire regs_we = regs_we_freceive | regs_we_fsm;
//--------------------- //---------------------
...@@ -179,9 +194,84 @@ module ahci_top#( ...@@ -179,9 +194,84 @@ module ahci_top#(
wire [31:0] dma_dout; // output[31:0] wire [31:0] dma_dout; // output[31:0]
wire dma_dav; // output wire dma_dav; // output
wire dma_re; // input wire dma_re; // input
wire [31:0] d2h_data;// input[31:0]
wire dma_in_ready; // output wire dma_in_ready; // output
wire dma_we; // input wire dma_we; // input
// ---------------------------------------
wire [31:0] xfer_cntr;
wire xfer_cntr_zero;
/* Instance template for module ahci_fsm */
ahci_fsm #(
.READ_REG_LATENCY(2),
.ADDRESS_BITS(10)
) ahci_fsm_i (
.hba_rst (hba_rst), // input
.mclk (mclk), // input
.soft_write_addr (soft_write_addr), // input[9:0]
.soft_write_data (soft_write_data), // input[31:0]
.soft_write_en (soft_write_en), // input
.regs_addr (regs_faddr), // output[9:0]
.regs_we (regs_we_fsm), // output
.regs_re (regs_re_fsm), // output[1:0]
.regs_din (regs_din_from_fsm), // output[31:0]
.regs_dout (regs_dout), // input[31:0]
.phy_ready(), // input
.fis_first_vld(), // input
.get_sig(), // output
.get_dsfis(), // output
.get_psfis(), // output
.get_rfis(), // output
.get_sdbfis(), // output
.get_ufis(), // output
.get_data_fis(), // output
.get_ignore(), // output
.get_fis_busy(), // input
.get_fis_done(), // input
.fis_ok(), // input
.fis_err(), // input
.fis_ferr(), // input
.update_err_sts (), // output
.update_prdbc(), // output
.clear_bsy_drq(), // output
.set_bsy(), // output
.set_sts_7f(), // output
.set_sts_80(), // output
.decr_dwc(), // output
.decr_DXC_dw(), // output[11:2]
.tfd_sts(), // input[7:0]
.tfd_err(), // input[7:0]
.fis_i(), // input
.sdb_n(), // input
.dma_a(), // input
.dma_d(), // input
.pio_i(), // input
.pio_d(), // input
.pio_es(), // input[7:0]
.xfer_cntr(), // input[31:2]
.xfer_cntr_zero(), // input
.fetch_cmd(), // output
.cfis_xmit(), // output
.dx_transmit(), // output
.atapi_xmit(), // output
.done(), // input
.busy(), // input
.clearCmdToIssue(), // output
.pCmdToIssue(), // input
.fetch_cmd_busy(), // input
.syncesc_recv(), // output
.xmit_err(), // output
.dx_err(), // input[1:0]
.ch_prdtl(), // input[15:0]
.ch_c(), // input
.ch_b(), // input
.ch_r(), // input
.ch_p(), // input
.ch_w(), // input
.ch_a(), // input
.ch_cfl(), // input[4:0]
.dwords_sent() // input[11:2]
);
...@@ -223,7 +313,8 @@ module ahci_top#( ...@@ -223,7 +313,8 @@ module ahci_top#(
.soft_write_addr (soft_write_addr), // output[9:0] .soft_write_addr (soft_write_addr), // output[9:0]
.soft_write_data (soft_write_data), // output[31:0] .soft_write_data (soft_write_data), // output[31:0]
.soft_write_en (soft_write_en), // output .soft_write_en (soft_write_en), // output
.soft_arst (soft_arst), // output .hba_arst (hba_arst), // output
.port_arst (port_arst), // output
.hba_clk (mclk), // input .hba_clk (mclk), // input
.hba_rst (hba_rst), // input .hba_rst (hba_rst), // input
.hba_addr (regs_addr), // input[9:0] .hba_addr (regs_addr), // input[9:0]
...@@ -239,7 +330,7 @@ module ahci_top#( ...@@ -239,7 +330,7 @@ module ahci_top#(
.hrst (hrst), // input .hrst (hrst), // input
.mclk (mclk), // input .mclk (mclk), // input
.hclk (hclk), // input .hclk (hclk), // input
.ctba (regs_dout[31:7]), // input[31:7] .ctba (regs_dout[31:7]),// input[31:7]
.ctba_ld (ctba_ld), // input .ctba_ld (ctba_ld), // input
.prdtl (prdtl), // input[15:0] .prdtl (prdtl), // input[15:0]
.dev_wr (dev_wr), // input .dev_wr (dev_wr), // input
...@@ -264,17 +355,7 @@ module ahci_top#( ...@@ -264,17 +355,7 @@ module ahci_top#(
.sys_in (d2h_data), // input[31:0] .sys_in (d2h_data), // input[31:0]
.sys_nfull (dma_in_ready), // output .sys_nfull (dma_in_ready), // output
.sys_we (dma_we), // input .sys_we (dma_we), // input
/*
// xmit: DMA (memory -> device) interface
input [31:0] dma_out, // 32-bit data from the DMA module, HBA -> device port
input dma_dav, // at least one dword is ready to be read from DMA module
output dma_re, // read dword from DMA module to the output register
// rcv: Forwarding data to the DMA engine
input dma_in_ready, // DMA engine ready to accept data
output dma_in_valid // Write data to DMA dev->memory channel
*/
.afi_awaddr (afi_awaddr), // output[31:0] .afi_awaddr (afi_awaddr), // output[31:0]
.afi_awvalid (afi_awvalid), // output .afi_awvalid (afi_awvalid), // output
.afi_awready (afi_awready), // input .afi_awready (afi_awready), // input
...@@ -326,6 +407,9 @@ module ahci_top#( ...@@ -326,6 +407,9 @@ module ahci_top#(
) ahci_fis_receive_i ( ) ahci_fis_receive_i (
.hba_rst (hba_rst), // input .hba_rst (hba_rst), // input
.mclk (mclk), // input .mclk (mclk), // input
.fis_first_vld (), // output reg
.get_sig (), // input .get_sig (), // input
.get_dsfis (), // input .get_dsfis (), // input
.get_psfis (), // input .get_psfis (), // input
...@@ -334,8 +418,9 @@ module ahci_top#( ...@@ -334,8 +418,9 @@ module ahci_top#(
.get_ufis (), // input .get_ufis (), // input
.get_data_fis (), // input .get_data_fis (), // input
.get_ignore (), // input .get_ignore (), // input
.get_fis_busy (), // output reg .get_fis_busy (), // output reg
.fis_first_vld (), // output reg .get_fis_done (), // output reg
.fis_ok (), // output reg .fis_ok (), // output reg
.fis_err (), // output reg .fis_err (), // output reg
.fis_ferr (), // output .fis_ferr (), // output
...@@ -356,18 +441,19 @@ module ahci_top#( ...@@ -356,18 +441,19 @@ module ahci_top#(
.pio_i (), // output reg .pio_i (), // output reg
.pio_d (), // output reg .pio_d (), // output reg
.pio_es (), // output[7:0] reg .pio_es (), // output[7:0] reg
.xfer_cntr (), // output[31:2] .xfer_cntr (xfer_cntr[31:2]), // output[31:2]
.xfer_cntr_zero (), // output reg .xfer_cntr_zero (xfer_cntr_zero), // output reg
.reg_addr (regs_waddr), // output[9:0] reg .reg_addr (regs_waddr), // output[9:0] reg
.reg_we (regs_we), // output reg .reg_we (regs_we_freceive), // output reg
.reg_data (regs_din), // output[31:0] reg .reg_data (regs_din_from_freceive), // output[31:0] reg
.hba_data_in (d2h_data), // input[31:0] .hba_data_in (d2h_data), // input[31:0]
.hba_data_in_type (d2h_type), // input[1:0] .hba_data_in_type (d2h_type), // input[1:0]
.hba_data_in_valid (d2h_valid), // input .hba_data_in_valid (d2h_valid), // input
.hba_data_in_many (d2h_many), // input .hba_data_in_many (d2h_many), // input
.hba_data_in_ready (d2h_ready), // output .hba_data_in_ready (d2h_ready), // output
.dma_in_ready (), // input .dma_in_ready (dma_in_ready), // input
.dma_in_valid () // output .dma_in_valid (dma_we) // output
); );
ahci_fis_transmit #( ahci_fis_transmit #(
...@@ -378,10 +464,12 @@ module ahci_top#( ...@@ -378,10 +464,12 @@ module ahci_top#(
) ahci_fis_transmit_i ( ) ahci_fis_transmit_i (
.hba_rst (hba_rst), // input .hba_rst (hba_rst), // input
.mclk (mclk), // input .mclk (mclk), // input
.fetch_cmd (), // input .fetch_cmd (), // input
.cfis_xmit (), // input .cfis_xmit (), // input
.dx_transmit (), // input .dx_transmit (), // input
.atapi_xmit (), // input .atapi_xmit (), // input
.done (), // output reg .done (), // output reg
.busy (), // output reg .busy (), // output reg
.clearCmdToIssue (), // input .clearCmdToIssue (), // input
...@@ -400,21 +488,21 @@ module ahci_top#( ...@@ -400,21 +488,21 @@ module ahci_top#(
.ch_cfl (), // output[4:0] .ch_cfl (), // output[4:0]
.dwords_sent (), // output[11:2] reg .dwords_sent (), // output[11:2] reg
.reg_addr (regs_raddr), // output[9:0] reg .reg_addr (regs_raddr), // output[9:0] reg
.reg_re (regs_re), // output[1:0] .reg_re (regs_re_ftransmit), // output[1:0]
.reg_rdata (regs_dout), // input[31:0] .reg_rdata (regs_dout), // input[31:0]
.xfer_cntr (), // input[31:2] .xfer_cntr (xfer_cntr[31:2]), // input[31:2]
.dma_ctba_ld (ctba_ld), // output .dma_ctba_ld (ctba_ld), // output
.dma_start (dma_cmd_start), // output .dma_start (dma_cmd_start), // output
.dma_dev_wr (), // output .dma_dev_wr (dev_wr), // output
.dma_ct_busy (), // input .dma_ct_busy (dma_ct_busy), // input
.dma_prd_start (dma_prd_start), // output reg .dma_prd_start (dma_prd_start), // output reg
.dma_cmd_abort (dma_cmd_abort), // output reg .dma_cmd_abort (dma_cmd_abort), // output reg
.ct_addr (dma_ct_addr), // output[4:0] reg .ct_addr (dma_ct_addr), // output[4:0] reg
.ct_re (dma_ct_re), // output[1:0] .ct_re (dma_ct_re), // output[1:0]
.ct_data (), // input[31:0] .ct_data (dma_ct_data), // input[31:0]
.dma_out (), // input[31:0] .dma_out (dma_dout), // input[31:0]
.dma_dav (), // input .dma_dav (dma_dav), // input
.dma_re (), // output .dma_re (dma_re), // output
.todev_data (h2d_data), // output[31:0] reg .todev_data (h2d_data), // output[31:0] reg
.todev_type (h2d_type), // output[1:0] reg .todev_type (h2d_type), // output[1:0] reg
.todev_valid (h2d_valid), // output .todev_valid (h2d_valid), // output
......
...@@ -39,7 +39,8 @@ ...@@ -39,7 +39,8 @@
module axi_ahci_regs#( module axi_ahci_regs#(
// parameter ADDRESS_BITS = 8 // number of memory address bits // parameter ADDRESS_BITS = 8 // number of memory address bits
parameter ADDRESS_BITS = 10 // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle) parameter ADDRESS_BITS = 10, // number of memory address bits - now fixed. Low half - RO/RW/RWC,RW1 (2-cycle write), 2-nd just RW (single-cycle)
parameter HBA_RESET_BITS = 9 // duration of HBA reset in aclk periods (9: ~10usec)
)( )(
input aclk, // clock - should be buffered input aclk, // clock - should be buffered
input arst, // @aclk sync reset, active high input arst, // @aclk sync reset, active high
...@@ -85,11 +86,12 @@ module axi_ahci_regs#( ...@@ -85,11 +86,12 @@ module axi_ahci_regs#(
output [ADDRESS_BITS-1:0] soft_write_addr, // register address written by software output [ADDRESS_BITS-1:0] soft_write_addr, // register address written by software
output [31:0] soft_write_data, // register data written (after applying wstb and type (RO, RW, RWC, RW1) output [31:0] soft_write_data, // register data written (after applying wstb and type (RO, RW, RWC, RW1)
output soft_write_en, // write enable for data write output soft_write_en, // write enable for data write
output soft_arst, // reset SATA PHY not relying on SATA clock output hba_arst, // hba async reset (currently does ~ the same as port reset)
// TODO: Decode from {bram_addr, ahci_regs_di}, bram_wen_d output port_arst, // port0 async reset by software
// 2. HBA R/W registers, use hba clock // 2. HBA R/W registers, use hba clock
input hba_clk, input hba_clk, // SATA clock, now 75MHz
input hba_rst, input hba_rst, // when PLL locked, SATA PHY reset is over, this signal is released
input [ADDRESS_BITS-1:0] hba_addr, input [ADDRESS_BITS-1:0] hba_addr,
input hba_we, input hba_we,
// input [3:0] hba_wstb, Needed? // input [3:0] hba_wstb, Needed?
...@@ -97,6 +99,18 @@ module axi_ahci_regs#( ...@@ -97,6 +99,18 @@ module axi_ahci_regs#(
input [31:0] hba_din, input [31:0] hba_din,
output [31:0] hba_dout output [31:0] hba_dout
); );
`include "includes/ahci_localparams.vh" // @SuppressThisWarning VEditor : Unused localparams
/*
localparam GHC__GHC__HR__ADDR = 'h1;
localparam GHC__GHC__HR__MASK = 'h1;
localparam GHC__GHC__HR__DFLT = 'h0;
// RO: Device Detection Initialization
localparam HBA_PORT__PxSCTL__DET__ADDR = 'h4b;
localparam HBA_PORT__PxSCTL__DET__MASK = 'hf;
localparam HBA_PORT__PxSCTL__DET__DFLT = 'h0;
*/
wire [ADDRESS_BITS-1:0] bram_waddr; wire [ADDRESS_BITS-1:0] bram_waddr;
// wire [ADDRESS_BITS-1:0] pre_awaddr; // wire [ADDRESS_BITS-1:0] pre_awaddr;
wire [ADDRESS_BITS-1:0] bram_raddr; wire [ADDRESS_BITS-1:0] bram_raddr;
...@@ -123,9 +137,19 @@ module axi_ahci_regs#( ...@@ -123,9 +137,19 @@ module axi_ahci_regs#(
// wire [31:0] wmask = {{8{bram_wstb[3]}},{8{bram_wstb[2]}},{8{bram_wstb[1]}},{8{bram_wstb[0]}}}; // wire [31:0] wmask = {{8{bram_wstb[3]}},{8{bram_wstb[2]}},{8{bram_wstb[1]}},{8{bram_wstb[0]}}};
wire [31:0] wmask = {{8{bram_wstb_r[3]}},{8{bram_wstb_r[2]}},{8{bram_wstb_r[1]}},{8{bram_wstb_r[0]}}}; wire [31:0] wmask = {{8{bram_wstb_r[3]}},{8{bram_wstb_r[2]}},{8{bram_wstb_r[1]}},{8{bram_wstb_r[0]}}};
reg [ADDRESS_BITS-1:0] bram_waddr_r; reg [ADDRESS_BITS-1:0] bram_waddr_r;
reg [HBA_RESET_BITS-1:0] hba_reset_cntr = 1; // time to keep hba_reset_r active after writing to GHC.HR
reg hba_nrst_r; // hba _reset (currently does ~ the same as port reset)
reg port_nrst_r; // port _reset by software
wire high_sel = bram_waddr_r[ADDRESS_BITS-1]; // high addresses - use single-cycle writes without read-modify-write wire high_sel = bram_waddr_r[ADDRESS_BITS-1]; // high addresses - use single-cycle writes without read-modify-write
// assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen ? bram_waddr : pre_awaddr); // assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen ? bram_waddr : pre_awaddr);
assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen_r ? bram_waddr_r : bram_waddr); assign bram_addr = bram_ren[0] ? bram_raddr : (bram_wen_r ? bram_waddr_r : bram_waddr);
assign hba_arst = !hba_nrst_r; // hba _reset (currently does ~ the same as port reset)
assign port_arst = !port_nrst_r; // port _reset by software
always @(posedge aclk) begin always @(posedge aclk) begin
if (arst) write_busy_r <= 0; if (arst) write_busy_r <= 0;
else if (write_start_burst) write_busy_r <= 1; else if (write_start_burst) write_busy_r <= 1;
...@@ -156,6 +180,57 @@ module axi_ahci_regs#( ...@@ -156,6 +180,57 @@ module axi_ahci_regs#(
end end
endgenerate endgenerate
always @(posedge aclk) begin
if (arst) hba_reset_cntr <= 1;
else if (bram_wen_r && !high_sel &&
(bram_addr == GHC__GHC__HR__ADDR) &&
(ahci_regs_di & GHC__GHC__HR__MASK)) hba_reset_cntr <= {HBA_RESET_BITS{1'b1}};
else if (|hba_reset_cntr) hba_reset_cntr <= hba_reset_cntr - 1;
hba_nrst_r <= hba_reset_cntr == 0;
if (arst) port_nrst_r <= 0;
else if (bram_wen_r && !high_sel &&
(bram_addr == HBA_PORT__PxSCTL__DET__ADDR) &&
((ahci_regs_di & HBA_PORT__PxSCTL__DET__MASK | 1) == HBA_PORT__PxSCTL__DET__MASK))
port_nrst_r <= !ahci_regs_di[0]; // write "1" - reset on, write 0 - reset off
end
/*
Will generate async reset on both HBA reset(for some time) and port reset (until released)
until it is more clear about GTX reset options. Such reset will be applied to both PLL and GTX,
sata_phy_rst_out will be released after the sata clock is stable
output soft_arst, // reset SATA PHY not relying on SATA clock
// TODO: Decode from {bram_addr, ahci_regs_di}, bram_wen_d
input sata_phy_rst_out, // when PLL locked, SATA PHY reset is over, this signal is released
localparam GHC__GHC__HR__ADDR = 'h1;
localparam GHC__GHC__HR__MASK = 'h1;
localparam GHC__GHC__HR__DFLT = 'h0;
reg [HBA_RESET_BITS-1:0] hba_reset_cntr; // time to keep hba_reset_r active after writing to GHC.HR
reg hba_rst_r; // hba reset (currently does ~ the same as port reset)
reg port_rst_r; // port reset by software
.rst (1'b0), // input
.rrst (hba_rst), // input
.wrst (arst), // input
.rclk (hba_clk), // input
.wclk (aclk), // input
.we (bram_wen_r && !high_sel), // input
.re (soft_write_en), // input
.data_in ({bram_addr, ahci_regs_di}), // input[15:0]
.data_out ({soft_write_addr,soft_write_data}), // output[15:0]
.nempty (soft_write_en), // output
.half_empty () // output
// RO: Device Detection Initialization
localparam HBA_PORT__PxSCTL__DET__ADDR = 'h4b;
localparam HBA_PORT__PxSCTL__DET__MASK = 'hf;
localparam HBA_PORT__PxSCTL__DET__DFLT = 'h0;
*/
axibram_write #( axibram_write #(
.ADDRESS_BITS(ADDRESS_BITS) .ADDRESS_BITS(ADDRESS_BITS)
) axibram_write_i ( ) axibram_write_i (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment