Skip to content

Instantly share code, notes, and snippets.

@C47D
Last active July 8, 2017 07:01
Show Gist options
  • Save C47D/847c5f4f66a59f74999fd199a25595d3 to your computer and use it in GitHub Desktop.
Save C47D/847c5f4f66a59f74999fd199a25595d3 to your computer and use it in GitHub Desktop.
generic gray code generator written in verilog.
// file: gray.pcf
set_io clk_out 95
set_io gray_leds[3] 96
set_io gray_leds[2] 97
set_io gray_leds[1] 98
set_io gray_leds[0] 99
set_io clk 21
set_io rst 112
// synthesis with yosys for ice40hx1k device (iceStick)
// $ yosys -p "synth_ice40 -blif gray.blif" gray.v gray_code_generator.v binary_counter.v clk_divider.v
// $ arachne-pnr -d 1k -p gray.pcf gray.blif -o gray.asc
// $ icepack gray.asc gray.bin
// program the icestick
// $ iceprog gray.bin
// time analysis
// $ icetime -p gray.pcf -d hx1k gray.asc
// file: gray.v
`timescale 1ns / 1ps
`default_nettype none
module top
(
input clk,
input rst,
output [3:0] gray_leds,
output clk_out
);
wire clk_1hz;
assign clk_out = clk_1hz;
localparam CLK_DIVISOR = 6_000_000;
localparam GRAY_CODE_BITS = 4;
clk_divider #(.DIVIDER(CLK_DIVISOR))
div(
.clk(clk),
.rst(rst),
.clk_o(clk_1hz)
);
gray_code_counter #(.BITS(GRAY_CODE_BITS))
g_counter (
.clk(clk_1hz),
.rst(rst),
.gray_code(gray_leds)
);
endmodule
// 4bits Gray count:
// 0000
// 0001
// 0011
// 0010
// 0110
// 0111
// 0101
// 0100
// 1100
// 1101
// 1111
// 1110
// 1010
// 1011
// 1001
// 1000
// and back to 0000
// file: gray_code_generator.v
module gray_code_counter #(
parameter BITS = 2
)(
input clk,
input rst,
output [BITS-1:0] gray_code
);
wire [BITS-1:0] bin_cnt_output;
binary_counter #(.BITS(BITS))
b_counter (
.clk(clk),
.rst(rst),
.cnt(bin_cnt_output)
);
assign gray_code = bin_cnt_output ^ bin_cnt_output[BITS-1:1];
endmodule
// file: binary_counter.v
module binary_counter #(
parameter BITS = 2
)(
input clk,
input rst,
output reg [BITS-1:0] cnt
);
always @ (posedge clk) begin
if ( rst ) cnt <= 0;
else cnt <= cnt + 1;
end
endmodule
// file: clk_divider.v
module clk_divider #(
parameter DIVIDER = 6_000_000
)(
input clk,
input rst,
output reg clk_o
);
reg [$clog2(DIVIDER)-1:0] cnt = 0;
always @(posedge clk) begin
if ( rst ) begin
cnt <= 0;
clk_o <= 0;
end else begin
if (cnt == DIVIDER) begin
clk_o <= ~clk_o;
cnt <= 0;
end
else cnt <= cnt + 1;
end
end
endmodule
@C47D
Copy link
Author

C47D commented Jul 7, 2017

rev 3: Remove a reg named rst on the clk_divider module, use the rst_n input instead.
rev 4: Fix the rst_n signal on the clk_divider, make sure it's active low.
rev 5: Remove redundant comments.
rev 6: Fix indentation and code style.
rev 7: Change the polarity of the rst signal, changed from active low to active high, the FFs reset signal on the iCE40 devices are active high.
rev 8: Fixed typo on always block of the clk_divider module (from rst_n to rst).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment