windowsでiverilog その8

#概要

windowsでiverilogやってみた。
serialのテストベンチ、書いてみた。

#仕組み

8bitデータをclkを数えて、serialで送る。
serialをclkで数えて8bitデータを得る。

#サンプルコード


```
`timescale 1ns / 1ps

module UART_TX(input clk, input reset_n, input active, input [7:0] send_data, output reg UART_TXD = 1);
	parameter rate_div = 5208;
	reg [15:0] cnt_p;
	reg [15:0] cnt_n;
	reg out_p;
	reg out_n;
	reg [4:0] state;
	assign uart_tx_clk = out_p ^ out_n;
	initial
	begin
		cnt_p = 16'd1;
		cnt_n = 16'd1;
		out_p = 0;
		out_n = 0;
	end
	always @(posedge clk)
	begin
		cnt_p <= cnt_n + 16'd1;
		if (cnt_n == rate_div)
		begin
			cnt_p <= 16'd1;
			out_p <= ~out_p;
		end
	end
	always @(negedge clk)
	begin
		cnt_n <= cnt_p + 16'd1;
		if (cnt_p == rate_div)
		begin
			cnt_n <= 16'd1;
			out_n <= ~out_n;
		end
	end
	initial
	begin
		state = 0;
		UART_TXD = 1;
	end
	always @(posedge uart_tx_clk or negedge reset_n)
	begin
		if (!reset_n)
		begin
			state <= 0;
			UART_TXD <= 1;
		end
		else
		begin
			if (!active && state == 0)
			begin
				state <= 1;
			end
			else if (state != 0)
			begin
				if (state == 1 && active)
				begin
					state <= 1;
				end
				else
				begin
					state <= state + 1;
					if (state == 2)
					begin
						UART_TXD <= 0;
					end
					else if (state > 2 && state <= 10)
					begin
						UART_TXD <= send_data[state - 3];
					end
					else if (state == 11)
					begin
						state <= 0;
						UART_TXD <= 1;
					end
				end
			end
		end
	end
endmodule


module UART_RX(input clk, input reset_n, input UART_RXD, output reg [7:0] get_data);
	reg [15:0] cnt_p;
	reg [15:0] cnt_n;
	reg out_p;
	reg out_n;
	reg [4:0] state;
	reg [2:0] clk_cnt;
	reg [2:0] get_startbit;
	parameter rate_div = 1302;
	assign uart_rx_clk = out_p ^ out_n;
	initial
	begin
		cnt_p = 16'd1;
		cnt_n = 16'd1;
		out_p = 0;
		out_n = 0;
	end
	always@(posedge clk)
	begin
		cnt_p <= cnt_n + 16'd1;
		if (cnt_n == rate_div)
		begin
			cnt_p <= 16'd1;
			out_p <= ~out_p;
		end
	end
	always@(negedge clk)
	begin
		cnt_n <= cnt_p + 16'd1;
		if (cnt_p == rate_div)
		begin
			cnt_n <= 16'd1;
			out_n <= ~out_n;
		end
	end
	initial
	begin
		get_data = '0;
		state = '0;
		clk_cnt = '0;
		get_startbit = '1;
	end
	always@(posedge uart_rx_clk)
	begin
		if (!reset_n)
		begin
			state <= 0;
			get_data <= 0;
			clk_cnt <= 0;
			get_startbit <= 1;
		end
		else
		begin
			get_startbit <= {get_startbit[1:0], UART_RXD};
			if (state == 0)
			begin
				if (get_startbit == 3'b000)
				begin
					state <= 5'd1;
				end
			end
			else if (state <= 5'd8)
			begin
				if (clk_cnt == 3'd3)
				begin
					state <= state + 5'd1;
					clk_cnt <= 0;
					get_data[state - 1] <= UART_RXD;
				end
				else
				begin
					clk_cnt <= clk_cnt + 1;
				end
			end
			else if (state == 5'd9)
			begin
				if (clk_cnt == 3'd3)
				begin
					state <= 0;
					clk_cnt <= 0;
				end
				else
				begin
					clk_cnt <= clk_cnt + 1;
				end
			end
		end
	end
endmodule

module test();
	reg clk;
	reg reset_n;
	reg active;
	reg [7:0] send_data;
	wire [7:0] get_data;
	wire bus;
	UART_TX tx(.clk(clk), .reset_n(reset_n), .active(active), .send_data(send_data), .UART_TXD(bus));
	UART_RX rx(.clk(clk), .reset_n(reset_n), .UART_RXD(bus), .get_data(get_data));
	initial
	begin
		clk = 0;
		reset_n = 1;
		active = 1;
		#10000
			reset_n = 0;
		#10000
			reset_n = 1;
		#10000
			send_data = 8'h55;
		#10000
			active = 0;
		#900000
			$finish;
	end
	always
	begin
		#5
			clk = 1;
		#5
			clk = 0;
	end
	initial
	begin
		$dumpfile("test.vcd");
		$dumpvars(0, tx);
		$display("send     s get");
		$monitor("%b %b %b", send_data, bus, get_data);
	end
endmodule


```

#結果


```

send     s get
xxxxxxxx 1 00000000
01010101 1 00000000
01010101 0 00000000
01010101 1 00000000
01010101 1 00000001
01010101 0 00000001
01010101 1 00000001
01010101 1 00000101
01010101 0 00000101
01010101 1 00000101
01010101 1 00010101
01010101 0 00010101
01010101 1 00010101
01010101 1 01010101
01010101 0 01010101
01010101 1 01010101
01010101 0 01010101
01010101 1 01010101
01010101 0 01010101


```


以上。