rtl:perips: remove flash_ctrl module

Signed-off-by: liangkangnan <liangkangnan@163.com>
verilator
liangkangnan 2023-04-01 15:50:29 +08:00
parent ad3dbd1a51
commit 6d37b9fc9c
9 changed files with 0 additions and 1846 deletions

View File

@ -1,71 +0,0 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "flash_ctrl",
clocking: [{clock: "clk_i", reset: "rst_ni"}],
bus_interfaces: [
{ protocol: "tlul", direction: "device" }
],
regwidth: "32",
registers: [
{ name: "CTRL",
desc: "flash_ctrl control register",
swaccess: "rw",
hwaccess: "hrw",
hwqe: "true",
fields: [
{ bits: "0",
name: "START",
desc: "start read or write",
}
{ bits: "2:1",
name: "OP_MODE",
desc: "0: read, 1: program, 2: erase, 3: qspi init",
}
{ bits: "3",
name: "SW_CTRL",
desc: "0: hardware ctrl, 1: software ctrl",
}
{ bits: "4",
name: "PROGRAM_INIT",
desc: "0: not program, 1: prepare for program",
}
{ bits: "5",
name: "WRITE_ERROR",
swaccess: "ro",
desc: "0: write succ, 1: write error",
}
{ bits: "31:6",
swaccess: "r0w1c",
name: "RESERVED",
desc: "reserved, not use",
}
]
}
{ name: "ADDR",
desc: "flash_ctrl address register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "22:0",
name: "RW_ADDRESS",
desc: "read or write address",
}
{ bits: "31:23",
swaccess: "r0w1c",
name: "RESERVED",
desc: "reserved, not use",
}
]
}
{ name: "DATA",
desc: "flash_ctrl data register",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "31:0",
}
]
}
]
}

View File

