diff --git a/rtl/perips/flash_ctrl/flash_ctrl.hjson b/rtl/perips/flash_ctrl/flash_ctrl.hjson deleted file mode 100644 index c42b2e7..0000000 --- a/rtl/perips/flash_ctrl/flash_ctrl.hjson +++ /dev/null @@ -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", - } - ] - } - ] -} diff --git a/rtl/perips/flash_ctrl/flash_ctrl_core.sv b/rtl/perips/flash_ctrl/flash_ctrl_core.sv deleted file mode 100644 index 4c0e7c8..0000000 --- a/rtl/perips/flash_ctrl/flash_ctrl_core.sv +++ /dev/null @@ -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 diff --git a/rtl/perips/flash_ctrl/flash_ctrl_reg_pkg.sv b/rtl/perips/flash_ctrl/flash_ctrl_reg_pkg.sv deleted file mode 100644 index c3f69c5..0000000 --- a/rtl/perips/flash_ctrl/flash_ctrl_reg_pkg.sv +++ /dev/null @@ -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 - diff --git a/rtl/perips/flash_ctrl/flash_ctrl_reg_top.sv b/rtl/perips/flash_ctrl/flash_ctrl_reg_top.sv deleted file mode 100644 index 58c8842..0000000 --- a/rtl/perips/flash_ctrl/flash_ctrl_reg_top.sv +++ /dev/null @@ -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: __{wd|we|qs} - // or _{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 diff --git a/rtl/perips/flash_ctrl/flash_ctrl_top.sv b/rtl/perips/flash_ctrl/flash_ctrl_top.sv deleted file mode 100644 index 278925f..0000000 --- a/rtl/perips/flash_ctrl/flash_ctrl_top.sv +++ /dev/null @@ -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 diff --git a/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_pkg.sv b/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_pkg.sv deleted file mode 100644 index b396bb3..0000000 --- a/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_pkg.sv +++ /dev/null @@ -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 diff --git a/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_top.sv b/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_top.sv deleted file mode 100644 index 4ef70ae..0000000 --- a/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_top.sv +++ /dev/null @@ -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 diff --git a/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_tran_pkg.sv b/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_tran_pkg.sv deleted file mode 100644 index 4689557..0000000 --- a/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_tran_pkg.sv +++ /dev/null @@ -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 diff --git a/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_tran_seq.sv b/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_tran_seq.sv deleted file mode 100644 index 4f6912a..0000000 --- a/rtl/perips/flash_ctrl/flash_n25q/flash_n25q_tran_seq.sv +++ /dev/null @@ -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