From d578aab00d511d4254ec200558bf2f17db481b73 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 30 Jun 2007 17:45:54 +0200 Subject: Added hdlcounter for CPLD. Verilog source files and test cases. --- digital/asserv/src/hdlcounter/Makefile | 25 ++++ digital/asserv/src/hdlcounter/README | 30 +++++ digital/asserv/src/hdlcounter/common.v | 85 ++++++++++++ digital/asserv/src/hdlcounter/counter_top.v | 58 ++++++++ digital/asserv/src/hdlcounter/input_latch.v | 46 +++++++ digital/asserv/src/hdlcounter/noise_filter.v | 56 ++++++++ digital/asserv/src/hdlcounter/quad_decoder_div4.v | 75 +++++++++++ digital/asserv/src/hdlcounter/quad_decoder_full.v | 71 ++++++++++ digital/asserv/src/hdlcounter/test_counter_top.v | 147 +++++++++++++++++++++ .../asserv/src/hdlcounter/test_counter_top.wave | 18 +++ digital/asserv/src/hdlcounter/test_input_latch.v | 100 ++++++++++++++ .../asserv/src/hdlcounter/test_input_latch.wave | 14 ++ digital/asserv/src/hdlcounter/test_noise_filter.v | 111 ++++++++++++++++ .../asserv/src/hdlcounter/test_noise_filter.wave | 10 ++ digital/asserv/src/hdlcounter/test_quad_decoder.v | 95 +++++++++++++ .../asserv/src/hdlcounter/test_quad_decoder.wave | 17 +++ .../asserv/src/hdlcounter/test_updown_counter.v | 82 ++++++++++++ digital/asserv/src/hdlcounter/updown_counter.v | 55 ++++++++ 18 files changed, 1095 insertions(+) create mode 100644 digital/asserv/src/hdlcounter/Makefile create mode 100644 digital/asserv/src/hdlcounter/README create mode 100644 digital/asserv/src/hdlcounter/common.v create mode 100644 digital/asserv/src/hdlcounter/counter_top.v create mode 100644 digital/asserv/src/hdlcounter/input_latch.v create mode 100644 digital/asserv/src/hdlcounter/noise_filter.v create mode 100644 digital/asserv/src/hdlcounter/quad_decoder_div4.v create mode 100644 digital/asserv/src/hdlcounter/quad_decoder_full.v create mode 100644 digital/asserv/src/hdlcounter/test_counter_top.v create mode 100644 digital/asserv/src/hdlcounter/test_counter_top.wave create mode 100644 digital/asserv/src/hdlcounter/test_input_latch.v create mode 100644 digital/asserv/src/hdlcounter/test_input_latch.wave create mode 100644 digital/asserv/src/hdlcounter/test_noise_filter.v create mode 100644 digital/asserv/src/hdlcounter/test_noise_filter.wave create mode 100644 digital/asserv/src/hdlcounter/test_quad_decoder.v create mode 100644 digital/asserv/src/hdlcounter/test_quad_decoder.wave create mode 100644 digital/asserv/src/hdlcounter/test_updown_counter.v create mode 100644 digital/asserv/src/hdlcounter/updown_counter.v (limited to 'digital') diff --git a/digital/asserv/src/hdlcounter/Makefile b/digital/asserv/src/hdlcounter/Makefile new file mode 100644 index 00000000..13de43bb --- /dev/null +++ b/digital/asserv/src/hdlcounter/Makefile @@ -0,0 +1,25 @@ +EXEC = test_input_latch test_noise_filter test_updown_counter \ + test_quad_decoder test_counter_top + +test_input_latch_SOURCES = test_input_latch.v input_latch.v +test_noise_filter_SOURCES = test_noise_filter.v noise_filter.v +test_updown_counter_SOURCES = test_updown_counter.v updown_counter.v +test_quad_decoder_SOURCES = test_quad_decoder.v quad_decoder_div4.v \ + quad_decoder_full.v +test_counter_top_SOURCES = test_counter_top.v counter_top.v input_latch.v \ + noise_filter.v quad_decoder_div4.v \ + quad_decoder_full.v + +all: $(EXEC:%=%.vcd) + +%.vcd: % + vvp $< + +define EXEC_TEMPLATE +$1: $$($1_SOURCES) common.v + iverilog -Wall -o $$@ $$($1_SOURCES) +endef +$(foreach exec,$(EXEC),$(eval $(call EXEC_TEMPLATE,$(exec)))) + +clean: + rm -f $(EXEC) $(EXEC:%=%.vcd) diff --git a/digital/asserv/src/hdlcounter/README b/digital/asserv/src/hdlcounter/README new file mode 100644 index 00000000..b91a1eca --- /dev/null +++ b/digital/asserv/src/hdlcounter/README @@ -0,0 +1,30 @@ +hdlcounter - Incremental encoder counter on programmable logic. + +Microcontrolers often have counter inputs, but they do not have any dedicated +inputs for incremental encoders which are therefore tendious to decode without +any external logic. + +The hdlcounter implements this decoder in a CPLD or FPGA chip, allowing +integration of several counter in one chip depending on the number of flip +flop available. + + +Copyright (C) 2007 Nicolas Schodet + +Robot APB Team 2008. + Web: http://apbteam.org/ + Email: team AT apbteam DOT org + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. diff --git a/digital/asserv/src/hdlcounter/common.v b/digital/asserv/src/hdlcounter/common.v new file mode 100644 index 00000000..bfa6087c --- /dev/null +++ b/digital/asserv/src/hdlcounter/common.v @@ -0,0 +1,85 @@ +// common.v - Common useful test utilities. +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} + + initial begin + $timeformat (-9, 0, "", 3); + end + + task assert; + input a, b; + begin + if (a != b) begin + $display ("%t: assertion failled ", $time, a, " != ", b); + if (!debug) + $finish; + end + else if (debug) + $display ("%t: assertion ok ", $time, a, " == ", b); + end + endtask + + // How to make this works for any size? + task assertv7; + parameter size = 7; + input [size-1:0] a, b; + begin + if (a != b) begin + $display ("%t: assertion failled ", $time, a, " != ", b); + if (!debug) + $finish; + end + else if (debug) + $display ("%t: assertion ok ", $time, a, " == ", b); + end + endtask + + task assertv8; + parameter size = 8; + input [size-1:0] a, b; + begin + if (a != b) begin + $display ("%t: assertion failled ", $time, a, " != ", b); + if (!debug) + $finish; + end + else if (debug) + $display ("%t: assertion ok ", $time, a, " == ", b); + end + endtask + + task assertv12; + parameter size = 12; + input [size-1:0] a, b; + begin + if (a != b) begin + $display ("%t: assertion failled ", $time, a, " != ", b); + if (!debug) + $finish; + end + else if (debug) + $display ("%t: assertion ok ", $time, a, " == ", b); + end + endtask + diff --git a/digital/asserv/src/hdlcounter/counter_top.v b/digital/asserv/src/hdlcounter/counter_top.v new file mode 100644 index 00000000..fa1b737c --- /dev/null +++ b/digital/asserv/src/hdlcounter/counter_top.v @@ -0,0 +1,58 @@ +// counter_top.v +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +module counter_top(clk, rst, q0, q1, q2, q3, oe, sel, count); + parameter size = 8; + input clk; + input rst; + input [1:0] q0, q1, q2, q3; + input oe; + input [1:0] sel; + output [size-1:0] count; + + wire [1:0] qf0, qf1, qf2, qf3; + wire [size-1:0] count0, count1, count2, count3; + + noise_filter f0[1:0] (clk, rst, q0, qf0); + quad_decoder_div4 qd0 (clk, rst, qf0, count0); + + noise_filter f1[1:0] (clk, rst, q1, qf1); + quad_decoder_div4 qd1 (clk, rst, qf1, count1); + + input_latch f2[1:0] (clk, rst, q2, qf2); + quad_decoder_full qd2 (clk, rst, qf2, count2); + + input_latch f3[1:0] (clk, rst, q3, qf3); + quad_decoder_full qd3 (clk, rst, qf3, count3); + + assign count = + !oe ? 8'bz : + sel == 0 ? count0 : + sel == 1 ? count1 : + sel == 2 ? count2 : + count3; + +endmodule diff --git a/digital/asserv/src/hdlcounter/input_latch.v b/digital/asserv/src/hdlcounter/input_latch.v new file mode 100644 index 00000000..5eb059d4 --- /dev/null +++ b/digital/asserv/src/hdlcounter/input_latch.v @@ -0,0 +1,46 @@ +// input_latch.v - Input latch to protect from input change near clock edge. +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +// Input should be latched at clock rising edge in one and only one flip-flop. +// If this latch is not done, two flip-flops connected to the input might +// receive a different value if the input switch near the clock rising edge. + +module input_latch(clk, rst, q, ql); + input clk; + input rst; + input q; + output ql; + + reg ql; + + always @(posedge clk or negedge rst) begin + if (!rst) + ql <= 0; + else + ql <= q; + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/noise_filter.v b/digital/asserv/src/hdlcounter/noise_filter.v new file mode 100644 index 00000000..7de58ab5 --- /dev/null +++ b/digital/asserv/src/hdlcounter/noise_filter.v @@ -0,0 +1,56 @@ +// noise_filter.v - Low pass noise filter. +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +// To switch output, input should be stable for a number of cycle. This will +// filter small spikes. As input is latched in only one flip-flop, this +// module can be used directly on an input pin. See input_latch.v for more +// details. + +module noise_filter(clk, rst, q, qf); + parameter size = 3; + input clk; + input rst; + input q; + output qf; + + reg qf; + reg [size-1:0] hist; + + always @(posedge clk or negedge rst) begin + if (!rst) begin + qf <= 0; + hist <= 0; + end + else begin + if (&hist) + qf <= 1; + else if (~|hist) + qf <= 0; + hist <= { hist[size-2:0], q }; + end + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/quad_decoder_div4.v b/digital/asserv/src/hdlcounter/quad_decoder_div4.v new file mode 100644 index 00000000..5021141b --- /dev/null +++ b/digital/asserv/src/hdlcounter/quad_decoder_div4.v @@ -0,0 +1,75 @@ +// quad_decoder_div4.v - One out of four quadrature signal decoder. +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +// Here is the signal: +// +// q[0]: _____------______------______---- +// q[1]: --______------______------______- +// ^ ^ ^ +// +// Counting is always done at the same point in order not to count false +// steps. When the encoder signal is going forward (to the right on the +// drawing), counting is done on the rising edge of q[1]. When the encoder is +// going backward, counting is done on the falling edge of q[1]. Actually, +// this is the same edge, but seen from an different point of view (forward or +// backward). Counting is only done when q[0] is low. +// +// Timing constraints: one state duration should not be shorter than one clock +// period, except when changing direction. In actual device, of course +// a security factor should be added, beware of optical encoders tolerance. + +module quad_decoder_div4(clk, rst, q, count); + parameter bits = 8; + input clk; + input rst; + input [1:0] q; + output [bits-1:0] count; + + reg [bits-1:0] count; + // Old input, only one channel to remember. + reg zq1; + + always @(posedge clk or negedge rst) begin + if (!rst) begin + count <= 0; + zq1 <= 0; + end + else begin + case ({ q[0], zq1, q[1] }) + // 1 to 0 transition on q[1], when q[0] is 0. + 2'b0_1_0: + count <= count + 1; + // 0 to 1 transition on q[1], when q[0] is 0. + 2'b0_0_1: + count <= count - 1; + default: + count <= count; + endcase + zq1 <= q[1]; + end + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/quad_decoder_full.v b/digital/asserv/src/hdlcounter/quad_decoder_full.v new file mode 100644 index 00000000..cdad0161 --- /dev/null +++ b/digital/asserv/src/hdlcounter/quad_decoder_full.v @@ -0,0 +1,71 @@ +// quad_decoder_full.v - Full quadrature signal decoder. +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +// Here is the signal: +// +// q[0]: _____------______------______---- +// q[1]: --______------______------______- +// ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ +// +// Counting is done on any rising or falling edge. The encoder can be seen as +// a absolute grey code encoder with two bits and four position. When one bit +// change, it is easy to know what is the direction of the encoder knowing the +// old state. +// +// Timing constraints: one state duration should not be shorter than one clock +// period, except when changing direction. In actual device, of course +// a security factor should be added, beware of optical encoders tolerance. + +module quad_decoder_full(clk, rst, q, count); + parameter bits = 8; + input clk; + input rst; + input [1:0] q; + output [bits-1:0] count; + + reg [bits-1:0] count; + // Old input. + reg [1:0] zq; + + always @(posedge clk or negedge rst) begin + if (!rst) begin + count <= 0; + zq <= 0; + end + else begin + case ({ zq, q }) + 4'b00_01, 4'b01_11, 4'b11_10, 4'b10_00: + count <= count + 1; + 4'b01_00, 4'b11_01, 4'b10_11, 4'b00_10: + count <= count - 1; + default: + count <= count; + endcase + zq <= q; + end + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/test_counter_top.v b/digital/asserv/src/hdlcounter/test_counter_top.v new file mode 100644 index 00000000..b0ff69a1 --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_counter_top.v @@ -0,0 +1,147 @@ +// test_counter_top.v +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +module test_counter_top(); + parameter debug = 0; + parameter nc = 4; + reg clk; + reg rst; + reg [1:0] q[0:nc-1]; + reg oe; + reg [1:0] sel; + wire [7:0] countout; + + `include "common.v" + + // Clock generator. + always #5 clk <= !clk; + + // Counter top setup. + wire [0:nc-1] quad_full = 4'b0011; + reg [31:0] filter_size[0:nc-1]; + parameter max_filter = 5; + initial begin + filter_size[0] = 4; + filter_size[1] = 4; + filter_size[2] = 1; + filter_size[3] = 1; + end + + // Instantiation. + counter_top uut (clk, rst, q[0], q[1], q[2], q[3], oe, sel, countout); + + // The count variable is the true encoder position, multiplied by 32, + // which is more than one encoder minimum period with a noise filter of + // size 3 to satisfy decoding logic timing constraints. + integer i; + integer n[0:nc-1], diff[0:nc-1]; + reg [31:0] count[0:nc-1]; + reg [27:0] countdiv32[0:nc-1]; + reg [1:0] q_nat; + + wire [27:0] countdiv32_0 = countdiv32[0], + countdiv32_1 = countdiv32[1], + countdiv32_2 = countdiv32[2], + countdiv32_3 = countdiv32[3]; + + initial begin + $dumpfile ("test_counter_top.vcd"); + $dumpvars (1, clk, rst, countdiv32_0, countdiv32_1, countdiv32_2, + countdiv32_3, uut, oe, sel, countout, countassert, a); + clk <= 1; + rst <= 0; + for (i = 0; i < nc; i = i + 1) begin + q[i] <= 0; + n[i] = 0; + count[i] = 0; + countdiv32[i] <= 0; + end + #2 rst <= 1; + #6 // 2 ns before clock edge. + repeat (debug ? 5000 : 100000) begin + #1 + for (i = 0; i < nc; i = i + 1) begin + if (n[i] == 0) begin + n[i] = $random; + n[i] = n[i] > 0 ? n[i] : -n[i]; + n[i] = n[i] % 50 + 1; + diff[i] = $random % 2; + if (debug) + $display ("%t.%1d: n %1d diff %1d", $time, i, n[i], diff[i]); + end + n[i] = n[i] - 1; + count[i] = count[i] + diff[i]; + q_nat = (count[i] / 32) % 4; + countdiv32[i] <= count[i] / 32; + q[i] <= { q_nat[1], q_nat[0] ^ q_nat[1] }; + end + end + $finish; + end + + // This simulates a two dimension array. + reg [27:0] countdiv32_smp[0:nc*max_filter-1]; + integer j; + reg [27:0] countassert; + reg [7:0] countassert8; + + wire [27:0] a = countdiv32_smp[0*max_filter+4]; + + initial begin + forever begin + @(posedge clk) + // Sample countdiv32 at rising edge. + for (j = 1; j < nc*max_filter; j = j + 1) + countdiv32_smp[j] <= countdiv32_smp[j-1]; + for (j = 0; j < nc; j = j + 1) + countdiv32_smp[j * max_filter] <= countdiv32[j]; + @(negedge clk) + // Check result *after* rising edge. + if (oe) begin + countassert = countdiv32_smp[sel*max_filter + filter_size[sel]]; + countassert8 = quad_full[sel] ? countassert[7:0] : countassert[9:2]; + // If equiped with a noise filter, accept a difference of 1. + // This is more difficult to find the exact expected value (I + // mean, without copy-paste the unit under test verbatim). + if (filter_size[sel] > 1) + assert ((countassert8 - countout) | 1, 1); + else + assertv8 (countassert8, countout); + end + else begin + assertv8 (8'bz, countout); + end + // Prepare next check. + if (($mti_random & 6'b111111) == 0) + oe = 0; + else begin + oe = 1; + sel = $random & 2'b11; + end + end + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/test_counter_top.wave b/digital/asserv/src/hdlcounter/test_counter_top.wave new file mode 100644 index 00000000..338660ef --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_counter_top.wave @@ -0,0 +1,18 @@ +*-17,989300 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +@28 +test_counter_top.clk +test_counter_top.rst +@420 +test_counter_top.countdiv32_0[27:0] +test_counter_top.countdiv32_1[27:0] +test_counter_top.countdiv32_2[27:0] +test_counter_top.countdiv32_3[27:0] +@28 +test_counter_top.oe +test_counter_top.sel[1:0] +@22 +test_counter_top.countout[7:0] +test_counter_top.uut.count0[7:0] +test_counter_top.uut.count1[7:0] +test_counter_top.uut.count2[7:0] +test_counter_top.uut.count3[7:0] diff --git a/digital/asserv/src/hdlcounter/test_input_latch.v b/digital/asserv/src/hdlcounter/test_input_latch.v new file mode 100644 index 00000000..744ee09b --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_input_latch.v @@ -0,0 +1,100 @@ +// test_input_latch.v +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +module test_input_latch(); + parameter debug = 0; + reg clk; + reg rst; + reg q; + wire ql; + + `include "common.v" + + // Clock generator. + always #5 clk <= !clk; + + // Instantiation. + input_latch uut (clk, rst, q, ql); + + // This demonstrates what could happen without a latch. The wire qnl1 and + // qnl2 represents the input signal after two different paths in the chip, + // where the qnl2 path is longer. On clock edge, q is sampled, but the + // flip flops are incoherent. + wire qnl1, qnl2; + reg qnlr1, qnlr2; + assign #1 qnl1 = q; + assign #2 qnl2 = ~q; + always @(posedge clk or negedge rst) begin + if (!rst) begin + qnlr1 <= 0; + qnlr2 <= 1; + end + else begin + // Actual equation is qnlr1 = q, qnl1 simulates delay inside the + // chip. + qnlr1 <= qnl1; + // Actual equation is qnlr2 = ~q, qnl2 simulates a longer delay + // inside the chip. + qnlr2 <= qnl2; + end + end + + // Now, with latched input. + wire ql1, ql2; + reg qlr1, qlr2; + assign #1 ql1 = ql; + assign #2 ql2 = ~ql; + always @(posedge clk or negedge rst) begin + if (!rst) begin + qlr1 <= 0; + qlr2 <= 1; + end + else begin + qlr1 <= ql1; + qlr2 <= ql2; + end + end + + initial begin + $dumpfile ("test_input_latch.vcd"); + $dumpvars; + clk <= 1; + rst <= 0; + q <= 0; + #2 rst <= 1; + repeat (15) begin + // One more than clock period to test several switch time. + #11 q <= ~q; + end + $finish; + end + + initial begin + #1 forever + #1 assert (qlr1, ~qlr2); + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/test_input_latch.wave b/digital/asserv/src/hdlcounter/test_input_latch.wave new file mode 100644 index 00000000..50af7fd0 --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_input_latch.wave @@ -0,0 +1,14 @@ +*-15,452410 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +@28 +test_input_latch.clk +test_input_latch.rst +test_input_latch.q +test_input_latch.ql +test_input_latch.ql1 +test_input_latch.ql2 +test_input_latch.qlr1 +test_input_latch.qlr2 +test_input_latch.qnl1 +test_input_latch.qnl2 +test_input_latch.qnlr1 +test_input_latch.qnlr2 diff --git a/digital/asserv/src/hdlcounter/test_noise_filter.v b/digital/asserv/src/hdlcounter/test_noise_filter.v new file mode 100644 index 00000000..05737845 --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_noise_filter.v @@ -0,0 +1,111 @@ +// test_noise_filter.v +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +module test_noise_filter(); + parameter debug = 0; + reg clk; + reg rst; + reg q; + wire ql2, ql3, ql5; + reg zql2, zql3, zql5; + + `include "common.v" + + // Clock generator. + always #5 clk <= !clk; + + // Instantiation. + noise_filter #(2) uut_size2 (clk, rst, q, ql2); + noise_filter uut_size3 (clk, rst, q, ql3); + noise_filter #(5) uut_size5 (clk, rst, q, ql5); + + integer i; + time r, to; + + initial begin + $dumpfile ("test_noise_filter.vcd"); + $dumpvars; + clk <= 1; + rst <= 0; + q <= 0; + zql2 <= 0; zql3 <= 0; zql5 <= 0; + #2 rst <= 1; + #6 // 2 ns before clock edge. + // Toggle q, then draw a random delay. Check that filtered output + // switch at the right time. + q <= ~q; + repeat (1000) begin + #1 r = $random; + r = r % 8 + 1; + to = (r * 10) - 1; + if (debug) + $display ("%t: rand %1d", $time, r); + fork + // This checks the filtered output is unchanged before the + // right clock edge, and changed after, or not changed at all + // when the delay is too small. + // Did not found an easy way to factorise this (tasks sample + // input at invocation): + begin + if (r > 2) begin + #(2 * 10) assert (ql2, zql2); + #2 assert (ql2, q); + end + else + #(to) assert (ql2, zql2); + if (r >= 2) + zql2 <= q; + end + begin + if (r > 3) begin + #(3 * 10) assert (ql3, zql3); + #2 assert (ql3, q); + end + else + #(to) assert (ql3, zql3); + if (r >= 3) + zql3 <= q; + end + begin + if (r > 5) begin + #(5 * 10) assert (ql5, zql5); + #2 assert (ql5, q); + end + else + #(to) assert (ql5, zql5); + if (r >= 5) + zql5 <= q; + end + begin + #(to) q <= ~q; + end + join + r = 0; + end + $finish; + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/test_noise_filter.wave b/digital/asserv/src/hdlcounter/test_noise_filter.wave new file mode 100644 index 00000000..ca69157e --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_noise_filter.wave @@ -0,0 +1,10 @@ +*-16,630791 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +@28 +test_noise_filter.clk +test_noise_filter.rst +test_noise_filter.q +test_noise_filter.ql2 +test_noise_filter.ql3 +test_noise_filter.ql5 +@25 +test_noise_filter.r[63:0] diff --git a/digital/asserv/src/hdlcounter/test_quad_decoder.v b/digital/asserv/src/hdlcounter/test_quad_decoder.v new file mode 100644 index 00000000..8e0b0c23 --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_quad_decoder.v @@ -0,0 +1,95 @@ +// test_quad_decoder.v +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +module test_quad_decoder(); + parameter debug = 0; + reg clk; + reg rst; + reg [1:0] q; + wire [7:0] count_div4, count_full; + + `include "common.v" + + // Clock generator. + always #5 clk <= !clk; + + // Instantiation. + quad_decoder_div4 uut_div4 (clk, rst, q, count_div4); + quad_decoder_full uut_full (clk, rst, q, count_full); + + // The count variable is the true encoder position, multiplied by 16, + // which is more than one clock period to satisfy decoding logic timing + // constraints. + integer n, diff; + reg [31:0] count; + reg [27:0] countdiv16; + reg [1:0] q_nat; + + initial begin + $dumpfile ("test_quad_decoder.vcd"); + $dumpvars; + clk <= 1; + rst <= 0; + q <= 0; + n = 0; + count = 0; + countdiv16 <= 0; + #2 rst <= 1; + #6 // 2 ns before clock edge. + repeat (debug ? 1000 : 100000) begin + #1 + if (n == 0) begin + n = $random; + n = n > 0 ? n : -n; + n = n % 50 + 1; + diff = $random % 2; + if (debug) + $display ("%t: n %1d diff %1d", $time, n, diff); + end + n = n - 1; + count = count + diff; + q_nat = (count / 16) % 4; + countdiv16 <= count / 16; + q <= { q_nat[1], q_nat[0] ^ q_nat[1] }; + end + $finish; + end + + reg [27:0] countdiv16_smp; + + initial begin + forever begin + @(posedge clk) + // Sample countdiv16 at rising edge. + countdiv16_smp <= countdiv16; + @(negedge clk) + // Check result *after* rising edge. + assertv8 (countdiv16_smp[7:0], count_full); + assertv8 (countdiv16_smp[9:2], count_div4); + end + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/test_quad_decoder.wave b/digital/asserv/src/hdlcounter/test_quad_decoder.wave new file mode 100644 index 00000000..01ae64b9 --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_quad_decoder.wave @@ -0,0 +1,17 @@ +*-14,155944 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +@28 +test_quad_decoder.clk +test_quad_decoder.rst +@24 +test_quad_decoder.n[31:0] +@420 +test_quad_decoder.diff[31:0] +test_quad_decoder.count[31:0] +test_quad_decoder.countdiv16[27:0] +test_quad_decoder.countdiv16_smp[27:0] +@28 +test_quad_decoder.q_nat[1:0] +test_quad_decoder.q[1:0] +@22 +test_quad_decoder.count_div4[7:0] +test_quad_decoder.count_full[7:0] diff --git a/digital/asserv/src/hdlcounter/test_updown_counter.v b/digital/asserv/src/hdlcounter/test_updown_counter.v new file mode 100644 index 00000000..ebe5d115 --- /dev/null +++ b/digital/asserv/src/hdlcounter/test_updown_counter.v @@ -0,0 +1,82 @@ +// test_updown_counter.v +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +module test_updown_counter(); + parameter debug = 0; + reg clk; + reg rst; + reg [1:0] updown; + wire [7:0] count8; + wire [11:0] count12; + + `include "common.v" + + // Clock generator. + always #5 clk <= !clk; + + // Instantiation. + updown_counter uut_size8 (clk, rst, updown, count8); + updown_counter #(12) uut_size12 (clk, rst, updown, count12); + + integer n, count, diff; + + initial begin + $dumpfile ("test_updown_counter.vcd"); + $dumpvars; + clk <= 1; + rst <= 0; + updown <= 0; + count = 0; + n = 0; + #2 rst <= 1; + repeat (1000) begin + @(negedge clk) + if (n == 0) begin + n = $random; + n = n > 0 ? n : -n; + n = n % 16 + 1; + diff = $random % 2; + if (debug) + $display ("%t: n %1d diff %1d", $time, n, diff); + end + n = n - 1; + count = count + diff; + if (diff > 0) + updown <= 2'b10; + else if (diff < 0) + updown <= 2'b01; + else + updown <= 2'b00; + @(posedge clk) #1 + assertv8 (count[7:0], count8); + assertv12 (count[11:0], count12); + end + if (debug) + $display ("%t: count %1d", $time, count); + $finish; + end + +endmodule diff --git a/digital/asserv/src/hdlcounter/updown_counter.v b/digital/asserv/src/hdlcounter/updown_counter.v new file mode 100644 index 00000000..04f73bbd --- /dev/null +++ b/digital/asserv/src/hdlcounter/updown_counter.v @@ -0,0 +1,55 @@ +// updown_counter.v - Up and down counter. +// hdlcounter - Incremental encoder counter on programmable logic. {{{ +// +// Copyright (C) 2007 Nicolas Schodet +// +// Robot APB Team 2008. +// Web: http://apbteam.org/ +// Email: team AT apbteam DOT org +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// }}} +`timescale 1ns / 1ps + +module updown_counter(clk, rst, updown, counter); + parameter bits = 8; + input clk; + input rst; + // Bit updown[1] is for up and bit updown[0] is for down. + input [1:0] updown; + output [bits-1:0] counter; + + reg [bits-1:0] counter; + + always @(posedge clk or negedge rst) begin + if (!rst) begin + counter <= 0; + end + else begin + case (updown) + 2'b00: + counter <= counter; + 2'b10: + counter <= counter + 1; + 2'b01: + counter <= counter - 1; + // Do not synthesis useless logic, 2'b11 is an undefined case. + default: + counter <= { bits { 1'bX }}; + endcase + end + end +endmodule -- cgit v1.2.3