@ -1,279 +0,0 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module flash_ctrl_core (
input logic clk_i,
input logic rst_ni,
// SPI引脚信号
output logic spi_clk_o,
output logic spi_clk_oe_o,
output logic spi_ss_o,
output logic spi_ss_oe_o,
input logic spi_dq0_i,
output logic spi_dq0_o,
output logic spi_dq0_oe_o,
input logic spi_dq1_i,
output logic spi_dq1_o,
output logic spi_dq1_oe_o,
input logic spi_dq2_i,
output logic spi_dq2_o,
output logic spi_dq2_oe_o,
input logic spi_dq3_i,
output logic spi_dq3_o,
output logic spi_dq3_oe_o,
// OBI总线接口信号
input logic req_i,
input logic we_i,
input logic [ 3:0] be_i,
input logic [31:0] addr_i,
input logic [31:0] data_i,
output logic gnt_o,
output logic rvalid_o,
output logic [31:0] data_o
);
import flash_ctrl_reg_pkg::*;
flash_ctrl_reg_pkg::flash_ctrl_reg2hw_t reg2hw;
flash_ctrl_reg_pkg::flash_ctrl_hw2reg_t hw2reg;
// 状态
localparam S_IDLE = 5'b00001;
localparam S_INIT = 5'b00010;
localparam S_READ = 5'b00100;
localparam S_PROGRAM = 5'b01000;
localparam S_ERASE = 5'b10000;
// 操作
localparam OP_READ = 2'b00;
localparam OP_PROGRAM = 2'b01;
localparam OP_ERASE = 2'b10;
localparam OP_QSPI_INIT = 2'b11;
logic [4:0] state_d, state_q;
logic [31:0] op_addr_d, op_addr_q;
logic [31:0] op_data_d, op_data_q;
logic [1:0] op_mode_d, op_mode_q;
logic op_start_d, op_start_q;
logic sw_access_d, sw_access_q;
logic we;
logic re;
logic [31:0] addr;
logic [31:0] reg_rdata;
logic rvalid;
logic sw_access;
logic op_ready;
logic op_idle, op_idle_q;
logic op_error;
logic [31:0] op_rdata;
logic sw_start;
logic [1:0] sw_op_mode;
logic sw_ctrl;
logic sw_program_init;
logic sw_program_init_q;
logic [31:0] sw_rw_addr;
logic [31:0] sw_rw_data;
logic hw_write_start_bit_en;
logic hw_write_start_bit_data;
// 寄存器值
assign sw_start = reg2hw.ctrl.start.q && reg2hw.ctrl.start.qe;
assign sw_op_mode = reg2hw.ctrl.op_mode.q;
assign sw_ctrl = reg2hw.ctrl.sw_ctrl.q;
assign sw_program_init = reg2hw.ctrl.program_init.q;
assign sw_rw_addr = {9'h0, reg2hw.addr.rw_address.q};
assign sw_rw_data = reg2hw.data.q;
always_comb begin
// 操作完成清start位
if ((op_ready && sw_access_q) ||
((~op_idle_q) && op_idle)) begin
hw_write_start_bit_en = 1'b1;
hw_write_start_bit_data = 1'b0;
end else if (sw_program_init_q && (~sw_program_init)) begin
hw_write_start_bit_en = 1'b1;
hw_write_start_bit_data = 1'b1;
end else begin
hw_write_start_bit_en = 1'b0;
hw_write_start_bit_data = 1'b0;
end
end
// 硬件清start位
assign hw2reg.ctrl.start.d = hw_write_start_bit_data;
assign hw2reg.ctrl.start.de = hw_write_start_bit_en;
// 硬件更新data寄存器
assign hw2reg.data.d = op_rdata;
assign hw2reg.data.de = op_ready && sw_access_q && (state_q == S_READ);
// 硬件更新write result位
assign hw2reg.ctrl.write_error.d = op_error;
assign hw2reg.ctrl.write_error.de = op_ready && sw_access_q;
assign we = req_i && we_i;
assign re = req_i && (~we_i);
assign addr = {9'h0, addr_i[22:0]};
// 软件访问addr_i[23]=0表示是软件访问addr_i[23]=1表示硬件访问(取指或者取数据)
assign sw_access = (~addr_i[23]);
always_comb begin
state_d = state_q;
op_addr_d = op_addr_q;
op_data_d = op_data_q;
op_mode_d = op_mode_q;
op_start_d = 1'b0;
sw_access_d = sw_access_q;
case (state_q)
S_IDLE: begin
op_data_d = sw_rw_data;
// addr_i[23]表示硬件访问(取指或者取数据)
sw_access_d = sw_access;
// 软件访问(读、编程、QSPI初始化)
if (sw_start && sw_ctrl) begin
if (sw_op_mode == OP_READ) begin
state_d = S_READ;
end else if (sw_op_mode == OP_PROGRAM) begin
state_d = S_PROGRAM;
end else if (sw_op_mode == OP_ERASE) begin
state_d = S_ERASE;
end else begin
state_d = S_INIT;
end
op_addr_d = sw_rw_addr;
op_mode_d = sw_op_mode;
op_start_d = 1'b1;
// 硬件访问(取指、取数据)
end else if (re && (~sw_access)) begin
state_d = S_READ;
op_addr_d = addr;
op_mode_d = OP_READ;
op_start_d = 1'b1;
end
end
S_INIT: begin
if (op_ready) begin
state_d = S_IDLE;
end
end
S_READ: begin
if (op_ready) begin
state_d = S_IDLE;
end
end
S_PROGRAM: begin
if (op_ready) begin
state_d = S_IDLE;
end
end
S_ERASE: begin
if (op_ready) begin
state_d = S_IDLE;
end
end
default: ;
endcase
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
state_q <= S_IDLE;
op_addr_q <= '0;
op_data_q <= '0;
op_mode_q <= '0;
op_start_q <= '0;
sw_access_q <= '0;
end else begin
state_q <= state_d;
op_addr_q <= op_addr_d;
op_data_q <= op_data_d;
op_mode_q <= op_mode_d;
op_start_q <= op_start_d;
sw_access_q <= sw_access_d;
end
end
assign gnt_o = (state_q == S_IDLE) && req_i;
assign rvalid = (sw_access && req_i) || op_ready;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
rvalid_o <= '0;
data_o <= '0;
op_idle_q <= 1'b1;
sw_program_init_q <= '0;
end else begin
rvalid_o <= rvalid;
data_o <= (op_ready ? op_rdata : reg_rdata);
op_idle_q <= op_idle;
sw_program_init_q <= sw_program_init;
end
end
flash_n25q_top u_flash_n25q_top (
.clk_i,
.rst_ni,
.start_i (op_start_q),
.program_init_i (sw_program_init),
.addr_i (op_addr_q),
.data_i (op_data_q),
.op_mode_i (op_mode_q),
.data_o (op_rdata),
.ready_o (op_ready),
.idle_o (op_idle),
.write_error_o (op_error),
.spi_clk_o,
.spi_clk_oe_o,
.spi_ss_o,
.spi_ss_oe_o,
.spi_dq0_i,
.spi_dq0_o,
.spi_dq0_oe_o,
.spi_dq1_i,
.spi_dq1_o,
.spi_dq1_oe_o,
.spi_dq2_i,
.spi_dq2_o,
.spi_dq2_oe_o,
.spi_dq3_i,
.spi_dq3_o,
.spi_dq3_oe_o
);
flash_ctrl_reg_top u_flash_ctrl_reg_top (
.clk_i (clk_i),
.rst_ni (rst_ni),
.reg2hw (reg2hw),
.hw2reg (hw2reg),
.reg_we (we & sw_access),
.reg_re (re & sw_access),
.reg_wdata (data_i),
.reg_be (be_i),
.reg_addr (addr),
.reg_rdata (reg_rdata)
);
endmodule

View File

@ -1,121 +0,0 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Register Package auto-generated by `reggen` containing data structure
package flash_ctrl_reg_pkg;
// Address widths within the block
parameter int BlockAw = 4;
////////////////////////////
// Typedefs for registers //
////////////////////////////
typedef struct packed {
struct packed {
logic q;
logic qe;
} start;
struct packed {
logic [1:0] q;
logic qe;
} op_mode;
struct packed {
logic q;
logic qe;
} sw_ctrl;
struct packed {
logic q;
logic qe;
} program_init;
struct packed {
logic q;
logic qe;
} write_error;
struct packed {
logic [25:0] q;
logic qe;
} reserved;
} flash_ctrl_reg2hw_ctrl_reg_t;
typedef struct packed {
struct packed {
logic [22:0] q;
} rw_address;
struct packed {
logic [8:0] q;
} reserved;
} flash_ctrl_reg2hw_addr_reg_t;
typedef struct packed {
logic [31:0] q;
} flash_ctrl_reg2hw_data_reg_t;
typedef struct packed {
struct packed {
logic d;
logic de;
} start;
struct packed {
logic [1:0] d;
logic de;
} op_mode;
struct packed {
logic d;
logic de;
} sw_ctrl;
struct packed {
logic d;
logic de;
} program_init;
struct packed {
logic d;
logic de;
} write_error;
struct packed {
logic [25:0] d;
logic de;
} reserved;
} flash_ctrl_hw2reg_ctrl_reg_t;
typedef struct packed {
logic [31:0] d;
logic de;
} flash_ctrl_hw2reg_data_reg_t;
// Register -> HW type
typedef struct packed {
flash_ctrl_reg2hw_ctrl_reg_t ctrl; // [101:64]
flash_ctrl_reg2hw_addr_reg_t addr; // [63:32]
flash_ctrl_reg2hw_data_reg_t data; // [31:0]
} flash_ctrl_reg2hw_t;
// HW -> register type
typedef struct packed {
flash_ctrl_hw2reg_ctrl_reg_t ctrl; // [70:33]
flash_ctrl_hw2reg_data_reg_t data; // [32:0]
} flash_ctrl_hw2reg_t;
// Register offsets
parameter logic [BlockAw-1:0] FLASH_CTRL_CTRL_OFFSET = 4'h0;
parameter logic [BlockAw-1:0] FLASH_CTRL_ADDR_OFFSET = 4'h4;
parameter logic [BlockAw-1:0] FLASH_CTRL_DATA_OFFSET = 4'h8;
// Register index
typedef enum int {
FLASH_CTRL_CTRL,
FLASH_CTRL_ADDR,
FLASH_CTRL_DATA
} flash_ctrl_id_e;
// Register width information to check illegal writes
parameter logic [3:0] FLASH_CTRL_PERMIT [3] = '{
4'b1111, // index[0] FLASH_CTRL_CTRL
4'b1111, // index[1] FLASH_CTRL_ADDR
4'b1111 // index[2] FLASH_CTRL_DATA
};
endpackage

View File

@ -1,375 +0,0 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Register Top module auto-generated by `reggen`
module flash_ctrl_reg_top (
input logic clk_i,
input logic rst_ni,
// To HW
output flash_ctrl_reg_pkg::flash_ctrl_reg2hw_t reg2hw, // Write
input flash_ctrl_reg_pkg::flash_ctrl_hw2reg_t hw2reg, // Read
input logic reg_we,
input logic reg_re,
input logic [31:0] reg_wdata,
input logic [ 3:0] reg_be,
input logic [31:0] reg_addr,
output logic [31:0] reg_rdata
);
import flash_ctrl_reg_pkg::* ;
localparam int AW = 4;
localparam int DW = 32;
localparam int DBW = DW/8; // Byte Width
logic reg_error;
logic addrmiss, wr_err;
logic [DW-1:0] reg_rdata_next;
assign reg_rdata = reg_rdata_next;
assign reg_error = wr_err;
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
// or <reg>_{wd|we|qs} if field == 1 or 0
logic ctrl_we;
logic ctrl_start_qs;
logic ctrl_start_wd;
logic [1:0] ctrl_op_mode_qs;
logic [1:0] ctrl_op_mode_wd;
logic ctrl_sw_ctrl_qs;
logic ctrl_sw_ctrl_wd;
logic ctrl_program_init_qs;
logic ctrl_program_init_wd;
logic ctrl_write_error_qs;
logic [25:0] ctrl_reserved_wd;
logic addr_we;
logic [22:0] addr_rw_address_qs;
logic [22:0] addr_rw_address_wd;
logic [8:0] addr_reserved_wd;
logic data_we;
logic [31:0] data_qs;
logic [31:0] data_wd;
// Register instances
// R[ctrl]: V(False)
// F[start]: 0:0
prim_subreg #(
.DW (1),
.SWACCESS("RW"),
.RESVAL (1'h0)
) u_ctrl_start (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (ctrl_we),
.wd (ctrl_start_wd),
// from internal hardware
.de (hw2reg.ctrl.start.de),
.d (hw2reg.ctrl.start.d),
// to internal hardware
.qe (reg2hw.ctrl.start.qe),
.q (reg2hw.ctrl.start.q),
// to register interface (read)
.qs (ctrl_start_qs)
);
// F[op_mode]: 2:1
prim_subreg #(
.DW (2),
.SWACCESS("RW"),
.RESVAL (2'h0)
) u_ctrl_op_mode (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (ctrl_we),
.wd (ctrl_op_mode_wd),
// from internal hardware
.de (hw2reg.ctrl.op_mode.de),
.d (hw2reg.ctrl.op_mode.d),
// to internal hardware
.qe (reg2hw.ctrl.op_mode.qe),
.q (reg2hw.ctrl.op_mode.q),
// to register interface (read)
.qs (ctrl_op_mode_qs)
);
// F[sw_ctrl]: 3:3
prim_subreg #(
.DW (1),
.SWACCESS("RW"),
.RESVAL (1'h0)
) u_ctrl_sw_ctrl (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (ctrl_we),
.wd (ctrl_sw_ctrl_wd),
// from internal hardware
.de (hw2reg.ctrl.sw_ctrl.de),
.d (hw2reg.ctrl.sw_ctrl.d),
// to internal hardware
.qe (reg2hw.ctrl.sw_ctrl.qe),
.q (reg2hw.ctrl.sw_ctrl.q),
// to register interface (read)
.qs (ctrl_sw_ctrl_qs)
);
// F[program_init]: 4:4
prim_subreg #(
.DW (1),
.SWACCESS("RW"),
.RESVAL (1'h0)
) u_ctrl_program_init (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (ctrl_we),
.wd (ctrl_program_init_wd),
// from internal hardware
.de (hw2reg.ctrl.program_init.de),
.d (hw2reg.ctrl.program_init.d),
// to internal hardware
.qe (reg2hw.ctrl.program_init.qe),
.q (reg2hw.ctrl.program_init.q),
// to register interface (read)
.qs (ctrl_program_init_qs)
);
// F[write_error]: 5:5
prim_subreg #(
.DW (1),
.SWACCESS("RO"),
.RESVAL (1'h0)
) u_ctrl_write_error (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (1'b0),
.wd ('0),
// from internal hardware
.de (hw2reg.ctrl.write_error.de),
.d (hw2reg.ctrl.write_error.d),
// to internal hardware
.qe (reg2hw.ctrl.write_error.qe),
.q (reg2hw.ctrl.write_error.q),
// to register interface (read)
.qs (ctrl_write_error_qs)
);
// F[reserved]: 31:6
prim_subreg #(
.DW (26),
.SWACCESS("W1C"),
.RESVAL (26'h0)
) u_ctrl_reserved (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (ctrl_we),
.wd (ctrl_reserved_wd),
// from internal hardware
.de (hw2reg.ctrl.reserved.de),
.d (hw2reg.ctrl.reserved.d),
// to internal hardware
.qe (reg2hw.ctrl.reserved.qe),
.q (reg2hw.ctrl.reserved.q),
// to register interface (read)
.qs ()
);
// R[addr]: V(False)
// F[rw_address]: 22:0
prim_subreg #(
.DW (23),
.SWACCESS("RW"),
.RESVAL (23'h0)
) u_addr_rw_address (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (addr_we),
.wd (addr_rw_address_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.addr.rw_address.q),
// to register interface (read)
.qs (addr_rw_address_qs)
);
// F[reserved]: 31:23
prim_subreg #(
.DW (9),
.SWACCESS("W1C"),
.RESVAL (9'h0)
) u_addr_reserved (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (addr_we),
.wd (addr_reserved_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.addr.reserved.q),
// to register interface (read)
.qs ()
);
// R[data]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_data (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (data_we),
.wd (data_wd),
// from internal hardware
.de (hw2reg.data.de),
.d (hw2reg.data.d),
// to internal hardware
.qe (),
.q (reg2hw.data.q),
// to register interface (read)
.qs (data_qs)
);
logic [2:0] addr_hit;
always_comb begin
addr_hit = '0;
addr_hit[0] = (reg_addr == FLASH_CTRL_CTRL_OFFSET);
addr_hit[1] = (reg_addr == FLASH_CTRL_ADDR_OFFSET);
addr_hit[2] = (reg_addr == FLASH_CTRL_DATA_OFFSET);
end
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
// Check sub-word write is permitted
always_comb begin
wr_err = (reg_we &
((addr_hit[0] & (|(FLASH_CTRL_PERMIT[0] & ~reg_be))) |
(addr_hit[1] & (|(FLASH_CTRL_PERMIT[1] & ~reg_be))) |
(addr_hit[2] & (|(FLASH_CTRL_PERMIT[2] & ~reg_be)))));
end
assign ctrl_we = addr_hit[0] & reg_we & !reg_error;
assign ctrl_start_wd = reg_wdata[0];
assign ctrl_op_mode_wd = reg_wdata[2:1];
assign ctrl_sw_ctrl_wd = reg_wdata[3];
assign ctrl_program_init_wd = reg_wdata[4];
assign ctrl_reserved_wd = reg_wdata[31:6];
assign addr_we = addr_hit[1] & reg_we & !reg_error;
assign addr_rw_address_wd = reg_wdata[22:0];
assign addr_reserved_wd = reg_wdata[31:23];
assign data_we = addr_hit[2] & reg_we & !reg_error;
assign data_wd = reg_wdata[31:0];
// Read data return
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
addr_hit[0]: begin
reg_rdata_next[0] = ctrl_start_qs;
reg_rdata_next[2:1] = ctrl_op_mode_qs;
reg_rdata_next[3] = ctrl_sw_ctrl_qs;
reg_rdata_next[4] = ctrl_program_init_qs;
reg_rdata_next[5] = ctrl_write_error_qs;
reg_rdata_next[31:6] = '0;
end
addr_hit[1]: begin
reg_rdata_next[22:0] = addr_rw_address_qs;
reg_rdata_next[31:23] = '0;
end
addr_hit[2]: begin
reg_rdata_next[31:0] = data_qs;
end
default: begin
reg_rdata_next = '1;
end
endcase
end
// Unused signal tieoff
// wdata / byte enable are not always fully used
// add a blanket unused statement to handle lint waivers
logic unused_wdata;
logic unused_be;
assign unused_wdata = ^reg_wdata;
assign unused_be = ^reg_be;
endmodule

View File

@ -1,79 +0,0 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module flash_ctrl_top (
input logic clk_i,
input logic rst_ni,
// SPI引脚信号
output logic spi_clk_o,
output logic spi_clk_oe_o,
output logic spi_ss_o,
output logic spi_ss_oe_o,
input logic spi_dq0_i,
output logic spi_dq0_o,
output logic spi_dq0_oe_o,
input logic spi_dq1_i,
output logic spi_dq1_o,
output logic spi_dq1_oe_o,
input logic spi_dq2_i,
output logic spi_dq2_o,
output logic spi_dq2_oe_o,
input logic spi_dq3_i,
output logic spi_dq3_o,
output logic spi_dq3_oe_o,
// OBI总线接口信号
input logic req_i,
input logic we_i,
input logic [ 3:0] be_i,
input logic [31:0] addr_i,
input logic [31:0] data_i,
output logic gnt_o,
output logic rvalid_o,
output logic [31:0] data_o
);
flash_ctrl_core u_flash_ctrl_core (
.clk_i,
.rst_ni,
.spi_clk_o,
.spi_clk_oe_o,
.spi_ss_o,
.spi_ss_oe_o,
.spi_dq0_i,
.spi_dq0_o,
.spi_dq0_oe_o,
.spi_dq1_i,
.spi_dq1_o,
.spi_dq1_oe_o,
.spi_dq2_i,
.spi_dq2_o,
.spi_dq2_oe_o,
.spi_dq3_i,
.spi_dq3_o,
.spi_dq3_oe_o,
.req_i,
.we_i,
.be_i,
.addr_i,
.data_i,
.gnt_o,
.rvalid_o,
.data_o
);
endmodule

View File

@ -1,54 +0,0 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flash_n25q_pkg;
parameter logic [7:0] MANF_ID = 8'h20;
parameter logic [7:0] DEV_ID = 8'hBA;
// dummy个数. bytes = dummy / 2
parameter logic [3:0] DUMMY_CNT = 4'd10;
// SS引脚延时时钟数
parameter logic [7:0] SS_DELAY_CNT = 8'd30;
// 命令
parameter logic [7:0] CMD_READ_ID = 8'h9F;
parameter logic [7:0] CMD_MULTIO_READ_ID = 8'hAF;
parameter logic [7:0] CMD_READ_QSPI_REG = 8'h65;
parameter logic [7:0] CMD_WRITE_QSPI_REG = 8'h61;
parameter logic [7:0] CMD_READ = 8'h03;
parameter logic [7:0] CMD_READ_STATUS_REG = 8'h05;
parameter logic [7:0] CMD_READ_FLAG_STATUS_REG = 8'h70;
parameter logic [7:0] CMD_CLEAR_FLAG_STATUS_REG = 8'h50;
parameter logic [7:0] CMD_FAST_READ = 8'h0B;
parameter logic [7:0] CMD_PAGE_PROG = 8'h02;
parameter logic [7:0] CMD_SUBSECTOR_ERASE = 8'h20;
parameter logic [7:0] CMD_WRITE_ENABLE = 8'h06;
parameter logic [7:0] CMD_WRITE_DISABLE = 8'h04;
parameter logic [7:0] CMD_READ_DUMMY_REG = 8'h85;
parameter logic [7:0] CMD_WRITE_DUMMY_REG = 8'h81;
// SPI CPOL/CPHL模式
parameter logic [1:0] CPOL_0_CPHA_0 = 2'b00;
parameter logic [1:0] CPOL_0_CPHA_1 = 2'b01;
parameter logic [1:0] CPOL_1_CPHA_0 = 2'b10;
parameter logic [1:0] CPOL_1_CPHA_1 = 2'b11;
// SPI模式
parameter logic [1:0] MODE_STAND_SPI = 2'b00;
parameter logic [1:0] MODE_DUAL_SPI = 2'b01;
parameter logic [1:0] MODE_QUAD_SPI = 2'b10;
endpackage

View File

@ -1,461 +0,0 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module flash_n25q_top (
input logic clk_i,
input logic rst_ni,
input logic start_i, // 开始操作
input logic program_init_i, // 编程中
input logic [31:0] addr_i, // 读或者编程地址
input logic [31:0] data_i, // 编程数据
input logic [1:0] op_mode_i, // 哪一种操作
output logic [31:0] data_o, // 操作完成返回的数据
output logic ready_o, // 操作完成
output logic idle_o, // 空闲
output logic write_error_o, // 空闲
// SPI引脚信号
output logic spi_clk_o,
output logic spi_clk_oe_o,
output logic spi_ss_o,
output logic spi_ss_oe_o,
input logic spi_dq0_i,
output logic spi_dq0_o,
output logic spi_dq0_oe_o,
input logic spi_dq1_i,
output logic spi_dq1_o,
output logic spi_dq1_oe_o,
input logic spi_dq2_i,
output logic spi_dq2_o,
output logic spi_dq2_oe_o,
input logic spi_dq3_i,
output logic spi_dq3_o,
output logic spi_dq3_oe_o
);
import flash_n25q_tran_pkg::*;
import flash_n25q_pkg::*;
// 状态
localparam S_IDLE = 14'h1; // 主状态
localparam S_READ = 14'h2; // 主状态
localparam S_PROGRAM = 14'h4; // 主状态
localparam S_ERASE = 14'h8; // 主状态
localparam S_WRITE_ENABLE = 14'h10; // 子主状态
localparam S_WRITE_DISABLE = 14'h20; // 子主状态
localparam S_CHECK_BUSY = 14'h40; // 子主状态
localparam S_QSPI_INIT = 14'h80; // 主状态
localparam S_MULTIIO_READ_ID = 14'h100; // 子主状态
localparam S_WRITE_DUMMY_REG = 14'h200; // 子主状态
localparam S_WRITE_QSPI_REG = 14'h400; // 子主状态
localparam S_WAIT_DATA = 14'h800; // 子主状态
localparam S_READ_FLAG_STATUS_REG = 14'h1000; // 子主状态
localparam S_CLEAR_FLAG_STATUS_REG = 14'h2000; // 子主状态
logic [13:0] state_d, state_q, state_prev_q, return_state_d, return_state_q;
logic [1:0] spi_mode_d, spi_mode_q;
logic [31:0] rdata_d, rdata_q;
logic write_error_d, write_error_q;
logic tran_idle;
flash_n25q_tran_pkg::flash_n25q_tran_req_t tran_req_d, tran_req_q;
flash_n25q_tran_pkg::flash_n25q_tran_resp_t tran_resp;
always_comb begin
state_d = state_q;
tran_req_d = tran_req_q;
tran_req_d.start = 1'b0;
return_state_d = return_state_q;
spi_mode_d = spi_mode_q;
rdata_d = rdata_q;
write_error_d = write_error_q;
case (state_q)
S_IDLE: begin
if (start_i) begin
if (op_mode_i == 2'b00) begin
state_d = S_READ;
end else if (op_mode_i == 2'b01) begin
state_d = S_PROGRAM;
end else if (op_mode_i == 2'b10) begin
state_d = S_ERASE;
end else begin
// 当前不为QSPI模式时才初始化
if (spi_mode_q != MODE_QUAD_SPI) begin
state_d = S_QSPI_INIT;
end
end
end
end
// 读数据
S_READ: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = spi_mode_q;
if (spi_mode_q == MODE_QUAD_SPI) begin
tran_req_d.cmd = CMD_FAST_READ;
end else begin
tran_req_d.cmd = CMD_READ;
end
tran_req_d.addr.d = addr_i;
tran_req_d.addr.be = 4'b0111;
tran_req_d.dummy.d = '0;
if (spi_mode_q == MODE_QUAD_SPI) begin
tran_req_d.dummy.cnt = {1'b0, DUMMY_CNT[3:1]};
end else begin
tran_req_d.dummy.cnt = '0;
end
tran_req_d.data.d = '0;
// 以word为单位每次操作最多读一个word
tran_req_d.data.be = 4'b1111;
tran_req_d.op = OP_READ;
// 读完成
end else if (tran_resp.ready) begin
rdata_d = tran_resp.data;
state_d = S_IDLE;
end
end
// 写使能(命令)
S_WRITE_ENABLE: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = spi_mode_q;
tran_req_d.cmd = CMD_WRITE_ENABLE;
tran_req_d.addr.d = '0;
tran_req_d.addr.be = 4'b0000;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = '0;
tran_req_d.data.be = 4'b0000;
tran_req_d.op = OP_WRITE;
end else begin
if (tran_resp.ready) begin
state_d = return_state_q;
end
end
end
// 写失能命令
S_WRITE_DISABLE: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = spi_mode_q;
tran_req_d.cmd = CMD_WRITE_DISABLE;
tran_req_d.addr.d = '0;
tran_req_d.addr.be = 4'b0000;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = '0;
tran_req_d.data.be = 4'b0000;
tran_req_d.op = OP_WRITE;
end else begin
if (tran_resp.ready) begin
state_d = return_state_q;
end
end
end
// 检查ready位直到ready位为1才返回
S_CHECK_BUSY: begin
// 从其他状态进来或者ready位为0
if ((state_q ^ state_prev_q) ||
(tran_resp.ready && (~tran_resp.data[7]))) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = spi_mode_q;
tran_req_d.cmd = CMD_READ_FLAG_STATUS_REG;
tran_req_d.addr.d = '0;
tran_req_d.addr.be = '0;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = '0;
tran_req_d.data.be = 4'b0001;
tran_req_d.op = OP_READ;
end else begin
if (tran_resp.ready && (tran_resp.data[7])) begin
state_d = return_state_q;
write_error_d = tran_resp.data[5] | tran_resp.data[4];
end
end
end
S_CLEAR_FLAG_STATUS_REG: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = spi_mode_q;
tran_req_d.cmd = CMD_CLEAR_FLAG_STATUS_REG;
tran_req_d.addr.d = '0;
tran_req_d.addr.be = 4'b0000;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = '0;
tran_req_d.data.be = 4'b0000;
tran_req_d.op = OP_WRITE;
end else begin
if (tran_resp.ready) begin
state_d = return_state_q;
end
end
end
S_WAIT_DATA: begin
if (program_init_i) begin
if (start_i && (op_mode_i == 2'b01)) begin
state_d = S_PROGRAM;
end
end else begin
if (tran_idle) begin
state_d = S_CHECK_BUSY;
return_state_d = S_PROGRAM;
end
end
end
// 编程
S_PROGRAM: begin
if (state_prev_q == S_IDLE) begin
state_d = S_WRITE_ENABLE;
return_state_d = S_PROGRAM;
end else if ((state_prev_q == S_WRITE_ENABLE) ||
(state_prev_q == S_WAIT_DATA)) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = spi_mode_q;
tran_req_d.cmd = CMD_PAGE_PROG;
tran_req_d.addr.d = addr_i;
tran_req_d.addr.be = 4'b0111;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = data_i;
tran_req_d.data.be = 4'b1111;
tran_req_d.op = OP_WRITE;
end else if (state_prev_q == S_PROGRAM) begin
if (tran_resp.ready) begin
if (program_init_i) begin
state_d = S_WAIT_DATA;
return_state_d = S_PROGRAM;
end else begin
state_d = S_CHECK_BUSY;
return_state_d = S_PROGRAM;
end
end
end else if (state_prev_q == S_CHECK_BUSY) begin
if (write_error_q) begin
state_d = S_CLEAR_FLAG_STATUS_REG;
return_state_d = S_PROGRAM;
end else begin
state_d = S_IDLE;
end
end else if (state_prev_q == S_CLEAR_FLAG_STATUS_REG) begin
state_d = S_IDLE;
end
end
// 擦除(子扇区)
S_ERASE: begin
if (state_prev_q == S_IDLE) begin
state_d = S_WRITE_ENABLE;
return_state_d = S_ERASE;
end else if (state_prev_q == S_WRITE_ENABLE) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = spi_mode_q;
tran_req_d.cmd = CMD_SUBSECTOR_ERASE;
tran_req_d.addr.d = addr_i;
tran_req_d.addr.be = 4'b0111;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = '0;
tran_req_d.data.be = 4'b0000;
tran_req_d.op = OP_WRITE;
end else if (state_prev_q == S_ERASE) begin
if (tran_resp.ready) begin
state_d = S_CHECK_BUSY;
return_state_d = S_ERASE;
end
end else if (state_prev_q == S_CHECK_BUSY) begin
if (write_error_q) begin
state_d = S_CLEAR_FLAG_STATUS_REG;
return_state_d = S_ERASE;
end else begin
state_d = S_IDLE;
end
end else if (state_prev_q == S_CLEAR_FLAG_STATUS_REG) begin
state_d = S_IDLE;
end
end
// QSPI模式读ID
S_MULTIIO_READ_ID: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
tran_req_d.start = 1'b1;
// 用QSPI模式去try
tran_req_d.spi_mode = MODE_QUAD_SPI;
tran_req_d.cmd = CMD_MULTIO_READ_ID;
tran_req_d.addr.d = '0;
tran_req_d.addr.be = '0;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = '0;
tran_req_d.data.be = 4'b0001;
tran_req_d.op = OP_READ;
end else begin
if (tran_resp.ready) begin
// 读到的ID正确
if (tran_resp.data[7:0] == MANF_ID) begin
spi_mode_d = MODE_QUAD_SPI;
state_d = S_IDLE;
end else begin
state_d = return_state_q;
end
end
end
end
// 设置dummy数
S_WRITE_DUMMY_REG: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = MODE_STAND_SPI;
tran_req_d.cmd = CMD_WRITE_DUMMY_REG;
tran_req_d.addr.d = '0;
tran_req_d.addr.be = 4'b0000;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = {24'h0, DUMMY_CNT, 4'b1011};
tran_req_d.data.be = 4'b0001;
tran_req_d.op = OP_WRITE;
end else begin
if (tran_resp.ready) begin
state_d = return_state_q;
end
end
end
// 设置为QSPI模式
S_WRITE_QSPI_REG: begin
if (state_q ^ state_prev_q) begin
tran_req_d.start = 1'b1;
tran_req_d.spi_mode = MODE_STAND_SPI;
tran_req_d.cmd = CMD_WRITE_QSPI_REG;
tran_req_d.addr.d = '0;
tran_req_d.addr.be = 4'b0000;
tran_req_d.dummy.d = '0;
tran_req_d.dummy.cnt = '0;
tran_req_d.data.d = {24'h0, 8'b01011111};
tran_req_d.data.be = 4'b0001;
tran_req_d.op = OP_WRITE;
end else begin
if (tran_resp.ready) begin
state_d = return_state_q;
end
end
end
// QSPI初始化
S_QSPI_INIT: begin
if (state_prev_q == S_IDLE) begin
state_d = S_MULTIIO_READ_ID;
return_state_d = S_QSPI_INIT;
end else if (state_prev_q == S_MULTIIO_READ_ID) begin
state_d = S_WRITE_ENABLE;
return_state_d = S_QSPI_INIT;
end else if (state_prev_q == S_WRITE_ENABLE) begin
//state_d = S_WRITE_DUMMY_REG;
state_d = S_WRITE_QSPI_REG;
return_state_d = S_QSPI_INIT;
end else if (state_prev_q == S_WRITE_DUMMY_REG) begin
state_d = S_WRITE_QSPI_REG;
return_state_d = S_QSPI_INIT;
end else if (state_prev_q == S_WRITE_QSPI_REG) begin
spi_mode_d = MODE_QUAD_SPI;
state_d = S_IDLE;
end
end
default: ;
endcase
end
assign ready_o = ((state_q == S_IDLE) && (state_prev_q != S_IDLE)) ||
((state_q == S_WAIT_DATA) && (state_prev_q == S_PROGRAM));
assign idle_o = (state_q == S_IDLE) && tran_idle;
assign data_o = rdata_q;
assign write_error_o = write_error_q;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
state_q <= S_IDLE;
state_prev_q <= S_IDLE;
tran_req_q <= '0;
return_state_q <= S_IDLE;
spi_mode_q <= MODE_STAND_SPI;
rdata_q <= '0;
write_error_q <= '0;
end else begin
state_q <= state_d;
state_prev_q <= state_q;
tran_req_q <= tran_req_d;
return_state_q <= return_state_d;
spi_mode_q <= spi_mode_d;
rdata_q <= rdata_d;
write_error_q <= write_error_d;
end
end
flash_n25q_tran_seq #(
.SS_DELAY_CNT(SS_DELAY_CNT),
`ifdef VERILATOR
.CLK_DIV(3'd1),
`else
.CLK_DIV(3'd5),
`endif
.CP_MODE(CPOL_0_CPHA_0),
.MSB_FIRST(1'b1)
) u_flash_n25q_tran_seq (
.clk_i,
.rst_ni,
.program_init_i,
.tran_req_i (tran_req_q),
.tran_resp_o (tran_resp),
.idle_o (tran_idle),
.spi_clk_o,
.spi_clk_oe_o,
.spi_ss_o,
.spi_ss_oe_o,
.spi_dq0_i,
.spi_dq0_o,
.spi_dq0_oe_o,
.spi_dq1_i,
.spi_dq1_o,
.spi_dq1_oe_o,
.spi_dq2_i,
.spi_dq2_o,
.spi_dq2_oe_o,
.spi_dq3_i,
.spi_dq3_o,
.spi_dq3_oe_o
);
endmodule

View File

@ -1,52 +0,0 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package flash_n25q_tran_pkg;
// 操作方式
typedef enum logic [1:0] {
OP_NOP = 2'h0,
OP_READ = 2'h1,
OP_WRITE = 2'h2
} tran_op_e;
// 请求数据
typedef struct packed {
logic start;
logic [1:0] spi_mode;
logic [7:0] cmd;
struct packed {
logic [31:0] d;
logic [ 3:0] be;
} addr;
struct packed {
logic [7:0] d;
logic [3:0] cnt;
} dummy;
struct packed {
logic [31:0] d;
logic [ 3:0] be;
} data;
tran_op_e op;
} flash_n25q_tran_req_t;
// 响应数据
typedef struct packed {
logic ready;
logic [31:0] data;
} flash_n25q_tran_resp_t;
endpackage

View File

@ -1,354 +0,0 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module flash_n25q_tran_seq #(
parameter logic [7:0] SS_DELAY_CNT = 8'd10,
parameter logic [2:0] CLK_DIV = 3'd5,
parameter logic [1:0] CP_MODE = 2'd0,
parameter bit MSB_FIRST = 1'b1
)(
input logic clk_i,
input logic rst_ni,
input logic program_init_i, // 编程中
output logic idle_o, // 空闲
input flash_n25q_tran_pkg::flash_n25q_tran_req_t tran_req_i,
output flash_n25q_tran_pkg::flash_n25q_tran_resp_t tran_resp_o,
// SPI引脚信号
output logic spi_clk_o,
output logic spi_clk_oe_o,
output logic spi_ss_o,
output logic spi_ss_oe_o,
input logic spi_dq0_i,
output logic spi_dq0_o,
output logic spi_dq0_oe_o,
input logic spi_dq1_i,
output logic spi_dq1_o,
output logic spi_dq1_oe_o,
input logic spi_dq2_i,
output logic spi_dq2_o,
output logic spi_dq2_oe_o,
input logic spi_dq3_i,
output logic spi_dq3_o,
output logic spi_dq3_oe_o
);
import flash_n25q_tran_pkg::*;
// 状态
localparam S_IDLE = 8'h1;
localparam S_SS_LOW = 8'h2;
localparam S_CMD = 8'h4;
localparam S_DATA = 8'h8;
localparam S_WAIT_DATA = 8'h10;
localparam S_ADDR = 8'h20;
localparam S_DUMMY = 8'h40;
localparam S_SS_HIGH = 8'h80;
logic [7:0] state_d, state_q, state_prev_q;
logic spi_ss_level_d, spi_ss_level_q;
logic [7:0] spi_data_in_d, spi_data_in_q;
logic spi_read_d, spi_read_q;
logic spi_start_d, spi_start_q;
logic [3:0] seq_counter_d, seq_counter_q;
logic [31:0] spi_rdata_d, spi_rdata_q;
logic [7:0] spi_data_out;
logic spi_data_valid;
logic [7:0] spi_ss_delay_count;
logic spi_ss_delay_counter_clear;
logic spi_ss_delay_counter_enable_d, spi_ss_delay_counter_enable_q;
always_comb begin
state_d = state_q;
spi_ss_delay_counter_enable_d = spi_ss_delay_counter_enable_q;
spi_ss_delay_counter_clear = '0;
spi_ss_level_d = spi_ss_level_q;
spi_data_in_d = spi_data_in_q;
spi_read_d = spi_read_q;
spi_start_d = 1'b0;
seq_counter_d = seq_counter_q;
spi_rdata_d = spi_rdata_q;
// 每传输完一个字节就将计数加1
if (spi_data_valid) begin
seq_counter_d = seq_counter_q + 1'b1;
end
case (state_q)
S_IDLE: begin
// SS引脚默认输出高电平
spi_ss_level_d = 1'b1;
if (tran_req_i.start && (tran_req_i.op != OP_NOP)) begin
state_d = S_SS_LOW;
end
end
// 拉低SS引脚
S_SS_LOW: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
// 清零计数器
spi_ss_delay_counter_clear = 1'b1;
// 开始计时
spi_ss_delay_counter_enable_d = 1'b1;
end
// 2倍计时时间到
if (spi_ss_delay_count == (SS_DELAY_CNT * 2)) begin
spi_ss_level_d = 1'b0;
end
// 3倍计时时间到
if (spi_ss_delay_count == (SS_DELAY_CNT * 3)) begin
spi_ss_delay_counter_clear = 1'b1;
spi_ss_delay_counter_enable_d = 1'b0;
state_d = S_CMD;
end
end
// 发送command
S_CMD: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
spi_data_in_d = tran_req_i.cmd;
spi_read_d = 1'b0;
spi_start_d = 1'b1;
end
if (spi_data_valid) begin
// 发送地址
if (tran_req_i.addr.be != 4'h0) begin
state_d = S_ADDR;
// 发送数据
end else if (tran_req_i.data.be != 4'h0) begin
state_d = S_DATA;
end else begin
state_d = S_SS_HIGH;
end
end
end
// 发送地址(3个bytes)
S_ADDR: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
seq_counter_d = '0;
spi_data_in_d = tran_req_i.addr.d[23:16];
spi_read_d = 1'b0;
spi_start_d = 1'b1;
end
if (spi_data_valid) begin
if (seq_counter_q == 4'd0) begin
spi_data_in_d = tran_req_i.addr.d[15:8];
spi_read_d = 1'b0;
spi_start_d = 1'b1;
end else if (seq_counter_q == 4'd1) begin
spi_data_in_d = tran_req_i.addr.d[7:0];
spi_read_d = 1'b0;
spi_start_d = 1'b1;
end else begin
// 需要发送dummy
if (tran_req_i.dummy.cnt != 4'h0) begin
state_d = S_DUMMY;
// 需要发送数据
end else if (tran_req_i.data.be != 4'h0) begin
state_d = S_DATA;
end else begin
state_d = S_SS_HIGH;
end
end
end
end
// 发送dummy
S_DUMMY: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
seq_counter_d = '0;
spi_data_in_d = '0;
// 注意: 这里设置为读方式
spi_read_d = 1'b1;
spi_start_d = 1'b1;
end
if (spi_data_valid) begin
// 发完dummy
if (seq_counter_q == (tran_req_i.dummy.cnt - 1)) begin
// 需要发送数据
if (tran_req_i.data.be != 4'h0) begin
state_d = S_DATA;
end else begin
state_d = S_SS_HIGH;
end
end else begin
spi_data_in_d = '0;
spi_read_d = 1'b1;
spi_start_d = 1'b1;
end
end
end
// 等待编程数据
S_WAIT_DATA: begin
if (program_init_i) begin
if (tran_req_i.start && (tran_req_i.op == OP_WRITE)) begin
state_d = S_DATA;
end
end else begin
state_d = S_SS_HIGH;
end
end
// 发送或者接收数据
S_DATA: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
seq_counter_d = '0;
// 读数据
if (tran_req_i.op == OP_READ) begin
spi_data_in_d = '0;
spi_read_d = 1'b1;
// 发数据
end else begin
spi_data_in_d = tran_req_i.data.d[7:0];
spi_read_d = 1'b0;
end
spi_start_d = 1'b1;
end
if (spi_data_valid) begin
if (spi_read_q) begin
// 保存接收到的数据
spi_rdata_d = {spi_data_out, spi_rdata_q[31:8]};
end
spi_start_d = 1'b1;
if (seq_counter_q == 4'd0) begin
if (tran_req_i.data.be[3]) begin
spi_data_in_d = tran_req_i.data.d[15:8];
end else begin
spi_start_d = 1'b0;
state_d = S_SS_HIGH;
end
end else if (seq_counter_q == 4'd1) begin
spi_data_in_d = tran_req_i.data.d[23:16];
end else if (seq_counter_q == 4'd2) begin
spi_data_in_d = tran_req_i.data.d[31:24];
end else begin
spi_start_d = 1'b0;
if (program_init_i) begin
state_d = S_WAIT_DATA;
end else begin
state_d = S_SS_HIGH;
end
end
end
end
// 拉高SS引脚
S_SS_HIGH: begin
// 从其他状态进来
if (state_q ^ state_prev_q) begin
spi_ss_delay_counter_clear = 1'b1;
spi_ss_delay_counter_enable_d = 1'b1;
end
if (spi_ss_delay_count == SS_DELAY_CNT) begin
spi_ss_level_d = 1'b1;
spi_ss_delay_counter_clear = 1'b1;
spi_ss_delay_counter_enable_d = 1'b0;
state_d = S_IDLE;
end
end
default: ;
endcase
end
assign tran_resp_o.ready = ((state_q == S_IDLE) && (state_prev_q == S_SS_HIGH)) ||
((state_q == S_WAIT_DATA) && (state_prev_q == S_DATA));
assign tran_resp_o.data = spi_rdata_q;
assign idle_o = (state_q == S_IDLE);
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
state_q <= S_IDLE;
state_prev_q <= S_IDLE;
spi_ss_delay_counter_enable_q <= '0;
spi_ss_level_q <= 1'b1;
spi_data_in_q <= '0;
spi_read_q <= '0;
spi_start_q <= '0;
seq_counter_q <= '0;
spi_rdata_q <= '0;
end else begin
state_q <= state_d;
state_prev_q <= state_q;
spi_ss_delay_counter_enable_q <= spi_ss_delay_counter_enable_d;
spi_ss_level_q <= spi_ss_level_d;
spi_data_in_q <= spi_data_in_d;
spi_read_q <= spi_read_d;
spi_start_q <= spi_start_d;
seq_counter_q <= seq_counter_d;
spi_rdata_q <= spi_rdata_d;
end
end
up_counter #(
.WIDTH(8)
) spi_ss_delay_counter (
.clk_i (clk_i),
.rst_ni (rst_ni),
.clear_i (spi_ss_delay_counter_clear),
.en_i (spi_ss_delay_counter_enable_q),
.q_o (spi_ss_delay_count),
.overflow_o ()
);
// 以byte为单位进行传输
spi_master u_spi_master (
.clk_i,
.rst_ni,
.start_i (spi_start_q),
.read_i (spi_read_q),
.data_i (spi_data_in_q),
.spi_mode_i (tran_req_i.spi_mode),
.cp_mode_i (CP_MODE),
.div_ratio_i (CLK_DIV),
.msb_first_i (MSB_FIRST),
.ss_delay_cnt_i (4'd5),
.ss_sw_ctrl_i (1'b1),
.ss_level_i (spi_ss_level_q),
.data_o (spi_data_out),
.ready_o (),
.data_valid_o (spi_data_valid),
.spi_clk_o,
.spi_clk_oe_o,
.spi_ss_o,
.spi_ss_oe_o,
.spi_dq0_i,
.spi_dq0_o,
.spi_dq0_oe_o,
.spi_dq1_i,
.spi_dq1_o,
.spi_dq1_oe_o,
.spi_dq2_i,
.spi_dq2_o,
.spi_dq2_oe_o,
.spi_dq3_i,
.spi_dq3_o,
.spi_dq3_oe_o
);
endmodule