aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Nazaryev <sergey@nazaryev.ru>2015-12-23 15:44:12 +0000
committerSergey Nazaryev <sergey@nazaryev.ru>2015-12-23 15:44:12 +0000
commite4381701562660b0594f09e9ad4d5f5c5ff66fc5 (patch)
tree3b5d8babc7be3ae0ff80fc4e347450fef2b7f59d
downloadcircuit-design-lab234-e4381701562660b0594f09e9ad4d5f5c5ff66fc5.zip
circuit-design-lab234-e4381701562660b0594f09e9ad4d5f5c5ff66fc5.tar.gz
circuit-design-lab234-e4381701562660b0594f09e9ad4d5f5c5ff66fc5.tar.bz2
initial
-rw-r--r--fifo.v52
-rw-r--r--rom_ctrl.v182
-rw-r--r--rom_wb.v91
-rw-r--r--spi_routine.v92
-rw-r--r--spi_writer.v129
-rw-r--r--testbench.v114
6 files changed, 660 insertions, 0 deletions
diff --git a/fifo.v b/fifo.v
new file mode 100644
index 0000000..a119aa2
--- /dev/null
+++ b/fifo.v
@@ -0,0 +1,52 @@
+module fifo #(
+ parameter NUM_WORDS = 128,
+ parameter DATA_W = 32
+) (
+ input clk_i,
+ input rst_i,
+
+ // Write side
+ input wr_i,
+ input [DATA_W-1:0] data_i,
+ output full_o,
+
+ // Read side
+ input rd_i,
+ output reg[DATA_W-1:0] data_o,
+ output empty_o
+);
+
+//***********************************
+// Parameters
+//***********************************
+localparam ADDR_WIDTH = 7;
+
+//***********************************
+// Signals
+//***********************************
+reg [ADDR_WIDTH-1:0] wr_addr;
+reg [ADDR_WIDTH-1:0] rd_addr;
+reg [NUM_WORDS-1:0] mem[DATA_W-1:0];
+
+//***********************************
+// Write side
+//***********************************
+always @(posedge clk_i)
+ if( wr_i )
+ wr_addr <= wr_addr + 1'd1;
+
+always @(posedge clk_i)
+ if( wr_i )
+ mem[wr_addr] <= data_i;
+
+//***********************************
+// Read side
+//***********************************
+always @(posedge clk_i)
+ if( rd_i )
+ begin
+ rd_addr <= rd_addr + 1'd1;
+ data_o <= mem[rd_addr];
+ end
+
+endmodule
diff --git a/rom_ctrl.v b/rom_ctrl.v
new file mode 100644
index 0000000..1957a03
--- /dev/null
+++ b/rom_ctrl.v
@@ -0,0 +1,182 @@
+module rom_ctrl(
+ input clk_i,
+ input rst_i,
+
+ input rd_i,
+ input wr_i,
+ input [31:0] dat_i,
+ input [4:0] adr_i,
+ output reg[31:0] dat_o,
+
+ output busy_o
+);
+
+wire buf_i_wr, buf_o_wr, buf_i_rd, buf_o_rd;
+wire buf_i_empty, buf_o_empty, buf_i_full, buf_o_full;
+wire buf_i_rst, buf_o_rst;
+wire[31:0] buf_i_data_i, buf_o_data_i, buf_i_data_o, buf_o_data_o;
+
+reg[7:0] spi_writer_count;
+reg spi_writer_wr;
+wire spi_writer_tx_need, spi_writer_finish;
+wire[23:0] spi_writer_addr;
+
+//***********************************
+// Controller state
+//***********************************
+
+// Memory for storing state
+reg[4:0] state;
+
+// Show state of controller for wb
+assign busy_o = ( state == IDLE ? 0 : 1 );
+
+// List of states
+localparam IDLE = 4'd0,
+ WRITING_DATA = 4'd1,
+ READING_DATA = 4'd2,
+ WRITING_STATUS = 4'd3,
+ READING_STATUS = 4'd4,
+ BULK_ERASE = 4'd5,
+ ERASING_SECTOR = 4'd6,
+ QUICK_OPERATION = 4'd7;
+
+//***********************************
+// Virtual registers
+//***********************************
+
+// Memory for storing registers
+reg[31:0] registers[8:0];
+
+// List of virtual registers
+localparam WADDR = 0,
+ WDATA = 1,
+ WLEN = 2,
+
+ RADDR = 3,
+ RDATA = 4,
+ RLEN = 5,
+
+ SEC_ADDR_ERASE = 6,
+ BULK_ERASE = 7,
+ STATUS = 8;
+
+//***********************************
+// WRITE BUFFER
+//***********************************
+
+// Empty WRITE BUFFER when write to WADDR
+assign buf_o_rst = ( wr_i && adr_i == WADDR );
+
+// Get data for writing from dat_i
+assign buf_o_data_i = dat_i;
+
+// Write to the WRITE BUFFER when write data to WDATA
+assign buf_o_wr = ( wr_i && adr_i == WDATA );
+
+// Read data from WRITE BUFFER when write data to SPI controller
+assign buf_o_rd = ( state == WRITING_DATA && spi_writer_tx_need );
+
+fifo buf_o(
+ .clk_i(clk_i),
+ .rst_i(buf_o_rst),
+
+ .wr_i(buf_o_wr),
+ .data_i(buf_o_data_i),
+
+ .rd_i(buf_o_rd),
+ .data_o(buf_o_data_o),
+
+ .empty_o(buf_o_empty),
+ .full_o(buf_o_full)
+);
+
+//***********************************
+// READ BUFFER
+//***********************************
+
+// Empty READ BUFFER when write to RADDR
+assign buf_i_rst = ( wr_i && adr_i == RADDR );
+
+// Mark as read top of READ BUFFER when read data from RDATA
+assign buf_i_rd = ( rd_i && adr_i == RDATA );
+
+// Write to READ BUFFER when read data from SPI controller
+//assign buf_i_wr = ( state == READING && spi_writer_tx_need );
+assign buf_i_wr = 1'b0; //FIXME
+// Get data for writing from SPI_DATA_I
+assign buf_i_data_i = 1'b0; //FIXME
+
+fifo buf_i(
+ .clk_i(clk_i),
+ .rst_i(buf_i_rst),
+ .rd_i(buf_i_rd),
+ .wr_i(buf_i_wr),
+ .empty_o(buf_i_empty),
+ .full_o(buf_i_full),
+ .data_i(buf_i_data_i),
+ .data_o(buf_i_data_o)
+);
+
+//***********************************
+// SPI Core
+//***********************************
+
+assign spi_writer_tx = buf_o_data_o;
+assign spi_writer_addr = registers[WADDR][23:0];
+/*
+spi_writer spi_writer(
+ .clk_i(clk_i),
+ .tx_i(spi_writer_tx),
+ .adr_i(spi_writer_addr),
+ .wr_i(spi_writer_wr),
+ .tx_need(spi_writer_tx_need),
+ .finish_o(spi_writer_finish)
+);*/
+
+always @(posedge clk_i, posedge rst_i)
+ if( state == IDLE )
+ if( wr_i )
+ registers[adr_i] <= dat_i;
+ else if( rd_i )
+ dat_o <= registers[adr_i];
+
+always @(posedge clk_i, posedge rst_i)
+ if( rst_i )
+ state <= IDLE;
+ else
+ state <= next_state;
+
+always @*
+ begin
+ next_state = state;
+ case( state ):
+ IDLE:
+ begin
+ case(adr_i)
+ RLEN:
+ next_state = READING_DATA;
+ WLEN:
+ next_state = WRITING_DATA;
+ SEC_ADDR_ERASE:
+ next_state = ERASING_SECTOR;
+ STATUS:
+ next_state = ( rd_i ? READING_STATUS : WRITING_STATUS );
+ default:
+ next_state = QUICK_OPERATION;
+ endcase
+ end
+
+ WRITING_DATA:
+ if( spi_writer_finish )
+ next_state = IDLE;
+
+ QUICK_OPERATION:
+ next_state = IDLE;
+
+ default:
+ next_state = state;
+ endcase
+ end
+
+endmodule
diff --git a/rom_wb.v b/rom_wb.v
new file mode 100644
index 0000000..3e52409
--- /dev/null
+++ b/rom_wb.v
@@ -0,0 +1,91 @@
+`timescale 1ns / 1ps
+module rom_wb (
+ input wb_clk_i,
+ input wb_rst_i,
+ input [31:0] wb_dat_i,
+ input [31:0] wb_adr_i,
+ input wb_we_i,
+ input [3:0] wb_sel_i,
+ input wb_cyc_i,
+ input wb_stb_i,
+
+ output reg [31:0] wb_dat_o,
+ output reg wb_ack_o
+);
+
+localparam BUSY = 1,
+ IDLE = 0;
+
+reg old_state = 1'b0;
+wire new_state;
+
+wb_conv wb_conv(
+ .wb_clk_i ( wb_clk_i ),
+ .wb_rst_i ( wb_rst_i ),
+ .wb_dat_i ( wb_dat_i ),
+ .wb_adr_i ( wb_adr_i ),
+ .wb_we_i ( wb_we_i ),
+ .wb_sel_i ( wb_sel_i ),
+ .wb_cyc_i ( wb_cyc_i ),
+ .wb_stb_i ( wb_stb_i ),
+
+ .wb_dat_o ( wb_dat_o ),
+ .wb_ack_o ( wb_ack_o ),
+
+ .data_
+ .addr_
+ .wr_en
+ .rd_en
+ .busy
+ .data_
+);
+
+spi_conv spi_conv(
+ .mosi
+ .miso
+ .clk
+ .ss
+
+ .data_
+ .addr_
+ .wr_en
+ .rd_en
+ .busy
+ .data_
+);
+
+
+
+assign rom_read_i = wb_cyc_i & wb_stb_i & !wb_we_i;
+assign rom_write_i = wb_cyc_i & wb_stb_i & wb_we_i;
+assign rom_dat_i = wb_dat_i;
+assign rom_dat_o = wb_dat_o;
+assign rom_addr_i = wb_adr_i;
+assign rom_clk_i = wb_adr_i;
+
+rom_ctrl rom_ctrl(
+ .clk_i(rom_clk_i),
+ .rst_i(0),
+
+ .adr_i(rom_addr_i),
+
+ .rd_i(rom_read_i),
+ .dat_o(rom_dat_o),
+
+ .wr_i(rom_write_i),
+ .dat_i(rom_dat_i),
+
+ .busy_o(new_state)
+);
+
+always @(posedge clk_i)
+begin
+ // если был занят, а стал свободен, значит контроллер завершил операцию и
+ // нужно дёрнуть один раз ACK_O и положить на следующем такте, чтобы wishbone
+ // master оповестился о конце операции slave'а
+
+ ack_o <= ( old_state == BUSY && new_state == IDLE ? 1 : 0);
+ old_state <= new_state;
+end
+
+endmodule
diff --git a/spi_routine.v b/spi_routine.v
new file mode 100644
index 0000000..3733e50
--- /dev/null
+++ b/spi_routine.v
@@ -0,0 +1,92 @@
+`timescale 1ns / 1ps
+
+module spi_routine
+(
+ input [7:0] tx_i,
+ output [7:0] rx_o,
+
+ input rst_i,
+
+ input miso_i,
+ input clk_i,
+ input ss_i,
+ output reg mosi_o,
+ output sclk_o
+
+ input rd_i,
+ input wr_i,
+
+ output finish_o
+);
+
+localparam ADDR_WIDTH = 3;
+
+reg in_progress = 0;
+
+reg [ADDR_WIDTH-1:0] idx = 0;
+reg [1:0] start = 0;
+
+
+reg [2:0] state;
+reg [2:0] next_state;
+
+
+wire finish_w;
+
+localparam READ_S = 3'd2,
+ WRITE_S = 3'd1,
+ IDLE_S = 3'd0;
+
+always @(posedge clk_i, posedge rst_i )
+ if( rst_i )
+ state <= IDLE_S;
+ else
+ state <= next_state;
+
+always @*
+begin
+ next_state = state;
+ case( state ):
+ IDLE_S:
+ begin
+ if( rd_i )
+ next_state = READ_S;
+ else
+ if( wr_i )
+ next_state = WRITE_S;
+ end
+ READ_S:
+ begin
+ if( finish_w )
+ next_state = IDLE_S;
+ end
+ WRITE_S:
+ begin
+ if( finish_w )
+ next_state = IDLE_S;
+ end
+ endcase
+end
+
+always @*
+ if( state == WRITE_S )
+ mosi <= tx_i[idx];
+ else
+ mosi <= 1'b1;
+
+reg [7:0] rx;
+always @(posedge clk)
+ if( state == READ_S )
+ rx[idx] <= miso;
+
+always @(posedge clk)
+ if( state == IDLE_S )
+ idx <= 2'd0;
+ else
+ idx <= idx + 2'd1;
+
+assign finish_w = (idx == 7);
+
+assign finish_o = finish_w;
+
+endmodule
diff --git a/spi_writer.v b/spi_writer.v
new file mode 100644
index 0000000..19db035
--- /dev/null
+++ b/spi_writer.v
@@ -0,0 +1,129 @@
+`timescale 1ns / 1ps
+
+module spi_writer(
+ input clk_i,
+ input[7:0] tx_i,
+ input[23:0] adr_i,
+ input wr_i,
+ output tx_need,
+ output finish_o
+);
+
+wire spi_miso_i, spi_sclk_i, spi_mosi_o, spi_ss_i;
+
+reg [7:0] spi_tx;
+reg [7:0] spi_rx;
+
+//***********************************
+// SPI M25P16 Writer state
+//***********************************
+
+// Memory for storing state
+reg[4:0] state;
+
+localparam IDLE = 0,
+ WRITE_ENABLE = 1,
+ WRITE_INSTR = 2,
+ WRITE_ADDR = 3,
+ WRITE_DATA = 4,
+ WRITE_DISABLE = 5;
+
+//***********************************
+// SPI Routine
+//***********************************
+
+assign spi_rd_i = 0;
+assign spi_sclk_i = clk_i;
+
+wire spi_finish;
+
+spi_routine (
+ .clk_i(spi_sclk_i),
+
+ .ss_i(spi_ss_i),
+ .mosi_o(spi_mosi_o),
+ .miso_i(spi_miso_i),
+
+ .rx_o(spi_rx),
+ .tx_i(spi_tx),
+
+ .rd_i(spi_rd_i),
+ .wr_i(spi_wr_i),
+
+ .finish_o(spi_finish)
+);
+
+always @(posedge clk_i)
+begin
+ case(state)
+ IDLE:
+ begin
+ if( wr_i ) begin
+ state <= WRITE_ENABLE;
+ spi_wr_i <= 0;
+ spi_ss_i <= 1;
+ end
+ end
+
+ WRITE_ENABLE:
+ begin
+ if( spi_finish ) begin
+ state <= WRITE_INSTR;
+ spi_ss_i <= 1;
+ end else begin
+ spi_wr_i <= 1;
+ spi_tx <= 8'h00;
+ spi_ss_i <= 0;
+ end
+ end
+
+ WRITE_INSTR:
+ begin
+ if( spi_finish )
+ state <= WRITE_ADDR;
+ else begin
+ spi_tx <= 8'h00;
+ spi_wr_i <= 1;
+ spi_ss_i <= 0;
+ end
+ end
+
+ WRITE_ADDR:
+ begin
+ if( spi_finish ) begin
+ state = WRITE_DATA;
+ end else begin
+ spi_tx <= 8'h00;
+ spi_wr_i <= 1;
+ spi_ss_i <= 0;
+ end
+ end
+
+ WRITE_DATA:
+ begin
+ if( spi_finish && !wr_i ) begin
+ state <= WRITE_DISABLE;
+ spi_ss_i <= 1;
+ end else if( spi_finish && wr_i ) begin
+ tx_need <= 1;
+ end else if( !spi_finish && wr_i ) begin
+ spi_tx <= tx_i;
+ spi_ss_i <= 0;
+ end
+ end
+
+ WRITE_DISABLE:
+ begin
+ if( spi_finish ) begin
+ state <= IDLE;
+ spi_ss_i <= 1;
+ finish_o <= 1;
+ end else begin
+ spi_tx <= 8'h00;
+ spi_wr_i <= 1;
+ spi_ss_i <= 0;
+ end
+ end
+end
+
+endmodule
diff --git a/testbench.v b/testbench.v
new file mode 100644
index 0000000..5e683a5
--- /dev/null
+++ b/testbench.v
@@ -0,0 +1,114 @@
+`timescale 1ns / 1ps
+
+////////////////////////////////////////////////////////////////////////////////
+// Company:
+// Engineer:
+//
+// Create Date: 03:00:40 12/10/2015
+// Design Name: fifo
+// Module Name: C:/Users/M25P16/ff.v
+// Project Name: M25P16
+// Target Device:
+// Tool versions:
+// Description:
+//
+// Verilog Test Fixture created by ISE for module: fifo
+//
+// Dependencies:
+//
+// Revision:
+// Revision 0.01 - File Created
+// Additional Comments:
+//
+////////////////////////////////////////////////////////////////////////////////
+
+module ff;
+
+ // Inputs
+ reg clk_i;
+ reg rst_i;
+ reg wr_i;
+ reg [31:0] data_i;
+ reg rd_i;
+
+ // Outputs
+ wire full_o;
+ wire [31:0] data_o;
+ wire empty_o;
+
+ // Instantiate the Unit Under Test (UUT)
+ fifo uut (
+ .clk_i(clk_i),
+ .rst_i(rst_i),
+ .wr_i(wr_i),
+ .data_i(data_i),
+ .full_o(full_o),
+ .rd_i(rd_i),
+ .data_o(data_o),
+ .empty_o(empty_o)
+ );
+
+ initial
+ begin
+ clk_i = 0;
+
+ forever
+ #5 clk_i = !clk_i;
+ end
+
+ initial begin
+ // Initialize Inputs
+ clk_i = 0;
+ rst_i = 0;
+ wr_i = 0;
+ data_i = 0;
+ rd_i = 0;
+
+ // Wait 100 ns for global reset to finish
+ #100;
+ @(posedge clk_i);
+
+ // Add stimulus here
+
+ wr_i = 1;
+ data_i = 32'hAABBCCDD;
+
+ @(posedge clk_i);
+
+ wr_i = 1;
+ data_i = 32'hCCBBCCDD;
+
+ @(posedge clk_i);
+
+ wr_i = 0;
+ rd_i = 1;
+
+ @(posedge clk_i);
+
+ rd_i = 0;
+ #100;
+
+ @(posedge clk_i);
+ rd_i = 1;
+
+ @(posedge clk_i);
+ rd_i = 0;
+ @(posedge clk_i);
+ rd_i = 1;
+
+ @(posedge clk_i);
+ rd_i = 0;
+ @(posedge clk_i);
+ rd_i = 1;
+
+ @(posedge clk_i);
+ rd_i = 0;
+ @(posedge clk_i);
+ rd_i = 1;
+
+ @(posedge clk_i);
+ rd_i = 0;
+ end
+
+endmodule
+