├── .gitignore ├── pic ├── crc_16.png ├── write_ok.jpg ├── illigal_reg.jpg ├── rx_03_normal.jpg ├── rx_04_normal.jpg ├── write_failed.jpg ├── write_ok_response.jpg ├── repsonse_03_normal.jpg ├── repsonse_04_normal.jpg ├── illigal_reg_response.jpg └── write_failed_response.jpg ├── doc └── Modbus_Application_Protocol_V1_1b3.pdf ├── crc_16.do ├── DPRAM_tb.do ├── uart_byte_tx_tb.do ├── uart_byte_rx_tb.do ├── ct_15t_gen_tb.do ├── ct_35t_gen_tb.do ├── exceptions_tb.do ├── frame_rx_tb.do ├── tx_response_tb.do ├── func_handler_tb.do ├── modbus_rtu_slave_top_tb.do ├── ct_35t_gen.v ├── ct_15t_gen.v ├── crc_16_tb.v ├── DPRAM.v ├── DPRAM_tb.v ├── README.md ├── crc_16.v ├── uart_byte_tx_tb.v ├── exceptions.v ├── uart_byte_tx.v ├── uart_byte_rx_tb.v ├── modbus_rtu_slave_top_tb.v ├── ct_15t_gen_tb.v ├── ct_35t_gen_tb.v ├── frame_rx.v ├── uart_byte_rx.v ├── modbus_rtu_slave_top.v ├── modbus_crc_16.v ├── func_handler.v ├── frame_rx_tb.v ├── exceptions_tb.v ├── tx_response.v ├── func_handler_tb.v └── tx_response_tb.v /.gitignore: -------------------------------------------------------------------------------- 1 | .git 2 | rtl_work 3 | vsim.wlf 4 | transcript 5 | -------------------------------------------------------------------------------- /pic/crc_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/crc_16.png -------------------------------------------------------------------------------- /pic/write_ok.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/write_ok.jpg -------------------------------------------------------------------------------- /pic/illigal_reg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/illigal_reg.jpg -------------------------------------------------------------------------------- /pic/rx_03_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/rx_03_normal.jpg -------------------------------------------------------------------------------- /pic/rx_04_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/rx_04_normal.jpg -------------------------------------------------------------------------------- /pic/write_failed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/write_failed.jpg -------------------------------------------------------------------------------- /pic/write_ok_response.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/write_ok_response.jpg -------------------------------------------------------------------------------- /pic/repsonse_03_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/repsonse_03_normal.jpg -------------------------------------------------------------------------------- /pic/repsonse_04_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/repsonse_04_normal.jpg -------------------------------------------------------------------------------- /pic/illigal_reg_response.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/illigal_reg_response.jpg -------------------------------------------------------------------------------- /pic/write_failed_response.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/pic/write_failed_response.jpg -------------------------------------------------------------------------------- /doc/Modbus_Application_Protocol_V1_1b3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yxgi5/modbus_rtu_slave/HEAD/doc/Modbus_Application_Protocol_V1_1b3.pdf -------------------------------------------------------------------------------- /crc_16.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | 10 | vlog -vlog01compat -work work {./crc_16_tb.v} 11 | vlog -vlog01compat -work work {./crc_16.v} 12 | 13 | #simulate 14 | #vsim -novopt crc_16_tb 15 | vsim -voptargs="+acc" crc_16_tb 16 | 17 | add wave -radix hexadecimal /crc_16_tb/* 18 | view structure 19 | view signals 20 | 21 | run -all 22 | 23 | 24 | -------------------------------------------------------------------------------- /DPRAM_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./DPRAM.vhd} 10 | vlog -vlog01compat -work work {./DPRAM.v} 11 | vlog -vlog01compat -work work {./DPRAM_tb.v} 12 | 13 | #simulate 14 | vsim -novopt DPRAM_tb 15 | 16 | #probe signals 17 | add wave -radix unsigned * 18 | add wave -radix unsigned /DPRAM_tb/UUT/* 19 | add wave -radix unsigned /DPRAM_tb/UUT/RAM 20 | 21 | view structure 22 | view signals 23 | 24 | #300 ns 25 | 26 | run 500ns 27 | -------------------------------------------------------------------------------- /uart_byte_tx_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./uart_byte_tx.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_tx.v} 11 | vlog -vlog01compat -work work {./uart_byte_tx_tb.v} 12 | 13 | 14 | #simulate 15 | #vsim -novopt uart_byte_tx_tb 16 | vsim -voptargs="+acc" uart_byte_tx_tb 17 | 18 | add wave -radix unsigned * 19 | add wave -radix hexadecimal /uart_byte_tx_tb/uart_byte_tx_inst0/* 20 | #add wave -radix unsigned /uart_byte_tx_tb/uart_byte_tx_inst0/* 21 | view structure 22 | view signals 23 | 24 | 25 | run 360us 26 | -------------------------------------------------------------------------------- /uart_byte_rx_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./uart_byte_tx.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_rx.v} 11 | vlog -vlog01compat -work work {./uart_byte_tx.v} 12 | vlog -vlog01compat -work work {./uart_byte_rx_tb.v} 13 | 14 | 15 | #simulate 16 | #vsim -novopt uart_byte_rx_tb 17 | vsim -voptargs="+acc" uart_byte_rx_tb 18 | 19 | add wave -radix unsigned * 20 | add wave -radix hexadecimal /uart_byte_rx_tb/uart_byte_rx_inst0/* 21 | #add wave -radix unsigned /uart_byte_rx_tb/uart_byte_rx_inst0/* 22 | view structure 23 | view signals 24 | 25 | 26 | run 400us 27 | -------------------------------------------------------------------------------- /ct_15t_gen_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./*.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_tx.v} 11 | vlog -vlog01compat -work work {./uart_byte_rx.v} 12 | vlog -vlog01compat -work work {./ct_15t_gen.v} 13 | vlog -vlog01compat -work work {./ct_15t_gen_tb.v} 14 | 15 | #simulate 16 | #vsim -novopt ct_15t_gen_tb 17 | vsim -voptargs="+acc" ct_15t_gen_tb 18 | 19 | add wave -radix unsigned * 20 | #add wave -radix hexadecimal /ct_15t_gen_tb/ct_15t_gen_inst0/* 21 | add wave -radix unsigned /ct_15t_gen_tb/ct_15t_gen_inst0/* 22 | view structure 23 | view signals 24 | 25 | 26 | run 1500us 27 | -------------------------------------------------------------------------------- /ct_35t_gen_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./*.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_tx.v} 11 | vlog -vlog01compat -work work {./uart_byte_rx.v} 12 | vlog -vlog01compat -work work {./ct_35t_gen.v} 13 | vlog -vlog01compat -work work {./ct_35t_gen_tb.v} 14 | 15 | #simulate 16 | #vsim -novopt ct_35t_gen_tb 17 | vsim -voptargs="+acc" ct_35t_gen_tb 18 | 19 | add wave -radix unsigned * 20 | add wave -radix hexadecimal /ct_35t_gen_tb/ct_35t_gen_inst0/* 21 | #add wave -radix unsigned /ct_35t_gen_tb/ct_35t_gen_inst0/* 22 | view structure 23 | view signals 24 | 25 | 26 | run 1500us 27 | -------------------------------------------------------------------------------- /exceptions_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./*.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_tx.v} 11 | vlog -vlog01compat -work work {./uart_byte_rx.v} 12 | vlog -vlog01compat -work work {./ct_35t_gen.v} 13 | vlog -vlog01compat -work work {./ct_15t_gen.v} 14 | vlog -vlog01compat -work work {./frame_rx.v} 15 | vlog -vlog01compat -work work {./modbus_crc_16.v} 16 | vlog -vlog01compat -work work {./crc_16.v} 17 | vlog -vlog01compat -work work {./exceptions.v} 18 | vlog -vlog01compat -work work {./exceptions_tb.v} 19 | 20 | #simulate 21 | #vsim -novopt exceptions_tb 22 | vsim -voptargs="+acc" exceptions_tb 23 | 24 | add wave -radix unsigned * 25 | add wave -radix hexadecimal /exceptions_tb/exceptions_inst0/* 26 | #add wave -radix unsigned /exceptions_tb/exceptions_inst0/* 27 | view structure 28 | view signals 29 | 30 | run 2400us 31 | 32 | -------------------------------------------------------------------------------- /frame_rx_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./*.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_tx.v} 11 | vlog -vlog01compat -work work {./uart_byte_rx.v} 12 | vlog -vlog01compat -work work {./ct_35t_gen.v} 13 | vlog -vlog01compat -work work {./ct_15t_gen.v} 14 | vlog -vlog01compat -work work {./frame_rx.v} 15 | vlog -vlog01compat -work work {./modbus_crc_16.v} 16 | vlog -vlog01compat -work work {./crc_16.v} 17 | vlog -vlog01compat -work work {./frame_rx_tb.v} 18 | 19 | #simulate 20 | #vsim -novopt frame_rx_tb 21 | vsim -voptargs="+acc" frame_rx_tb 22 | 23 | add wave -radix unsigned * 24 | add wave -position insertpoint sim:/frame_rx_tb/FRAME 25 | add wave -radix hexadecimal /frame_rx_tb/frame_rx_inst0/* 26 | add wave -radix hexadecimal /frame_rx_tb/u_modbus_crc_16/* 27 | #add wave -radix unsigned /frame_rx_tb/frame_rx_inst0/* 28 | view structure 29 | view signals 30 | 31 | run 2300us -------------------------------------------------------------------------------- /tx_response_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./*.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_tx.v} 11 | vlog -vlog01compat -work work {./uart_byte_rx.v} 12 | vlog -vlog01compat -work work {./ct_35t_gen.v} 13 | vlog -vlog01compat -work work {./ct_15t_gen.v} 14 | vlog -vlog01compat -work work {./frame_rx.v} 15 | vlog -vlog01compat -work work {./modbus_crc_16.v} 16 | vlog -vlog01compat -work work {./crc_16.v} 17 | vlog -vlog01compat -work work {./exceptions.v} 18 | vlog -vlog01compat -work work {./DPRAM.v} 19 | vlog -vlog01compat -work work {./func_handler.v} 20 | vlog -vlog01compat -work work {./tx_response.v} 21 | vlog -vlog01compat -work work {./tx_response_tb.v} 22 | 23 | #simulate 24 | #vsim -novopt tx_response_tb 25 | vsim -voptargs="+acc" tx_response_tb 26 | 27 | add wave -radix unsigned * 28 | add wave -radix hexadecimal /tx_response_tb/DPRAM_inst0/RAM 29 | add wave -radix hexadecimal /tx_response_tb/tx_response_inst0/* 30 | view structure 31 | view signals 32 | 33 | run 10ms 34 | 35 | 36 | -------------------------------------------------------------------------------- /func_handler_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./*.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_tx.v} 11 | vlog -vlog01compat -work work {./uart_byte_rx.v} 12 | vlog -vlog01compat -work work {./ct_35t_gen.v} 13 | vlog -vlog01compat -work work {./ct_15t_gen.v} 14 | vlog -vlog01compat -work work {./frame_rx.v} 15 | vlog -vlog01compat -work work {./modbus_crc_16.v} 16 | vlog -vlog01compat -work work {./crc_16.v} 17 | vlog -vlog01compat -work work {./exceptions.v} 18 | vlog -vlog01compat -work work {./DPRAM.v} 19 | vlog -vlog01compat -work work {./func_handler.v} 20 | vlog -vlog01compat -work work {./func_handler_tb.v} 21 | 22 | #simulate 23 | #vsim -novopt func_handler_tb 24 | vsim -voptargs="+acc" func_handler_tb 25 | 26 | add wave -radix unsigned * 27 | add wave -radix hexadecimal /func_handler_tb/DPRAM_inst0/RAM 28 | add wave -radix hexadecimal /func_handler_tb/func_handler_inst0/* 29 | add wave -radix hexadecimal /func_handler_tb/exceptions_inst0/* 30 | #add wave -radix unsigned /func_handler_tb/exceptions_inst0/* 31 | view structure 32 | view signals 33 | 34 | run 6ms 35 | 36 | 37 | -------------------------------------------------------------------------------- /modbus_rtu_slave_top_tb.do: -------------------------------------------------------------------------------- 1 | transcript on 2 | #compile 3 | if {[file exists rtl_work]} { 4 | vdel -lib rtl_work -all 5 | } 6 | vlib rtl_work 7 | vmap work rtl_work 8 | 9 | #vcom -2008 -work work {./*.vhd} 10 | vlog -vlog01compat -work work {./uart_byte_tx.v} 11 | vlog -vlog01compat -work work {./uart_byte_rx.v} 12 | vlog -vlog01compat -work work {./ct_35t_gen.v} 13 | vlog -vlog01compat -work work {./ct_15t_gen.v} 14 | vlog -vlog01compat -work work {./frame_rx.v} 15 | vlog -vlog01compat -work work {./exceptions.v} 16 | vlog -vlog01compat -work work {./DPRAM.v} 17 | vlog -vlog01compat -work work {./func_handler.v} 18 | vlog -vlog01compat -work work {./modbus_crc_16.v} 19 | vlog -vlog01compat -work work {./crc_16.v} 20 | vlog -vlog01compat -work work {./tx_response.v} 21 | vlog -vlog01compat -work work {./modbus_rtu_slave_top.v} 22 | vlog -vlog01compat -work work {./modbus_rtu_slave_top_tb.v} 23 | 24 | #simulate 25 | #vsim -novopt modbus_rtu_slave_top_tb 26 | vsim -voptargs="+acc" modbus_rtu_slave_top_tb 27 | 28 | add wave -radix unsigned * 29 | add wave -radix hexadecimal /modbus_rtu_slave_top_tb/modbus_rtu_slave_top_inst0/* 30 | add wave -position insertpoint sim:/modbus_rtu_slave_top_tb/modbus_rtu_slave_top_inst0/u_tx_response/rs485_tx_data 31 | #add wave -radix hexadecimal -position insertpoint sim:/modbus_rtu_slave_top_tb/modbus_rtu_slave_top_inst0/u_modbus_crc_16/* 32 | view structure 33 | view signals 34 | 35 | run -all 36 | 37 | 38 | -------------------------------------------------------------------------------- /ct_35t_gen.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module ct_35t_gen # 5 | ( 6 | parameter CLK_FREQ = 'd50000000,// 50MHz 7 | parameter BAUD_RATE = 'd9600 // 8 | ) 9 | ( 10 | input clk ,// system clock 11 | input rst_n ,// system reset, active low 12 | 13 | input rx_done ,// pos-pulse for 1 tick indicates 1 byte transfer done 14 | input rx_state , 15 | 16 | output rx_new_frame // if intervel >3.5T == 1 17 | ); 18 | 19 | localparam BPS_PARAM = (CLK_FREQ/BAUD_RATE); 20 | parameter DELAY_CNT = 35; 21 | 22 | reg cnt_en_flag;//计数器 23 | reg [19:0] bps_cnt ;//每一帧数据发送完毕后延时一段时间 24 | wire add_bps_cnt; 25 | wire end_bps_cnt; 26 | 27 | always@(posedge clk or negedge rst_n) 28 | begin 29 | if(!rst_n) 30 | begin 31 | cnt_en_flag <= `UD 1'b0; 32 | end 33 | else 34 | begin 35 | if(rx_done) 36 | begin 37 | cnt_en_flag <= `UD 1'b1; 38 | end 39 | else if(rx_state||end_bps_cnt) 40 | begin 41 | cnt_en_flag <= `UD 1'b0; 42 | end 43 | end 44 | end 45 | 46 | always @(posedge clk or negedge rst_n)begin 47 | if(!rst_n)begin 48 | bps_cnt <= `UD 0; 49 | end 50 | else if(add_bps_cnt)begin 51 | if(end_bps_cnt)begin 52 | bps_cnt <= `UD 0; 53 | end 54 | else begin 55 | bps_cnt <= `UD bps_cnt + 1; 56 | end 57 | end 58 | else begin 59 | bps_cnt <= `UD 0; 60 | end 61 | end 62 | 63 | assign add_bps_cnt = cnt_en_flag; 64 | assign end_bps_cnt = bps_cnt && bps_cnt >= DELAY_CNT*(BPS_PARAM-1); 65 | assign rx_new_frame = end_bps_cnt; 66 | 67 | endmodule 68 | -------------------------------------------------------------------------------- /ct_15t_gen.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module ct_15t_gen # 5 | ( 6 | parameter CLK_FREQ = 'd50000000,// 50MHz 7 | parameter BAUD_RATE = 'd9600 // 8 | ) 9 | ( 10 | input clk ,// system clock 11 | input rst_n ,// system reset, active low 12 | 13 | input rx_done ,// pos-pulse for 1 tick indicates 1 byte transfer done 14 | input rx_state , 15 | 16 | output rx_drop_frame// if intervel >1.5T == 1 17 | ); 18 | 19 | localparam BPS_PARAM = (CLK_FREQ/BAUD_RATE); 20 | parameter DELAY_CNT = 15; 21 | 22 | reg cnt_en_flag;//计数器 23 | reg [19:0] bps_cnt ;//每一帧数据发送完毕后延时一段时间 24 | wire add_bps_cnt; 25 | wire end_bps_cnt; 26 | 27 | always@(posedge clk or negedge rst_n) 28 | begin 29 | if(!rst_n) 30 | begin 31 | cnt_en_flag <= `UD 1'b0; 32 | end 33 | else 34 | begin 35 | if(rx_done) 36 | begin 37 | cnt_en_flag <= `UD 1'b1; 38 | end 39 | else if(rx_state||end_bps_cnt) 40 | begin 41 | cnt_en_flag <= `UD 1'b0; 42 | end 43 | end 44 | end 45 | 46 | always @(posedge clk or negedge rst_n)begin 47 | if(!rst_n)begin 48 | bps_cnt <= `UD 0; 49 | end 50 | else if(add_bps_cnt)begin 51 | if(end_bps_cnt)begin 52 | bps_cnt <= `UD 0; 53 | end 54 | else begin 55 | bps_cnt <= `UD bps_cnt + 1; 56 | end 57 | end 58 | else begin 59 | bps_cnt <= `UD 0; 60 | end 61 | end 62 | 63 | assign add_bps_cnt = cnt_en_flag; 64 | assign end_bps_cnt = bps_cnt && bps_cnt >= DELAY_CNT*(BPS_PARAM-1); 65 | assign rx_drop_frame = end_bps_cnt; 66 | 67 | endmodule 68 | 69 | -------------------------------------------------------------------------------- /crc_16_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module crc_16_tb(); 4 | //激励信号定义 5 | reg tb_clk ; 6 | reg tb_rst_n ; 7 | reg crc_en ; 8 | reg clear ; 9 | reg [7:0] data_in ; 10 | reg [3:0] byte_cnt; 11 | //输出信号定义 12 | wire [15:0] crc_out ; 13 | 14 | //时钟周期参数定义 15 | parameter CLOCK_CYCLE = 20; 16 | 17 | parameter CHECK_BYTES = 48'hf00300010001; 18 | 19 | crc_16 u_crc_16( 20 | /*input */.clk (tb_clk), 21 | /*input */.rst_n (tb_rst_n), 22 | /*input */.crc_en (crc_en), 23 | /*input */.crc_clr (clear), 24 | /*input [7:0] */.data_in (data_in), 25 | /*output reg [15:0] */.crc_out (crc_out) 26 | ); 27 | //产生时钟 28 | initial tb_clk = 1'b0; 29 | always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk; 30 | 31 | //产生激励 32 | initial begin 33 | tb_rst_n = 1'b1; 34 | #(CLOCK_CYCLE*2); 35 | tb_rst_n = 1'b0; 36 | #(CLOCK_CYCLE*20); 37 | tb_rst_n = 1'b1; 38 | #(CLOCK_CYCLE*200); 39 | 40 | $stop; 41 | end 42 | 43 | always @(posedge tb_clk or negedge tb_rst_n)begin 44 | if(!tb_rst_n)begin 45 | crc_en <= 1'b0; 46 | clear <= 1'b0; 47 | data_in <= 0; 48 | byte_cnt <= 0; 49 | end 50 | else if(byte_cnt <= 5) begin 51 | crc_en <= 1'b1; 52 | byte_cnt <= byte_cnt + 1; 53 | data_in <= CHECK_BYTES[(47 - byte_cnt*8) -:8]; 54 | end 55 | else begin 56 | clear <= 1'b1; 57 | crc_en <= 1'b0; 58 | data_in <= CHECK_BYTES; 59 | end 60 | end 61 | 62 | endmodule -------------------------------------------------------------------------------- /DPRAM.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module DPRAM # 5 | ( 6 | parameter A_WIDTH = 4, 7 | parameter D_WIDTH = 16 8 | ) 9 | ( 10 | CLKA, 11 | CLKB, 12 | ENA, 13 | ENB, 14 | WEA, 15 | WEB, 16 | ADDRA, 17 | ADDRB, 18 | DIA, 19 | DIB, 20 | DOA, 21 | DOB, 22 | ); 23 | 24 | input CLKA; 25 | input CLKB; 26 | input ENA; 27 | input ENB; 28 | input WEA; 29 | input WEB; 30 | input [A_WIDTH-1:0] ADDRA; 31 | input [A_WIDTH-1:0] ADDRB; 32 | input [D_WIDTH-1:0] DIA; 33 | input [D_WIDTH-1:0] DIB; 34 | output [D_WIDTH-1:0] DOA; 35 | output [D_WIDTH-1:0] DOB; 36 | 37 | reg [D_WIDTH-1:0] DOA; 38 | reg [D_WIDTH-1:0] DOB; 39 | 40 | 41 | reg [D_WIDTH-1:0] RAM [0:2**A_WIDTH-1];//2的A_WIDTH次幂 42 | 43 | //-------------------------------------------------------------------------------- 44 | //-- Schreiben/Lesen Port A 45 | //-------------------------------------------------------------------------------- 46 | always @(posedge CLKA) 47 | begin 48 | if (ENA == 1'b1) 49 | begin 50 | if (WEA == 1'b1) 51 | begin 52 | RAM[ADDRA] = `UD DIA; 53 | end 54 | //else 55 | //begin 56 | //DOA <= `UD RAM[ADDRA]; 57 | //end 58 | DOA = `UD RAM[ADDRA]; 59 | end 60 | end 61 | 62 | //-------------------------------------------------------------------------------- 63 | //-- Schreiben/Lesen Port B 64 | //-------------------------------------------------------------------------------- 65 | always @(posedge CLKB) 66 | begin 67 | if (ENB == 1'b1) 68 | begin 69 | if (WEB == 1'b1) 70 | begin 71 | RAM[ADDRB] = `UD DIB; 72 | end 73 | //else 74 | //begin 75 | //DOB <= `UD RAM[ADDRB]; 76 | //end 77 | DOB = `UD RAM[ADDRB]; 78 | end 79 | end 80 | 81 | endmodule 82 | /* 83 | always @(posedge CLOCK) 84 | begin 85 | if (RESET == 1'b1) 86 | begin 87 | end 88 | else 89 | begin 90 | end 91 | end 92 | */ 93 | 94 | -------------------------------------------------------------------------------- /DPRAM_tb.v: -------------------------------------------------------------------------------- 1 | // clk_div_5_5_tb.v 2 | // Testbench 3 | 4 | `timescale 1ns/ 1ns 5 | //`define CheckByteNum 6000 6 | //`ifndef xx 7 | //`define xx yy // or parameter xx = yy; 8 | //`endif 9 | //`undef XX 10 | 11 | module DPRAM_tb(); 12 | 13 | reg clka; // 180MHz sampling clock 14 | reg clkb; 15 | reg ena; 16 | reg enb; 17 | reg wea; 18 | reg web; 19 | 20 | 21 | parameter A_WIDTH = 4; 22 | parameter D_WIDTH = 16; 23 | 24 | reg [A_WIDTH-1:0] addra; 25 | reg [A_WIDTH-1:0] addrb; 26 | reg [D_WIDTH-1:0] dia; 27 | reg [D_WIDTH-1:0] dib; 28 | wire [D_WIDTH-1:0] doa; 29 | wire [D_WIDTH-1:0] dob; 30 | 31 | DPRAM 32 | #( 33 | .A_WIDTH (A_WIDTH), 34 | .D_WIDTH (D_WIDTH) 35 | )UUT 36 | ( 37 | .CLKA (clka), 38 | .CLKB (clkb), 39 | .ENA (ena), 40 | .ENB (enb), 41 | .WEA (wea), 42 | .WEB (web), 43 | .ADDRA (addra), 44 | .ADDRB (addrb), 45 | .DIA (dia), 46 | .DIB (dib), 47 | .DOA (doa), 48 | .DOB (dob) 49 | ); 50 | 51 | initial 52 | begin 53 | clka = 1'b1; 54 | clkb = 1'b1; 55 | ena = 1'b1; 56 | enb = 1'b1; 57 | wea = 1'b0; 58 | web = 1'b0; 59 | addra = 4'b0; 60 | addrb = 4'b0; 61 | dia = 16'h0000; 62 | dib = 16'h0000; 63 | 64 | // A向地址2写0x1235 65 | #(10*15 - 6); 66 | wea = 1'b1; 67 | addra = 4'b0010; 68 | dia = 16'h1235; 69 | 70 | #30; 71 | #30; 72 | wea = 1'b0; 73 | addra = 4'b0000; 74 | dia = 16'h0000; 75 | 76 | // B向地址3写0xc1a1 77 | web = 1'b1; 78 | addrb = 4'b0011; 79 | dib = 16'hc1a1; 80 | #30; 81 | #30; 82 | web = 1'b0; 83 | addrb = 4'b0000; 84 | dib = 16'h00; 85 | #30; 86 | #30; 87 | #30; 88 | #30; 89 | #30; 90 | #30; 91 | #30; 92 | #30; 93 | #30; 94 | 95 | // A读地址3 96 | wea = 1'b0; 97 | addra = 4'b0011; 98 | dia = 16'h0000; 99 | #30; 100 | #30; 101 | wea = 1'b0; 102 | addra = 4'b0000; 103 | dia = 16'h0000; 104 | #30; 105 | #30; 106 | #30; 107 | #30; 108 | #30; 109 | #30; 110 | 111 | end 112 | 113 | always 114 | begin 115 | #15 clka = ~clka; 116 | end 117 | always 118 | begin 119 | #22 clkb = ~clkb; 120 | end 121 | 122 | endmodule 123 | 124 | 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Modbus RTU Slave Pure RTL design for FPGA 2 | design a ip implements Modbus RTU slave sub function 03 04 06 on FPGA. 3 | 4 | Function code: 03 04 06 5 | 6 | Exception code: 01 02 03 04 7 | 8 | Function 03: ligal reg 0001, ligal quantiy 0001 9 | 10 | Function 04: ligal reg 0001~0004, ligal quantiy + ligal reg < 0005 11 | 12 | Function 06: ligal reg 0001, ligal data 0000~0017, coresponding to Function 03 reg 0001 13 | 14 | slave address assigned by port. 15 | 16 | ## uart tx and uart rx 17 | done 18 | 19 | uart_byte_tx_tb.do 20 | 21 | uart_byte_rx_tb.do 22 | 23 | ## rx 3.5T and 1.5T interval detect 24 | 25 | done 26 | 27 | ct_35t_gen_tb.do 28 | 29 | ct_15t_gen_tb.do 30 | 31 | ## rx slave address and frame check 32 | 33 | done 34 | 35 | frame_rx_tb.do 36 | 37 | ## checksum if slave address check pass 38 | 39 | done 40 | 41 | modbus_crc_tb.do 42 | 43 | ## Exception handling (exclude 04) 44 | ### checksum mismatch then do nothing 45 | ### illegal fuction code retrun 01 46 | ### illegal address return 02 47 | ### illegal quantity return 03 48 | 49 | done 50 | 51 | exceptions_tb.do 52 | 53 | # read / write func logic 54 | 55 | done 56 | 57 | func_handler_tb.do 58 | 59 | # response frame 60 | 61 | ## read response frame 62 | 63 | ### rs485 tx en signal (before tx 1T enable, after tx 1T disable) 64 | 65 | ### tx crc 66 | 67 | ## fuction code 06 68 | 69 | ### write fail return Exception 04 70 | 71 | ### write ok response frame 72 | 73 | done 74 | 75 | tx_response_tb.do 76 | 77 | 78 | # wave 79 | 80 | tx_response_tb.do 81 | 82 | ## func_code 03 83 | 84 | ![](pic/rx_03_normal.jpg) 85 | 86 | assign code 03 reg 0001 value 0451 87 | 88 | ![](pic/repsonse_03_normal.jpg) 89 | 90 | response is ok 91 | 92 | ## illegal exception response 93 | 94 | ![](pic/illigal_reg.jpg) 95 | 96 | here 06 dosen't have reg 0002, so it's illegal 97 | 98 | ![](pic/illigal_reg_response.jpg) 99 | 100 | response is ok 101 | 102 | ## func_code 04 103 | 104 | ![](pic/rx_04_normal.jpg) 105 | 106 | read 4 regs from 0001 107 | 108 | ![](pic/repsonse_04_normal.jpg) 109 | 110 | response is ok 111 | 112 | ## write fail exception 113 | 114 | ![](pic/write_failed.jpg) 115 | 116 | after a write fail 117 | 118 | ![](pic/write_failed_response.jpg) 119 | 120 | response is ok 121 | 122 | ## write ok response 123 | 124 | ![](pic/write_ok.jpg) 125 | 126 | ![](pic/write_ok_response.jpg) 127 | 128 | response is ok 129 | 130 | # top wrapper 131 | 132 | done 133 | 134 | modbus_rtu_slave_top_tb.do -------------------------------------------------------------------------------- /crc_16.v: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2009 OutputLogic.com 3 | // This source file may be used and distributed without restriction 4 | // provided that this copyright statement is not removed from the file 5 | // and that any derivative work contains the original copyright notice 6 | // and the associated disclaimer. 7 | // 8 | // THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS 9 | // OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 10 | // WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 11 | //----------------------------------------------------------------------------- 12 | // CRC module for data[7:0] , crc[15:0]=1+x^2+x^15+x^16; 13 | //----------------------------------------------------------------------------- 14 | `timescale 1ns / 1ns 15 | `define UD #1 16 | module crc_16( 17 | input clk, 18 | input rst_n, 19 | input crc_en, 20 | input crc_clr, //crc数据复位信号 21 | input [7:0] data_in, 22 | output [15:0] crc_out 23 | ); 24 | 25 | reg [15:0] lfsr_q; 26 | wire [7:0 ] data_in_c; 27 | wire [15:0] lfsr_c; 28 | //输入待校验8位数据,需要先将高低位互换 29 | assign data_in_c = {data_in[0],data_in[1],data_in[2],data_in[3],data_in[4],data_in[5],data_in[6],data_in[7]}; 30 | 31 | assign lfsr_c[0 ] = crc_en & (lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in_c[0] ^ data_in_c[1] ^ data_in_c[2] ^ data_in_c[3] ^ data_in_c[4] ^ data_in_c[5] ^ data_in_c[6] ^ data_in_c[7]); 32 | assign lfsr_c[1 ] = crc_en & (lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in_c[1] ^ data_in_c[2] ^ data_in_c[3] ^ data_in_c[4] ^ data_in_c[5] ^ data_in_c[6] ^ data_in_c[7]); 33 | assign lfsr_c[2 ] = crc_en & (lfsr_q[8] ^ lfsr_q[9] ^ data_in_c[0] ^ data_in_c[1] ); 34 | assign lfsr_c[3 ] = crc_en & (lfsr_q[9] ^ lfsr_q[10] ^ data_in_c[1] ^ data_in_c[2] ); 35 | assign lfsr_c[4 ] = crc_en & (lfsr_q[10] ^ lfsr_q[11] ^ data_in_c[2] ^ data_in_c[3]); 36 | assign lfsr_c[5 ] = crc_en & (lfsr_q[11] ^ lfsr_q[12] ^ data_in_c[3] ^ data_in_c[4]); 37 | assign lfsr_c[6 ] = crc_en & (lfsr_q[12] ^ lfsr_q[13] ^ data_in_c[4] ^ data_in_c[5]); 38 | assign lfsr_c[7 ] = crc_en & (lfsr_q[13] ^ lfsr_q[14] ^ data_in_c[5] ^ data_in_c[6]); 39 | assign lfsr_c[8 ] = crc_en & (lfsr_q[0] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in_c[6] ^ data_in_c[7]); 40 | assign lfsr_c[9 ] = crc_en & (lfsr_q[1] ^ lfsr_q[15] ^ data_in_c[7]); 41 | assign lfsr_c[10] = lfsr_q[2]; 42 | assign lfsr_c[11] = lfsr_q[3]; 43 | assign lfsr_c[12] = lfsr_q[4]; 44 | assign lfsr_c[13] = lfsr_q[5]; 45 | assign lfsr_c[14] = lfsr_q[6]; 46 | assign lfsr_c[15] = crc_en & (lfsr_q[7] ^ lfsr_q[8] ^ lfsr_q[9] ^ lfsr_q[10] ^ lfsr_q[11] ^ lfsr_q[12] ^ lfsr_q[13] ^ lfsr_q[14] ^ lfsr_q[15] ^ data_in_c[0] ^ data_in_c[1] ^ data_in_c[2] ^ data_in_c[3] ^ data_in_c[4] ^ data_in_c[5] ^ data_in_c[6] ^ data_in_c[7]); 47 | 48 | always @(posedge clk or negedge rst_n) 49 | begin 50 | if(!rst_n) 51 | lfsr_q <= `UD 16'hff_ff; 52 | else if(crc_clr) //CRC校验值复位 53 | lfsr_q <= `UD 16'hff_ff; 54 | else begin 55 | lfsr_q <= `UD crc_en ? lfsr_c : lfsr_q; 56 | end 57 | end 58 | 59 | //输出检验完的16位数据,同样需要先将高低位互换 60 | assign crc_out = {lfsr_q[0],lfsr_q[1],lfsr_q[2],lfsr_q[3],lfsr_q[4],lfsr_q[5],lfsr_q[6],lfsr_q[7],lfsr_q[8],lfsr_q[9],lfsr_q[10],lfsr_q[11],lfsr_q[12],lfsr_q[13],lfsr_q[14],lfsr_q[15]}; 61 | 62 | endmodule // crc 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /uart_byte_tx_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module uart_byte_tx_tb; 5 | reg sys_clk; 6 | reg reset_n; 7 | 8 | wire UART_TX; 9 | 10 | reg tx_start; 11 | reg [7:0] tx_data; 12 | wire tx_state; 13 | wire tx_done; 14 | 15 | reg test; 16 | 17 | uart_byte_tx # 18 | ( 19 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 20 | .BAUD_RATE ('d115200 ) 21 | )uart_byte_tx_inst0 22 | ( 23 | .clk (sys_clk ), // system clock 24 | .rst_n (reset_n ), // system reset, active low 25 | .tx_start (tx_start ), // start with pos edge 26 | .tx_data (tx_data ), // data need to transfer 27 | .tx_done (tx_done ), // transfer done 28 | .tx_state (tx_state ), // sending duration 29 | .rs232_tx (UART_TX ) // uart transfer pin 30 | ); 31 | 32 | initial sys_clk = 1; 33 | always #(`clk_period/2) sys_clk = ~sys_clk; 34 | 35 | initial reset_n = 0; 36 | always #(`clk_period*50) reset_n = 1'b1; 37 | 38 | initial 39 | begin 40 | tx_start = 0; 41 | tx_data = 8'h0; 42 | test = 0; 43 | 44 | #(`clk_period*50) 45 | test = 1; 46 | #(`clk_period*1) 47 | test = 0; 48 | 49 | // #(`clk_period*50) 50 | // tx_data = 8'haa; 51 | 52 | // #(`clk_period*10) 53 | // tx_start = 1; 54 | 55 | // #(`clk_period*2) 56 | // tx_start = 0; 57 | //@(posedge rx_done) 58 | //#(`clk_period*5000); 59 | //$stop; 60 | end 61 | 62 | parameter IDLE = 5'b0_0001; 63 | parameter TX_S0 = 5'b0_0010; 64 | parameter TX_S1 = 5'b0_0100; 65 | parameter TX_S2 = 5'b0_1000; 66 | parameter TX_S3 = 5'b1_0000; 67 | reg [4:0] state; 68 | reg FF; 69 | always @(posedge sys_clk or negedge reset_n) 70 | begin 71 | if(!reset_n) 72 | begin 73 | state<=IDLE; 74 | FF<=1'b1; 75 | end 76 | else 77 | begin 78 | case(state) 79 | IDLE: 80 | begin 81 | if(test) 82 | begin 83 | state <= TX_S0; 84 | FF<=1'b1; 85 | end 86 | else 87 | begin 88 | state <= IDLE; 89 | FF<=1'b1; 90 | end 91 | end 92 | TX_S0: 93 | begin 94 | if(FF) 95 | begin 96 | tx_start <= 1'b1; 97 | tx_data <= 8'hc2; 98 | FF<=1'b0; 99 | end 100 | else if(tx_done) 101 | begin 102 | state <= TX_S1; 103 | FF<=1'b1; 104 | end 105 | else 106 | begin 107 | tx_start <= 1'b0; 108 | end 109 | end 110 | TX_S1: 111 | begin 112 | if(FF) 113 | begin 114 | tx_start <= 1'b1; 115 | tx_data <= 8'hb3; 116 | FF<=1'b0; 117 | end 118 | else if(tx_done) 119 | begin 120 | state <= TX_S2; 121 | FF<=1'b1; 122 | end 123 | else 124 | begin 125 | tx_start <= 1'b0; 126 | end 127 | end 128 | TX_S2: 129 | begin 130 | if(FF) 131 | begin 132 | tx_start <= 1'b1; 133 | tx_data <= 8'ha4; 134 | FF<=1'b0; 135 | end 136 | else if(tx_done) 137 | begin 138 | state <= TX_S3; 139 | FF<=1'b1; 140 | end 141 | else 142 | begin 143 | tx_start <= 1'b0; 144 | end 145 | end 146 | TX_S3: 147 | begin 148 | if(FF) 149 | begin 150 | tx_start <= 1'b1; 151 | tx_data <= 8'h95; 152 | FF<=1'b0; 153 | end 154 | else if(tx_done) 155 | begin 156 | state <= IDLE; 157 | FF<=1'b1; 158 | end 159 | else 160 | begin 161 | tx_start <= 1'b0; 162 | end 163 | end 164 | default: 165 | begin 166 | state <= IDLE; 167 | end 168 | endcase 169 | end 170 | end 171 | 172 | endmodule 173 | 174 | -------------------------------------------------------------------------------- /exceptions.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module exceptions 5 | ( 6 | input clk ,// system clock 7 | input rst_n ,// system reset, active low 8 | 9 | input rx_message_done ,//一帧消息正确接收完毕 10 | input [7:0] func_code , 11 | input [15:0] addr , 12 | input [15:0] data , 13 | 14 | output reg exception_done , 15 | output reg [7:0] exception 16 | ); 17 | 18 | reg [7:0] func_code_r; 19 | reg [15:0] addr_r; 20 | reg [15:0] data_r; 21 | reg rx_message_done_r; 22 | 23 | 24 | always@(posedge clk or negedge rst_n) 25 | begin 26 | if( !rst_n ) 27 | begin 28 | func_code_r <= `UD 8'b0; 29 | addr_r <= `UD 16'b0; 30 | data_r <= `UD 16'b0; 31 | rx_message_done_r <= `UD 1'b0; 32 | end 33 | else 34 | begin 35 | if(rx_message_done) 36 | begin 37 | func_code_r <= `UD func_code; 38 | addr_r <= `UD addr; 39 | data_r <= `UD data; 40 | rx_message_done_r <= `UD 1'b1; 41 | end 42 | else if(exception_done) 43 | begin 44 | func_code_r <= `UD 8'b0; 45 | addr_r <= `UD 16'b0; 46 | data_r <= `UD 16'b0; 47 | rx_message_done_r <= `UD 1'b0; 48 | end 49 | end 50 | end 51 | 52 | 53 | always@(posedge clk or negedge rst_n) 54 | begin 55 | if( !rst_n ) 56 | begin 57 | exception_done <= `UD 1'b0; 58 | exception <= `UD 8'h00; 59 | end 60 | else if(exception_done) 61 | begin 62 | exception_done <= `UD 1'b0; 63 | exception <= `UD 8'h00; 64 | end 65 | else 66 | begin 67 | if(rx_message_done_r) 68 | begin 69 | if((func_code_r!=8'h03)&&(func_code_r!=8'h04)&&(func_code_r!=8'h06)) 70 | begin 71 | exception_done <= `UD 1'b1; 72 | exception <= `UD 8'h01;//illegal fuction code retrun 01 73 | end 74 | else 75 | begin 76 | if(func_code_r==8'h03) 77 | begin 78 | if(addr==16'h0001) 79 | begin 80 | if(data>16'h0001) 81 | begin 82 | exception_done <= `UD 1'b1; 83 | exception <= `UD 8'h03;//illegal quantity return 03 84 | end 85 | else 86 | begin 87 | exception_done <= `UD 1'b1; 88 | exception <= `UD 8'h0; 89 | end 90 | end 91 | else 92 | begin 93 | exception_done <= `UD 1'b1; 94 | exception <= `UD 8'h02;//illegal reg address return 02 95 | end 96 | end 97 | else if(func_code_r==8'h04) 98 | begin 99 | if(addr+data<=16'h0005) 100 | begin 101 | exception_done <= `UD 1'b1; 102 | exception <= `UD 8'h0; 103 | end 104 | else if(addr>16'h0004) 105 | begin 106 | exception_done <= `UD 1'b1; 107 | exception <= `UD 8'h02; 108 | end 109 | else 110 | begin 111 | exception_done <= `UD 1'b1; 112 | exception <= `UD 8'h03; 113 | end 114 | end 115 | else if(func_code_r==8'h06) 116 | begin 117 | if(addr==16'h0001) 118 | begin 119 | if(data>16'h18) 120 | begin 121 | exception_done <= `UD 1'b1; 122 | exception <= `UD 8'h03; 123 | end 124 | else 125 | begin 126 | exception_done <= `UD 1'b1; 127 | exception <= `UD 8'h0; 128 | end 129 | end 130 | else 131 | begin 132 | exception_done <= `UD 1'b1; 133 | exception <= `UD 8'h02; 134 | end 135 | end 136 | end 137 | end 138 | end 139 | end 140 | 141 | endmodule 142 | -------------------------------------------------------------------------------- /uart_byte_tx.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module uart_byte_tx # 5 | ( 6 | parameter CLK_FREQ = 'd50000000,// 50MHz 7 | parameter BAUD_RATE = 'd9600 // 8 | ) 9 | ( 10 | input clk , // system clock 11 | input rst_n , // system reset, active low 12 | 13 | input tx_start, // start transfer with pos edge 14 | input [7:0] tx_data , // data need to transfer 15 | 16 | output reg tx_state, // sending duration 17 | output reg tx_done , // pos-pulse for 1 tick indicates 1 byte transfer done 18 | output reg rs232_tx // uart transfer pin 19 | ); 20 | 21 | 22 | localparam START_BIT = 1'b0; 23 | localparam STOP_BIT = 1'b1; 24 | localparam BPS_PARAM = CLK_FREQ/BAUD_RATE; 25 | 26 | //start 8bit_data transfer operation 27 | reg tx_start_r0; 28 | reg tx_start_r1; 29 | wire tx_start_pos; 30 | always@(posedge clk or negedge rst_n) 31 | begin 32 | if(!rst_n) 33 | begin 34 | tx_start_r0 <= `UD 1'b0; 35 | tx_start_r1 <= `UD 1'b0; 36 | end 37 | else 38 | begin 39 | tx_start_r0 <= `UD tx_start; 40 | tx_start_r1 <= `UD tx_start_r0; 41 | end 42 | end 43 | assign tx_start_pos = ~tx_start_r1 & tx_start_r0; 44 | 45 | always@(posedge clk or negedge rst_n) 46 | begin 47 | if(!rst_n) 48 | begin 49 | tx_state <= `UD 1'b0; 50 | end 51 | else 52 | begin 53 | if(tx_start_pos) 54 | begin 55 | tx_state <= `UD 1'b1; 56 | end 57 | else if(tx_done) 58 | begin 59 | tx_state <= `UD 1'b0; 60 | end 61 | else 62 | begin 63 | tx_state <= `UD tx_state; 64 | end 65 | end 66 | end 67 | 68 | reg [15:0] baud_rate_cnt; 69 | always@(posedge clk or negedge rst_n) 70 | begin 71 | if(!rst_n) 72 | begin 73 | baud_rate_cnt <= `UD 16'd0; 74 | end 75 | else 76 | begin 77 | if(tx_state) 78 | begin 79 | if(baud_rate_cnt >= BPS_PARAM - 1) 80 | begin 81 | baud_rate_cnt <= `UD 16'd0; 82 | end 83 | else 84 | begin 85 | baud_rate_cnt <= `UD baud_rate_cnt + 1'b1; 86 | end 87 | end 88 | else 89 | begin 90 | baud_rate_cnt <= `UD 16'd0; 91 | end 92 | end 93 | end 94 | 95 | // generate bps_clk signal 96 | reg bps_clk; 97 | always @ (posedge clk or negedge rst_n) 98 | begin 99 | if(!rst_n) 100 | begin 101 | bps_clk <= `UD 1'b0; 102 | end 103 | else 104 | begin 105 | if(baud_rate_cnt == 16'd1 ) 106 | begin 107 | bps_clk <= `UD 1'b1; 108 | end 109 | else 110 | begin 111 | bps_clk <= `UD 1'b0; 112 | end 113 | end 114 | end 115 | 116 | //bps counter 117 | reg [3:0] bps_cnt; 118 | always@(posedge clk or negedge rst_n) 119 | begin 120 | if(!rst_n) 121 | begin 122 | bps_cnt <= `UD 4'd0; 123 | end 124 | else 125 | begin 126 | if(bps_cnt == 4'd11) 127 | begin 128 | bps_cnt <= `UD 4'd0; 129 | end 130 | else if(bps_clk) 131 | begin 132 | bps_cnt <= `UD bps_cnt + 1'b1; 133 | end 134 | else 135 | begin 136 | bps_cnt <= `UD bps_cnt; 137 | end 138 | end 139 | end 140 | 141 | always@(posedge clk or negedge rst_n) 142 | begin 143 | if(!rst_n) 144 | begin 145 | tx_done <= `UD 1'b0; 146 | end 147 | else if(bps_cnt == 4'd11) 148 | begin 149 | tx_done <= `UD 1'b1; 150 | end 151 | else 152 | begin 153 | tx_done <= `UD 1'b0; 154 | end 155 | end 156 | 157 | reg [7:0] tx_data_r; 158 | always@(posedge clk or negedge rst_n) 159 | begin 160 | if(!rst_n) 161 | begin 162 | tx_data_r <= `UD 8'b0; 163 | end 164 | else 165 | begin 166 | if(tx_start_pos) 167 | begin 168 | tx_data_r <= `UD tx_data; 169 | end 170 | else 171 | begin 172 | tx_data_r <= `UD tx_data_r; 173 | end 174 | end 175 | end 176 | 177 | always@(posedge clk or negedge rst_n) 178 | begin 179 | if(!rst_n) 180 | begin 181 | rs232_tx <= `UD 1'b1; 182 | end 183 | else begin 184 | case(bps_cnt) 185 | 0:rs232_tx <= `UD 1'b1; // idle hi 186 | 187 | 1:rs232_tx <= `UD START_BIT; // start bit lo 188 | 2:rs232_tx <= `UD tx_data_r[0]; // LSB first 189 | 3:rs232_tx <= `UD tx_data_r[1]; // 190 | 4:rs232_tx <= `UD tx_data_r[2]; // 191 | 5:rs232_tx <= `UD tx_data_r[3]; // 192 | 6:rs232_tx <= `UD tx_data_r[4]; // 193 | 7:rs232_tx <= `UD tx_data_r[5]; // 194 | 8:rs232_tx <= `UD tx_data_r[6]; // 195 | 9:rs232_tx <= `UD tx_data_r[7]; // MSB last 196 | // No parity 197 | 10:rs232_tx <= `UD STOP_BIT; // stop bit hi 198 | 199 | default:rs232_tx <= `UD 1'b1; // idle hi 200 | endcase 201 | end 202 | end 203 | 204 | endmodule 205 | -------------------------------------------------------------------------------- /uart_byte_rx_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module uart_byte_rx_tb; 5 | reg sys_clk; 6 | reg reset_n; 7 | 8 | wire UART_TX; 9 | 10 | reg tx_start; 11 | reg [7:0] tx_data; 12 | wire tx_state; 13 | wire tx_done; 14 | 15 | reg test; 16 | 17 | uart_byte_tx # 18 | ( 19 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 20 | .BAUD_RATE ('d115200 ) 21 | )uart_byte_tx_inst0 22 | ( 23 | .clk (sys_clk ), // system clock 24 | .rst_n (reset_n ), // system reset, active low 25 | .tx_start (tx_start ), // start with pos edge 26 | .tx_data (tx_data ), // data need to transfer 27 | .tx_done (tx_done ), // transfer done 28 | .tx_state (tx_state ), // sending duration 29 | .rs232_tx (UART_TX ) // uart transfer pin 30 | ); 31 | 32 | wire [7:0] rx_data; 33 | wire rx_done; 34 | wire rx_state; 35 | 36 | uart_byte_rx # 37 | ( 38 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 39 | .BAUD_RATE ('d115200 ) 40 | )uart_byte_rx_inst0 41 | ( 42 | .clk (sys_clk ), // system clock 43 | .rst_n (reset_n ), // system reset, active low 44 | .rx_data (rx_data ), // data need to transfer 45 | .rx_done (rx_done ), // transfer done 46 | .rx_state (rx_state ), // sending duration 47 | .rs232_rx (UART_TX ) // uart transfer pin 48 | ); 49 | 50 | 51 | initial sys_clk = 1; 52 | always #(`clk_period/2) sys_clk = ~sys_clk; 53 | 54 | initial reset_n = 0; 55 | always #(`clk_period*50) reset_n = 1'b1; 56 | 57 | initial 58 | begin 59 | tx_start = 0; 60 | tx_data = 8'h0; 61 | test = 0; 62 | 63 | #(`clk_period*50) 64 | test = 1; 65 | #(`clk_period*1) 66 | test = 0; 67 | 68 | // #(`clk_period*50) 69 | // tx_data = 8'haa; 70 | 71 | // #(`clk_period*10) 72 | // tx_start = 1; 73 | 74 | // #(`clk_period*2) 75 | // tx_start = 0; 76 | //@(posedge rx_done) 77 | //#(`clk_period*5000); 78 | //$stop; 79 | end 80 | 81 | parameter IDLE = 5'b0_0001; 82 | parameter TX_S0 = 5'b0_0010; 83 | parameter TX_S1 = 5'b0_0100; 84 | parameter TX_S2 = 5'b0_1000; 85 | parameter TX_S3 = 5'b1_0000; 86 | reg [4:0] state; 87 | reg FF; 88 | always @(posedge sys_clk or negedge reset_n) 89 | begin 90 | if(!reset_n) 91 | begin 92 | state<=IDLE; 93 | FF<=1'b1; 94 | end 95 | else 96 | begin 97 | case(state) 98 | IDLE: 99 | begin 100 | if(test) 101 | begin 102 | state <= TX_S0; 103 | FF<=1'b1; 104 | end 105 | else 106 | begin 107 | state <= IDLE; 108 | FF<=1'b1; 109 | end 110 | end 111 | TX_S0: 112 | begin 113 | if(FF) 114 | begin 115 | tx_start <= 1'b1; 116 | tx_data <= 8'hc2; 117 | FF<=1'b0; 118 | end 119 | else if(tx_done) 120 | begin 121 | state <= TX_S1; 122 | FF<=1'b1; 123 | end 124 | else 125 | begin 126 | tx_start <= 1'b0; 127 | end 128 | end 129 | TX_S1: 130 | begin 131 | if(FF) 132 | begin 133 | tx_start <= 1'b1; 134 | tx_data <= 8'hb3; 135 | FF<=1'b0; 136 | end 137 | else if(tx_done) 138 | begin 139 | state <= TX_S2; 140 | FF<=1'b1; 141 | end 142 | else 143 | begin 144 | tx_start <= 1'b0; 145 | end 146 | end 147 | TX_S2: 148 | begin 149 | if(FF) 150 | begin 151 | tx_start <= 1'b1; 152 | tx_data <= 8'ha4; 153 | FF<=1'b0; 154 | end 155 | else if(tx_done) 156 | begin 157 | state <= TX_S3; 158 | FF<=1'b1; 159 | end 160 | else 161 | begin 162 | tx_start <= 1'b0; 163 | end 164 | end 165 | TX_S3: 166 | begin 167 | if(FF) 168 | begin 169 | tx_start <= 1'b1; 170 | tx_data <= 8'h95; 171 | FF<=1'b0; 172 | end 173 | else if(tx_done) 174 | begin 175 | state <= IDLE; 176 | FF<=1'b1; 177 | end 178 | else 179 | begin 180 | tx_start <= 1'b0; 181 | end 182 | end 183 | default: 184 | begin 185 | state <= IDLE; 186 | end 187 | endcase 188 | end 189 | end 190 | 191 | endmodule 192 | -------------------------------------------------------------------------------- /modbus_rtu_slave_top_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module modbus_rtu_slave_top_tb; 5 | 6 | reg sys_clk; 7 | reg reset_n; 8 | 9 | wire rs485_rx; 10 | wire rs485_tx; 11 | wire rs485_oe; 12 | 13 | reg tx_start; 14 | reg [7:0] tx_data; 15 | wire tx_state; 16 | wire tx_done; 17 | 18 | reg test; 19 | 20 | uart_byte_tx # 21 | ( 22 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 23 | .BAUD_RATE ('d115200 ) 24 | )uart_byte_tx_inst0 25 | ( 26 | .clk (sys_clk ), // system clock 27 | .rst_n (reset_n ), // system reset, active low 28 | .tx_start (tx_start ), // start with pos edge 29 | .tx_data (tx_data ), // data need to transfer 30 | .tx_done (tx_done ), // transfer done 31 | .tx_state (tx_state ), // sending duration 32 | .rs232_tx (rs485_rx ) // uart transfer pin 33 | ); 34 | 35 | wire [15:0] reg_03_01_o; 36 | wire reg_03_01_update; 37 | wire response_done; 38 | reg [7:0] dev_addr; 39 | modbus_rtu_slave_top # 40 | ( 41 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 42 | .BAUD_RATE ('d115200 ) 43 | )modbus_rtu_slave_top_inst0 44 | ( 45 | .clk (sys_clk ), // system clock 46 | .rst_n (reset_n ), // system reset, active low 47 | 48 | .dev_addr (dev_addr ),//改的有问题 49 | .read_04_01 (16'h5347 ), 50 | .read_04_02 (16'h7414 ), 51 | .read_04_03 (16'h2021 ), 52 | .read_04_04 (16'h0402 ), 53 | 54 | .reg_03_01_o (reg_03_01_o ), 55 | .reg_03_01_update (reg_03_01_update ), 56 | 57 | .rs485_rx (rs485_rx ), 58 | .rs485_tx (rs485_tx ), 59 | .rs485_oe (rs485_oe ), 60 | 61 | .response_done (response_done ) 62 | ); 63 | 64 | initial sys_clk = 1; 65 | always #(`clk_period/2) sys_clk = ~sys_clk; 66 | 67 | initial reset_n = 0; 68 | always #(`clk_period*50) reset_n = 1'b1; 69 | 70 | initial 71 | begin 72 | tx_start = 0; 73 | tx_data = 8'h0; 74 | test = 0; 75 | #(`clk_period*50) 76 | dev_addr = 8'hf0;//变换设备地址 77 | send_frame(64'hf0_03_0001_0001_c0eb); 78 | @(posedge response_done) 79 | 80 | dev_addr = 8'h01;//变换设备地址 81 | #(`clk_period*20000) 82 | send_frame(64'h01_03_0001_0001_d5ca); 83 | @(posedge response_done) 84 | 85 | #(`clk_period*20000) 86 | send_frame(64'h01_06_0002_0005_e809);// illegal 87 | @(posedge response_done) 88 | 89 | #(`clk_period*20000) 90 | send_frame(64'h01_04_0001_0004_a009); 91 | @(posedge response_done) 92 | 93 | #(`clk_period*20000) 94 | send_frame(64'h01_04_0001_0003_e1cb); 95 | @(posedge response_done) 96 | 97 | #(`clk_period*20000) 98 | send_frame(64'h01_04_0002_0001_900a); 99 | @(posedge response_done) 100 | 101 | dev_addr = 8'hff;//变换设备地址 102 | #(`clk_period*20000) 103 | send_frame(64'hff_04_0002_0001_85d4); 104 | @(posedge response_done) 105 | 106 | #(`clk_period*20000) 107 | send_frame(64'hff_04_0002_0002_c5d5); 108 | @(posedge response_done) 109 | 110 | dev_addr = 8'h01;//变换设备地址 111 | #(`clk_period*20000) 112 | send_frame(64'h01_04_0002_0003_11cb); 113 | @(posedge response_done) 114 | 115 | #(`clk_period*20000) 116 | send_frame(64'h01_04_0003_0002_81cb); 117 | @(posedge response_done) 118 | 119 | #(`clk_period*20000) 120 | send_frame(64'h01_04_0003_0003_400b);// illegal 121 | @(posedge response_done) 122 | 123 | #(`clk_period*20000) 124 | send_frame(64'h01_06_0001_0007_99c8); 125 | @(posedge response_done) 126 | 127 | #(`clk_period*20000) 128 | send_frame(64'h01_03_0001_0001_d5ca); 129 | @(posedge response_done) 130 | 131 | $display("simulation stop\n"); 132 | 133 | $stop; 134 | end 135 | 136 | 137 | integer i; 138 | parameter BYTE_NUM = 8; 139 | task send_frame(input [8*BYTE_NUM-1:0] frame_data); 140 | begin 141 | #(`clk_period*5); 142 | for(i=BYTE_NUM;i>0;i=i-1) 143 | begin 144 | if(i!=BYTE_NUM)//发生第一个数据不需要检测tx_done 145 | begin 146 | @(negedge tx_done); 147 | end 148 | #(`clk_period); 149 | tx_start <=1'b1; 150 | tx_data <= frame_data[(i*BYTE_NUM-1) -:8];//高8位 151 | #(`clk_period); 152 | tx_start <=1'b0; 153 | end 154 | #(`clk_period*50); 155 | end 156 | endtask 157 | 158 | endmodule 159 | 160 | 161 | 162 | /* 163 | checksum mismatch then do nothing//设备地址错误do nothing 164 | illegal fuction code retrun 01 165 | illegal address return 02 //寄存器地址 166 | illegal quantity return 03 //数据长度或数量 167 | 168 | 04功能码下共四个寄存器,如{DEV_ADDR,FUN_CODE,addr_data,CRC_L,CRC_H} 169 | addr代表从哪个寄存器开始,data代表读几个寄存器数据 170 | 171 | 读响应格式{DEV_ADDR,FUN_CODE,length,data,CRC_L,CRC_H} 172 | length为1Byte,data为2Byte 173 | 174 | 写响应格式与发送写寄存器命令格式一致,相等 175 | 176 | 读命令异常和写异常响应格式为{SADDR, func_code|8'h80, exception, crc_out[7:0], crc_out[15:8]} 177 | exception范围为01,02,03 178 | 179 | 写失败响应格式为{SADDR, func_code|8'h80, 04, crc_out[7:0], crc_out[15:8]} 180 | 181 | */ -------------------------------------------------------------------------------- /ct_15t_gen_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module ct_15t_gen_tb; 5 | reg sys_clk; 6 | reg reset_n; 7 | 8 | wire UART_TX; 9 | 10 | reg tx_start; 11 | reg [7:0] tx_data; 12 | wire tx_state; 13 | wire tx_done; 14 | 15 | reg test; 16 | 17 | uart_byte_tx # 18 | ( 19 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 20 | .BAUD_RATE ('d115200 ) 21 | )uart_byte_tx_inst0 22 | ( 23 | .clk (sys_clk ), // system clock 24 | .rst_n (reset_n ), // system reset, active low 25 | .tx_start (tx_start ), // start with pos edge 26 | .tx_data (tx_data ), // data need to transfer 27 | .tx_done (tx_done ), // transfer done 28 | .tx_state (tx_state ), // sending duration 29 | .rs232_tx (UART_TX ) // uart transfer pin 30 | ); 31 | 32 | wire [7:0] rx_data; 33 | wire rx_done; 34 | wire rx_state; 35 | 36 | uart_byte_rx # 37 | ( 38 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 39 | .BAUD_RATE ('d115200 ) 40 | )uart_byte_rx_inst0 41 | ( 42 | .clk (sys_clk ), // system clock 43 | .rst_n (reset_n ), // system reset, active low 44 | .rx_data (rx_data ), // data need to transfer 45 | .rx_done (rx_done ), // transfer done 46 | .rx_state (rx_state ), // sending duration 47 | .rs232_rx (UART_TX ) // uart transfer pin 48 | ); 49 | 50 | wire rx_drop_frame; 51 | ct_15t_gen # 52 | ( 53 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 54 | .BAUD_RATE ('d115200 ) 55 | )ct_15t_gen_inst0 56 | ( 57 | .clk (sys_clk ), // system clock 58 | .rst_n (reset_n ), // system reset, active low 59 | .rx_done (rx_done ), // transfer done 60 | .rx_state (rx_state ), // sending duration 61 | .rx_drop_frame (rx_drop_frame ) 62 | ); 63 | 64 | initial sys_clk = 1; 65 | always #(`clk_period/2) sys_clk = ~sys_clk; 66 | 67 | initial reset_n = 0; 68 | always #(`clk_period*50) reset_n = 1'b1; 69 | 70 | reg TT; 71 | initial 72 | begin 73 | tx_start = 0; 74 | tx_data = 8'h0; 75 | test = 0; 76 | 77 | #(`clk_period*50) 78 | test = 1; 79 | #(`clk_period*1) 80 | test = 0; 81 | 82 | @(posedge TT) 83 | #(`clk_period*20000) 84 | test = 1; 85 | #(`clk_period*1) 86 | test = 0; 87 | 88 | // #(`clk_period*50) 89 | // tx_data = 8'haa; 90 | 91 | // #(`clk_period*10) 92 | // tx_start = 1; 93 | 94 | // #(`clk_period*2) 95 | // tx_start = 0; 96 | //@(posedge rx_done) 97 | //#(`clk_period*5000); 98 | //$stop; 99 | end 100 | 101 | parameter IDLE = 5'b0_0001; 102 | parameter TX_S0 = 5'b0_0010; 103 | parameter TX_S1 = 5'b0_0100; 104 | parameter TX_S2 = 5'b0_1000; 105 | parameter TX_S3 = 5'b1_0000; 106 | reg [4:0] state; 107 | reg FF; 108 | 109 | always @(posedge sys_clk or negedge reset_n) 110 | begin 111 | if(!reset_n) 112 | begin 113 | state<=IDLE; 114 | FF<=1'b1; 115 | TT<=1'b0; 116 | end 117 | else 118 | begin 119 | case(state) 120 | IDLE: 121 | begin 122 | if(test) 123 | begin 124 | state <= TX_S0; 125 | FF<=1'b1; 126 | TT<=1'b0; 127 | end 128 | else 129 | begin 130 | state <= IDLE; 131 | FF<=1'b1; 132 | TT<=1'b0; 133 | end 134 | end 135 | TX_S0: 136 | begin 137 | if(FF) 138 | begin 139 | tx_start <= 1'b1; 140 | tx_data <= 8'hc2; 141 | FF<=1'b0; 142 | end 143 | else if(tx_done) 144 | begin 145 | state <= TX_S1; 146 | FF<=1'b1; 147 | end 148 | else 149 | begin 150 | tx_start <= 1'b0; 151 | end 152 | end 153 | TX_S1: 154 | begin 155 | if(FF) 156 | begin 157 | tx_start <= 1'b1; 158 | tx_data <= 8'hb3; 159 | FF<=1'b0; 160 | end 161 | else if(tx_done) 162 | begin 163 | state <= TX_S2; 164 | FF<=1'b1; 165 | end 166 | else 167 | begin 168 | tx_start <= 1'b0; 169 | end 170 | end 171 | TX_S2: 172 | begin 173 | if(FF) 174 | begin 175 | tx_start <= 1'b1; 176 | tx_data <= 8'ha4; 177 | FF<=1'b0; 178 | end 179 | else if(tx_done) 180 | begin 181 | state <= TX_S3; 182 | FF<=1'b1; 183 | end 184 | else 185 | begin 186 | tx_start <= 1'b0; 187 | end 188 | end 189 | TX_S3: 190 | begin 191 | if(FF) 192 | begin 193 | tx_start <= 1'b1; 194 | tx_data <= 8'h95; 195 | FF<=1'b0; 196 | end 197 | else if(tx_done) 198 | begin 199 | state <= IDLE; 200 | FF<=1'b1; 201 | TT<=1'b1; 202 | end 203 | else 204 | begin 205 | tx_start <= 1'b0; 206 | end 207 | end 208 | default: 209 | begin 210 | state <= IDLE; 211 | end 212 | endcase 213 | end 214 | end 215 | 216 | endmodule 217 | -------------------------------------------------------------------------------- /ct_35t_gen_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module ct_35t_gen_tb; 5 | reg sys_clk; 6 | reg reset_n; 7 | 8 | wire UART_TX; 9 | 10 | reg tx_start; 11 | reg [7:0] tx_data; 12 | wire tx_state; 13 | wire tx_done; 14 | 15 | reg test; 16 | 17 | uart_byte_tx # 18 | ( 19 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 20 | .BAUD_RATE ('d115200 ) 21 | )uart_byte_tx_inst0 22 | ( 23 | .clk (sys_clk ), // system clock 24 | .rst_n (reset_n ), // system reset, active low 25 | .tx_start (tx_start ), // start with pos edge 26 | .tx_data (tx_data ), // data need to transfer 27 | .tx_done (tx_done ), // transfer done 28 | .tx_state (tx_state ), // sending duration 29 | .rs232_tx (UART_TX ) // uart transfer pin 30 | ); 31 | 32 | wire [7:0] rx_data; 33 | wire rx_done; 34 | wire rx_state; 35 | 36 | uart_byte_rx # 37 | ( 38 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 39 | .BAUD_RATE ('d115200 ) 40 | )uart_byte_rx_inst0 41 | ( 42 | .clk (sys_clk ), // system clock 43 | .rst_n (reset_n ), // system reset, active low 44 | .rx_data (rx_data ), // data need to transfer 45 | .rx_done (rx_done ), // transfer done 46 | .rx_state (rx_state ), // sending duration 47 | .rs232_rx (UART_TX ) // uart transfer pin 48 | ); 49 | 50 | wire rx_new_frame; 51 | ct_35t_gen # 52 | ( 53 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 54 | .BAUD_RATE ('d115200 ) 55 | )ct_35t_gen_inst0 56 | ( 57 | .clk (sys_clk ), // system clock 58 | .rst_n (reset_n ), // system reset, active low 59 | .rx_done (rx_done ), // transfer done 60 | .rx_state (rx_state ), // sending duration 61 | .rx_new_frame (rx_new_frame ) 62 | ); 63 | 64 | initial sys_clk = 1; 65 | always #(`clk_period/2) sys_clk = ~sys_clk; 66 | 67 | initial reset_n = 0; 68 | always #(`clk_period*50) reset_n = 1'b1; 69 | 70 | reg TT; 71 | initial 72 | begin 73 | tx_start = 0; 74 | tx_data = 8'h0; 75 | test = 0; 76 | 77 | #(`clk_period*50) 78 | test = 1; 79 | #(`clk_period*1) 80 | test = 0; 81 | 82 | @(posedge TT) 83 | #(`clk_period*20000) 84 | test = 1; 85 | #(`clk_period*1) 86 | test = 0; 87 | 88 | // #(`clk_period*50) 89 | // tx_data = 8'haa; 90 | 91 | // #(`clk_period*10) 92 | // tx_start = 1; 93 | 94 | // #(`clk_period*2) 95 | // tx_start = 0; 96 | //@(posedge rx_done) 97 | //#(`clk_period*5000); 98 | //$stop; 99 | end 100 | 101 | parameter IDLE = 5'b0_0001; 102 | parameter TX_S0 = 5'b0_0010; 103 | parameter TX_S1 = 5'b0_0100; 104 | parameter TX_S2 = 5'b0_1000; 105 | parameter TX_S3 = 5'b1_0000; 106 | reg [4:0] state; 107 | reg FF; 108 | 109 | always @(posedge sys_clk or negedge reset_n) 110 | begin 111 | if(!reset_n) 112 | begin 113 | state<=IDLE; 114 | FF<=1'b1; 115 | TT<=1'b0; 116 | end 117 | else 118 | begin 119 | case(state) 120 | IDLE: 121 | begin 122 | if(test) 123 | begin 124 | state <= TX_S0; 125 | FF<=1'b1; 126 | TT<=1'b0; 127 | end 128 | else 129 | begin 130 | state <= IDLE; 131 | FF<=1'b1; 132 | TT<=1'b0; 133 | end 134 | end 135 | TX_S0: 136 | begin 137 | if(FF) 138 | begin 139 | tx_start <= 1'b1; 140 | tx_data <= 8'hc2; 141 | FF<=1'b0; 142 | end 143 | else if(tx_done) 144 | begin 145 | state <= TX_S1; 146 | FF<=1'b1; 147 | end 148 | else 149 | begin 150 | tx_start <= 1'b0; 151 | end 152 | end 153 | TX_S1: 154 | begin 155 | if(FF) 156 | begin 157 | tx_start <= 1'b1; 158 | tx_data <= 8'hb3; 159 | FF<=1'b0; 160 | end 161 | else if(tx_done) 162 | begin 163 | state <= TX_S2; 164 | FF<=1'b1; 165 | end 166 | else 167 | begin 168 | tx_start <= 1'b0; 169 | end 170 | end 171 | TX_S2: 172 | begin 173 | if(FF) 174 | begin 175 | tx_start <= 1'b1; 176 | tx_data <= 8'ha4; 177 | FF<=1'b0; 178 | end 179 | else if(tx_done) 180 | begin 181 | state <= TX_S3; 182 | FF<=1'b1; 183 | end 184 | else 185 | begin 186 | tx_start <= 1'b0; 187 | end 188 | end 189 | TX_S3: 190 | begin 191 | if(FF) 192 | begin 193 | tx_start <= 1'b1; 194 | tx_data <= 8'h95; 195 | FF<=1'b0; 196 | end 197 | else if(tx_done) 198 | begin 199 | state <= IDLE; 200 | FF<=1'b1; 201 | TT<=1'b1; 202 | end 203 | else 204 | begin 205 | tx_start <= 1'b0; 206 | end 207 | end 208 | default: 209 | begin 210 | state <= IDLE; 211 | end 212 | endcase 213 | end 214 | end 215 | 216 | endmodule 217 | -------------------------------------------------------------------------------- /frame_rx.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module frame_rx 5 | ( 6 | input clk ,// system clock 7 | input rst_n ,// system reset, active low 8 | 9 | input [7:0] dev_addr , 10 | input rx_drop_frame ,// 1.5T interval 11 | input rx_new_frame ,// 3.5T interval 12 | input rx_done ,// 13 | input [7:0] rx_data ,// 14 | 15 | input rx_crc_error ,//校验出错 16 | input rx_crc_done ,//校验无误 17 | 18 | output reg rx_crc_vld , 19 | output reg rx_message_done , 20 | output reg [7:0] func_code , 21 | output reg [15:0] addr , 22 | output reg [15:0] data , 23 | output reg [15:0] crc_rx_code 24 | ); 25 | 26 | 27 | reg rx_message_sig; 28 | always@(posedge clk or negedge rst_n) 29 | begin 30 | if(!rst_n) 31 | begin 32 | rx_message_sig <= `UD 1'b1; 33 | end 34 | else if(rx_new_frame) 35 | begin 36 | rx_message_sig <= `UD 1'b1;//代表可以接收新帧 37 | end 38 | else if(rx_done) 39 | begin 40 | rx_message_sig <= `UD 1'b0; 41 | end 42 | else 43 | begin 44 | rx_message_sig <= `UD rx_message_sig; 45 | end 46 | end 47 | 48 | 49 | reg [6:0] state_cnt; 50 | always@(posedge clk or negedge rst_n) 51 | begin 52 | if(!rst_n) 53 | begin 54 | state_cnt <= `UD 7'd0; 55 | rx_message_done <= `UD 1'b0; 56 | func_code <= `UD 8'b0; 57 | addr <= `UD 16'b0; 58 | data <= `UD 16'b0; 59 | crc_rx_code <= `UD 16'b0; 60 | rx_crc_vld <= `UD 1'b0; 61 | end 62 | else 63 | begin 64 | case(state_cnt) 65 | 7'd0 : 66 | begin 67 | if( rx_message_sig & rx_done ) 68 | state_cnt <= `UD 7'd1; 69 | else if( rx_drop_frame ) 70 | begin 71 | state_cnt <= `UD 7'd0; 72 | rx_message_done <= `UD 1'b0; 73 | func_code <= `UD 8'b0; 74 | addr <= `UD 16'b0; 75 | data <= `UD 16'b0; 76 | crc_rx_code <= `UD 16'b0; 77 | rx_crc_vld <= `UD 1'b0; 78 | end 79 | else 80 | state_cnt <= `UD 7'd0; 81 | end 82 | 7'd1 : 83 | begin 84 | if( rx_drop_frame )//大于1.5T还没接收到数据 85 | state_cnt <= `UD 7'd0; 86 | else if( rx_data == dev_addr )//新帧第一个字节为设备地址 87 | state_cnt <= `UD 7'd2; 88 | else 89 | state_cnt <= `UD 7'd0; 90 | end 91 | 7'd2 : 92 | begin 93 | if( rx_drop_frame ) 94 | begin 95 | state_cnt <= `UD 7'd0; 96 | func_code <= `UD 8'b0; 97 | end 98 | else if( rx_done ) 99 | begin 100 | func_code <= `UD rx_data; 101 | state_cnt <= `UD 7'd3; 102 | end 103 | else 104 | state_cnt <= `UD 7'd2; 105 | end 106 | 7'd3 : 107 | begin 108 | if( rx_drop_frame ) 109 | begin 110 | state_cnt <= `UD 7'd0; 111 | addr[15:0] <= `UD 16'b0; 112 | end 113 | else if( rx_done ) 114 | begin 115 | addr[15:8] <= `UD rx_data; 116 | state_cnt <= `UD 7'd4; 117 | end 118 | else 119 | state_cnt <= `UD 7'd3; 120 | end 121 | 7'd4 : 122 | begin 123 | if( rx_drop_frame ) 124 | begin 125 | state_cnt <= `UD 7'd0; 126 | addr[15:0] <= `UD 16'b0; 127 | end 128 | else if( rx_done ) 129 | begin 130 | addr[7:0] <= `UD rx_data; 131 | state_cnt <= `UD 7'd5; 132 | end 133 | else 134 | state_cnt <= `UD 7'd4; 135 | end 136 | 7'd5 : 137 | begin 138 | if( rx_drop_frame ) 139 | begin 140 | state_cnt <= `UD 7'd0; 141 | data[15:0] <= `UD 16'b0; 142 | end 143 | else if( rx_done ) 144 | begin 145 | data[15:8] <= `UD rx_data; 146 | state_cnt <= `UD 7'd6; 147 | end 148 | else 149 | state_cnt <= `UD 7'd5; 150 | end 151 | 7'd6 : 152 | begin 153 | if( rx_drop_frame ) 154 | begin 155 | state_cnt <= `UD 7'd0; 156 | data[15:0] <= `UD 16'b0; 157 | end 158 | else if( rx_done ) 159 | begin 160 | data[7:0] <= `UD rx_data; 161 | state_cnt <= `UD 7'd7; 162 | end 163 | else 164 | state_cnt <= `UD 7'd6; 165 | end 166 | 7'd7 : 167 | begin 168 | if( rx_drop_frame ) 169 | begin 170 | state_cnt <= `UD 7'd0; 171 | crc_rx_code[15:0] <= `UD 16'b0; 172 | end 173 | else if( rx_done ) 174 | begin 175 | crc_rx_code[7:0] <= `UD rx_data; 176 | state_cnt <= `UD 7'd8; 177 | end 178 | else 179 | state_cnt <= `UD 7'd7; 180 | end 181 | 7'd8 : 182 | begin 183 | if( rx_drop_frame ) 184 | begin 185 | state_cnt <= `UD 7'd0; 186 | crc_rx_code[15:0] <= `UD 16'b0; 187 | end 188 | else if( rx_done ) 189 | begin 190 | crc_rx_code[15:8] <= `UD rx_data; 191 | state_cnt <= `UD 7'd9; 192 | end 193 | else 194 | state_cnt <= `UD 7'd8; 195 | end 196 | 7'd9 : 197 | begin 198 | rx_crc_vld <= `UD 1'b1;//start crc check 199 | state_cnt <= `UD 7'd10; 200 | end 201 | 7'd10 : 202 | begin 203 | if(rx_crc_error && !rx_crc_done) 204 | begin 205 | rx_message_done <= `UD 1'b0; 206 | state_cnt <= `UD 7'd0; 207 | end 208 | else if(!rx_crc_error && rx_crc_done) 209 | begin 210 | rx_message_done <= `UD 1'b1; 211 | state_cnt <= `UD 7'd11; 212 | end 213 | else 214 | begin 215 | rx_message_done <= `UD 1'b0; 216 | rx_crc_vld <= `UD 1'b0; 217 | state_cnt <= `UD state_cnt; 218 | end 219 | 220 | end 221 | 7'd11 : 222 | begin 223 | rx_message_done <= `UD 1'b0; 224 | state_cnt <= `UD 7'd0; 225 | end 226 | 227 | default; 228 | endcase 229 | end 230 | end 231 | 232 | endmodule 233 | -------------------------------------------------------------------------------- /uart_byte_rx.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module uart_byte_rx # 5 | ( 6 | parameter CLK_FREQ = 'd50000000,// 50MHz 7 | parameter BAUD_RATE = 'd9600 // 8 | ) 9 | ( 10 | input clk , // system clock 11 | input rst_n , // system reset, active low 12 | 13 | output reg [7:0] rx_data , // data need to transfer 14 | output reg rx_state, // recieving duration 15 | output reg rx_done , // pos-pulse for 1 tick indicates 1 byte transfer done 16 | input rs232_rx // uart transfer pin 17 | ); 18 | 19 | localparam BPS_PARAM = (CLK_FREQ/BAUD_RATE)>>4; // oversample by x16 20 | 21 | // sample sum registers, sum of 6 samples 22 | reg [2:0] rx_data_r [0:7]; 23 | reg [2:0] START_BIT; 24 | reg [2:0] STOP_BIT; 25 | 26 | reg [7:0] bps_cnt; 27 | 28 | reg rs232_rx0,rs232_rx1,rs232_rx2; 29 | //Detect negedge of rs232_rx 30 | always @ (posedge clk or negedge rst_n) begin 31 | if(!rst_n) begin 32 | rs232_rx0 <= `UD 1'b0; 33 | rs232_rx1 <= `UD 1'b0; 34 | rs232_rx2 <= `UD 1'b0; 35 | end else begin 36 | rs232_rx0 <= `UD rs232_rx; 37 | rs232_rx1 <= `UD rs232_rx0; 38 | rs232_rx2 <= `UD rs232_rx1; 39 | end 40 | end 41 | wire neg_rs232_rx; 42 | assign neg_rs232_rx = rs232_rx2 & ~rs232_rx1; 43 | 44 | always@(posedge clk or negedge rst_n) 45 | begin 46 | if(!rst_n) 47 | begin 48 | rx_state <= `UD 1'b0; 49 | end 50 | else 51 | begin 52 | if(neg_rs232_rx) 53 | begin 54 | rx_state <= `UD 1'b1; 55 | end 56 | else if(rx_done || (bps_cnt == 8'd12 && (START_BIT > 2))) // at least 3 of 6 samples are 1, START_BIT not ok 57 | begin 58 | rx_state <= `UD 1'b0; 59 | end 60 | else 61 | begin 62 | rx_state <= `UD rx_state; 63 | end 64 | end 65 | end 66 | 67 | reg [15:0] baud_rate_cnt; 68 | always@(posedge clk or negedge rst_n) 69 | begin 70 | if(!rst_n) 71 | begin 72 | baud_rate_cnt <= `UD 16'd0; 73 | end 74 | else 75 | begin 76 | if(rx_state) 77 | begin 78 | if(baud_rate_cnt >= BPS_PARAM - 1) 79 | begin 80 | baud_rate_cnt <= `UD 16'd0; 81 | end 82 | else 83 | begin 84 | baud_rate_cnt <= `UD baud_rate_cnt + 1'b1; 85 | end 86 | end 87 | else 88 | begin 89 | baud_rate_cnt <= `UD 16'd0; 90 | end 91 | end 92 | end 93 | 94 | // generate bps_clk signal 95 | reg bps_clk; 96 | always @ (posedge clk or negedge rst_n) 97 | begin 98 | if(!rst_n) 99 | begin 100 | bps_clk <= `UD 1'b0; 101 | end 102 | else 103 | begin 104 | if(baud_rate_cnt == BPS_PARAM>>1 )//sample in cnt center 105 | begin 106 | bps_clk <= `UD 1'b1; 107 | end 108 | else 109 | begin 110 | bps_clk <= `UD 1'b0; 111 | end 112 | end 113 | end 114 | 115 | //bps counter 116 | 117 | always@(posedge clk or negedge rst_n) 118 | begin 119 | if(!rst_n) 120 | begin 121 | bps_cnt <= `UD 8'd0; 122 | end 123 | else 124 | begin 125 | if(bps_cnt == 8'd159 || (bps_cnt == 8'd12 && (START_BIT > 2))) 126 | begin 127 | bps_cnt <= `UD 8'd0; 128 | end 129 | else if(baud_rate_cnt >= BPS_PARAM - 1'b1 ) 130 | begin 131 | bps_cnt <= `UD bps_cnt + 1'b1; 132 | end 133 | else 134 | begin 135 | bps_cnt <= `UD bps_cnt; 136 | end 137 | end 138 | end 139 | 140 | always@(posedge clk or negedge rst_n) 141 | begin 142 | if(!rst_n) 143 | begin 144 | rx_done <= `UD 1'b0; 145 | end 146 | else 147 | begin 148 | if(bps_cnt == 8'd159) 149 | begin 150 | rx_done <= `UD 1'b1; 151 | end 152 | else 153 | begin 154 | rx_done <= `UD 1'b0; 155 | end 156 | end 157 | end 158 | 159 | 160 | 161 | always@(posedge clk or negedge rst_n) 162 | begin 163 | if(!rst_n) 164 | begin 165 | START_BIT <= `UD 3'd0; 166 | rx_data_r[0] <= `UD 3'd0; 167 | rx_data_r[1] <= `UD 3'd0; 168 | rx_data_r[2] <= `UD 3'd0; 169 | rx_data_r[3] <= `UD 3'd0; 170 | rx_data_r[4] <= `UD 3'd0; 171 | rx_data_r[5] <= `UD 3'd0; 172 | rx_data_r[6] <= `UD 3'd0; 173 | rx_data_r[7] <= `UD 3'd0; 174 | STOP_BIT <= `UD 3'd0; 175 | end 176 | else 177 | begin 178 | if(bps_clk) 179 | begin 180 | case(bps_cnt) 181 | 0: 182 | begin 183 | START_BIT <= `UD 3'd0; 184 | rx_data_r[0] <= `UD 3'd0; 185 | rx_data_r[1] <= `UD 3'd0; 186 | rx_data_r[2] <= `UD 3'd0; 187 | rx_data_r[3] <= `UD 3'd0; 188 | rx_data_r[4] <= `UD 3'd0; 189 | rx_data_r[5] <= `UD 3'd0; 190 | rx_data_r[6] <= `UD 3'd0; 191 | rx_data_r[7] <= `UD 3'd0; 192 | STOP_BIT <= `UD 3'd0; 193 | end 194 | // 160 bps_cnt from 0 to 159 in a byte, each bit has 16 bps_clk (0~15), 195 | // sample form 6 to 11 is the middle 6 of 16 bps_clk 196 | 6,7,8,9,10,11: 197 | begin 198 | START_BIT <= `UD START_BIT + rs232_rx2; 199 | end 200 | 22,23,24,25,26,27: 201 | begin 202 | rx_data_r[0] <= `UD rx_data_r[0] + rs232_rx2; 203 | end 204 | 38,39,40,41,42,43: 205 | begin 206 | rx_data_r[1] <= `UD rx_data_r[1] + rs232_rx2; 207 | end 208 | 54,55,56,57,58,59: 209 | begin 210 | rx_data_r[2] <= `UD rx_data_r[2] + rs232_rx2; 211 | end 212 | 70,71,72,73,74,75: 213 | begin 214 | rx_data_r[3] <= `UD rx_data_r[3] + rs232_rx2; 215 | end 216 | 86,87,88,89,90,91: 217 | begin 218 | rx_data_r[4] <= `UD rx_data_r[4] + rs232_rx2; 219 | end 220 | 102,103,104,105,106,107: 221 | begin 222 | rx_data_r[5] <= `UD rx_data_r[5] + rs232_rx2; 223 | end 224 | 118,119,120,121,122,123: 225 | begin 226 | rx_data_r[6] <= `UD rx_data_r[6] + rs232_rx2; 227 | end 228 | 134,135,136,137,138,139: 229 | begin 230 | rx_data_r[7] <= `UD rx_data_r[7] + rs232_rx2; 231 | end 232 | 150,151,152,153,154,155: 233 | begin 234 | STOP_BIT <= `UD STOP_BIT + rs232_rx2; 235 | end 236 | default: 237 | begin 238 | START_BIT <= `UD START_BIT; 239 | rx_data_r[0] <= `UD rx_data_r[0]; 240 | rx_data_r[1] <= `UD rx_data_r[1]; 241 | rx_data_r[2] <= `UD rx_data_r[2]; 242 | rx_data_r[3] <= `UD rx_data_r[3]; 243 | rx_data_r[4] <= `UD rx_data_r[4]; 244 | rx_data_r[5] <= `UD rx_data_r[5]; 245 | rx_data_r[6] <= `UD rx_data_r[6]; 246 | rx_data_r[7] <= `UD rx_data_r[7]; 247 | STOP_BIT <= `UD STOP_BIT; 248 | end 249 | endcase 250 | end 251 | end 252 | end 253 | 254 | always@(posedge clk or negedge rst_n) 255 | begin 256 | if(!rst_n) 257 | begin 258 | rx_data <= `UD 8'd0; 259 | end 260 | else 261 | begin 262 | if(bps_cnt == 8'd159) 263 | begin 264 | // rx_data_r[x] has 3 width, actual sample sum range 0~6, rx_data_r[x][2] means sum/4 265 | // if sum >=4 sample value == 1, else sum < 4 sample value == 0 266 | rx_data[0] <= `UD rx_data_r[0][2]; 267 | rx_data[1] <= `UD rx_data_r[1][2]; 268 | rx_data[2] <= `UD rx_data_r[2][2]; 269 | rx_data[3] <= `UD rx_data_r[3][2]; 270 | rx_data[4] <= `UD rx_data_r[4][2]; 271 | rx_data[5] <= `UD rx_data_r[5][2]; 272 | rx_data[6] <= `UD rx_data_r[6][2]; 273 | rx_data[7] <= `UD rx_data_r[7][2]; 274 | end 275 | end 276 | end 277 | 278 | 279 | endmodule 280 | -------------------------------------------------------------------------------- /modbus_rtu_slave_top.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module modbus_rtu_slave_top # 5 | ( 6 | parameter CLK_FREQ = 'd50000000, // 50MHz 7 | parameter BAUD_RATE = 'd115200 // 8 | ) 9 | ( 10 | input clk , // system clock 11 | input rst_n , // system reset, active low 12 | 13 | input [7:0] dev_addr , 14 | input [15:0] read_04_01 , 15 | input [15:0] read_04_02 , 16 | input [15:0] read_04_03 , 17 | input [15:0] read_04_04 , 18 | 19 | output wire [15:0] reg_03_01_o , 20 | output wire reg_03_01_update, 21 | 22 | input rs485_rx , 23 | output wire rs485_tx , 24 | output wire rs485_oe , 25 | 26 | output wire response_done // for debug 27 | ); 28 | 29 | wire [7:0] rx_data ; 30 | wire rx_done ; 31 | wire rx_state ; 32 | 33 | uart_byte_rx # 34 | ( 35 | .CLK_FREQ (CLK_FREQ ), // 50MHz system clock 36 | .BAUD_RATE (BAUD_RATE ) 37 | )uart_byte_rx_inst0 38 | ( 39 | .clk (clk ), // system clock 40 | .rst_n (rst_n ), // system reset, active low 41 | .rx_data (rx_data ), // data need to transfer 42 | .rx_done (rx_done ), // transfer done 43 | .rx_state (rx_state ), // sending duration 44 | .rs232_rx (rs485_rx ) // uart transfer pin 45 | ); 46 | 47 | wire rx_new_frame ; 48 | ct_35t_gen # 49 | ( 50 | .CLK_FREQ (CLK_FREQ ), // 50MHz system clock 51 | .BAUD_RATE (BAUD_RATE ) 52 | )ct_35t_gen_inst0 53 | ( 54 | .clk (clk ), // system clock 55 | .rst_n (rst_n ), // system reset, active low 56 | .rx_done (rx_done ), // transfer done 57 | .rx_state (rx_state ), // sending duration 58 | .rx_new_frame (rx_new_frame ) 59 | ); 60 | 61 | wire rx_drop_frame; 62 | ct_15t_gen # 63 | ( 64 | .CLK_FREQ (CLK_FREQ ), // 50MHz system clock 65 | .BAUD_RATE (BAUD_RATE ) 66 | )ct_15t_gen_inst0 67 | ( 68 | .clk (clk ), // system clock 69 | .rst_n (rst_n ), // system reset, active low 70 | .rx_done (rx_done ), // transfer done 71 | .rx_state (rx_state ), // sending duration 72 | .rx_drop_frame (rx_drop_frame ) 73 | ); 74 | 75 | wire rx_message_done; 76 | wire [7:0] func_code ; 77 | wire [15:0] addr ; 78 | wire [15:0] data ; 79 | wire [15:0] crc_rx_code ; 80 | wire rx_crc_vld ; 81 | wire rx_crc_error ; 82 | wire rx_crc_done ; 83 | frame_rx frame_rx_inst0 84 | ( 85 | .clk (clk ),// system clock 86 | .rst_n (rst_n ),// system reset, active low 87 | .dev_addr (dev_addr ),//device address 88 | .rx_drop_frame (rx_drop_frame ),// 1.5T interval 89 | .rx_new_frame (rx_new_frame ),// 3.5T interval 90 | .rx_done (rx_done ),// 91 | .rx_data (rx_data ),// 92 | 93 | .rx_crc_error (rx_crc_error ),//校验出错 94 | .rx_crc_done (rx_crc_done ),//校验无误 95 | .rx_crc_vld (rx_crc_vld ), 96 | .rx_message_done(rx_message_done), 97 | .func_code (func_code ), 98 | .addr (addr ), 99 | .data (data ), 100 | .crc_rx_code (crc_rx_code ) 101 | ); 102 | 103 | 104 | wire exception_done; 105 | wire [7:0] exception; 106 | exceptions exceptions_inst0 107 | ( 108 | .clk (clk ), // system clock 109 | .rst_n (rst_n ), // system reset, active low 110 | .rx_message_done(rx_message_done), 111 | .func_code (func_code ), 112 | .addr (addr ), 113 | .data (data ), 114 | .exception_done (exception_done ), 115 | .exception (exception ) 116 | ); 117 | 118 | wire handler_done ; 119 | wire [15:0] dia ; 120 | wire wea ; 121 | wire [7:0] addra ; 122 | wire [7:0] tx_quantity ; 123 | wire [7:0] exception_out ; 124 | wire [7:0] func_code_r ; 125 | wire [15:0] addr_r ; 126 | wire [15:0] data_r ; 127 | wire [15:0] crc_rx_code_r ; 128 | wire reg_wen ; 129 | wire [15:0] reg_wdat ; 130 | reg reg_w_done ; 131 | reg reg_w_status ; 132 | reg [15:0] read_03_01_r ; 133 | func_hander func_handler_inst0 134 | ( 135 | .clk (clk ), // system clock 136 | .rst_n (rst_n ), // system reset, active low 137 | .dev_addr (dev_addr ), //device address 138 | .rx_message_done(rx_message_done), 139 | .func_code (func_code ), 140 | .addr (addr ), 141 | .data (data ), 142 | .crc_rx_code (crc_rx_code ), 143 | .exception_done (exception_done ), 144 | .exception_in (exception ), 145 | .read_03_01 (read_03_01_r ), 146 | .read_04_01 (read_04_01 ), 147 | .read_04_02 (read_04_02 ), 148 | .read_04_03 (read_04_03 ), 149 | .read_04_04 (read_04_04 ), 150 | .tx_quantity (tx_quantity ), 151 | .func_code_r (func_code_r ), 152 | .addr_r (addr_r ), 153 | .data_r (data_r ), 154 | .crc_rx_code_r (crc_rx_code_r ), 155 | .exception_out (exception_out ), 156 | .dpram_wen (wea ), 157 | .dpram_addr (addra ), 158 | .dpram_wdata (dia ), 159 | .reg_wen (reg_wen ), 160 | .reg_wdat (reg_wdat ), 161 | .reg_w_done (reg_w_done ), 162 | .reg_w_status (reg_w_status ), 163 | .handler_done (handler_done ) 164 | ); 165 | 166 | 167 | always@(posedge clk or negedge rst_n) 168 | begin 169 | if( !rst_n ) 170 | begin 171 | read_03_01_r <= `UD 16'h0;// modify if needed 172 | reg_w_done <= `UD 1'b0; 173 | reg_w_status <= `UD 1'b0; 174 | end 175 | else 176 | begin 177 | if(reg_wen) 178 | begin 179 | read_03_01_r <= `UD reg_wdat; 180 | reg_w_done <= `UD 1'b1; 181 | reg_w_status <= `UD 1'b0; 182 | end 183 | else 184 | begin 185 | read_03_01_r <= `UD read_03_01_r; 186 | reg_w_done <= `UD 1'b0; 187 | reg_w_status <= `UD 1'b0; 188 | end 189 | end 190 | end 191 | assign reg_03_01_o = read_03_01_r; 192 | assign reg_03_01_update = reg_w_done; 193 | 194 | wire [15:0] tx_data_b; 195 | wire [7:0] tx_addr ; 196 | DPRAM 197 | #( 198 | .A_WIDTH ('d2), 199 | .D_WIDTH ('d16) 200 | )DPRAM_inst0 201 | ( 202 | .CLKA (clk ), 203 | .CLKB (clk ), 204 | .ENA (1'd1 ), 205 | .ENB (1'd1 ), 206 | .WEA (wea ), 207 | .WEB (1'd0 ), 208 | .ADDRA (addra ), 209 | .ADDRB (tx_addr ), 210 | .DIA (dia ), 211 | .DIB (16'b0 ), 212 | .DOA (), 213 | .DOB (tx_data_b) 214 | ); 215 | 216 | wire tx_06_rp_start ; 217 | wire tx_exp_rp_start ; 218 | wire tx_03_04_rp_start ; 219 | wire [39:0] exception_seq ; 220 | wire [63:0] code06_response ; 221 | wire [103:0] code03_04_response; 222 | modbus_crc_16 u_modbus_crc_16( 223 | .clk (clk ), 224 | .rst_n (rst_n ), 225 | .dev_addr (dev_addr ), 226 | .func_code (func_code ), 227 | .addr (addr ), 228 | .data (data ), 229 | .crc_rx_code (crc_rx_code ), 230 | .rx_crc_vld (rx_crc_vld ), 231 | .rx_crc_error (rx_crc_error ), 232 | .rx_crc_done (rx_crc_done ), 233 | 234 | .tx_quantity (tx_quantity ), 235 | .rd_dpram_data (tx_data_b ), 236 | .rd_dpram_addr (tx_addr ), 237 | 238 | .handler_done (handler_done ), 239 | .exception (exception_out ), 240 | .tx_06_rp_start (tx_06_rp_start ), 241 | .tx_exp_rp_start (tx_exp_rp_start ), 242 | .tx_03_04_rp_start (tx_03_04_rp_start ), 243 | .exception_seq (exception_seq ), 244 | .code06_response (code06_response ), 245 | .code03_04_response (code03_04_response) 246 | ); 247 | 248 | tx_response # 249 | ( 250 | .CLK_FREQ (CLK_FREQ ), // 50MHz system clock 251 | .BAUD_RATE (BAUD_RATE ) 252 | ) 253 | u_tx_response( 254 | .clk (clk ),// system clock 255 | .rst_n (rst_n ),// system reset, active low . 256 | .tx_06_rp_start (tx_06_rp_start ), 257 | .tx_exp_rp_start (tx_exp_rp_start ), 258 | .tx_03_04_rp_start (tx_03_04_rp_start ), 259 | .tx_quantity (tx_quantity ), 260 | .exception_seq (exception_seq ), 261 | .code06_response (code06_response ), 262 | .code03_04_response (code03_04_response ), 263 | .response_done (response_done ), 264 | .rs485_tx (rs485_tx ), 265 | .rs485_tx_en (rs485_oe ) 266 | ); 267 | 268 | endmodule 269 | -------------------------------------------------------------------------------- /modbus_crc_16.v: -------------------------------------------------------------------------------- 1 | /**************************************功能介绍*********************************** 2 | Copyright: 3 | Date : 4 | Author : 5 | Version : 6 | Description:何时进行数据校验,何时进行数据发送 7 | *********************************************************************************/ 8 | `timescale 1ns / 1ns 9 | `define UD #1 10 | module modbus_crc_16 11 | ( 12 | input clk , 13 | input rst_n , 14 | 15 | //frame_rx interface 16 | input [7:0] dev_addr , 17 | input [7:0] func_code, 18 | input [15:0] addr, 19 | input [15:0] data, 20 | input [15:0] crc_rx_code, 21 | input rx_crc_vld, 22 | output reg rx_crc_error, 23 | output reg rx_crc_done , 24 | 25 | // 26 | input [7:0] tx_quantity, 27 | input [15:0] rd_dpram_data, 28 | output reg [7:0] rd_dpram_addr, 29 | 30 | 31 | // 32 | input handler_done, 33 | input [7:0] exception, 34 | // 35 | output reg tx_06_rp_start, 36 | output reg tx_exp_rp_start, 37 | output reg tx_03_04_rp_start, 38 | output reg [39:0] exception_seq ,//异常响应数据 39 | output reg [63:0] code06_response,//06正常响应 40 | output reg [103:0] code03_04_response//功能码03,04的响应,最长13个字节 41 | 42 | ); 43 | 44 | reg crc_en ; 45 | reg crc_clr ; 46 | reg rx_crc_flag ; 47 | reg tx_crc_flag ; 48 | reg [7:0] data_in ; 49 | reg [3:0] byte_cnt ; 50 | reg [87:0] check_byte ;//最长需校验11个字节 51 | 52 | reg [7:0] exception_r; 53 | wire [15:0] crc_out; 54 | 55 | reg [7:0] dev_addr_r ; 56 | reg [7:0] func_code_r; 57 | reg [15:0] addr_r; 58 | reg [15:0] data_r; 59 | reg [15:0] crc_rx_code_r; 60 | reg rx_crc_vld_r; 61 | reg handler_done_r; 62 | 63 | always@(posedge clk or negedge rst_n) 64 | begin 65 | if( !rst_n ) 66 | begin 67 | dev_addr_r <= `UD 8'h0; 68 | func_code_r <= `UD 8'h0; 69 | addr_r <= `UD 16'h0; 70 | data_r <= `UD 16'b0; 71 | crc_rx_code_r <= `UD 16'b0; 72 | rx_crc_vld_r <= `UD 1'b0; 73 | end 74 | else 75 | begin if(rx_crc_vld) 76 | begin 77 | dev_addr_r <= `UD dev_addr; 78 | func_code_r <= `UD func_code; 79 | addr_r <= `UD addr; 80 | data_r <= `UD data; 81 | crc_rx_code_r <= `UD crc_rx_code; 82 | rx_crc_vld_r <= rx_crc_vld; 83 | end 84 | else 85 | begin 86 | rx_crc_vld_r <= `UD 1'b0; 87 | end 88 | end 89 | end 90 | 91 | //将handler_done_r和exception_r寄存一拍进行同步 92 | always @(posedge clk or negedge rst_n)begin 93 | if(!rst_n)begin 94 | handler_done_r <= `UD 1'b0; 95 | exception_r <= `UD 8'h0; 96 | end 97 | else if(handler_done)begin 98 | handler_done_r <= `UD 1'b1; 99 | exception_r <= `UD exception; 100 | end 101 | else if(handler_done_r) 102 | begin 103 | handler_done_r <= `UD 1'b0; 104 | end 105 | else 106 | begin 107 | handler_done_r <= handler_done_r; 108 | exception_r <= `UD exception_r; 109 | end 110 | end 111 | 112 | reg crc_done;//打一拍,与校验结果同步 113 | always @(posedge clk or negedge rst_n)begin 114 | if(!rst_n)begin 115 | crc_done <= `UD 1'b0; 116 | end 117 | else if(rx_crc_flag && byte_cnt == 6 && !tx_crc_flag) 118 | begin 119 | crc_done <= `UD 1'b1; 120 | end 121 | else if(tx_crc_flag && byte_cnt == ((tx_quantity<<1)+3) && !exception_r)//03,04,normal read response crc check down 122 | begin 123 | crc_done <= `UD 1'b1; 124 | end 125 | else if(tx_crc_flag && byte_cnt == 3 && exception_r)//exception response crc check down 126 | begin 127 | crc_done <= `UD 1'b1; 128 | end 129 | else 130 | begin 131 | crc_done <= `UD 1'b0; 132 | end 133 | end 134 | 135 | 136 | //接收数据时的校验判断 137 | always @(posedge clk or negedge rst_n)begin 138 | if(!rst_n)begin 139 | rx_crc_done = `UD 1'b0; 140 | rx_crc_error = `UD 1'b0; 141 | rx_crc_flag <= `UD 1'b0; 142 | tx_crc_flag <= `UD 1'b0; 143 | check_byte <= `UD 88'd0; 144 | rd_dpram_addr <= `UD 8'd0; 145 | end 146 | else if(rx_crc_vld_r && !rx_crc_flag)begin//开始一帧数据的校验 147 | rx_crc_flag <= `UD 1'b1; 148 | check_byte <= `UD {dev_addr_r,func_code_r,addr_r,data_r};//6字节数据 149 | end 150 | else if(crc_done && rx_crc_flag)//一帧数据校验完毕 151 | begin 152 | rx_crc_done = `UD (crc_out == crc_rx_code)?1'b1:1'b0; 153 | rx_crc_error = `UD (crc_out != crc_rx_code)?1'b1:1'b0; 154 | rx_crc_flag <= `UD 1'b0; 155 | check_byte <= `UD 88'd0; 156 | end 157 | else if(crc_done && tx_crc_flag)//异常代码校验完毕 158 | begin 159 | tx_crc_flag <= `UD 1'b0; 160 | rd_dpram_addr <= `UD 8'd0; 161 | check_byte <= `UD 88'd0; 162 | end 163 | else if(!exception_r && func_code_r!=8'h06 && !tx_crc_flag && rd_dpram_addr != 8'd0)//若tx_quantity不等于1 164 | begin 165 | if(rd_dpram_addr == tx_quantity) 166 | begin 167 | rd_dpram_addr <= `UD 8'd0; 168 | check_byte <= `UD {check_byte[71:0],rd_dpram_data};//最后一次移位 169 | tx_crc_flag <= `UD 1'b1;//数据已装载完 170 | end 171 | else if(rd_dpram_addr != 8'd1)//延迟一拍取数据 172 | begin 173 | rd_dpram_addr <= `UD rd_dpram_addr + 1'b1; 174 | check_byte <= `UD {check_byte[71:0],rd_dpram_data};//左移16位 175 | end 176 | else 177 | begin 178 | rd_dpram_addr <= `UD rd_dpram_addr + 1'b1; 179 | end 180 | end 181 | else if(handler_done_r && !exception_r && func_code_r!=8'h06 && !tx_crc_flag && rd_dpram_addr <= tx_quantity )//03,04,normal read response 182 | begin 183 | tx_crc_flag <= `UD tx_quantity == 8'h01 ? 1'b1 :1'b0;//若tx_quantity等于1 184 | rd_dpram_addr <= `UD rd_dpram_addr + 1'b1; 185 | check_byte <= `UD {dev_addr_r,func_code_r,data_r[7:0],rd_dpram_data}; 186 | end 187 | else if(handler_done_r && exception_r && !tx_crc_flag)//exception code crc check 188 | begin 189 | tx_crc_flag <= `UD 1'b1; 190 | check_byte <= `UD {dev_addr_r,func_code_r|8'h80,exception_r};//3字节数据 191 | end 192 | else 193 | begin 194 | rd_dpram_addr <= `UD 8'd0; 195 | rx_crc_done = `UD 1'b0; 196 | rx_crc_error = `UD 1'b0; 197 | end 198 | end 199 | 200 | 201 | //指示开始数据发送与数据拼接 202 | always @(posedge clk or negedge rst_n)begin 203 | if(!rst_n)begin 204 | tx_06_rp_start <= `UD 1'd0; 205 | tx_exp_rp_start <= `UD 1'd0; 206 | tx_03_04_rp_start <= `UD 1'd0; 207 | code06_response <= `UD 64'd0; 208 | exception_seq <= `UD 40'd0; 209 | code03_04_response <= `UD 103'd0; 210 | end 211 | else if(handler_done_r && !exception_r && func_code_r==8'h06) 212 | begin//06,normal respond 213 | code06_response <= `UD {dev_addr_r, func_code_r, addr_r, data_r, crc_rx_code_r[7:0], crc_rx_code_r[15:8]}; 214 | tx_06_rp_start <= `UD 1'd1; 215 | end 216 | else if(crc_done && tx_crc_flag && !exception_r && func_code_r !=8'h06) 217 | begin//03,04,normal read response 218 | tx_03_04_rp_start <= `UD 1'd1; 219 | code03_04_response <= `UD {check_byte, crc_out[7:0], crc_out[15:8]}; 220 | end 221 | else if(crc_done && tx_crc_flag && exception_r)//异常代码校验完毕 222 | begin//exception response 223 | exception_seq <= `UD {dev_addr_r, func_code_r|8'h80, exception_r, crc_out[7:0], crc_out[15:8]}; 224 | tx_exp_rp_start <= `UD 1'd1; 225 | end 226 | else begin 227 | tx_06_rp_start <= `UD 1'd0; 228 | tx_exp_rp_start <= `UD 1'd0; 229 | tx_03_04_rp_start <= `UD 1'd0; 230 | end 231 | end 232 | 233 | 234 | always @(posedge clk or negedge rst_n)begin 235 | if(!rst_n)begin 236 | crc_en <= `UD 1'b0; 237 | data_in <= `UD 8'd0; 238 | byte_cnt <= `UD 4'd0; 239 | crc_clr <= `UD 1'b0; 240 | end 241 | else if(byte_cnt <= 5 && rx_crc_flag) 242 | begin 243 | crc_en <= 1'b1; 244 | crc_clr <= `UD 1'b0; 245 | byte_cnt <= `UD byte_cnt + 1; 246 | data_in <= `UD check_byte[(47 - byte_cnt*8) -:8]; 247 | end 248 | else if((byte_cnt <= (tx_quantity<<1)+2) && tx_crc_flag && !exception_r && !crc_done)//03_04 249 | begin 250 | crc_en <= `UD 1'd1;//开始进行crc校验 251 | crc_clr <= `UD 1'b0; 252 | byte_cnt <= `UD byte_cnt + 1; 253 | data_in <= `UD check_byte[(((tx_quantity<<1)+3 - byte_cnt)*8)-1 -:8]; 254 | end 255 | else if(byte_cnt <= 2 && tx_crc_flag && exception_r && !crc_done)//exception response 256 | begin 257 | crc_en <= `UD 1'd1;//开始进行crc校验 258 | crc_clr <= `UD 1'b0; 259 | byte_cnt <= `UD byte_cnt + 1; 260 | data_in <= `UD check_byte[(23 - byte_cnt*8) -:8]; 261 | end 262 | else begin 263 | crc_en <= 1'b0; 264 | crc_clr <= `UD 1'b1; 265 | byte_cnt <= `UD 4'd0; 266 | data_in <= `UD 8'd0; 267 | end 268 | end 269 | 270 | 271 | crc_16 u_crc_16( 272 | /*input */.clk (clk), 273 | /*input */.rst_n (rst_n), 274 | /*input */.crc_en (crc_en), 275 | /*input */.crc_clr (crc_clr), 276 | /*input [7:0] */.data_in (data_in), 277 | /*output reg [15:0] */.crc_out (crc_out) 278 | ); 279 | 280 | 281 | endmodule -------------------------------------------------------------------------------- /func_handler.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module func_hander 5 | ( 6 | input clk ,// system clock 7 | input rst_n ,// system reset, active low 8 | 9 | input [7:0] dev_addr , 10 | input rx_message_done , 11 | input [7:0] func_code , 12 | input [15:0] addr , 13 | input [15:0] data , 14 | input [15:0] crc_rx_code , 15 | 16 | input exception_done , 17 | input [7:0] exception_in , 18 | 19 | input [15:0] read_03_01 , 20 | input [15:0] read_04_01 , 21 | input [15:0] read_04_02 , 22 | input [15:0] read_04_03 , 23 | input [15:0] read_04_04 , 24 | 25 | output reg [7:0] tx_quantity , 26 | output reg [7:0] exception_out , 27 | 28 | output reg [7:0] func_code_r , 29 | output reg [15:0] addr_r , 30 | output reg [15:0] data_r , 31 | output reg [15:0] crc_rx_code_r , 32 | 33 | output reg dpram_wen , 34 | output reg [7:0] dpram_addr , 35 | output reg [15:0] dpram_wdata , 36 | output reg reg_wen , 37 | output reg [15:0] reg_wdat , 38 | input reg_w_done , 39 | input reg_w_status , 40 | 41 | output reg handler_done 42 | 43 | 44 | ); 45 | 46 | always@(posedge clk or negedge rst_n) 47 | begin 48 | if( !rst_n ) 49 | begin 50 | func_code_r <= `UD 8'h0; 51 | addr_r <= `UD 16'h0; 52 | data_r <= `UD 16'b0; 53 | crc_rx_code_r <= `UD 16'b0; 54 | end 55 | else 56 | begin 57 | if(rx_message_done) 58 | begin 59 | func_code_r <= `UD func_code; 60 | addr_r <= `UD addr; 61 | data_r <= `UD data; 62 | crc_rx_code_r <= `UD crc_rx_code; 63 | end 64 | end 65 | end 66 | 67 | reg [7:0] exception_in_r; 68 | always@(posedge clk or negedge rst_n) 69 | begin 70 | if( !rst_n ) 71 | begin 72 | exception_in_r <= `UD 8'h0; 73 | end 74 | else 75 | begin 76 | if(exception_done) 77 | begin 78 | exception_in_r <= `UD exception_in; 79 | end 80 | // else if(handler_done) 81 | // begin 82 | // exception_in_r <= `UD 8'h0; 83 | // end 84 | end 85 | end 86 | 87 | reg [7:0] op_state; 88 | reg [7:0] sub_state_03; 89 | reg [7:0] sub_state_04; 90 | reg [7:0] sub_state_06; 91 | reg FF; 92 | reg [15:0] raddr_index; 93 | always@(posedge clk or negedge rst_n) 94 | begin 95 | if( !rst_n ) 96 | begin 97 | op_state <= `UD 8'h0; 98 | FF <= `UD 1'b1; 99 | sub_state_03 <= `UD 8'h0; 100 | sub_state_04 <= `UD 8'h0; 101 | sub_state_06 <= `UD 8'h0; 102 | handler_done <= `UD 1'b0; 103 | tx_quantity <= `UD 8'h0; 104 | exception_out <= `UD 8'h0; 105 | dpram_wen <= `UD 1'b0; 106 | dpram_addr <= `UD 8'h0; 107 | dpram_wdata <= `UD 16'h0; 108 | raddr_index <= `UD 16'h0; 109 | reg_wen <= `UD 1'b0; 110 | reg_wdat <= `UD 16'h0; 111 | end 112 | else 113 | begin 114 | case(op_state) 115 | 8'd0: // IDEL 116 | begin 117 | if(exception_done) 118 | begin 119 | if(exception_in==8'd1) 120 | begin 121 | op_state <= `UD 8'd5; 122 | exception_out <= `UD exception_in; 123 | tx_quantity <= `UD 16'd0; 124 | end 125 | else if(exception_in==8'd2) 126 | begin 127 | op_state <= `UD 8'd5; 128 | exception_out <= `UD exception_in; 129 | tx_quantity <= `UD 16'd0; 130 | end 131 | else if(exception_in==8'd3) 132 | begin 133 | op_state <= `UD 8'd5; 134 | exception_out <= `UD exception_in; 135 | tx_quantity <= `UD 16'd0; 136 | end 137 | else if(exception_in==8'd0) 138 | begin 139 | op_state <= `UD 8'd1; 140 | end 141 | end 142 | else 143 | begin 144 | op_state <= `UD 8'h0; 145 | FF <= `UD 1'b1; 146 | sub_state_03 <= `UD 8'h0; 147 | sub_state_04 <= `UD 8'h0; 148 | sub_state_06 <= `UD 8'h0; 149 | handler_done <= `UD 1'b0; 150 | // tx_quantity <= `UD 8'h0; 151 | //exception_out <= `UD 8'h0; 152 | dpram_wen <= `UD 1'b0; 153 | dpram_addr <= `UD 8'h0; 154 | dpram_wdata <= `UD 16'h0; 155 | raddr_index <= `UD 16'h0; 156 | reg_wen <= `UD 1'b0; 157 | reg_wdat <= `UD 16'h0; 158 | end 159 | end 160 | 8'd1: // normal handler start 161 | begin 162 | if(func_code==8'h03) 163 | begin 164 | op_state <= `UD 8'd2; 165 | exception_out <= `UD exception_in_r; 166 | end 167 | else if(func_code==8'h04) 168 | begin 169 | op_state <= `UD 8'd3; 170 | exception_out <= `UD exception_in_r; 171 | end 172 | else if(func_code==8'h06) 173 | begin 174 | op_state <= `UD 8'd4; 175 | end 176 | end 177 | 8'd2: 178 | begin 179 | if(FF) 180 | begin 181 | FF <= `UD 1'b0; 182 | sub_state_03 <= `UD 8'd0; 183 | dpram_wen <= `UD 1'b1; 184 | end 185 | else 186 | begin 187 | case(sub_state_03) 188 | 8'd0: 189 | begin 190 | if(addr_r==16'h0001) 191 | begin 192 | dpram_addr <= `UD 8'h00; 193 | dpram_wdata <= `UD read_03_01; 194 | sub_state_03 <= `UD 8'd1; 195 | end 196 | end 197 | 8'd1: 198 | begin 199 | op_state <= `UD 8'd5; 200 | tx_quantity <= `UD 8'd1; 201 | sub_state_03 <= `UD 8'd0; 202 | dpram_wen <= `UD 1'b0; 203 | FF <= `UD 1'b1; 204 | end 205 | default: 206 | begin 207 | FF <= `UD 1'b1; 208 | sub_state_03 <= `UD 8'd0; 209 | end 210 | endcase 211 | end 212 | end 213 | 8'd3: 214 | begin 215 | if(FF) 216 | begin 217 | FF <= `UD 1'b0; 218 | sub_state_04 <= `UD 8'd0; 219 | dpram_wen <= `UD 1'b1; 220 | end 221 | else 222 | begin 223 | case(sub_state_04) 224 | 8'd0: 225 | begin 226 | raddr_index <= `UD addr_r; 227 | sub_state_04 <= `UD 8'd1; 228 | end 229 | 8'd1: 230 | begin 231 | if(raddr_index < addr_r + data_r) 232 | begin 233 | dpram_addr <= `UD (raddr_index-addr_r); 234 | case(raddr_index) 235 | 8'h1:dpram_wdata <= `UD read_04_01; 236 | 8'h2:dpram_wdata <= `UD read_04_02; 237 | 8'h3:dpram_wdata <= `UD read_04_03; 238 | 8'h4:dpram_wdata <= `UD read_04_04; 239 | default; 240 | endcase 241 | raddr_index <= `UD raddr_index + 1'b1; 242 | sub_state_04 <= `UD 8'd1; 243 | end 244 | else 245 | begin 246 | sub_state_04 <= `UD 8'd2; 247 | end 248 | end 249 | 8'd2: 250 | begin 251 | op_state <= `UD 8'd5; 252 | tx_quantity <= `UD data_r; 253 | sub_state_04 <= `UD 8'd0; 254 | dpram_wen <= `UD 1'b0; 255 | FF <= `UD 1'b1; 256 | end 257 | default: 258 | begin 259 | FF <= `UD 1'b1; 260 | sub_state_04 <= `UD 8'd0; 261 | end 262 | endcase 263 | end 264 | end 265 | 8'd4: 266 | begin 267 | if(FF) 268 | begin 269 | FF <= `UD 1'b0; 270 | sub_state_06 <= `UD 8'd0; 271 | reg_wen <= `UD 1'b1; 272 | reg_wdat <= `UD data_r; 273 | end 274 | else 275 | begin 276 | case(sub_state_06) 277 | 8'd0: 278 | begin 279 | if(addr_r==16'h0001) 280 | begin 281 | reg_wen <= `UD 1'b0; 282 | sub_state_06 <= `UD 8'd1; 283 | end 284 | else 285 | begin 286 | op_state <= `UD 8'd0; 287 | FF <= `UD 1'b1; 288 | end 289 | end 290 | 8'd1: 291 | begin 292 | if(reg_w_done) 293 | begin 294 | if(reg_w_status) // write failed 295 | begin 296 | exception_out <= `UD 8'h04; 297 | op_state <= `UD 8'd5; 298 | tx_quantity <= `UD 16'd0; 299 | sub_state_06 <= `UD 8'd0; 300 | FF <= `UD 1'b1; 301 | end 302 | else 303 | begin 304 | exception_out <= `UD exception_in_r; 305 | op_state <= `UD 8'd5; 306 | tx_quantity <= `UD 16'd1; 307 | sub_state_06 <= `UD 8'd0; 308 | FF <= `UD 1'b1; 309 | end 310 | end 311 | end 312 | default: 313 | begin 314 | FF <= `UD 1'b1; 315 | sub_state_06 <= `UD 8'd0; 316 | end 317 | endcase 318 | end 319 | end 320 | 321 | 8'd5: 322 | begin 323 | if(FF) 324 | begin 325 | FF <= `UD 1'b0; 326 | handler_done <= `UD 1'b1; 327 | end 328 | else 329 | begin 330 | FF <= `UD 1'b1; 331 | op_state <= `UD 8'd0; 332 | handler_done <= `UD 1'b0; 333 | end 334 | end 335 | 336 | default: 337 | begin 338 | op_state <= `UD 8'h0; 339 | FF <= `UD 1'b1; 340 | handler_done <= `UD 1'b0; 341 | end 342 | endcase 343 | end 344 | end 345 | 346 | endmodule -------------------------------------------------------------------------------- /frame_rx_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module frame_rx_tb; 5 | reg sys_clk; 6 | reg reset_n; 7 | 8 | wire UART_TX; 9 | 10 | reg tx_start; 11 | reg [7:0] tx_data; 12 | wire tx_state; 13 | wire tx_done; 14 | reg [7:0] dev_addr; 15 | 16 | reg test; 17 | 18 | uart_byte_tx # 19 | ( 20 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 21 | .BAUD_RATE ('d115200 ) 22 | )uart_byte_tx_inst0 23 | ( 24 | .clk (sys_clk ), // system clock 25 | .rst_n (reset_n ), // system reset, active low 26 | .tx_start (tx_start ), // start with pos edge 27 | .tx_data (tx_data ), // data need to transfer 28 | .tx_done (tx_done ), // transfer done 29 | .tx_state (tx_state ), // sending duration 30 | .rs232_tx (UART_TX ) // uart transfer pin 31 | ); 32 | 33 | wire [7:0] rx_data; 34 | wire rx_done; 35 | wire rx_state; 36 | 37 | uart_byte_rx # 38 | ( 39 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 40 | .BAUD_RATE ('d115200 ) 41 | )uart_byte_rx_inst0 42 | ( 43 | .clk (sys_clk ), // system clock 44 | .rst_n (reset_n ), // system reset, active low 45 | .rx_data (rx_data ), // data need to transfer 46 | .rx_done (rx_done ), // transfer done 47 | .rx_state (rx_state ), // sending duration 48 | .rs232_rx (UART_TX ) // uart transfer pin 49 | ); 50 | 51 | wire rx_new_frame; 52 | ct_35t_gen # 53 | ( 54 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 55 | .BAUD_RATE ('d115200 ) 56 | )ct_35t_gen_inst0 57 | ( 58 | .clk (sys_clk ), // system clock 59 | .rst_n (reset_n ), // system reset, active low 60 | .rx_done (rx_done ), // transfer done 61 | .rx_state (rx_state ), // sending duration 62 | .rx_new_frame (rx_new_frame ) 63 | ); 64 | 65 | wire rx_drop_frame; 66 | ct_15t_gen # 67 | ( 68 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 69 | .BAUD_RATE ('d115200 ) 70 | )ct_15t_gen_inst0 71 | ( 72 | .clk (sys_clk ), // system clock 73 | .rst_n (reset_n ), // system reset, active low 74 | .rx_done (rx_done ), // transfer done 75 | .rx_state (rx_state ), // sending duration 76 | .rx_drop_frame (rx_drop_frame ) 77 | ); 78 | 79 | wire rx_message_done; 80 | wire [7:0] func_code; 81 | wire [15:0] addr; 82 | wire [15:0] data; 83 | wire [15:0] crc_rx_code; 84 | wire rx_crc_vld ; 85 | wire rx_crc_error ; 86 | wire rx_crc_done ; 87 | frame_rx frame_rx_inst0 88 | ( 89 | .clk (sys_clk ), // system clock 90 | .rst_n (reset_n ), // system reset, active low 91 | .dev_addr (dev_addr ), 92 | .rx_drop_frame (rx_drop_frame ), // 1.5T interval 93 | .rx_new_frame (rx_new_frame ), // 3.5T interval 94 | .rx_done (rx_done ), // 95 | .rx_data (rx_data ), // 96 | .rx_crc_error (rx_crc_error ), 97 | .rx_crc_done (rx_crc_done ), 98 | .rx_crc_vld (rx_crc_vld ), 99 | .rx_message_done(rx_message_done), 100 | .func_code (func_code ), 101 | .addr (addr ), 102 | .data (data ), 103 | .crc_rx_code (crc_rx_code ) 104 | ); 105 | 106 | wire [39:0] exception_seq ; 107 | wire [63:0] code06_response ; 108 | wire [103:0] code03_04_response; 109 | modbus_crc_16 u_modbus_crc_16( 110 | .clk (sys_clk ), 111 | .rst_n (reset_n ), 112 | .dev_addr (dev_addr ), 113 | .func_code (func_code ), 114 | .addr (addr ), 115 | .data (data ), 116 | .crc_rx_code (crc_rx_code ), 117 | .rx_crc_vld (rx_crc_vld ), 118 | .rx_crc_error (rx_crc_error ), 119 | .rx_crc_done (rx_crc_done ), 120 | 121 | .tx_quantity (tx_quantity ), 122 | .rd_dpram_data (tx_data_b ), 123 | .rd_dpram_addr (tx_addr ), 124 | 125 | .handler_done (handler_done ), 126 | .exception (exception_out ), 127 | .tx_06_rp_start (tx_06_rp_start ), 128 | .tx_exp_rp_start (tx_exp_rp_start ), 129 | .tx_03_04_rp_start (tx_03_04_rp_start ), 130 | .exception_seq (exception_seq ), 131 | .code06_response (code06_response ), 132 | .code03_04_response (code03_04_response) 133 | ); 134 | 135 | initial sys_clk = 1; 136 | always #(`clk_period/2) sys_clk = ~sys_clk; 137 | 138 | initial reset_n = 0; 139 | always #(`clk_period*50) reset_n = 1'b1; 140 | 141 | reg [7:0] FRAME [0:7]; 142 | reg TT; 143 | initial 144 | begin 145 | tx_start = 0; 146 | tx_data = 8'h0; 147 | test = 0; 148 | 149 | #(`clk_period*50) 150 | dev_addr = 8'h01; 151 | FRAME[0] = 8'h01; 152 | FRAME[1] = 8'h03; 153 | FRAME[2] = 8'h00; 154 | FRAME[3] = 8'h01; 155 | FRAME[4] = 8'h00; 156 | FRAME[5] = 8'h01; 157 | FRAME[6] = 8'hd5; 158 | FRAME[7] = 8'hca; 159 | test = 1; 160 | #(`clk_period*1) 161 | test = 0; 162 | 163 | @(posedge TT) 164 | #(`clk_period*20000) 165 | FRAME[0] = 8'h01; 166 | FRAME[1] = 8'h06; 167 | FRAME[2] = 8'h00; 168 | FRAME[3] = 8'h01; 169 | FRAME[4] = 8'h00; 170 | FRAME[5] = 8'h05; 171 | FRAME[6] = 8'h18; 172 | FRAME[7] = 8'h09; 173 | test = 1; 174 | #(`clk_period*1) 175 | test = 0; 176 | 177 | // #(`clk_period*50) 178 | // tx_data = 8'haa; 179 | 180 | // #(`clk_period*10) 181 | // tx_start = 1; 182 | 183 | // #(`clk_period*2) 184 | // tx_start = 0; 185 | //@(posedge rx_done) 186 | //#(`clk_period*5000); 187 | //$stop; 188 | end 189 | 190 | parameter IDLE = 8'b0000_0000; 191 | parameter TX_S0 = 8'b0000_0001; 192 | parameter TX_S1 = 8'b0000_0010; 193 | parameter TX_S2 = 8'b0000_0100; 194 | parameter TX_S3 = 8'b0000_1000; 195 | parameter TX_S4 = 8'b0001_0000; 196 | parameter TX_S5 = 8'b0010_0000; 197 | parameter TX_S6 = 8'b0100_0000; 198 | parameter TX_S7 = 8'b1000_0000; 199 | reg [7:0] state; 200 | reg FF; 201 | 202 | always @(posedge sys_clk or negedge reset_n) 203 | begin 204 | if(!reset_n) 205 | begin 206 | state<=IDLE; 207 | FF<=1'b1; 208 | TT<=1'b0; 209 | end 210 | else 211 | begin 212 | case(state) 213 | IDLE: 214 | begin 215 | if(test) 216 | begin 217 | state <= TX_S0; 218 | FF<=1'b1; 219 | TT<=1'b0; 220 | end 221 | else 222 | begin 223 | state <= IDLE; 224 | FF<=1'b1; 225 | TT<=1'b0; 226 | end 227 | end 228 | TX_S0: 229 | begin 230 | if(FF) 231 | begin 232 | tx_start <= 1'b1; 233 | tx_data <= FRAME[0]; 234 | FF<=1'b0; 235 | end 236 | else if(tx_done) 237 | begin 238 | state <= TX_S1; 239 | FF<=1'b1; 240 | end 241 | else 242 | begin 243 | tx_start <= 1'b0; 244 | end 245 | end 246 | TX_S1: 247 | begin 248 | if(FF) 249 | begin 250 | tx_start <= 1'b1; 251 | tx_data <= FRAME[1]; 252 | FF<=1'b0; 253 | end 254 | else if(tx_done) 255 | begin 256 | state <= TX_S2; 257 | FF<=1'b1; 258 | end 259 | else 260 | begin 261 | tx_start <= 1'b0; 262 | end 263 | end 264 | TX_S2: 265 | begin 266 | if(FF) 267 | begin 268 | tx_start <= 1'b1; 269 | tx_data <= FRAME[2]; 270 | FF<=1'b0; 271 | end 272 | else if(tx_done) 273 | begin 274 | state <= TX_S3; 275 | FF<=1'b1; 276 | end 277 | else 278 | begin 279 | tx_start <= 1'b0; 280 | end 281 | end 282 | TX_S3: 283 | begin 284 | if(FF) 285 | begin 286 | tx_start <= 1'b1; 287 | tx_data <= FRAME[3]; 288 | FF<=1'b0; 289 | end 290 | else if(tx_done) 291 | begin 292 | state <= TX_S4; 293 | FF<=1'b1; 294 | end 295 | else 296 | begin 297 | tx_start <= 1'b0; 298 | end 299 | end 300 | TX_S4: 301 | begin 302 | if(FF) 303 | begin 304 | tx_start <= 1'b1; 305 | tx_data <= FRAME[4]; 306 | FF<=1'b0; 307 | end 308 | else if(tx_done) 309 | begin 310 | state <= TX_S5; 311 | FF<=1'b1; 312 | end 313 | else 314 | begin 315 | tx_start <= 1'b0; 316 | end 317 | end 318 | TX_S5: 319 | begin 320 | if(FF) 321 | begin 322 | tx_start <= 1'b1; 323 | tx_data <= FRAME[5]; 324 | FF<=1'b0; 325 | end 326 | else if(tx_done) 327 | begin 328 | state <= TX_S6; 329 | FF<=1'b1; 330 | end 331 | else 332 | begin 333 | tx_start <= 1'b0; 334 | end 335 | end 336 | TX_S6: 337 | begin 338 | if(FF) 339 | begin 340 | tx_start <= 1'b1; 341 | tx_data <= FRAME[6]; 342 | FF<=1'b0; 343 | end 344 | else if(tx_done) 345 | begin 346 | state <= TX_S7; 347 | FF<=1'b1; 348 | end 349 | else 350 | begin 351 | tx_start <= 1'b0; 352 | end 353 | end 354 | TX_S7: 355 | begin 356 | if(FF) 357 | begin 358 | tx_start <= 1'b1; 359 | tx_data <= FRAME[7]; 360 | FF<=1'b0; 361 | end 362 | else if(tx_done) 363 | begin 364 | state <= IDLE; 365 | FF<=1'b1; 366 | TT<=1'b1; 367 | end 368 | else 369 | begin 370 | tx_start <= 1'b0; 371 | end 372 | end 373 | default: 374 | begin 375 | state <= IDLE; 376 | end 377 | endcase 378 | end 379 | end 380 | 381 | endmodule 382 | -------------------------------------------------------------------------------- /exceptions_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module exceptions_tb; 5 | reg sys_clk; 6 | reg reset_n; 7 | 8 | wire UART_TX; 9 | 10 | reg tx_start; 11 | reg [7:0] tx_data; 12 | wire tx_state; 13 | wire tx_done; 14 | reg [7:0] dev_addr; 15 | 16 | reg test; 17 | 18 | uart_byte_tx # 19 | ( 20 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 21 | .BAUD_RATE ('d115200 ) 22 | )uart_byte_tx_inst0 23 | ( 24 | .clk (sys_clk ), // system clock 25 | .rst_n (reset_n ), // system reset, active low 26 | .tx_start (tx_start ), // start with pos edge 27 | .tx_data (tx_data ), // data need to transfer 28 | .tx_done (tx_done ), // transfer done 29 | .tx_state (tx_state ), // sending duration 30 | .rs232_tx (UART_TX ) // uart transfer pin 31 | ); 32 | 33 | wire [7:0] rx_data; 34 | wire rx_done; 35 | wire rx_state; 36 | 37 | uart_byte_rx # 38 | ( 39 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 40 | .BAUD_RATE ('d115200 ) 41 | )uart_byte_rx_inst0 42 | ( 43 | .clk (sys_clk ), // system clock 44 | .rst_n (reset_n ), // system reset, active low 45 | .rx_data (rx_data ), // data need to transfer 46 | .rx_done (rx_done ), // transfer done 47 | .rx_state (rx_state ), // sending duration 48 | .rs232_rx (UART_TX ) // uart transfer pin 49 | ); 50 | 51 | wire rx_new_frame; 52 | ct_35t_gen # 53 | ( 54 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 55 | .BAUD_RATE ('d115200 ) 56 | )ct_35t_gen_inst0 57 | ( 58 | .clk (sys_clk ), // system clock 59 | .rst_n (reset_n ), // system reset, active low 60 | .rx_done (rx_done ), // transfer done 61 | .rx_state (rx_state ), // sending duration 62 | .rx_new_frame (rx_new_frame ) 63 | ); 64 | 65 | wire rx_drop_frame; 66 | ct_15t_gen # 67 | ( 68 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 69 | .BAUD_RATE ('d115200 ) 70 | )ct_15t_gen_inst0 71 | ( 72 | .clk (sys_clk ), // system clock 73 | .rst_n (reset_n ), // system reset, active low 74 | .rx_done (rx_done ), // transfer done 75 | .rx_state (rx_state ), // sending duration 76 | .rx_drop_frame (rx_drop_frame ) 77 | ); 78 | 79 | wire rx_message_done; 80 | wire [7:0] func_code; 81 | wire [15:0] addr; 82 | wire [15:0] data; 83 | wire [15:0] crc_rx_code; 84 | wire rx_crc_vld ; 85 | wire rx_crc_error ; 86 | wire rx_crc_done ; 87 | frame_rx frame_rx_inst0 88 | ( 89 | .clk (sys_clk ), // system clock 90 | .rst_n (reset_n ), // system reset, active low 91 | .dev_addr (dev_addr ), 92 | .rx_drop_frame (rx_drop_frame ), // 1.5T interval 93 | .rx_new_frame (rx_new_frame ), // 3.5T interval 94 | .rx_done (rx_done ), // 95 | .rx_data (rx_data ), // 96 | .rx_crc_error (rx_crc_error ), 97 | .rx_crc_done (rx_crc_done ), 98 | .rx_crc_vld (rx_crc_vld ), 99 | .rx_message_done(rx_message_done), 100 | .func_code (func_code ), 101 | .addr (addr ), 102 | .data (data ), 103 | .crc_rx_code (crc_rx_code ) 104 | ); 105 | 106 | wire exception_done; 107 | wire [7:0] exception; 108 | exceptions exceptions_inst0 109 | ( 110 | .clk (sys_clk ), // system clock 111 | .rst_n (reset_n ), // system reset, active low 112 | .rx_message_done(rx_message_done), 113 | .func_code (func_code ), 114 | .addr (addr ), 115 | .data (data ), 116 | .exception_done (exception_done ), 117 | .exception (exception ) 118 | ); 119 | 120 | wire [39:0] exception_seq ; 121 | wire [63:0] code06_response ; 122 | wire [103:0] code03_04_response; 123 | modbus_crc_16 u_modbus_crc_16( 124 | .clk (sys_clk ), 125 | .rst_n (reset_n ), 126 | .dev_addr (dev_addr ), 127 | .func_code (func_code ), 128 | .addr (addr ), 129 | .data (data ), 130 | .crc_rx_code (crc_rx_code ), 131 | .rx_crc_vld (rx_crc_vld ), 132 | .rx_crc_error (rx_crc_error ), 133 | .rx_crc_done (rx_crc_done ), 134 | 135 | .tx_quantity (tx_quantity ), 136 | .rd_dpram_data (tx_data_b ), 137 | .rd_dpram_addr (tx_addr ), 138 | 139 | .handler_done (handler_done ), 140 | .exception (exception_out ), 141 | .tx_06_rp_start (tx_06_rp_start ), 142 | .tx_exp_rp_start (tx_exp_rp_start ), 143 | .tx_03_04_rp_start (tx_03_04_rp_start ), 144 | .exception_seq (exception_seq ), 145 | .code06_response (code06_response ), 146 | .code03_04_response (code03_04_response) 147 | ); 148 | 149 | initial sys_clk = 1; 150 | always #(`clk_period/2) sys_clk = ~sys_clk; 151 | 152 | initial reset_n = 0; 153 | always #(`clk_period*50) reset_n = 1'b1; 154 | 155 | reg [7:0] FRAME [0:7]; 156 | reg TT; 157 | initial 158 | begin 159 | tx_start = 0; 160 | tx_data = 8'h0; 161 | test = 0; 162 | 163 | #(`clk_period*50) 164 | dev_addr = 8'h01; 165 | FRAME[0] = 8'h01; 166 | FRAME[1] = 8'h03; 167 | FRAME[2] = 8'h00; 168 | FRAME[3] = 8'h01; 169 | FRAME[4] = 8'h00; 170 | FRAME[5] = 8'h01; 171 | FRAME[6] = 8'hd5; 172 | FRAME[7] = 8'hca; 173 | test = 1; 174 | #(`clk_period*1) 175 | test = 0; 176 | 177 | @(posedge TT) 178 | #(`clk_period*20000) 179 | // FRAME[0] = 8'h01; 180 | // FRAME[1] = 8'h06; 181 | // FRAME[2] = 8'h00; 182 | // FRAME[3] = 8'h01; 183 | // FRAME[4] = 8'h00; 184 | // FRAME[5] = 8'h05; 185 | // FRAME[6] = 8'h18; 186 | // FRAME[7] = 8'h09; 187 | FRAME[0] = 8'h01; 188 | FRAME[1] = 8'h06; 189 | FRAME[2] = 8'h00; 190 | FRAME[3] = 8'h02; // illegal 191 | FRAME[4] = 8'h00; 192 | FRAME[5] = 8'h05; 193 | FRAME[6] = 8'he8; 194 | FRAME[7] = 8'h09; 195 | test = 1; 196 | #(`clk_period*1) 197 | test = 0; 198 | 199 | // #(`clk_period*50) 200 | // tx_data = 8'haa; 201 | 202 | // #(`clk_period*10) 203 | // tx_start = 1; 204 | 205 | // #(`clk_period*2) 206 | // tx_start = 0; 207 | //@(posedge rx_done) 208 | //#(`clk_period*5000); 209 | //$stop; 210 | end 211 | 212 | parameter IDLE = 8'b0000_0000; 213 | parameter TX_S0 = 8'b0000_0001; 214 | parameter TX_S1 = 8'b0000_0010; 215 | parameter TX_S2 = 8'b0000_0100; 216 | parameter TX_S3 = 8'b0000_1000; 217 | parameter TX_S4 = 8'b0001_0000; 218 | parameter TX_S5 = 8'b0010_0000; 219 | parameter TX_S6 = 8'b0100_0000; 220 | parameter TX_S7 = 8'b1000_0000; 221 | reg [7:0] state; 222 | reg FF; 223 | 224 | always @(posedge sys_clk or negedge reset_n) 225 | begin 226 | if(!reset_n) 227 | begin 228 | state<=IDLE; 229 | FF<=1'b1; 230 | TT<=1'b0; 231 | end 232 | else 233 | begin 234 | case(state) 235 | IDLE: 236 | begin 237 | if(test) 238 | begin 239 | state <= TX_S0; 240 | FF<=1'b1; 241 | TT<=1'b0; 242 | end 243 | else 244 | begin 245 | state <= IDLE; 246 | FF<=1'b1; 247 | TT<=1'b0; 248 | end 249 | end 250 | TX_S0: 251 | begin 252 | if(FF) 253 | begin 254 | tx_start <= 1'b1; 255 | tx_data <= FRAME[0]; 256 | FF<=1'b0; 257 | end 258 | else if(tx_done) 259 | begin 260 | state <= TX_S1; 261 | FF<=1'b1; 262 | end 263 | else 264 | begin 265 | tx_start <= 1'b0; 266 | end 267 | end 268 | TX_S1: 269 | begin 270 | if(FF) 271 | begin 272 | tx_start <= 1'b1; 273 | tx_data <= FRAME[1]; 274 | FF<=1'b0; 275 | end 276 | else if(tx_done) 277 | begin 278 | state <= TX_S2; 279 | FF<=1'b1; 280 | end 281 | else 282 | begin 283 | tx_start <= 1'b0; 284 | end 285 | end 286 | TX_S2: 287 | begin 288 | if(FF) 289 | begin 290 | tx_start <= 1'b1; 291 | tx_data <= FRAME[2]; 292 | FF<=1'b0; 293 | end 294 | else if(tx_done) 295 | begin 296 | state <= TX_S3; 297 | FF<=1'b1; 298 | end 299 | else 300 | begin 301 | tx_start <= 1'b0; 302 | end 303 | end 304 | TX_S3: 305 | begin 306 | if(FF) 307 | begin 308 | tx_start <= 1'b1; 309 | tx_data <= FRAME[3]; 310 | FF<=1'b0; 311 | end 312 | else if(tx_done) 313 | begin 314 | state <= TX_S4; 315 | FF<=1'b1; 316 | end 317 | else 318 | begin 319 | tx_start <= 1'b0; 320 | end 321 | end 322 | TX_S4: 323 | begin 324 | if(FF) 325 | begin 326 | tx_start <= 1'b1; 327 | tx_data <= FRAME[4]; 328 | FF<=1'b0; 329 | end 330 | else if(tx_done) 331 | begin 332 | state <= TX_S5; 333 | FF<=1'b1; 334 | end 335 | else 336 | begin 337 | tx_start <= 1'b0; 338 | end 339 | end 340 | TX_S5: 341 | begin 342 | if(FF) 343 | begin 344 | tx_start <= 1'b1; 345 | tx_data <= FRAME[5]; 346 | FF<=1'b0; 347 | end 348 | else if(tx_done) 349 | begin 350 | state <= TX_S6; 351 | FF<=1'b1; 352 | end 353 | else 354 | begin 355 | tx_start <= 1'b0; 356 | end 357 | end 358 | TX_S6: 359 | begin 360 | if(FF) 361 | begin 362 | tx_start <= 1'b1; 363 | tx_data <= FRAME[6]; 364 | FF<=1'b0; 365 | end 366 | else if(tx_done) 367 | begin 368 | state <= TX_S7; 369 | FF<=1'b1; 370 | end 371 | else 372 | begin 373 | tx_start <= 1'b0; 374 | end 375 | end 376 | TX_S7: 377 | begin 378 | if(FF) 379 | begin 380 | tx_start <= 1'b1; 381 | tx_data <= FRAME[7]; 382 | FF<=1'b0; 383 | end 384 | else if(tx_done) 385 | begin 386 | state <= IDLE; 387 | FF<=1'b1; 388 | TT<=1'b1; 389 | end 390 | else 391 | begin 392 | tx_start <= 1'b0; 393 | end 394 | end 395 | default: 396 | begin 397 | state <= IDLE; 398 | end 399 | endcase 400 | end 401 | end 402 | 403 | endmodule 404 | 405 | -------------------------------------------------------------------------------- /tx_response.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define UD #1 3 | 4 | module tx_response # 5 | ( 6 | parameter CLK_FREQ = 'd50000000,// 50MHz 7 | parameter BAUD_RATE = 'd9600 // 8 | ) 9 | ( 10 | input clk ,// system clock 11 | input rst_n ,// system reset, active low 12 | 13 | input tx_06_rp_start , 14 | input tx_exp_rp_start , 15 | input tx_03_04_rp_start , 16 | 17 | input [7:0] tx_quantity , 18 | input [39:0] exception_seq , 19 | input [63:0] code06_response , 20 | input [103:0] code03_04_response , 21 | 22 | output reg response_done , 23 | output wire rs485_tx , 24 | output reg rs485_tx_en 25 | ); 26 | 27 | localparam BPS_PARAM = (CLK_FREQ/BAUD_RATE); 28 | 29 | reg tx_start_pos; 30 | 31 | reg cnt_en; 32 | reg response_done_r; 33 | 34 | reg [7:0] rs485_tx_data; 35 | reg rs485_tx_start; 36 | wire tx_done; 37 | reg [3:0] byte_cnt; 38 | 39 | reg [3:0] op_state; 40 | reg FF; 41 | 42 | reg cnt_en_flag;//计数器 43 | reg [19:0] bps_cnt ;//每一帧数据发送完毕后延时一段时间 44 | wire add_bps_cnt; 45 | wire end_bps_cnt; 46 | 47 | 48 | always@(posedge clk or negedge rst_n) 49 | begin 50 | if(!rst_n ) 51 | begin 52 | op_state <= `UD 8'd0; 53 | FF <= `UD 1'b1; 54 | rs485_tx_data <= `UD 8'h0; 55 | rs485_tx_start <= `UD 1'b0; 56 | response_done_r <= `UD 1'b0; 57 | rs485_tx_en <= `UD 1'b0; 58 | response_done <= `UD 1'b0; 59 | tx_start_pos <= `UD 1'b0; 60 | byte_cnt <= `UD 4'd0; 61 | end 62 | else 63 | begin 64 | case(op_state) 65 | 8'd0: 66 | begin 67 | if(tx_exp_rp_start) 68 | begin 69 | rs485_tx_en <= `UD 1'b1; 70 | op_state <= `UD 8'd1; 71 | end 72 | else if(tx_06_rp_start)//06,normal 73 | begin 74 | rs485_tx_en <= `UD 1'b1; 75 | op_state <= `UD 8'd3; 76 | end 77 | else if(tx_03_04_rp_start) 78 | begin // func_code==8'h03||func_code==8'h04 ,and normal 79 | rs485_tx_en <= `UD 1'b1; 80 | op_state <= `UD 8'd5; 81 | end 82 | else 83 | begin 84 | op_state <= `UD 8'd0; 85 | FF <= `UD 1'b1; 86 | rs485_tx_data <= `UD 8'h0; 87 | rs485_tx_start <= `UD 1'b0; 88 | response_done_r <= `UD 1'b0; 89 | rs485_tx_en <= `UD 1'b0; 90 | response_done <= `UD 1'b0; 91 | tx_start_pos <= `UD 1'b0; 92 | byte_cnt <= `UD 4'd0; 93 | end 94 | end 95 | 96 | 8'd1: 97 | begin 98 | if(FF) 99 | begin 100 | tx_start_pos <= `UD 1'b1; 101 | FF <= `UD 1'b0; 102 | end 103 | else 104 | begin 105 | tx_start_pos <= `UD 1'b0; 106 | if(end_bps_cnt) 107 | begin 108 | rs485_tx_data <= `UD exception_seq[39:32]; 109 | FF <= `UD 1'b1; 110 | op_state <= `UD 8'd2; 111 | rs485_tx_start <= `UD 1'b0; 112 | end 113 | else 114 | begin 115 | FF <= `UD 1'b0; 116 | end 117 | end 118 | end 119 | 120 | 8'd2: 121 | begin 122 | if(FF) 123 | begin 124 | rs485_tx_start <= `UD 1'b1; 125 | FF <= `UD 1'b0; 126 | end 127 | else 128 | begin 129 | if(tx_done) 130 | begin 131 | if(byte_cnt < 4'd4) 132 | begin 133 | FF <= `UD 1'b1; 134 | rs485_tx_data <= `UD exception_seq[(31-8*byte_cnt) -:8]; 135 | byte_cnt <= `UD byte_cnt + 1'b1; 136 | rs485_tx_start <= `UD 1'b0; 137 | end 138 | if(byte_cnt == 4'd4) 139 | begin 140 | op_state <= `UD 8'd7; 141 | byte_cnt <= `UD 4'd0; 142 | response_done_r <= `UD 1'b1; 143 | rs485_tx_data <= `UD 8'h0; 144 | FF <= `UD 1'b1; 145 | end 146 | else begin 147 | op_state <= `UD 8'd2; 148 | response_done_r <= `UD 1'b0; 149 | end 150 | end 151 | else 152 | begin 153 | rs485_tx_start <= `UD 1'b0; 154 | FF <= `UD 1'b0; 155 | end 156 | end 157 | end 158 | 159 | 8'd3: 160 | begin 161 | if(FF) 162 | begin 163 | tx_start_pos <= `UD 1'b1; 164 | FF <= `UD 1'b0; 165 | end 166 | else 167 | begin 168 | tx_start_pos <= `UD 1'b0; 169 | if(end_bps_cnt) 170 | begin 171 | rs485_tx_data <= `UD code06_response[63:56]; 172 | FF <= `UD 1'b1; 173 | op_state <= `UD 8'd4; 174 | rs485_tx_start <= `UD 1'b0; 175 | end 176 | else 177 | begin 178 | FF <= `UD 1'b0; 179 | end 180 | end 181 | end 182 | 183 | 8'd4: 184 | begin 185 | if(FF) 186 | begin 187 | rs485_tx_start <= `UD 1'b1; 188 | FF <= `UD 1'b0; 189 | end 190 | else 191 | begin 192 | if(tx_done) 193 | begin 194 | if(byte_cnt < 4'd7) 195 | begin 196 | FF <= `UD 1'b1; 197 | rs485_tx_data <= `UD code06_response[(55-8*byte_cnt) -:8]; 198 | byte_cnt <= `UD byte_cnt + 1'b1; 199 | rs485_tx_start <= `UD 1'b0; 200 | end 201 | if(byte_cnt == 4'd7) 202 | begin 203 | op_state <= `UD 8'd7; 204 | byte_cnt <= `UD 4'd0; 205 | response_done_r <= `UD 1'b1; 206 | rs485_tx_data <= `UD 8'h0; 207 | FF <= `UD 1'b1; 208 | end 209 | else begin 210 | op_state <= `UD 8'd4; 211 | response_done_r <= `UD 1'b0; 212 | end 213 | end 214 | else 215 | begin 216 | rs485_tx_start <= `UD 1'b0; 217 | FF <= `UD 1'b0; 218 | end 219 | end 220 | end 221 | 222 | 8'd5: 223 | begin 224 | if(FF) 225 | begin 226 | tx_start_pos <= `UD 1'b1; 227 | FF <= `UD 1'b0; 228 | end 229 | else 230 | begin 231 | tx_start_pos <= `UD 1'b0; 232 | if(end_bps_cnt) 233 | begin 234 | rs485_tx_data <= `UD code03_04_response[(((tx_quantity<<1)+5)<<3)-1 -:8]; 235 | FF <= `UD 1'b1; 236 | op_state <= `UD 8'd6; 237 | rs485_tx_start <= `UD 1'b0; 238 | end 239 | else 240 | begin 241 | FF <= `UD 1'b0; 242 | end 243 | end 244 | end 245 | 246 | 8'd6: 247 | begin 248 | if(FF) 249 | begin 250 | rs485_tx_start <= `UD 1'b1; 251 | FF <= `UD 1'b0; 252 | end 253 | else 254 | begin 255 | if(tx_done) 256 | begin 257 | if(byte_cnt < ((tx_quantity<<1)+4)) 258 | begin 259 | FF <= `UD 1'b1; 260 | rs485_tx_data <= `UD code03_04_response[(((tx_quantity<<1)- byte_cnt +4)<<3)-1 -:8]; 261 | byte_cnt <= `UD byte_cnt + 1'b1; 262 | rs485_tx_start <= `UD 1'b0; 263 | end 264 | if(byte_cnt == ((tx_quantity<<1)+4)) 265 | begin 266 | op_state <= `UD 8'd7; 267 | byte_cnt <= `UD 4'd0; 268 | response_done_r <= `UD 1'b1; 269 | rs485_tx_data <= `UD 8'h0; 270 | FF <= `UD 1'b1; 271 | end 272 | else begin 273 | op_state <= `UD 8'd6; 274 | response_done_r <= `UD 1'b0; 275 | end 276 | end 277 | else 278 | begin 279 | rs485_tx_start <= `UD 1'b0; 280 | FF <= `UD 1'b0; 281 | end 282 | end 283 | end 284 | 285 | 8'd7: 286 | begin 287 | if(FF) 288 | begin 289 | response_done_r <= `UD 1'b0; 290 | FF <= `UD 1'b0; 291 | end 292 | else if(end_bps_cnt) 293 | begin 294 | op_state <= `UD 8'd0; 295 | FF <= `UD 1'b1; 296 | rs485_tx_en <= `UD 1'b0; 297 | response_done <= `UD 1'b1; 298 | end 299 | else 300 | begin 301 | rs485_tx_data <= `UD 8'h0; 302 | rs485_tx_start <= `UD 1'b0; 303 | FF <= `UD 1'b0; 304 | end 305 | end 306 | default:; 307 | endcase 308 | end 309 | end 310 | 311 | //一帧数据中两字节发送间隔小于1.5T 312 | always@(posedge clk or negedge rst_n) 313 | begin 314 | if(!rst_n) 315 | begin 316 | cnt_en <= `UD 1'b0; 317 | end 318 | else 319 | begin 320 | if(tx_start_pos||response_done_r) 321 | begin 322 | cnt_en <= `UD 1'b1; 323 | end 324 | else if(end_bps_cnt) 325 | begin 326 | cnt_en <= `UD 1'b0; 327 | end 328 | end 329 | end 330 | 331 | always @(posedge clk or negedge rst_n) 332 | begin 333 | if(!rst_n)begin 334 | cnt_en_flag <= `UD 1'b0; 335 | end 336 | else if(tx_start_pos||response_done_r) 337 | begin 338 | cnt_en_flag <= `UD 1'b1; 339 | end 340 | else if(end_bps_cnt) 341 | begin 342 | cnt_en_flag <= `UD 1'b0; 343 | end 344 | end 345 | 346 | always @(posedge clk or negedge rst_n)begin 347 | if(!rst_n)begin 348 | bps_cnt <= `UD 0; 349 | end 350 | else if(add_bps_cnt)begin 351 | if(end_bps_cnt)begin 352 | bps_cnt <= `UD 0; 353 | end 354 | else begin 355 | bps_cnt <= `UD bps_cnt + 1; 356 | end 357 | end 358 | else begin 359 | bps_cnt <= `UD 0; 360 | end 361 | end 362 | 363 | assign add_bps_cnt = cnt_en_flag; 364 | assign end_bps_cnt = bps_cnt && bps_cnt == 10*(BPS_PARAM-1); 365 | 366 | uart_byte_tx # 367 | ( 368 | .CLK_FREQ (CLK_FREQ ), // 50MHz system clock 369 | .BAUD_RATE (BAUD_RATE ) 370 | )uart_byte_tx_inst0 371 | ( 372 | .clk (clk ), // system clock 373 | .rst_n (rst_n ), // system reset, active low 374 | .tx_start (rs485_tx_start ), // start with pos edge 375 | .tx_data (rs485_tx_data ), // data need to transfer 376 | .tx_done (tx_done ), // transfer done 377 | .tx_state ( ), // sending duration 378 | .rs232_tx (rs485_tx ) // uart transfer pin 379 | ); 380 | 381 | endmodule 382 | -------------------------------------------------------------------------------- /func_handler_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module func_handler_tb; 5 | 6 | reg sys_clk; 7 | reg reset_n; 8 | 9 | wire UART_TX; 10 | 11 | reg tx_start; 12 | reg [7:0] tx_data; 13 | wire tx_state; 14 | wire tx_done; 15 | reg [7:0] dev_addr; 16 | 17 | reg test; 18 | 19 | uart_byte_tx # 20 | ( 21 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 22 | .BAUD_RATE ('d115200 ) 23 | )uart_byte_tx_inst0 24 | ( 25 | .clk (sys_clk ), // system clock 26 | .rst_n (reset_n ), // system reset, active low 27 | .tx_start (tx_start ), // start with pos edge 28 | .tx_data (tx_data ), // data need to transfer 29 | .tx_done (tx_done ), // transfer done 30 | .tx_state (tx_state ), // sending duration 31 | .rs232_tx (UART_TX ) // uart transfer pin 32 | ); 33 | 34 | wire [7:0] rx_data; 35 | wire rx_done; 36 | wire rx_state; 37 | 38 | uart_byte_rx # 39 | ( 40 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 41 | .BAUD_RATE ('d115200 ) 42 | )uart_byte_rx_inst0 43 | ( 44 | .clk (sys_clk ), // system clock 45 | .rst_n (reset_n ), // system reset, active low 46 | .rx_data (rx_data ), // data need to transfer 47 | .rx_done (rx_done ), // transfer done 48 | .rx_state (rx_state ), // sending duration 49 | .rs232_rx (UART_TX ) // uart transfer pin 50 | ); 51 | 52 | wire rx_new_frame; 53 | ct_35t_gen # 54 | ( 55 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 56 | .BAUD_RATE ('d115200 ) 57 | )ct_35t_gen_inst0 58 | ( 59 | .clk (sys_clk ), // system clock 60 | .rst_n (reset_n ), // system reset, active low 61 | .rx_done (rx_done ), // transfer done 62 | .rx_state (rx_state ), // sending duration 63 | .rx_new_frame (rx_new_frame ) 64 | ); 65 | 66 | wire rx_drop_frame; 67 | ct_15t_gen # 68 | ( 69 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 70 | .BAUD_RATE ('d115200 ) 71 | )ct_15t_gen_inst0 72 | ( 73 | .clk (sys_clk ), // system clock 74 | .rst_n (reset_n ), // system reset, active low 75 | .rx_done (rx_done ), // transfer done 76 | .rx_state (rx_state ), // sending duration 77 | .rx_drop_frame (rx_drop_frame ) 78 | ); 79 | 80 | wire rx_message_done; 81 | wire [7:0] func_code; 82 | wire [15:0] addr; 83 | wire [15:0] data; 84 | wire [15:0] crc_rx_code; 85 | wire rx_crc_vld ; 86 | wire rx_crc_error ; 87 | wire rx_crc_done ; 88 | frame_rx frame_rx_inst0 89 | ( 90 | .clk (sys_clk ), // system clock 91 | .rst_n (reset_n ), // system reset, active low 92 | .dev_addr (dev_addr ), 93 | .rx_drop_frame (rx_drop_frame ), // 1.5T interval 94 | .rx_new_frame (rx_new_frame ), // 3.5T interval 95 | .rx_done (rx_done ), // 96 | .rx_data (rx_data ), // 97 | .rx_crc_error (rx_crc_error ), 98 | .rx_crc_done (rx_crc_done ), 99 | .rx_crc_vld (rx_crc_vld ), 100 | .rx_message_done(rx_message_done), 101 | .func_code (func_code ), 102 | .addr (addr ), 103 | .data (data ), 104 | .crc_rx_code (crc_rx_code ) 105 | ); 106 | 107 | wire exception_done; 108 | wire [7:0] exception; 109 | exceptions exceptions_inst0 110 | ( 111 | .clk (sys_clk ), // system clock 112 | .rst_n (reset_n ), // system reset, active low 113 | .rx_message_done(rx_message_done), 114 | .func_code (func_code ), 115 | .addr (addr ), 116 | .data (data ), 117 | .exception_done (exception_done ), 118 | .exception (exception ) 119 | ); 120 | 121 | wire handler_done ; 122 | wire [15:0] dia ; 123 | wire wea ; 124 | wire [7:0] addra ; 125 | wire [7:0] tx_quantity ; 126 | wire [7:0] exception_out ; 127 | wire [7:0] func_code_r ; 128 | wire [15:0] addr_r ; 129 | wire [15:0] data_r ; 130 | wire [15:0] crc_rx_code_r ; 131 | wire reg_wen ; 132 | wire [15:0] reg_wdat ; 133 | reg reg_w_done ; 134 | reg reg_w_status ; 135 | //reg [15:0] read_03_01_r ; 136 | func_hander func_handler_inst0 137 | ( 138 | .clk (sys_clk ), // system clock 139 | .rst_n (reset_n ), // system reset, active low 140 | .dev_addr (dev_addr ), //device address 141 | .rx_message_done(rx_message_done), 142 | .func_code (func_code ), 143 | .addr (addr ), 144 | .data (data ), 145 | .crc_rx_code (crc_rx_code ), 146 | .exception_done (exception_done ), 147 | .exception_in (exception ), 148 | .read_03_01 (16'h0451 ), 149 | .read_04_01 (16'h5347 ), 150 | .read_04_02 (16'h7414 ), 151 | .read_04_03 (16'h2021 ), 152 | .read_04_04 (16'h0402 ), 153 | .tx_quantity (tx_quantity ), 154 | .func_code_r (func_code_r ), 155 | .addr_r (addr_r ), 156 | .data_r (data_r ), 157 | .crc_rx_code_r (crc_rx_code_r ), 158 | .exception_out (exception_out ), 159 | .dpram_wen (wea ), 160 | .dpram_addr (addra ), 161 | .dpram_wdata (dia ), 162 | .reg_wen (reg_wen ), 163 | .reg_wdat (reg_wdat ), 164 | .reg_w_done (reg_w_done ), 165 | .reg_w_status (reg_w_status ), 166 | .handler_done (handler_done ) 167 | ); 168 | 169 | wire [15:0] tx_data_b; 170 | wire [7:0] tx_addr ; 171 | DPRAM 172 | #( 173 | .A_WIDTH ('d2), 174 | .D_WIDTH ('d16) 175 | )DPRAM_inst0 176 | ( 177 | .CLKA (sys_clk), 178 | .CLKB (sys_clk), 179 | .ENA (1'd1), 180 | .ENB (1'd1), 181 | .WEA (wea), 182 | .WEB (1'd0), 183 | .ADDRA (addra), 184 | .ADDRB (tx_addr), 185 | .DIA (dia), 186 | .DIB (16'b0), 187 | .DOA (), 188 | .DOB (tx_data_b) 189 | ); 190 | 191 | wire [39:0] exception_seq ; 192 | wire [63:0] code06_response ; 193 | wire [103:0] code03_04_response; 194 | modbus_crc_16 u_modbus_crc_16( 195 | .clk (sys_clk ), 196 | .rst_n (reset_n ), 197 | .dev_addr (dev_addr ), 198 | .func_code (func_code ), 199 | .addr (addr ), 200 | .data (data ), 201 | .crc_rx_code (crc_rx_code ), 202 | .rx_crc_vld (rx_crc_vld ), 203 | .rx_crc_error (rx_crc_error ), 204 | .rx_crc_done (rx_crc_done ), 205 | 206 | .tx_quantity (tx_quantity ), 207 | .rd_dpram_data (tx_data_b ), 208 | .rd_dpram_addr (tx_addr ), 209 | 210 | .handler_done (handler_done ), 211 | .exception (exception_out ), 212 | .tx_06_rp_start (tx_06_rp_start ), 213 | .tx_exp_rp_start (tx_exp_rp_start ), 214 | .tx_03_04_rp_start (tx_03_04_rp_start ), 215 | .exception_seq (exception_seq ), 216 | .code06_response (code06_response ), 217 | .code03_04_response (code03_04_response) 218 | ); 219 | 220 | initial sys_clk = 1; 221 | always #(`clk_period/2) sys_clk = ~sys_clk; 222 | 223 | initial reset_n = 0; 224 | always #(`clk_period*50) reset_n = 1'b1; 225 | 226 | initial 227 | begin 228 | reg_w_done = 1'b0; 229 | reg_w_status = 1'b0; 230 | 231 | @(posedge reg_wen) 232 | #(`clk_period*2000) 233 | reg_w_done = 1'b1; 234 | reg_w_status = 1'b1; 235 | #(`clk_period*1) 236 | reg_w_done = 1'b0; 237 | reg_w_status = 1'b0; 238 | 239 | @(posedge reg_wen) 240 | #(`clk_period*2000) 241 | reg_w_done = 1'b1; 242 | #(`clk_period*1) 243 | reg_w_done = 1'b0; 244 | end 245 | 246 | reg [7:0] FRAME [0:7]; 247 | reg TT; 248 | initial 249 | begin 250 | tx_start = 0; 251 | tx_data = 8'h0; 252 | test = 0; 253 | 254 | #(`clk_period*50) 255 | dev_addr = 8'h01; 256 | FRAME[0] = 8'h01; 257 | FRAME[1] = 8'h03; 258 | FRAME[2] = 8'h00; 259 | FRAME[3] = 8'h01; 260 | FRAME[4] = 8'h00; 261 | FRAME[5] = 8'h01; 262 | FRAME[6] = 8'hd5; 263 | FRAME[7] = 8'hca; 264 | test = 1; 265 | #(`clk_period*1) 266 | test = 0; 267 | 268 | @(posedge TT) 269 | #(`clk_period*20000) 270 | // FRAME[0] = 8'h01; 271 | // FRAME[1] = 8'h06; 272 | // FRAME[2] = 8'h00; 273 | // FRAME[3] = 8'h01; 274 | // FRAME[4] = 8'h00; 275 | // FRAME[5] = 8'h05; 276 | // FRAME[6] = 8'h18; 277 | // FRAME[7] = 8'h09; 278 | FRAME[0] = 8'h01; 279 | FRAME[1] = 8'h06; 280 | FRAME[2] = 8'h00; 281 | FRAME[3] = 8'h02; // illegal 282 | FRAME[4] = 8'h00; 283 | FRAME[5] = 8'h05; 284 | FRAME[6] = 8'he8; 285 | FRAME[7] = 8'h09; 286 | test = 1; 287 | #(`clk_period*1) 288 | test = 0; 289 | 290 | @(posedge TT) 291 | #(`clk_period*20000) 292 | FRAME[0] = 8'h01; 293 | FRAME[1] = 8'h04; 294 | FRAME[2] = 8'h00; 295 | FRAME[3] = 8'h01; 296 | FRAME[4] = 8'h00; 297 | FRAME[5] = 8'h04; 298 | FRAME[6] = 8'ha0; 299 | FRAME[7] = 8'h09; 300 | test = 1; 301 | #(`clk_period*1) 302 | test = 0; 303 | 304 | @(posedge TT) 305 | #(`clk_period*20000) 306 | FRAME[0] = 8'h01; 307 | FRAME[1] = 8'h06; 308 | FRAME[2] = 8'h00; 309 | FRAME[3] = 8'h01; 310 | FRAME[4] = 8'h00; 311 | FRAME[5] = 8'h03; 312 | FRAME[6] = 8'h98; 313 | FRAME[7] = 8'h0b; 314 | test = 1; 315 | #(`clk_period*1) 316 | test = 0; 317 | 318 | @(posedge TT) 319 | #(`clk_period*20000) 320 | FRAME[0] = 8'h01; 321 | FRAME[1] = 8'h06; 322 | FRAME[2] = 8'h00; 323 | FRAME[3] = 8'h01; 324 | FRAME[4] = 8'h00; 325 | FRAME[5] = 8'h07; 326 | FRAME[6] = 8'h99; 327 | FRAME[7] = 8'hc8; 328 | test = 1; 329 | #(`clk_period*1) 330 | test = 0; 331 | 332 | // #(`clk_period*50) 333 | // tx_data = 8'haa; 334 | 335 | // #(`clk_period*10) 336 | // tx_start = 1; 337 | 338 | // #(`clk_period*2) 339 | // tx_start = 0; 340 | //@(posedge rx_done) 341 | //#(`clk_period*5000); 342 | //$stop; 343 | end 344 | 345 | parameter IDLE = 8'b0000_0000; 346 | parameter TX_S0 = 8'b0000_0001; 347 | parameter TX_S1 = 8'b0000_0010; 348 | parameter TX_S2 = 8'b0000_0100; 349 | parameter TX_S3 = 8'b0000_1000; 350 | parameter TX_S4 = 8'b0001_0000; 351 | parameter TX_S5 = 8'b0010_0000; 352 | parameter TX_S6 = 8'b0100_0000; 353 | parameter TX_S7 = 8'b1000_0000; 354 | reg [7:0] state; 355 | reg FF; 356 | 357 | always @(posedge sys_clk or negedge reset_n) 358 | begin 359 | if(!reset_n) 360 | begin 361 | state<=IDLE; 362 | FF<=1'b1; 363 | TT<=1'b0; 364 | end 365 | else 366 | begin 367 | case(state) 368 | IDLE: 369 | begin 370 | if(test) 371 | begin 372 | state <= TX_S0; 373 | FF<=1'b1; 374 | TT<=1'b0; 375 | end 376 | else 377 | begin 378 | state <= IDLE; 379 | FF<=1'b1; 380 | TT<=1'b0; 381 | end 382 | end 383 | TX_S0: 384 | begin 385 | if(FF) 386 | begin 387 | tx_start <= 1'b1; 388 | tx_data <= FRAME[0]; 389 | FF<=1'b0; 390 | end 391 | else if(tx_done) 392 | begin 393 | state <= TX_S1; 394 | FF<=1'b1; 395 | end 396 | else 397 | begin 398 | tx_start <= 1'b0; 399 | end 400 | end 401 | TX_S1: 402 | begin 403 | if(FF) 404 | begin 405 | tx_start <= 1'b1; 406 | tx_data <= FRAME[1]; 407 | FF<=1'b0; 408 | end 409 | else if(tx_done) 410 | begin 411 | state <= TX_S2; 412 | FF<=1'b1; 413 | end 414 | else 415 | begin 416 | tx_start <= 1'b0; 417 | end 418 | end 419 | TX_S2: 420 | begin 421 | if(FF) 422 | begin 423 | tx_start <= 1'b1; 424 | tx_data <= FRAME[2]; 425 | FF<=1'b0; 426 | end 427 | else if(tx_done) 428 | begin 429 | state <= TX_S3; 430 | FF<=1'b1; 431 | end 432 | else 433 | begin 434 | tx_start <= 1'b0; 435 | end 436 | end 437 | TX_S3: 438 | begin 439 | if(FF) 440 | begin 441 | tx_start <= 1'b1; 442 | tx_data <= FRAME[3]; 443 | FF<=1'b0; 444 | end 445 | else if(tx_done) 446 | begin 447 | state <= TX_S4; 448 | FF<=1'b1; 449 | end 450 | else 451 | begin 452 | tx_start <= 1'b0; 453 | end 454 | end 455 | TX_S4: 456 | begin 457 | if(FF) 458 | begin 459 | tx_start <= 1'b1; 460 | tx_data <= FRAME[4]; 461 | FF<=1'b0; 462 | end 463 | else if(tx_done) 464 | begin 465 | state <= TX_S5; 466 | FF<=1'b1; 467 | end 468 | else 469 | begin 470 | tx_start <= 1'b0; 471 | end 472 | end 473 | TX_S5: 474 | begin 475 | if(FF) 476 | begin 477 | tx_start <= 1'b1; 478 | tx_data <= FRAME[5]; 479 | FF<=1'b0; 480 | end 481 | else if(tx_done) 482 | begin 483 | state <= TX_S6; 484 | FF<=1'b1; 485 | end 486 | else 487 | begin 488 | tx_start <= 1'b0; 489 | end 490 | end 491 | TX_S6: 492 | begin 493 | if(FF) 494 | begin 495 | tx_start <= 1'b1; 496 | tx_data <= FRAME[6]; 497 | FF<=1'b0; 498 | end 499 | else if(tx_done) 500 | begin 501 | state <= TX_S7; 502 | FF<=1'b1; 503 | end 504 | else 505 | begin 506 | tx_start <= 1'b0; 507 | end 508 | end 509 | TX_S7: 510 | begin 511 | if(FF) 512 | begin 513 | tx_start <= 1'b1; 514 | tx_data <= FRAME[7]; 515 | FF<=1'b0; 516 | end 517 | else if(tx_done) 518 | begin 519 | state <= IDLE; 520 | FF<=1'b1; 521 | TT<=1'b1; 522 | end 523 | else 524 | begin 525 | tx_start <= 1'b0; 526 | end 527 | end 528 | default: 529 | begin 530 | state <= IDLE; 531 | end 532 | endcase 533 | end 534 | end 535 | 536 | endmodule -------------------------------------------------------------------------------- /tx_response_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ns 2 | `define clk_period 20 3 | 4 | module tx_response_tb; 5 | 6 | reg sys_clk; 7 | reg reset_n; 8 | 9 | wire UART_TX; 10 | 11 | reg tx_start; 12 | reg [7:0] tx_data; 13 | wire tx_state; 14 | wire tx_done; 15 | reg [7:0] dev_addr; 16 | 17 | reg test; 18 | 19 | uart_byte_tx # 20 | ( 21 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 22 | .BAUD_RATE ('d115200 ) 23 | )uart_byte_tx_inst0 24 | ( 25 | .clk (sys_clk ), // system clock 26 | .rst_n (reset_n ), // system reset, active low 27 | .tx_start (tx_start ), // start with pos edge 28 | .tx_data (tx_data ), // data need to transfer 29 | .tx_done (tx_done ), // transfer done 30 | .tx_state (tx_state ), // sending duration 31 | .rs232_tx (UART_TX ) // uart transfer pin 32 | ); 33 | 34 | wire [7:0] rx_data; 35 | wire rx_done; 36 | wire rx_state; 37 | 38 | uart_byte_rx # 39 | ( 40 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 41 | .BAUD_RATE ('d115200 ) 42 | )uart_byte_rx_inst0 43 | ( 44 | .clk (sys_clk ), // system clock 45 | .rst_n (reset_n ), // system reset, active low 46 | .rx_data (rx_data ), // data need to transfer 47 | .rx_done (rx_done ), // transfer done 48 | .rx_state (rx_state ), // sending duration 49 | .rs232_rx (UART_TX ) // uart transfer pin 50 | ); 51 | 52 | wire rx_new_frame; 53 | ct_35t_gen # 54 | ( 55 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 56 | .BAUD_RATE ('d115200 ) 57 | )ct_35t_gen_inst0 58 | ( 59 | .clk (sys_clk ), // system clock 60 | .rst_n (reset_n ), // system reset, active low 61 | .rx_done (rx_done ), // transfer done 62 | .rx_state (rx_state ), // sending duration 63 | .rx_new_frame (rx_new_frame ) 64 | ); 65 | 66 | wire rx_drop_frame; 67 | ct_15t_gen # 68 | ( 69 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 70 | .BAUD_RATE ('d115200 ) 71 | )ct_15t_gen_inst0 72 | ( 73 | .clk (sys_clk ), // system clock 74 | .rst_n (reset_n ), // system reset, active low 75 | .rx_done (rx_done ), // transfer done 76 | .rx_state (rx_state ), // sending duration 77 | .rx_drop_frame (rx_drop_frame ) 78 | ); 79 | 80 | wire rx_message_done; 81 | wire [7:0] func_code; 82 | wire [15:0] addr; 83 | wire [15:0] data; 84 | wire [15:0] crc_rx_code; 85 | wire rx_crc_vld ; 86 | wire rx_crc_error ; 87 | wire rx_crc_done ; 88 | frame_rx frame_rx_inst0 89 | ( 90 | .clk (sys_clk ), // system clock 91 | .rst_n (reset_n ), // system reset, active low 92 | .dev_addr (dev_addr ), 93 | .rx_drop_frame (rx_drop_frame ), // 1.5T interval 94 | .rx_new_frame (rx_new_frame ), // 3.5T interval 95 | .rx_done (rx_done ), // 96 | .rx_data (rx_data ), // 97 | .rx_crc_error (rx_crc_error ), 98 | .rx_crc_done (rx_crc_done ), 99 | .rx_crc_vld (rx_crc_vld ), 100 | .rx_message_done(rx_message_done), 101 | .func_code (func_code ), 102 | .addr (addr ), 103 | .data (data ), 104 | .crc_rx_code (crc_rx_code ) 105 | ); 106 | 107 | wire exception_done; 108 | wire [7:0] exception; 109 | exceptions exceptions_inst0 110 | ( 111 | .clk (sys_clk ), // system clock 112 | .rst_n (reset_n ), // system reset, active low 113 | .rx_message_done(rx_message_done), 114 | .func_code (func_code ), 115 | .addr (addr ), 116 | .data (data ), 117 | .exception_done (exception_done ), 118 | .exception (exception ) 119 | ); 120 | 121 | wire handler_done ; 122 | wire [15:0] dia ; 123 | wire wea ; 124 | wire [7:0] addra ; 125 | wire [7:0] tx_quantity ; 126 | wire [7:0] exception_out ; 127 | wire [7:0] func_code_r ; 128 | wire [15:0] addr_r ; 129 | wire [15:0] data_r ; 130 | wire [15:0] crc_rx_code_r ; 131 | wire reg_wen ; 132 | wire [15:0] reg_wdat ; 133 | reg reg_w_done ; 134 | reg reg_w_status ; 135 | //reg [15:0] read_03_01_r ; 136 | func_hander func_handler_inst0 137 | ( 138 | .clk (sys_clk ), // system clock 139 | .rst_n (reset_n ), // system reset, active low 140 | .dev_addr (dev_addr ), //device address 141 | .rx_message_done(rx_message_done), 142 | .func_code (func_code ), 143 | .addr (addr ), 144 | .data (data ), 145 | .crc_rx_code (crc_rx_code ), 146 | .exception_done (exception_done ), 147 | .exception_in (exception ), 148 | .read_03_01 (16'h0451 ), 149 | .read_04_01 (16'h5347 ), 150 | .read_04_02 (16'h7414 ), 151 | .read_04_03 (16'h2021 ), 152 | .read_04_04 (16'h0402 ), 153 | .tx_quantity (tx_quantity ), 154 | .func_code_r (func_code_r ), 155 | .addr_r (addr_r ), 156 | .data_r (data_r ), 157 | .crc_rx_code_r (crc_rx_code_r ), 158 | .exception_out (exception_out ), 159 | .dpram_wen (wea ), 160 | .dpram_addr (addra ), 161 | .dpram_wdata (dia ), 162 | .reg_wen (reg_wen ), 163 | .reg_wdat (reg_wdat ), 164 | .reg_w_done (reg_w_done ), 165 | .reg_w_status (reg_w_status ), 166 | .handler_done (handler_done ) 167 | ); 168 | 169 | wire [15:0] tx_data_b; 170 | wire [7:0] tx_addr ; 171 | DPRAM 172 | #( 173 | .A_WIDTH ('d2), 174 | .D_WIDTH ('d16) 175 | )DPRAM_inst0 176 | ( 177 | .CLKA (sys_clk), 178 | .CLKB (sys_clk), 179 | .ENA (1'd1), 180 | .ENB (1'd1), 181 | .WEA (wea), 182 | .WEB (1'd0), 183 | .ADDRA (addra), 184 | .ADDRB (tx_addr), 185 | .DIA (dia), 186 | .DIB (16'b0), 187 | .DOA (), 188 | .DOB (tx_data_b) 189 | ); 190 | 191 | wire tx_06_rp_start ; 192 | wire tx_exp_rp_start ; 193 | wire tx_03_04_rp_start ; 194 | wire [39:0] exception_seq ; 195 | wire [63:0] code06_response ; 196 | wire [103:0] code03_04_response; 197 | modbus_crc_16 u_modbus_crc_16( 198 | .clk (sys_clk ), 199 | .rst_n (reset_n ), 200 | .dev_addr (dev_addr ), 201 | .func_code (func_code ), 202 | .addr (addr ), 203 | .data (data ), 204 | .crc_rx_code (crc_rx_code ), 205 | .rx_crc_vld (rx_crc_vld ), 206 | .rx_crc_error (rx_crc_error ), 207 | .rx_crc_done (rx_crc_done ), 208 | 209 | .tx_quantity (tx_quantity ), 210 | .rd_dpram_data (tx_data_b ), 211 | .rd_dpram_addr (tx_addr ), 212 | 213 | .handler_done (handler_done ), 214 | .exception (exception_out ), 215 | .tx_06_rp_start (tx_06_rp_start ), 216 | .tx_exp_rp_start (tx_exp_rp_start ), 217 | .tx_03_04_rp_start (tx_03_04_rp_start ), 218 | .exception_seq (exception_seq ), 219 | .code06_response (code06_response ), 220 | .code03_04_response (code03_04_response) 221 | ); 222 | 223 | tx_response # 224 | ( 225 | .CLK_FREQ ('d50000000 ), // 50MHz system clock 226 | .BAUD_RATE ('d115200 ) 227 | ) 228 | tx_response_inst0( 229 | .clk (sys_clk ),// system clock 230 | .rst_n (reset_n ),// system reset, active low . 231 | .tx_06_rp_start (tx_06_rp_start ), 232 | .tx_exp_rp_start (tx_exp_rp_start ), 233 | .tx_03_04_rp_start (tx_03_04_rp_start ), 234 | .tx_quantity (tx_quantity ), 235 | .exception_seq (exception_seq ), 236 | .code06_response (code06_response ), 237 | .code03_04_response (code03_04_response ), 238 | .response_done (response_done ), 239 | .rs485_tx (rs485_tx ), 240 | .rs485_tx_en (rs485_oe ) 241 | ); 242 | 243 | initial sys_clk = 1; 244 | always #(`clk_period/2) sys_clk = ~sys_clk; 245 | 246 | initial reset_n = 0; 247 | always #(`clk_period*50) reset_n = 1'b1; 248 | 249 | initial 250 | begin 251 | reg_w_done = 1'b0; 252 | reg_w_status = 1'b0; 253 | 254 | @(posedge reg_wen) 255 | #(`clk_period*2000) 256 | reg_w_done = 1'b1; 257 | reg_w_status = 1'b1; 258 | #(`clk_period*1) 259 | reg_w_done = 1'b0; 260 | reg_w_status = 1'b0; 261 | 262 | @(posedge reg_wen) 263 | #(`clk_period*2000) 264 | reg_w_done = 1'b1; 265 | #(`clk_period*1) 266 | reg_w_done = 1'b0; 267 | end 268 | 269 | reg [7:0] FRAME [0:7]; 270 | reg TT; 271 | initial 272 | begin 273 | tx_start = 0; 274 | tx_data = 8'h0; 275 | test = 0; 276 | 277 | #(`clk_period*50) 278 | dev_addr = 8'h01; 279 | FRAME[0] = 8'h01; 280 | FRAME[1] = 8'h03; 281 | FRAME[2] = 8'h00; 282 | FRAME[3] = 8'h01; 283 | FRAME[4] = 8'h00; 284 | FRAME[5] = 8'h01; 285 | FRAME[6] = 8'hd5; 286 | FRAME[7] = 8'hca; 287 | test = 1; 288 | #(`clk_period*1) 289 | test = 0; 290 | 291 | @(posedge response_done) 292 | #(`clk_period*20000) 293 | // FRAME[0] = 8'h01; 294 | // FRAME[1] = 8'h06; 295 | // FRAME[2] = 8'h00; 296 | // FRAME[3] = 8'h01; 297 | // FRAME[4] = 8'h00; 298 | // FRAME[5] = 8'h05; 299 | // FRAME[6] = 8'h18; 300 | // FRAME[7] = 8'h09; 301 | FRAME[0] = 8'h01; 302 | FRAME[1] = 8'h06; 303 | FRAME[2] = 8'h00; 304 | FRAME[3] = 8'h02; // illegal 305 | FRAME[4] = 8'h00; 306 | FRAME[5] = 8'h05; 307 | FRAME[6] = 8'he8; 308 | FRAME[7] = 8'h09; 309 | test = 1; 310 | #(`clk_period*1) 311 | test = 0; 312 | 313 | @(posedge response_done) 314 | #(`clk_period*20000) 315 | FRAME[0] = 8'h01; 316 | FRAME[1] = 8'h04; 317 | FRAME[2] = 8'h00; 318 | FRAME[3] = 8'h01; 319 | FRAME[4] = 8'h00; 320 | FRAME[5] = 8'h04; 321 | FRAME[6] = 8'ha0; 322 | FRAME[7] = 8'h09; 323 | test = 1; 324 | #(`clk_period*1) 325 | test = 0; 326 | 327 | @(posedge response_done) 328 | #(`clk_period*20000) 329 | FRAME[0] = 8'h01; 330 | FRAME[1] = 8'h06; 331 | FRAME[2] = 8'h00; 332 | FRAME[3] = 8'h01; 333 | FRAME[4] = 8'h00; 334 | FRAME[5] = 8'h03; 335 | FRAME[6] = 8'h98; 336 | FRAME[7] = 8'h0b; 337 | test = 1; 338 | #(`clk_period*1) 339 | test = 0; 340 | 341 | @(posedge response_done) 342 | #(`clk_period*20000) 343 | FRAME[0] = 8'h01; 344 | FRAME[1] = 8'h06; 345 | FRAME[2] = 8'h00; 346 | FRAME[3] = 8'h01; 347 | FRAME[4] = 8'h00; 348 | FRAME[5] = 8'h07; 349 | FRAME[6] = 8'h99; 350 | FRAME[7] = 8'hc8; 351 | test = 1; 352 | #(`clk_period*1) 353 | test = 0; 354 | 355 | // #(`clk_period*50) 356 | // tx_data = 8'haa; 357 | 358 | // #(`clk_period*10) 359 | // tx_start = 1; 360 | 361 | // #(`clk_period*2) 362 | // tx_start = 0; 363 | //@(posedge rx_done) 364 | //#(`clk_period*5000); 365 | //$stop; 366 | end 367 | 368 | parameter IDLE = 8'b0000_0000; 369 | parameter TX_S0 = 8'b0000_0001; 370 | parameter TX_S1 = 8'b0000_0010; 371 | parameter TX_S2 = 8'b0000_0100; 372 | parameter TX_S3 = 8'b0000_1000; 373 | parameter TX_S4 = 8'b0001_0000; 374 | parameter TX_S5 = 8'b0010_0000; 375 | parameter TX_S6 = 8'b0100_0000; 376 | parameter TX_S7 = 8'b1000_0000; 377 | reg [7:0] state; 378 | reg FF; 379 | 380 | always @(posedge sys_clk or negedge reset_n) 381 | begin 382 | if(!reset_n) 383 | begin 384 | state<=IDLE; 385 | FF<=1'b1; 386 | TT<=1'b0; 387 | end 388 | else 389 | begin 390 | case(state) 391 | IDLE: 392 | begin 393 | if(test) 394 | begin 395 | state <= TX_S0; 396 | FF<=1'b1; 397 | TT<=1'b0; 398 | end 399 | else 400 | begin 401 | state <= IDLE; 402 | FF<=1'b1; 403 | TT<=1'b0; 404 | end 405 | end 406 | TX_S0: 407 | begin 408 | if(FF) 409 | begin 410 | tx_start <= 1'b1; 411 | tx_data <= FRAME[0]; 412 | FF<=1'b0; 413 | end 414 | else if(tx_done) 415 | begin 416 | state <= TX_S1; 417 | FF<=1'b1; 418 | end 419 | else 420 | begin 421 | tx_start <= 1'b0; 422 | end 423 | end 424 | TX_S1: 425 | begin 426 | if(FF) 427 | begin 428 | tx_start <= 1'b1; 429 | tx_data <= FRAME[1]; 430 | FF<=1'b0; 431 | end 432 | else if(tx_done) 433 | begin 434 | state <= TX_S2; 435 | FF<=1'b1; 436 | end 437 | else 438 | begin 439 | tx_start <= 1'b0; 440 | end 441 | end 442 | TX_S2: 443 | begin 444 | if(FF) 445 | begin 446 | tx_start <= 1'b1; 447 | tx_data <= FRAME[2]; 448 | FF<=1'b0; 449 | end 450 | else if(tx_done) 451 | begin 452 | state <= TX_S3; 453 | FF<=1'b1; 454 | end 455 | else 456 | begin 457 | tx_start <= 1'b0; 458 | end 459 | end 460 | TX_S3: 461 | begin 462 | if(FF) 463 | begin 464 | tx_start <= 1'b1; 465 | tx_data <= FRAME[3]; 466 | FF<=1'b0; 467 | end 468 | else if(tx_done) 469 | begin 470 | state <= TX_S4; 471 | FF<=1'b1; 472 | end 473 | else 474 | begin 475 | tx_start <= 1'b0; 476 | end 477 | end 478 | TX_S4: 479 | begin 480 | if(FF) 481 | begin 482 | tx_start <= 1'b1; 483 | tx_data <= FRAME[4]; 484 | FF<=1'b0; 485 | end 486 | else if(tx_done) 487 | begin 488 | state <= TX_S5; 489 | FF<=1'b1; 490 | end 491 | else 492 | begin 493 | tx_start <= 1'b0; 494 | end 495 | end 496 | TX_S5: 497 | begin 498 | if(FF) 499 | begin 500 | tx_start <= 1'b1; 501 | tx_data <= FRAME[5]; 502 | FF<=1'b0; 503 | end 504 | else if(tx_done) 505 | begin 506 | state <= TX_S6; 507 | FF<=1'b1; 508 | end 509 | else 510 | begin 511 | tx_start <= 1'b0; 512 | end 513 | end 514 | TX_S6: 515 | begin 516 | if(FF) 517 | begin 518 | tx_start <= 1'b1; 519 | tx_data <= FRAME[6]; 520 | FF<=1'b0; 521 | end 522 | else if(tx_done) 523 | begin 524 | state <= TX_S7; 525 | FF<=1'b1; 526 | end 527 | else 528 | begin 529 | tx_start <= 1'b0; 530 | end 531 | end 532 | TX_S7: 533 | begin 534 | if(FF) 535 | begin 536 | tx_start <= 1'b1; 537 | tx_data <= FRAME[7]; 538 | FF<=1'b0; 539 | end 540 | else if(tx_done) 541 | begin 542 | state <= IDLE; 543 | FF<=1'b1; 544 | TT<=1'b1; 545 | end 546 | else 547 | begin 548 | tx_start <= 1'b0; 549 | end 550 | end 551 | default: 552 | begin 553 | state <= IDLE; 554 | end 555 | endcase 556 | end 557 | end 558 | 559 | endmodule 560 | --------------------------------------------------------------------------------