diff options
author | Sergey Nazaryev <sergey@nazaryev.ru> | 2015-12-23 15:44:12 +0000 |
---|---|---|
committer | Sergey Nazaryev <sergey@nazaryev.ru> | 2015-12-23 15:44:12 +0000 |
commit | e4381701562660b0594f09e9ad4d5f5c5ff66fc5 (patch) | |
tree | 3b5d8babc7be3ae0ff80fc4e347450fef2b7f59d | |
download | circuit-design-lab234-e4381701562660b0594f09e9ad4d5f5c5ff66fc5.zip circuit-design-lab234-e4381701562660b0594f09e9ad4d5f5c5ff66fc5.tar.gz circuit-design-lab234-e4381701562660b0594f09e9ad4d5f5c5ff66fc5.tar.bz2 |
initial
-rw-r--r-- | fifo.v | 52 | ||||
-rw-r--r-- | rom_ctrl.v | 182 | ||||
-rw-r--r-- | rom_wb.v | 91 | ||||
-rw-r--r-- | spi_routine.v | 92 | ||||
-rw-r--r-- | spi_writer.v | 129 | ||||
-rw-r--r-- | testbench.v | 114 |
6 files changed, 660 insertions, 0 deletions
@@ -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 + |