練習九-利用狀態機實現比較復雜的接口設計
- 1,任務目的:
- 2,RTL代碼
- 3,RTL原理框圖
- 4,測試代碼
- 5,波形輸出
1,任務目的:
(1)學習運用狀態機控制的邏輯開關,并設計出一個比較復雜的接口邏輯;
(2)在復雜設計中使用任務(task)結構,以提高程序的可讀性;
(3)加深對可綜合風格模塊的認識。
下面例子是一個并行數據轉換為串行位流的變換器,利用雙向總線輸出。該案例來自于EPROM讀寫器,電路工作的步驟是:
(1)把并行地址存入寄存器; (2)把并行數據存入寄存器; (3)連接串行單總線; (4)地址的串行輸出; (5)數據的串行輸出; (6)掛起串行單總線; (7)給信號源應答; (8)讓信號源給出下一個操作對象; (9)結束寫操作。
2,RTL代碼
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/11/22 10:52:02
// Design Name:
// Module Name: writing
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module writing(
rst_n, clk, address, data, sda, ack);input rst_n, clk;
input [7:0] data, address;inout sda; // 串行數據的輸出或者輸入接口
output ack; // 模塊給出的應答信號
reg link_write; // link_write決定何時輸出reg [3:0] state; // 主狀態機的狀態字
reg [4:0] sh8out_state; // 從狀態機的狀態字
reg [7:0] sh8out_buf; // 輸入數據緩沖
reg finish_F; // 用以判斷是否處理完一個操作對象
reg ack;parameter idle = 0;
parameter addr_write = 1;
parameter data_write = 2;
parameter stop_ack = 3;parameter bit0 = 1;
parameter bit1 = 2;
parameter bit2 = 3;
parameter bit3 = 4;
parameter bit4 = 5;
parameter bit5 = 6;
parameter bit6 = 7;
parameter bit7 = 8;assign sda = link_write ? sh8out_buf[7] : 1'bz;always@(posedge clk) beginif(!rst_n) begin // 復位link_write <= 0; // 掛起串行總線sh8out_state <= idle;sh8out_buf <= 0;state <= idle;finish_F <= 0; // 結束標志清零ack <= 0;endelse case(state)idle: beginlink_write <= 0; // 斷開串行單總線sh8out_state <= idle;sh8out_buf <= address; // 并行地址存入寄存器state <= addr_write; // 進入下一個狀態finish_F <= 0; ack <= 0;endaddr_write: // 地址的輸入if(finish_F == 0) shift8_out ; // 地址的串行輸出// ? 任務else beginsh8out_state <= idle;sh8out_buf <= data; // 并行數據存入寄存器state <= data_write;finish_F <= 0;enddata_write: // 數據的寫入if(finish_F == 0)shift8_out ; // 數據的串行輸出// 任務else beginlink_write <= 0;state <= stop_ack;finish_F <= 0;ack <= 1; // 向信號源發出應答endstop_ack: begin // 向信號源發出應答結果ack <= 0;state <= idle;endendcase
endtask shift8_out; // 地址和數據的串行輸出
begincase(sh8out_state)idle: beginlink_write <= 1; // 連接串行單總線,立即輸出地址或數據的最高位(MSB)sh8out_state <= bit7;endbit7: beginlink_write <= 1; // 連接串行單總線sh8out_state <= bit6;sh8out_buf <= sh8out_buf << 1; // 輸出地址或數據的次高位(bit6)endbit6: beginsh8out_state <= bit5;sh8out_buf <= sh8out_buf << 1;endbit5: beginsh8out_state <= bit4;sh8out_buf <= sh8out_buf << 1;endbit4: beginsh8out_state <= bit3;sh8out_buf <= sh8out_buf << 1;endbit3: beginsh8out_state <= bit2;sh8out_buf <= sh8out_buf << 1;endbit2: beginsh8out_state <= bit1;sh8out_buf <= sh8out_buf << 1;endbit1: beginsh8out_state <= bit0;sh8out_buf <= sh8out_buf << 1; // 輸出地址或數據的最低位(LSB)endbit0: beginlink_write <= 0; // 掛起串行單總線finish_F <= 1; // 建立結束標志endendcase
end
endtaskendmodule
3,RTL原理框圖
4,測試代碼
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/11/22 10:53:46
// Design Name:
// Module Name: writing_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//// 測試代碼
`define clk_cycle 50
module writing_top;
reg rst_n, clk;
reg [7:0] data, address;
wire ack, sda;always #`clk_cycle clk = ~clk;initial beginclk = 0;rst_n = 1;data = 0;address = 0;#(2 * `clk_cycle) rst_n = 0;#(2 * `clk_cycle) rst_n = 1;#(100 * `clk_cycle) $stop;
endalways@(posedge ack) begin// 接收到應答信號后,給出下一個處理對象data = data + 1;address = address + 1;
endwriting u_writing(
.rst_n (rst_n ),
.clk (clk ),
.data (data ),
.address (address ),
.ack (ack ),
.sda (sda )
);endmodule
5,波形輸出