rtl:perips: add bootrom and xip
Signed-off-by: liangkangnan <liangkangnan@163.com>verilator
parent
6aa5f18429
commit
f704e47e4a
13
rtl.flist
13
rtl.flist
|
@ -69,14 +69,11 @@
|
||||||
../rtl/perips/pinmux/pinmux_reg_top.sv
|
../rtl/perips/pinmux/pinmux_reg_top.sv
|
||||||
../rtl/perips/pinmux/pinmux_core.sv
|
../rtl/perips/pinmux/pinmux_core.sv
|
||||||
../rtl/perips/pinmux/pinmux_top.sv
|
../rtl/perips/pinmux/pinmux_top.sv
|
||||||
../rtl/perips/flash_ctrl/flash_ctrl_reg_pkg.sv
|
../rtl/perips/xip/xip_top.sv
|
||||||
../rtl/perips/flash_ctrl/flash_n25q/flash_n25q_pkg.sv
|
../rtl/perips/xip/xip_core.sv
|
||||||
../rtl/perips/flash_ctrl/flash_n25q/flash_n25q_tran_pkg.sv
|
../rtl/perips/xip/xip_w25q64_ctrl.sv
|
||||||
../rtl/perips/flash_ctrl/flash_n25q/flash_n25q_top.sv
|
../rtl/perips/xip/spi_master_transmit.sv
|
||||||
../rtl/perips/flash_ctrl/flash_n25q/flash_n25q_tran_seq.sv
|
../rtl/perips/bootrom/bootrom_top.sv
|
||||||
../rtl/perips/flash_ctrl/flash_ctrl_top.sv
|
|
||||||
../rtl/perips/flash_ctrl/flash_ctrl_core.sv
|
|
||||||
../rtl/perips/flash_ctrl/flash_ctrl_reg_top.sv
|
|
||||||
|
|
||||||
../rtl/sys_bus/obi_interconnect.sv
|
../rtl/sys_bus/obi_interconnect.sv
|
||||||
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 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 bootrom_top(
|
||||||
|
input wire clk_i,
|
||||||
|
input wire rst_ni,
|
||||||
|
|
||||||
|
input wire req_i,
|
||||||
|
input wire we_i,
|
||||||
|
input wire [ 3:0] be_i,
|
||||||
|
input wire [31:0] addr_i,
|
||||||
|
input wire [31:0] data_i,
|
||||||
|
output wire gnt_o,
|
||||||
|
output wire rvalid_o,
|
||||||
|
output wire [31:0] data_o
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam RomSize = 4;
|
||||||
|
|
||||||
|
wire [RomSize-1:0][31:0] mem;
|
||||||
|
|
||||||
|
assign mem = {
|
||||||
|
32'h0000006f,
|
||||||
|
32'h000500e7,
|
||||||
|
32'h00451513,
|
||||||
|
32'h00200537
|
||||||
|
};
|
||||||
|
|
||||||
|
reg [5:0] addr_q;
|
||||||
|
|
||||||
|
always @(posedge clk_i) begin
|
||||||
|
if (req_i) begin
|
||||||
|
addr_q <= addr_i[7:2];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg rvalid_q;
|
||||||
|
|
||||||
|
always @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
rvalid_q <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
rvalid_q <= req_i;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reg[31:0] rdata;
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
rdata = 32'h0;
|
||||||
|
if (addr_q < 6'd38) begin
|
||||||
|
rdata = mem[addr_q];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign gnt_o = req_i;
|
||||||
|
assign data_o = rdata;
|
||||||
|
assign rvalid_o = rvalid_q;
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,557 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// SS信号由上层模块控制
|
||||||
|
module spi_master_transmit (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
input logic start_i, // 开始传输
|
||||||
|
input logic read_i, // 0: write, 1: read
|
||||||
|
input logic [1:0] spi_mode_i, // 0: Standard SPI, 1: Dual SPI, 2: Quad SPI, 3: Standard SPI
|
||||||
|
input logic [1:0] cp_mode_i, // [1]表示CPOL, [0]表示CPHA
|
||||||
|
input logic [1:0] data_width_i, // 数据宽度, 0: 8bits, 1: 16bits, 2: 32bits, 3: 8bits
|
||||||
|
input logic [31:0] data_i, // 数据输入
|
||||||
|
input logic [2:0] div_ratio_i, // 分频比(2 ^ div_ratio_i)
|
||||||
|
input logic msb_first_i, // 1: MSB, 0: LSB
|
||||||
|
output logic [31:0] data_o, // 接收到的数据输出
|
||||||
|
output logic idle_o, // 1: IDLE, 0: 正在传输
|
||||||
|
output logic data_valid_o, // 数据输出有效标志
|
||||||
|
|
||||||
|
// CLK
|
||||||
|
input logic spi_clk_i,
|
||||||
|
output logic spi_clk_o,
|
||||||
|
output logic spi_clk_oe_o,
|
||||||
|
// SS(slave模式使用)
|
||||||
|
input logic spi_ss_i,
|
||||||
|
// MOSI(DQ0)
|
||||||
|
input logic spi_dq0_i,
|
||||||
|
output logic spi_dq0_o,
|
||||||
|
output logic spi_dq0_oe_o,
|
||||||
|
// MISO(DQ1)
|
||||||
|
input logic spi_dq1_i,
|
||||||
|
output logic spi_dq1_o,
|
||||||
|
output logic spi_dq1_oe_o,
|
||||||
|
// DQ2
|
||||||
|
input logic spi_dq2_i,
|
||||||
|
output logic spi_dq2_o,
|
||||||
|
output logic spi_dq2_oe_o,
|
||||||
|
// DQ3
|
||||||
|
input logic spi_dq3_i,
|
||||||
|
output logic spi_dq3_o,
|
||||||
|
output logic spi_dq3_oe_o
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam MODE_STAND_SPI = 2'b00;
|
||||||
|
localparam MODE_DUAL_SPI = 2'b01;
|
||||||
|
localparam MODE_QUAD_SPI = 2'b10;
|
||||||
|
|
||||||
|
localparam S_IDLE = 3'b001;
|
||||||
|
localparam S_DATA = 3'b010;
|
||||||
|
localparam S_END = 3'b100;
|
||||||
|
|
||||||
|
logic tick;
|
||||||
|
|
||||||
|
logic [2:0] state_d, state_q;
|
||||||
|
logic [7:0] edge_cnt_d, edge_cnt_q;
|
||||||
|
logic [31:0] in_data_d, in_data_q;
|
||||||
|
logic [31:0] out_data_d, out_data_q;
|
||||||
|
logic [7:0] total_edge_cnt_d, total_edge_cnt_q;
|
||||||
|
logic data_valid_d, data_valid_q;
|
||||||
|
logic ready_d, ready_q;
|
||||||
|
logic read_d, read_q;
|
||||||
|
logic [1:0] spi_mode_d, spi_mode_q;
|
||||||
|
logic [1:0] cp_mode_d, cp_mode_q;
|
||||||
|
logic [1:0] data_width_d, data_width_q;
|
||||||
|
logic [2:0] div_ratio_d, div_ratio_q;
|
||||||
|
logic msb_first_d, msb_first_q;
|
||||||
|
|
||||||
|
logic spi_clk_d, spi_clk_q;
|
||||||
|
logic spi_clk_oe_d, spi_clk_oe_q;
|
||||||
|
logic spi_dq0_d, spi_dq0_q;
|
||||||
|
logic spi_dq0_oe_d, spi_dq0_oe_q;
|
||||||
|
logic spi_dq1_d, spi_dq1_q;
|
||||||
|
logic spi_dq1_oe_d, spi_dq1_oe_q;
|
||||||
|
logic spi_dq2_d, spi_dq2_q;
|
||||||
|
logic spi_dq2_oe_d, spi_dq2_oe_q;
|
||||||
|
logic spi_dq3_d, spi_dq3_q;
|
||||||
|
logic spi_dq3_oe_d, spi_dq3_oe_q;
|
||||||
|
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
state_d = state_q;
|
||||||
|
edge_cnt_d = edge_cnt_q;
|
||||||
|
in_data_d = in_data_q;
|
||||||
|
out_data_d = out_data_q;
|
||||||
|
data_valid_d = data_valid_q;
|
||||||
|
ready_d = ready_q;
|
||||||
|
read_d = read_q;
|
||||||
|
spi_mode_d = spi_mode_q;
|
||||||
|
cp_mode_d = cp_mode_q;
|
||||||
|
data_width_d = data_width_q;
|
||||||
|
div_ratio_d = div_ratio_q;
|
||||||
|
msb_first_d = msb_first_q;
|
||||||
|
|
||||||
|
spi_clk_d = spi_clk_q;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
spi_clk_d = cp_mode_i[1];
|
||||||
|
data_valid_d = 1'b0;
|
||||||
|
ready_d = 1'b1;
|
||||||
|
if (start_i) begin
|
||||||
|
edge_cnt_d = '0;
|
||||||
|
ready_d = 1'b0;
|
||||||
|
read_d = read_i;
|
||||||
|
spi_mode_d = spi_mode_i;
|
||||||
|
cp_mode_d = cp_mode_i;
|
||||||
|
data_width_d = data_width_i;
|
||||||
|
div_ratio_d = div_ratio_i;
|
||||||
|
msb_first_d = msb_first_i;
|
||||||
|
state_d = S_DATA;
|
||||||
|
if (msb_first_i) begin
|
||||||
|
out_data_d = data_i;
|
||||||
|
end else begin
|
||||||
|
out_data_d[31] = data_i[0];
|
||||||
|
out_data_d[30] = data_i[1];
|
||||||
|
out_data_d[29] = data_i[2];
|
||||||
|
out_data_d[28] = data_i[3];
|
||||||
|
out_data_d[27] = data_i[4];
|
||||||
|
out_data_d[26] = data_i[5];
|
||||||
|
out_data_d[25] = data_i[6];
|
||||||
|
out_data_d[24] = data_i[7];
|
||||||
|
out_data_d[23] = data_i[8];
|
||||||
|
out_data_d[22] = data_i[9];
|
||||||
|
out_data_d[21] = data_i[10];
|
||||||
|
out_data_d[20] = data_i[11];
|
||||||
|
out_data_d[19] = data_i[12];
|
||||||
|
out_data_d[18] = data_i[13];
|
||||||
|
out_data_d[17] = data_i[14];
|
||||||
|
out_data_d[16] = data_i[15];
|
||||||
|
out_data_d[15] = data_i[16];
|
||||||
|
out_data_d[14] = data_i[17];
|
||||||
|
out_data_d[13] = data_i[18];
|
||||||
|
out_data_d[12] = data_i[19];
|
||||||
|
out_data_d[11] = data_i[20];
|
||||||
|
out_data_d[10] = data_i[21];
|
||||||
|
out_data_d[9] = data_i[22];
|
||||||
|
out_data_d[8] = data_i[23];
|
||||||
|
out_data_d[7] = data_i[24];
|
||||||
|
out_data_d[6] = data_i[25];
|
||||||
|
out_data_d[5] = data_i[26];
|
||||||
|
out_data_d[4] = data_i[27];
|
||||||
|
out_data_d[3] = data_i[28];
|
||||||
|
out_data_d[2] = data_i[29];
|
||||||
|
out_data_d[1] = data_i[30];
|
||||||
|
out_data_d[0] = data_i[31];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_DATA: begin
|
||||||
|
if (tick) begin
|
||||||
|
spi_clk_d = ~spi_clk_q;
|
||||||
|
edge_cnt_d = edge_cnt_q + 1'b1;
|
||||||
|
// 第奇数个沿(1, 3, 5...)
|
||||||
|
if (!edge_cnt_q[0]) begin
|
||||||
|
// 出数据
|
||||||
|
if (cp_mode_q[0]) begin
|
||||||
|
// 第一个bit(s)在IDLE状态时已经送出了
|
||||||
|
if (edge_cnt_q != 8'd0) begin
|
||||||
|
case (spi_mode_q)
|
||||||
|
MODE_STAND_SPI: begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
out_data_d = {out_data_q[14:0], 1'b0};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
out_data_d = {out_data_q[30:0], 1'b0};
|
||||||
|
end else begin
|
||||||
|
out_data_d = {out_data_q[6:0], 1'b0};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_DUAL_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
out_data_d = {out_data_q[13:0], 2'b0};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
out_data_d = {out_data_q[29:0], 2'b0};
|
||||||
|
end else begin
|
||||||
|
out_data_d = {out_data_q[5:0], 2'b0};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_QUAD_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
out_data_d = {out_data_q[11:0], 4'b0};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
out_data_d = {out_data_q[27:0], 4'b0};
|
||||||
|
end else begin
|
||||||
|
out_data_d = {out_data_q[3:0], 4'b0};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
default: out_data_d = {out_data_q[6:0], 1'b0};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
// 采数据
|
||||||
|
end else begin
|
||||||
|
case (spi_mode_q)
|
||||||
|
MODE_STAND_SPI: begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
in_data_d = {in_data_q[14:0], spi_dq1_i};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
in_data_d = {in_data_q[30:0], spi_dq1_i};
|
||||||
|
end else begin
|
||||||
|
in_data_d = {in_data_q[6:0], spi_dq1_i};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_DUAL_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
in_data_d = {in_data_q[13:0], spi_dq1_i, spi_dq0_i};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
in_data_d = {in_data_q[29:0], spi_dq1_i, spi_dq0_i};
|
||||||
|
end else begin
|
||||||
|
in_data_d = {in_data_q[5:0], spi_dq1_i, spi_dq0_i};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_QUAD_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
in_data_d = {in_data_q[11:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
in_data_d = {in_data_q[27:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
|
||||||
|
end else begin
|
||||||
|
in_data_d = {in_data_q[3:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
default: in_data_d = {in_data_q[6:0], spi_dq1_i};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
// 第偶数个沿(2, 4, 6...)
|
||||||
|
end else begin
|
||||||
|
// 出数据
|
||||||
|
if (!cp_mode_q[0]) begin
|
||||||
|
case (spi_mode_q)
|
||||||
|
MODE_STAND_SPI: begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
out_data_d = {out_data_q[14:0], 1'b0};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
out_data_d = {out_data_q[30:0], 1'b0};
|
||||||
|
end else begin
|
||||||
|
out_data_d = {out_data_q[6:0], 1'b0};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_DUAL_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
out_data_d = {out_data_q[13:0], 2'b0};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
out_data_d = {out_data_q[29:0], 2'b0};
|
||||||
|
end else begin
|
||||||
|
out_data_d = {out_data_q[5:0], 2'b0};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_QUAD_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
out_data_d = {out_data_q[11:0], 4'b0};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
out_data_d = {out_data_q[27:0], 4'b0};
|
||||||
|
end else begin
|
||||||
|
out_data_d = {out_data_q[3:0], 4'b0};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
default: out_data_d = {out_data_q[6:0], 1'b0};
|
||||||
|
endcase
|
||||||
|
// 采数据
|
||||||
|
end else begin
|
||||||
|
case (spi_mode_q)
|
||||||
|
MODE_STAND_SPI: begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
in_data_d = {in_data_q[14:0], spi_dq1_i};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
in_data_d = {in_data_q[30:0], spi_dq1_i};
|
||||||
|
end else begin
|
||||||
|
in_data_d = {in_data_q[6:0], spi_dq1_i};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_DUAL_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
in_data_d = {in_data_q[13:0], spi_dq1_i, spi_dq0_i};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
in_data_d = {in_data_q[29:0], spi_dq1_i, spi_dq0_i};
|
||||||
|
end else begin
|
||||||
|
in_data_d = {in_data_q[5:0], spi_dq1_i, spi_dq0_i};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_QUAD_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
in_data_d = {in_data_q[11:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
in_data_d = {in_data_q[27:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
|
||||||
|
end else begin
|
||||||
|
in_data_d = {in_data_q[3:0], spi_dq3_i, spi_dq2_i, spi_dq1_i, spi_dq0_i};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
default: in_data_d = {in_data_q[6:0], spi_dq1_i};
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// 最后一个沿
|
||||||
|
if (edge_cnt_q == total_edge_cnt_q) begin
|
||||||
|
state_d = S_END;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_END: begin
|
||||||
|
if (tick) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
ready_d = 1'b1;
|
||||||
|
data_valid_d = 1'b1;
|
||||||
|
if (!msb_first_q) begin
|
||||||
|
in_data_d[0] = in_data_q[31];
|
||||||
|
in_data_d[1] = in_data_q[30];
|
||||||
|
in_data_d[2] = in_data_q[29];
|
||||||
|
in_data_d[3] = in_data_q[28];
|
||||||
|
in_data_d[4] = in_data_q[27];
|
||||||
|
in_data_d[5] = in_data_q[26];
|
||||||
|
in_data_d[6] = in_data_q[25];
|
||||||
|
in_data_d[7] = in_data_q[24];
|
||||||
|
in_data_d[8] = in_data_q[23];
|
||||||
|
in_data_d[9] = in_data_q[22];
|
||||||
|
in_data_d[10] = in_data_q[21];
|
||||||
|
in_data_d[11] = in_data_q[20];
|
||||||
|
in_data_d[12] = in_data_q[19];
|
||||||
|
in_data_d[13] = in_data_q[18];
|
||||||
|
in_data_d[14] = in_data_q[17];
|
||||||
|
in_data_d[15] = in_data_q[16];
|
||||||
|
in_data_d[16] = in_data_q[15];
|
||||||
|
in_data_d[17] = in_data_q[14];
|
||||||
|
in_data_d[18] = in_data_q[13];
|
||||||
|
in_data_d[19] = in_data_q[12];
|
||||||
|
in_data_d[20] = in_data_q[11];
|
||||||
|
in_data_d[21] = in_data_q[10];
|
||||||
|
in_data_d[22] = in_data_q[9];
|
||||||
|
in_data_d[23] = in_data_q[8];
|
||||||
|
in_data_d[24] = in_data_q[7];
|
||||||
|
in_data_d[25] = in_data_q[6];
|
||||||
|
in_data_d[26] = in_data_q[5];
|
||||||
|
in_data_d[27] = in_data_q[4];
|
||||||
|
in_data_d[28] = in_data_q[3];
|
||||||
|
in_data_d[29] = in_data_q[2];
|
||||||
|
in_data_d[30] = in_data_q[1];
|
||||||
|
in_data_d[31] = in_data_q[0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
total_edge_cnt_d = 8'd63;
|
||||||
|
|
||||||
|
case (spi_mode_q)
|
||||||
|
MODE_STAND_SPI: begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
total_edge_cnt_d = 8'd31;
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
total_edge_cnt_d = 8'd63;
|
||||||
|
end else begin
|
||||||
|
total_edge_cnt_d = 8'd15;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_DUAL_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
total_edge_cnt_d = 8'd15;
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
total_edge_cnt_d = 8'd31;
|
||||||
|
end else begin
|
||||||
|
total_edge_cnt_d = 8'd7;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
MODE_QUAD_SPI : begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
total_edge_cnt_d = 8'd7;
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
total_edge_cnt_d = 8'd15;
|
||||||
|
end else begin
|
||||||
|
total_edge_cnt_d = 8'd3;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
edge_cnt_q <= '0;
|
||||||
|
total_edge_cnt_q <= '0;
|
||||||
|
in_data_q <= '0;
|
||||||
|
out_data_q <= '0;
|
||||||
|
data_valid_q <= '0;
|
||||||
|
ready_q <= '0;
|
||||||
|
read_q <= '0;
|
||||||
|
spi_mode_q <= '0;
|
||||||
|
cp_mode_q <= '0;
|
||||||
|
data_width_q <= '0;
|
||||||
|
div_ratio_q <= '0;
|
||||||
|
msb_first_q <= '0;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
edge_cnt_q <= edge_cnt_d;
|
||||||
|
total_edge_cnt_q <= total_edge_cnt_d;
|
||||||
|
in_data_q <= in_data_d;
|
||||||
|
out_data_q <= out_data_d;
|
||||||
|
data_valid_q <= data_valid_d;
|
||||||
|
ready_q <= ready_d;
|
||||||
|
read_q <= read_d;
|
||||||
|
spi_mode_q <= spi_mode_d;
|
||||||
|
cp_mode_q <= cp_mode_d;
|
||||||
|
data_width_q <= data_width_d;
|
||||||
|
div_ratio_q <= div_ratio_d;
|
||||||
|
msb_first_q <= msb_first_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
spi_dq0_d = 1'b0;
|
||||||
|
spi_dq1_d = 1'b0;
|
||||||
|
spi_dq2_d = 1'b0;
|
||||||
|
spi_dq3_d = 1'b0;
|
||||||
|
spi_dq0_oe_d = 1'b0;
|
||||||
|
spi_dq1_oe_d = 1'b0;
|
||||||
|
spi_dq2_oe_d = 1'b0;
|
||||||
|
spi_dq3_oe_d = 1'b0;
|
||||||
|
|
||||||
|
case (spi_mode_q)
|
||||||
|
MODE_STAND_SPI: begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
spi_dq0_d = out_data_d[15];
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
spi_dq0_d = out_data_d[31];
|
||||||
|
end else begin
|
||||||
|
spi_dq0_d = out_data_d[7];
|
||||||
|
end
|
||||||
|
spi_dq0_oe_d = 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
MODE_DUAL_SPI: begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
spi_dq0_d = out_data_d[14];
|
||||||
|
spi_dq1_d = out_data_d[15];
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
spi_dq0_d = out_data_d[30];
|
||||||
|
spi_dq1_d = out_data_d[31];
|
||||||
|
end else begin
|
||||||
|
spi_dq0_d = out_data_d[6];
|
||||||
|
spi_dq1_d = out_data_d[7];
|
||||||
|
end
|
||||||
|
if (read_q) begin
|
||||||
|
spi_dq0_oe_d = 1'b0;
|
||||||
|
spi_dq1_oe_d = 1'b0;
|
||||||
|
end else begin
|
||||||
|
spi_dq0_oe_d = 1'b1;
|
||||||
|
spi_dq1_oe_d = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MODE_QUAD_SPI: begin
|
||||||
|
if (data_width_q == 2'd1) begin
|
||||||
|
spi_dq0_d = out_data_d[12];
|
||||||
|
spi_dq1_d = out_data_d[13];
|
||||||
|
spi_dq2_d = out_data_d[14];
|
||||||
|
spi_dq3_d = out_data_d[15];
|
||||||
|
end else if (data_width_q == 2'd2) begin
|
||||||
|
spi_dq0_d = out_data_d[28];
|
||||||
|
spi_dq1_d = out_data_d[29];
|
||||||
|
spi_dq2_d = out_data_d[30];
|
||||||
|
spi_dq3_d = out_data_d[31];
|
||||||
|
end else begin
|
||||||
|
spi_dq0_d = out_data_d[4];
|
||||||
|
spi_dq1_d = out_data_d[5];
|
||||||
|
spi_dq2_d = out_data_d[6];
|
||||||
|
spi_dq3_d = out_data_d[7];
|
||||||
|
end
|
||||||
|
if (read_q) begin
|
||||||
|
spi_dq0_oe_d = 1'b0;
|
||||||
|
spi_dq1_oe_d = 1'b0;
|
||||||
|
spi_dq2_oe_d = 1'b0;
|
||||||
|
spi_dq3_oe_d = 1'b0;
|
||||||
|
end else begin
|
||||||
|
spi_dq0_oe_d = 1'b1;
|
||||||
|
spi_dq1_oe_d = 1'b1;
|
||||||
|
spi_dq2_oe_d = 1'b1;
|
||||||
|
spi_dq3_oe_d = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign spi_clk_oe_d = 1'b1;
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
spi_clk_q <= '0;
|
||||||
|
spi_clk_oe_q <= '0;
|
||||||
|
spi_dq0_q <= '0;
|
||||||
|
spi_dq0_oe_q <= '0;
|
||||||
|
spi_dq1_q <= '0;
|
||||||
|
spi_dq1_oe_q <= '0;
|
||||||
|
spi_dq2_q <= '0;
|
||||||
|
spi_dq2_oe_q <= '0;
|
||||||
|
spi_dq3_q <= '0;
|
||||||
|
spi_dq3_oe_q <= '0;
|
||||||
|
end else begin
|
||||||
|
spi_clk_q <= spi_clk_d;
|
||||||
|
spi_clk_oe_q <= spi_clk_oe_d;
|
||||||
|
spi_dq0_q <= spi_dq0_d;
|
||||||
|
spi_dq0_oe_q <= spi_dq0_oe_d;
|
||||||
|
spi_dq1_q <= spi_dq1_d;
|
||||||
|
spi_dq1_oe_q <= spi_dq1_oe_d;
|
||||||
|
spi_dq2_q <= spi_dq2_d;
|
||||||
|
spi_dq2_oe_q <= spi_dq2_oe_d;
|
||||||
|
spi_dq3_q <= spi_dq3_d;
|
||||||
|
spi_dq3_oe_q <= spi_dq3_oe_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign data_o = in_data_q;
|
||||||
|
assign data_valid_o = data_valid_q;
|
||||||
|
assign idle_o = ready_q;
|
||||||
|
|
||||||
|
assign spi_clk_o = spi_clk_q;
|
||||||
|
assign spi_clk_oe_o = spi_clk_oe_q;
|
||||||
|
assign spi_dq0_o = spi_dq0_q;
|
||||||
|
assign spi_dq0_oe_o = spi_dq0_oe_q;
|
||||||
|
assign spi_dq1_o = spi_dq1_q;
|
||||||
|
assign spi_dq1_oe_o = spi_dq1_oe_q;
|
||||||
|
assign spi_dq2_o = spi_dq2_q;
|
||||||
|
assign spi_dq2_oe_o = spi_dq2_oe_q;
|
||||||
|
assign spi_dq3_o = spi_dq3_q;
|
||||||
|
assign spi_dq3_oe_o = spi_dq3_oe_q;
|
||||||
|
|
||||||
|
logic [15:0] ratio = 1 << div_ratio_q;
|
||||||
|
|
||||||
|
clk_div #(
|
||||||
|
.RATIO_WIDTH(16)
|
||||||
|
) u_clk_div (
|
||||||
|
.clk_i(clk_i),
|
||||||
|
.rst_ni(rst_ni || (~((state_q == S_IDLE) && start_i))),
|
||||||
|
.en_i(state_q != S_IDLE),
|
||||||
|
.ratio_i(ratio),
|
||||||
|
.clk_o(tick)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 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 xip_core #(
|
||||||
|
parameter int unsigned TX_FIFO_DEPTH = 8,
|
||||||
|
parameter int unsigned RX_FIFO_DEPTH = 8
|
||||||
|
)(
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
// SPI引脚信号
|
||||||
|
input logic spi_clk_i,
|
||||||
|
output logic spi_clk_o,
|
||||||
|
output logic spi_clk_oe_o,
|
||||||
|
input logic spi_ss_i,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam OP_READ = 2'b00;
|
||||||
|
localparam OP_WRITE = 2'b01;
|
||||||
|
localparam OP_SECTOR_ERASE = 2'b10;
|
||||||
|
|
||||||
|
localparam S_IDLE = 2'b01;
|
||||||
|
localparam S_WAIT = 2'b10;
|
||||||
|
|
||||||
|
logic[1:0] state_d, state_q;
|
||||||
|
logic valid_d, valid_q;
|
||||||
|
logic[31:0] rdata_d, rdata_q;
|
||||||
|
logic[31:0] addr;
|
||||||
|
logic[1:0] op;
|
||||||
|
logic[31:0] rdata;
|
||||||
|
logic valid;
|
||||||
|
|
||||||
|
// 去掉基地址
|
||||||
|
assign addr = {9'h0, addr_i[22:0]};
|
||||||
|
// addr_i[23], 1: 表示擦除扇区; 0: 表示编程数据
|
||||||
|
assign op = (!we_i) ? OP_READ : addr_i[23] ? OP_SECTOR_ERASE : OP_WRITE;
|
||||||
|
|
||||||
|
assign gnt_o = (req_i & (state_q == S_IDLE));
|
||||||
|
assign rvalid_o = valid_q;
|
||||||
|
assign data_o = rdata_q;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
state_d = state_q;
|
||||||
|
valid_d = valid_q;
|
||||||
|
rdata_d = rdata_q;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
valid_d = 1'b0;
|
||||||
|
if (req_i) begin
|
||||||
|
state_d = S_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_WAIT: begin
|
||||||
|
if (valid) begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
valid_d = 1'b1;
|
||||||
|
rdata_d = rdata;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
valid_q <= '0;
|
||||||
|
rdata_q <= '0;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
valid_q <= valid_d;
|
||||||
|
rdata_q <= rdata_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
xip_w25q64_ctrl u_flash(
|
||||||
|
.clk_i,
|
||||||
|
.rst_ni,
|
||||||
|
.req_i,
|
||||||
|
.op_i (op),
|
||||||
|
.addr_i (addr),
|
||||||
|
.wdata_i(data_i),
|
||||||
|
.valid_o(valid),
|
||||||
|
.rdata_o(rdata),
|
||||||
|
.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
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 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 xip_top (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
// SPI引脚信号
|
||||||
|
input logic spi_clk_i,
|
||||||
|
output logic spi_clk_o,
|
||||||
|
output logic spi_clk_oe_o,
|
||||||
|
input logic spi_ss_i,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
xip_core u_xip_core (
|
||||||
|
.clk_i (clk_i),
|
||||||
|
.rst_ni (rst_ni),
|
||||||
|
.spi_clk_o (spi_clk_o),
|
||||||
|
.spi_clk_oe_o (spi_clk_oe_o),
|
||||||
|
.spi_ss_o (spi_ss_o),
|
||||||
|
.spi_ss_oe_o (spi_ss_oe_o),
|
||||||
|
.spi_dq0_i (spi_dq0_i),
|
||||||
|
.spi_dq0_o (spi_dq0_o),
|
||||||
|
.spi_dq0_oe_o (spi_dq0_oe_o),
|
||||||
|
.spi_dq1_i (spi_dq1_i),
|
||||||
|
.spi_dq1_o (spi_dq1_o),
|
||||||
|
.spi_dq1_oe_o (spi_dq1_oe_o),
|
||||||
|
.spi_dq2_i (spi_dq2_i),
|
||||||
|
.spi_dq2_o (spi_dq2_o),
|
||||||
|
.spi_dq2_oe_o (spi_dq2_oe_o),
|
||||||
|
.spi_dq3_i (spi_dq3_i),
|
||||||
|
.spi_dq3_o (spi_dq3_o),
|
||||||
|
.spi_dq3_oe_o (spi_dq3_oe_o),
|
||||||
|
.req_i (req_i),
|
||||||
|
.we_i (we_i),
|
||||||
|
.be_i (be_i),
|
||||||
|
.addr_i (addr_i),
|
||||||
|
.data_i (data_i),
|
||||||
|
.gnt_o (gnt_o),
|
||||||
|
.rvalid_o (rvalid_o),
|
||||||
|
.data_o (data_o)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 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 xip_w25q64_ctrl(
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
input logic req_i,
|
||||||
|
input logic [1:0] op_i,
|
||||||
|
input logic [31:0] addr_i,
|
||||||
|
input logic [31:0] wdata_i,
|
||||||
|
output logic valid_o,
|
||||||
|
output logic [31:0] rdata_o,
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
// SPI模式
|
||||||
|
localparam MODE_STAND_SPI = 2'b00;
|
||||||
|
localparam MODE_DUAL_SPI = 2'b01;
|
||||||
|
localparam MODE_QUAD_SPI = 2'b10;
|
||||||
|
// 数据宽度
|
||||||
|
localparam SPI_DATA_WIDTH_8 = 2'b00;
|
||||||
|
localparam SPI_DATA_WIDTH_16 = 2'b01;
|
||||||
|
localparam SPI_DATA_WIDTH_32 = 2'b10;
|
||||||
|
// 2分频
|
||||||
|
localparam SPI_CLK_DIV = 3'd1;
|
||||||
|
// SPI极性
|
||||||
|
localparam SPI_CPOL_CPHA = 2'b00;
|
||||||
|
|
||||||
|
localparam OP_READ = 2'b00;
|
||||||
|
localparam OP_WRITE = 2'b01;
|
||||||
|
localparam OP_SECTOR_ERASE = 2'b10;
|
||||||
|
|
||||||
|
localparam STATE_NUM = 12;
|
||||||
|
localparam S_IDLE = 12'h001;
|
||||||
|
localparam S_SS_LOW = 12'h002;
|
||||||
|
localparam S_SS_HIGH = 12'h004;
|
||||||
|
localparam S_WRITE_ENABLE = 12'h008;
|
||||||
|
localparam S_WRITE_DISABLE = 12'h010;
|
||||||
|
localparam S_SECTOR_ERASE = 12'h020;
|
||||||
|
localparam S_PAGE_PROGRAM = 12'h040;
|
||||||
|
localparam S_WRITE_DATA = 12'h080;
|
||||||
|
localparam S_READ_DATA = 12'h100;
|
||||||
|
localparam S_READ = 12'h200;
|
||||||
|
localparam S_READ_STATUS = 12'h400;
|
||||||
|
localparam S_CHECK_WIP = 12'h800;
|
||||||
|
|
||||||
|
logic [STATE_NUM-1:0] state_d, state_q;
|
||||||
|
logic [STATE_NUM-1:0] next_state_d, next_state_q;
|
||||||
|
logic [31:0] addr_d, addr_q;
|
||||||
|
logic [31:0] wdata_d, wdata_q;
|
||||||
|
logic [1:0] op_d, op_q;
|
||||||
|
logic spi_ss_o_d, spi_ss_o_q;
|
||||||
|
|
||||||
|
logic start_d;
|
||||||
|
logic read_d;
|
||||||
|
logic [1:0] spi_mode_d;
|
||||||
|
logic [1:0] cp_mode_d;
|
||||||
|
logic [1:0] data_width_d;
|
||||||
|
logic [31:0] data_d;
|
||||||
|
logic [2:0] div_ratio_d;
|
||||||
|
logic msb_first_d;
|
||||||
|
|
||||||
|
logic spi_idle;
|
||||||
|
logic spi_valid;
|
||||||
|
logic [31:0] spi_data_out;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
state_d = state_q;
|
||||||
|
next_state_d = next_state_q;
|
||||||
|
addr_d = addr_q;
|
||||||
|
wdata_d = wdata_q;
|
||||||
|
op_d = op_q;
|
||||||
|
spi_ss_o_d = spi_ss_o_q;
|
||||||
|
|
||||||
|
start_d = '0;
|
||||||
|
read_d = '0;
|
||||||
|
spi_mode_d = '0;
|
||||||
|
data_width_d = '0;
|
||||||
|
data_d = '0;
|
||||||
|
cp_mode_d = SPI_CPOL_CPHA;
|
||||||
|
div_ratio_d = SPI_CLK_DIV;
|
||||||
|
msb_first_d = 1'b1;
|
||||||
|
|
||||||
|
case (state_q)
|
||||||
|
S_IDLE: begin
|
||||||
|
spi_ss_o_d = 1'b1;
|
||||||
|
if (req_i) begin
|
||||||
|
addr_d = addr_i;
|
||||||
|
op_d = op_i;
|
||||||
|
wdata_d = wdata_i;
|
||||||
|
state_d = S_SS_LOW;
|
||||||
|
if ((op_i == OP_WRITE) | (op_i == OP_SECTOR_ERASE)) begin
|
||||||
|
next_state_d = S_WRITE_ENABLE;
|
||||||
|
end else begin
|
||||||
|
next_state_d = S_READ_DATA;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_SS_LOW: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
spi_ss_o_d = 1'b0;
|
||||||
|
state_d = next_state_q;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_WRITE_ENABLE: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
start_d = 1'b1;
|
||||||
|
read_d = 1'b0;
|
||||||
|
spi_mode_d = MODE_STAND_SPI;
|
||||||
|
data_width_d = SPI_DATA_WIDTH_8;
|
||||||
|
data_d = 8'h06;
|
||||||
|
if (op_q == OP_SECTOR_ERASE) begin
|
||||||
|
next_state_d = S_SECTOR_ERASE;
|
||||||
|
end else begin
|
||||||
|
next_state_d = S_PAGE_PROGRAM;
|
||||||
|
end
|
||||||
|
state_d = S_SS_HIGH;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_WRITE_DISABLE: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
start_d = 1'b1;
|
||||||
|
read_d = 1'b0;
|
||||||
|
spi_mode_d = MODE_STAND_SPI;
|
||||||
|
data_width_d = SPI_DATA_WIDTH_8;
|
||||||
|
data_d = 8'h04;
|
||||||
|
state_d = S_SS_HIGH;
|
||||||
|
next_state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_PAGE_PROGRAM: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
start_d = 1'b1;
|
||||||
|
read_d = 1'b0;
|
||||||
|
spi_mode_d = MODE_STAND_SPI;
|
||||||
|
data_width_d = SPI_DATA_WIDTH_32;
|
||||||
|
data_d = {8'h02, addr_q[23:0]};
|
||||||
|
state_d = S_WRITE_DATA;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_WRITE_DATA: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
start_d = 1'b1;
|
||||||
|
read_d = 1'b0;
|
||||||
|
spi_mode_d = MODE_STAND_SPI;
|
||||||
|
data_width_d = SPI_DATA_WIDTH_32;
|
||||||
|
data_d = wdata_q;
|
||||||
|
state_d = S_SS_HIGH;
|
||||||
|
next_state_d = S_READ_STATUS;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_SECTOR_ERASE: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
start_d = 1'b1;
|
||||||
|
read_d = 1'b0;
|
||||||
|
spi_mode_d = MODE_STAND_SPI;
|
||||||
|
data_width_d = SPI_DATA_WIDTH_32;
|
||||||
|
data_d = {8'h20, addr_q[23:0]};
|
||||||
|
state_d = S_SS_HIGH;
|
||||||
|
next_state_d = S_READ_STATUS;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_READ_STATUS: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
start_d = 1'b1;
|
||||||
|
read_d = 1'b0;
|
||||||
|
spi_mode_d = MODE_STAND_SPI;
|
||||||
|
data_width_d = SPI_DATA_WIDTH_8;
|
||||||
|
data_d = 8'h05;
|
||||||
|
state_d = S_READ;
|
||||||
|
next_state_d = S_CHECK_WIP;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_CHECK_WIP: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
// flash is in WIP
|
||||||
|
if (spi_data_out[0]) begin
|
||||||
|
state_d = S_SS_HIGH;
|
||||||
|
next_state_d = S_READ_STATUS;
|
||||||
|
end else begin
|
||||||
|
state_d = S_SS_HIGH;
|
||||||
|
state_d = S_WRITE_DISABLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_READ_DATA: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
start_d = 1'b1;
|
||||||
|
read_d = 1'b0;
|
||||||
|
spi_mode_d = MODE_STAND_SPI;
|
||||||
|
data_width_d = SPI_DATA_WIDTH_32;
|
||||||
|
data_d = {8'h03, addr_q[23:0]};
|
||||||
|
state_d = S_READ;
|
||||||
|
next_state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_READ: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
start_d = 1'b1;
|
||||||
|
read_d = 1'b1;
|
||||||
|
spi_mode_d = MODE_STAND_SPI;
|
||||||
|
data_width_d = SPI_DATA_WIDTH_32;
|
||||||
|
state_d = S_SS_HIGH;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
S_SS_HIGH: begin
|
||||||
|
if (spi_idle) begin
|
||||||
|
spi_ss_o_d = 1'b1;
|
||||||
|
if (next_state_q != S_IDLE) begin
|
||||||
|
state_d = S_SS_LOW;
|
||||||
|
end else begin
|
||||||
|
state_d = S_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
assign valid_o = (state_q == S_SS_HIGH) & spi_idle & (next_state_q == S_IDLE);
|
||||||
|
assign rdata_o = spi_data_out;
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||||
|
if (!rst_ni) begin
|
||||||
|
state_q <= S_IDLE;
|
||||||
|
next_state_q <= S_IDLE;
|
||||||
|
addr_q <= '0;
|
||||||
|
wdata_q <= '0;
|
||||||
|
op_q <= '0;
|
||||||
|
spi_ss_o_q <= '0;
|
||||||
|
end else begin
|
||||||
|
state_q <= state_d;
|
||||||
|
next_state_q <= next_state_d;
|
||||||
|
addr_q <= addr_d;
|
||||||
|
wdata_q <= wdata_d;
|
||||||
|
op_q <= op_d;
|
||||||
|
spi_ss_o_q <= spi_ss_o_d;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign spi_ss_oe_o = 1'b1;
|
||||||
|
assign spi_ss_o = spi_ss_o_q;
|
||||||
|
|
||||||
|
spi_master_transmit u_spi_master (
|
||||||
|
.clk_i,
|
||||||
|
.rst_ni,
|
||||||
|
.start_i (start_d),
|
||||||
|
.read_i (read_d),
|
||||||
|
.spi_mode_i (spi_mode_d),
|
||||||
|
.cp_mode_i (cp_mode_d),
|
||||||
|
.data_width_i(data_width_d),
|
||||||
|
.data_i (data_d),
|
||||||
|
.div_ratio_i (div_ratio_d),
|
||||||
|
.msb_first_i (msb_first_d),
|
||||||
|
.data_o (spi_data_out),
|
||||||
|
.idle_o (spi_idle),
|
||||||
|
.data_valid_o(spi_valid),
|
||||||
|
.spi_clk_o,
|
||||||
|
.spi_clk_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
|
Loading…
Reference in New Issue