В этой статье я постараюсь рассказать про счетчики, про их описание на Verilog и их схемотехническое представление в RTLViever.
Счетчики широко применяются везде, где нужно посчитать число некоторых событий, да и не только для этого 
Двоичный счетчик.
Вот это просто двоичный счетчик. На входе данных группы триггеров стоит сумматор. Одно из слагаемых для сумматора - это предыдущее значение счетчика, а второе слагаемое - константа "единица".
reg [3:0]counter;
always @(posedge clk)
counter <= counter + 1'd1;
Вот представление этого счетчика в RTLViewer:

К сожалению симулировать такой счетчик не получится, так как симулятору не известно начальное значение регистров counter[3:0], значит он не сможет вычислить и все последующие значения счетчика. Чтобы провести симуляцию нам нужен двоичный счетчик с ассинхронным сбросом.
Двоичный счетчик с асинхронным сбросом.
reg [3:0]counter;
always @(posedge clk or posedge reset)
if(reset)
counter <= 4'd0;
else
counter <= counter + 1'd1;
Вот его схемотехническое представление в RTLViewer:

И вот его временная диаграмма:

Видно, что по фронту тактовой частоты в регистры счетчика будет записываться очередное значение, на единицу большее, чем предыдущее. Если в коде Verilog использовать минус, вместо плюса, то счетчик будет считать в обратную сторону.
Еще раз подчеркну, что ассинхронный сброс или установка как правило используются только в самом начале работы устройства.
Двоичный счетчик с синхронным сбросом.
Здесь обнуление регистров счетчика происходит по фронту тактовой частоты. В схеме появляется мультиплексор, который выбирает для записи в регистры счетчика либо следующее значение, либо ноль.
always @(posedge clk)
if(reset)
counter <= 4'd0;
else
counter <= counter + 1'd1;
Вот представление в RTL:

И его временная диаграмма:

Счетчик с асинхронным сбросом и входом разрешения и сигналом загрузки.
Чтобы как-то разнообразить описание счетчиков я решил в этом примере дать более "осмысленные" имена сигналам. Представим себе, что мы разрабатываем свой процессор:
- В процессоре есть указатель на исполняемую инструкцию instr_ptr[15:0].
- После сброса системы по сигналу reset этот указатель instr_ptr устанавливается на инструкцию по адресу ноль.
- С каждым тактом исполнение программы движется вперед - значение instr_ptr увеличивается и каждый раз выбирается следующая команда.
- Предположим, что некоторые инструкции исполняются дольше других. Это могут быть какие нибудь сложные команды типа умножения или деления. В этом случае АЛУ процессора (арифметико-логическое устройство) выдает нам сигнал cpu_wait вставляя такты ожидания. В эти такты ожидания instr_ptr не изменяется.
- Если же в какой-то момент времени дешифратор команд увидит команду безусловного перехода (jmp) или условного перехода (jz, jnz, jc и т.д.) и нужно перейти на другой адрес, то нам приходит сигнал branch_cond и в счетчик команд загружается адрес перехода branch_addr.
Вот так это все может быть записано на Verilog:
always @(posedge clk or posedge reset)
begin
if(reset)
instr_ptr <= 16'd0;
else
if(~cpu_wait)
begin
if(branch_cond)
instr_ptr <= branch_addr;
else
instr_ptr <= instr_ptr + 1'd1;
end
end
Давайте рассмотрим, что представляет из себя этот код в RTLViewer:

А вот временная диаграмма:

На этой диаграмме, как пример, видно такт ожидания на инструкции процессора по адресу 3 и переход с адреса 6 на адрес 35.
Еще счетчики могут быть не только двоичными. Вот, например:
Счетчик по модулю 10.
В этом примере максимальное число в регистре счетчика - это девять. Сигнал cout активен в этот последний такт счета. Следующий такт записывает в регистр ноль. Всего тактов, включая нулевой, получается десять. Отсюда и название - по модулю 10.
Понятно, что аналогично можно строить счетчики по любому модулю.
wire cout;
reg [3:0]counter;
always @(posedge clk or posedge reset)
begin
if(reset)
counter <= 4'd0;
else
if(counter==4'd9)
counter <= 4'b0;
else
counter <= counter + 1'd1;
end
assign cout = (counter==4'd9);
В представлении RTL видно, что кроме собственно регистра у нас есть еще сумматор и компаратор. Сумматор подготавливает для записи следующее значение счетчика, то есть counter+1. Компаратор сравнивает текущее значение счетчика с последним в последовательности (у нас это число 9).

Считает эта схема вот так:

Сигнал cout удобно использовать, например, для каскадного соединения счетчиков как сигнал разрешения счета для старших десятичных разрядов.
В следующей статье я хотел рассказать про сдвиговые регистры.

пришлите Ваш код на почту info
Удалите тогда лишний комментарий.
module keycnt(
input wire key0,
input wire key1,
output wire led0
);
wire clk;
assign clk=key0;
reg [3:0]counter;
assign led0=counter[3];
always @(posedge clk)
counter
Вот код:
module keycnt(
input wire key0,
//input wire key1,
output wire led0
);
wire clk;
assign clk=key0;
reg [3:0]counter;
assign led0=counter[3];
always @(posedge clk)
counter
у стандартного триггера есть только один вход чувствительный к фронту, поэтому не получается написать то, что вы хотите.
Вообще, по хорошему, такие конструкции как вы хотите лучше и не пытаться делать. В идеале схема тактируется только одной тактовой частотой. В этом случае все будет работать понятно и предсказуемо.
Внешние входные воздействия лучше сразу оцифровать тактовой частотой и потом выделять фронты примерно вот так: marsohod.org/.../...
Не поймите меня неправильно, но, я считаю, что если человек занялся изучением программируемой логики, то он достаточно хорошо разбирается в "обычной" цифровой технике, следовательно, для Вас не должно быть проблемой самостоятельно написать то, что Вы перечислили, опираясь на этот пример.
Дополните, пожалуйста, вычитающими, реверсивными и многоразрядными (десятичные), формирование сигнала cin для старших разрядов.
Скачал Ваши уроки по Verilog - осилил с пятого раза, вроде как разъясняется, споткнулся на следующем.
На странице 27 Вы объясняете блокирующие и неблокирующие присваивания. Вроде как понятно. НО!
На странице 28 Вы используете неблокирующее присваивание
Спасибо!
А я могу объявить reg[1000:0]?
объявление "reg [3:0]counter" обозначает 4х битный регистр. Биты нумеруются от 0 до 3 включительно.
Значит максимальное хранимое число будет 15.
В двоичном виде это 4'b1111 или в десятичном 4'd15 или в шестнадцатеричн ом виде 4'hf
странно - у меня все видно..
Вы используете переменную для хранения
counter типа reg[3:0].
В данной переменной мы можем хранить 2^3=8.
Какова наибольшая размерность reg может быть объявлена?