Muy buen proyecto, ya me habría gustado aprender electrónica digital de una forma tan gráfica y con una FPGA en la mano.Un saludo y mucho ánimo...
--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/98290788-f76a-46b2-8874-913642972905%40googlegroups.com.
--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/a47e060e-b009-4db0-bba0-3123263ce5b3%40googlegroups.com.
Hola,
always @(posedge clk) begin
if (rst==0) begin
q <= 0;
elsif en then
q <= d;
else
q <= q;
end
end

A pesar de que no está muy bien dibujado, se observan varias cuestiones:
Tomando la idea del mensaje de ayer, vamos a replantearlo. El objetivo es dibujarlo lo más sencillo posible, pero completo. Cuanto más simple sea el dibujo, más fácil será describirlo después:


Si
comparas este último diseño con el esquemático de un registro de
desplazamiento
(https://en.wikipedia.org/wiki/File:4-Bit_SIPO_Shift_Register.png),
observarás que diseñar circuitos digitales síncronos es hacer
continuamente shift-registers, con la particularidad de que entre uno y
otro se hace alguna operación, no sólo retener un dato. A eso se le
llama 'pipeline'. No es muy diferente de la cadena de producción en
cualquier nave industrial. Hay diferentes puestos, y la cinta
transportadora va llevando los datos de uno a otro.
PARA NOTA
Con los cambios que hemos visto, podemos imaginar otras soluciones aún más eficientes. Por ejemplo:


--
Has recibido este mensaje porque estás suscrito a un tema del grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este tema, visita https://groups.google.com/d/topic/fpga-wars-explorando-el-lado-libre/77Zw4ayF-DY/unsubscribe.
Para cancelar la suscripción a este grupo y a todos sus temas, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/d633e000-1d75-461d-9395-7dadf4b0b78a%40googlegroups.com.
Tomando la idea del mensaje de ayer, vamos a replantearlo. El objetivo es dibujarlo lo más sencillo posible, pero completo. Cuanto más simple sea el dibujo, más fácil será describirlo después:
PARA NOTA
Con los cambios que hemos visto, podemos imaginar otras soluciones aún más eficientes. Por ejemplo:
Y ya está. Ahora sí que lo dejo ;).
Por lo tanto, cada vez habrá menos aislamiento entre arquitectos de sistema, diseñadores de software embebido y diseñadores de ASICs. Ya que un sólo chip incluye ahora lo que hasta hace unos pocos años era un ordenador entero. Al mismo tiempo, habrá más distancia con respecto a los diseñadores de PCBs, que serán minoría. Esto es porque las frecuencias de reloj a las que pueden trabajar estos dispositivos, las potencias que hay que gestionar y el número de patillas complican notablemente el diseño de los PCBs en sí.
Bueno, en tal caso mi diseño sería el siguiente:


--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/1e374638-188d-4d8d-90e2-df6a78e1acf2%40googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-lib...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
always@(posedge clk) begin if (~rst) r_reg <= 0; else if (en) r_reg <= r_next; else r_reg <= r_reg;
!end
!end
endalways@(r_reg) begin no sé si es correcto
r_next = (r_reg == MAX)? 0 : r_reg + 1;
endassign r_next = (r_reg == MAX)? 0 : r_reg + 1;r_next <= (r_reg == MAX)? 0 : r_reg + 1;always@(posedge clk) begin if (en) r_reg <= r_next; else r_reg <= r_reg;
!end
end
r_next <= ((r_reg == MAX) || ~irst) ? 0 : r_reg + 1assign counter = r_reg;
assign enout = (r_reg == MAX)? 0 : 1;always@(posedge clk) begin if en; r_reg <= r_next; else r_reg <= r_reg; end
end
cmp <= (r_reg == MAX) ? 1 : 0;
r_next <= (cmp | ~irst) ? 0 : r_reg + 1;
assign counter = r_reg;
assign enout = cmp;El modulo del display lo abordaré después, una vez tenga claro los contadores.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-lib...@googlegroups.com.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/1e374638-188d-4d8d-90e2-df6a78e1acf2%40googlegroups.com.
--
Has recibido este mensaje porque estás suscrito a un tema del grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este tema, visita https://groups.google.com/d/topic/fpga-wars-explorando-el-lado-libre/77Zw4ayF-DY/unsubscribe.
Para cancelar la suscripción a este grupo y a todos sus temas, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/b06f7b7c-d400-45c3-b2ef-7b181099c3f5%40googlegroups.com.
Divisor de frecuencia con enable (Enablea duen maiztasun-zatitzailearen kodea)
Obtenido en el enlace: Baudgen.v: Modificación del divisor curso verilog cap. 22
//--M Maiztasun zatitzailea
//--M divisor de frecuencia
localparam N = $clog2(M);
reg [N-1:0] divcounter = 0;
always @(posedge clk)
if (clk_ena)
//-- Funcionamiento normal
divcounter <= (divcounter == M - 1) ? 0 : divcounter + 1;
else
//-- Contador "congelado" al valor maximo
divcounter <= M - 1;
//-- Sacar un pulso de anchura 1 ciclo de reloj si el generador
//-- esta habilitado (clk_ena == 1)
//-- en caso contrario se saca 0
assign clk_out = (divcounter == 0) ? clk_ena : 0;
Contadores (z0, z1 y z3) (Zenbatzaileen moduloak (z0, z1 eta z2))
// Zenbatzailea reset funtzioarekin
// Contador con función reset
reg [3:0] counter;
reg out;
always@(posedge clk) begin
if (counter == MAX)
out <= 1;
else
out <= 0;
if (~rst)
counter <= 0;
else
if (en)
if (counter==MAX)
counter <= 0;
else
counter <= counter + 1;
end
assign enout = out;
assign z0 = counter;
Contador último, z3 (Azkeneko zenbatzailearen, z3ren, moduloa):
// Zenbatzailea (azkenekoa) reset funtzioarekin
// Contador (último) con función reset
reg [3:0] counter;
always@(posedge clk) begin
if (~rst)
counter <= 0;
else
if (en)
if (counter==MAX)
counter <= 0;
else
counter <= counter + 1;
end
assign z3 = counter;
Control del display función pause (Displayaren kontrola pause funtzioa bidez)
reg [3:0] a;
reg [3:0] b;
reg [3:0] c;
reg [3:0] d;
always @(posedge clk) begin
if (pause) begin
a <= a;
b <= b;
c <= c;
d <= d;
end
else begin
a <= z0;
b <= z1;
c <= z2;
d <= z3;
end
end
assign {a3, a2, a1, a0} = a;
assign {b3, b2, b1, b0} = b;
assign {c3, c2, c1, c0} = c;
assign {d3, d2, d1, d0} = d;
Mux 16:4
reg _z0;
reg _z1;
reg _z2;
reg _z3;
wire [1:0] _sel;
assign _sel = {sel1, sel0};
always @(*) begin
case(_sel)
0: begin
_z0 = a0;
_z1 = a1;
_z2 = a2;
_z3 = a3;
end
1: begin
_z0 = b0;
_z1 = b1;
_z2 = b2;
_z3 = b3;
end
2: begin
_z0 = c0;
_z1 = c1;
_z2 = c2;
_z3 = c3;
end
3: begin
_z0 = d0;
_z1 = d1;
_z2 = d2;
_z3 = d3;
end
default: begin
_z0 = a0;
_z1 = a1;
_z2 = a2;
_z3 = a3;
end
endcase
end
assign z0 = _z0;
assign z1 = _z1;
assign z2 = _z2;
assign z3 = _z3;
Lorea
La siguiente explicación me la apunto:
- Cada señal en un proceso es un registro. Todas las demás son wire.
module zenbatzailea (clk, rst, en, tc, z );
parameter MAX = 9;
parameter WIDTH = $clog2(MAX);
input clk, rst, en;
output tc;
output [WIDTH-1:0] z;
reg [WIDTH-1:0] r_reg;
wire [WIDTH-1:0] r_next;
//Hemendik aurrera, zuk nahi duzun estiloa
always@(posedge clk) begin
if (en | rst) begin r_reg <= r_next;
end else begin r_reg <= r_reg; end
end
assign cmp = (r_reg == MAX) ? 1 : 0;
assign r_next = (cmp | rst) ? 0 : r_reg + 1;
assign z = r_reg;
assign tc = cmp;
endmodule
zenbatzailea #(.MAX(599)) zat1( .clk(clk), .rst(rst), .en(1'b1), .tc(ens), .z() );
zenbatzailea #(.MAX(19)) zat2( .clk(clk), .rst(rst), .en(ens), .tc(enout[0]), .z() );
zenbatzailea #(.MAX(3)) selzenb( .clk(clk), .rst(rst), .en(ens), .tc(), .z(s) );
assign en[0] = ens;
genvar i;
generate for (i=1; i < 5; i = i+1) begin
assign en[i]=en[i-1] & enout[i-1];
zenbatzailea #(.MAX(maxs(i)),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
end endgenerate
always @(posedge clk) begin if (~p) begin r <= z; end else begin r <= r; end
assign o = r[s]; input clk, rst, p; //(p)ause
output [3:0] o; //irteera, 7-seg-era doana
wire [4:0] en, enout; //enable eta zenbatzaile bakoitzaren tick-a
wire [3:0][3:0] z; //(z)enbatzailea
reg [3:0][3:0] r; //pause e(r)registroa
wire [1:0] s; //(s)el
wire ens; //1. zatitzailearen irteera
zenbatzailea #(.MAX(59999)) zat1( .clk(clk), .rst(rst), .en(1'b1), .tc(ens), .z() );
zenbatzailea #(.MAX(19)) zat2( .clk(clk), .rst(rst), .en(ens), .tc(enout[0]), .z() );
zenbatzailea #(.MAX(3)) selzenb( .clk(clk), .rst(rst), .en(ens), .tc(), .z(s) );
assign en[0] = ens;
genvar i; generate for (i=1; i <= 4; i = i+1) begin
assign en[i]=en[i-1] & enout[i-1];
zenbatzailea #(.MAX(maxs(i)),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
end endgeneratezenbatzailea #(.MAX(9)) zenb0( .clk(clk), .rst(rst), .en(en[1]), .tc(enout[1]), .z(z[0]) );
zenbatzailea #(.MAX(9)) zenb1( .clk(clk), .rst(rst), .en(en[2]), .tc(enout[2]), .z(z[1]) );
zenbatzailea #(.MAX(5)) zenb2( .clk(clk), .rst(rst), .en(en[3]), .tc(enout[3]), .z(z[2]) );
zenbatzailea #(.MAX(9)) zenb3( .clk(clk), .rst(rst), .en(en[4]), .tc(enout[4]), .z(z[3]) );
assign en[1]=en[0] & enout[0];
assign en[2]=en[1] & enout[1];
assign en[3]=en[2] & enout[2];
assign en[4]=en[3] & enout[3]; function integer maxs ([3:0] i);
case(i)
3: begin maxs = 5; end
default: begin maxs = 9; end
endcase
endfunction function integer maxs ([3:0] i); maxs = (i==3) ? 5 : 9; endfunction always @(posedge clk) begin if (~p) begin r <= z; end end
assign l = r[s];module tb ( );
reg clk, rst, p;
initial begin
$dumpfile("design.vcd"); // Emaitzak fitxategi batean gorde, gero ikusteko
$dumpvars(0, tb); // Seinale guzti-guztiak gorde
p = 0; // Pauseren hasierako balioa
clk = 0; forever begin clk = ~clk; #1; end //Erloju nagusia
end
always begin
rst = 1; #30; rst = 0; // Reset-a hasieran aktibatu eta 30 simulazio zikloren ostean desaktibatu
#5000000; $finish; // Hainbat zikloren ostean, simulazioa bukatarazi
end
always@(posedge clk) begin p = ~p; #120000; end // Pause seinalea, al tuntun, zeozer ikus dadin
top uut( .clk(clk), .rst(rst), .p(p), .o() ); // Gure zirkuitu nagusia
endmodule
module top ( clk, rst, p, o );
// Kontadoreen maximoa zehazteko funtzioa: beti 9, hirugarren izan ezik (honek 5).
function integer maxs ([3:0] i);
case(i)
3: begin maxs = 5; end
default: begin maxs = 9; end
endcase
endfunction
input clk, rst, p; // (p)ause
output [3:0] o; // irteera, 7-seg-era doana
wire [4:0] en, enout; // enable eta zenbatzaile bakoitzaren tick-a
wire [3:0][3:0] z; // (z)enbatzailea
reg [3:0][3:0] r; // pause e(r)registroa
wire [1:0] s; // (s)el
wire ens; // 1. zatitzailearen irteera
// Frekuentzia zatitzaileak
zenbatzailea #(.MAX(599)) zat1( .clk(clk), .rst(rst), .en(1'b1), .tc(ens), .z() );
zenbatzailea #(.MAX(19)) zat2( .clk(clk), .rst(rst), .en(ens), .tc(enout[0]), .z() );
// Sel kontadorea
zenbatzailea #(.MAX(3)) selzenb( .clk(clk), .rst(rst), .en(ens), .tc(), .z(s) );
// Kronometroaren lau kontadoreak
assign en[0] = ens;
genvar i;
generate for (i=1; i <= 4; i = i+1) begin
assign en[i]=en[i-1] & enout[i-1];
zenbatzailea #(.MAX(maxs(i)),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
end endgenerate
// Pause erregistroa
always @(posedge clk) begin if (~p) begin r <= z; end end
// Irteerako 16:4 mux-a
assign o = m[s];
endmodule
module zenbatzailea (clk, rst, en, tc, z );
parameter MAX = 9;
parameter WIDTH = $clog2(MAX);
input clk, rst, en;
output tc;
output [WIDTH-1:0] z;
reg [WIDTH-1:0] r_reg;
wire [WIDTH-1:0] r_next;
always@(posedge clk) begin
if (en | rst) begin r_reg <= r_next;
end else begin r_reg <= r_reg; end
end
assign cmp = (r_reg == MAX) ? 1 : 0;
assign r_next = (cmp | rst) ? 0 : r_reg + 1;
assign z = r_reg;
assign tc = cmp;
endmodule
iverilog -o design kronosetpause.v && ./design
gtkwave design.vcd &

--
Has recibido este mensaje porque estás suscrito a un tema del grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este tema, visita https://groups.google.com/d/topic/fpga-wars-explorando-el-lado-libre/77Zw4ayF-DY/unsubscribe.
Para cancelar la suscripción a este grupo y a todos sus temas, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/025712e5-0434-4167-b6df-69178c585cd5%40googlegroups.com.
genvar i;
generate for (i=1; i <= 4; i = i+1) begin
assign en[i]=en[i-1] & enout[i-1];
if (i==3) begin
zenbatzailea #(.MAX(5),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
end else begin
zenbatzailea #(.MAX(9),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
end
end endgenerate
integer j;
always @(posedge clk) begin
for (j=0; j < 4; j = j+1) begin if (~p) begin r[j] = z[j]; end else begin r[j] = r[j]; end
end end
¡No esperaba que viera "tan bien"!
En cuanto a la primera página, donde está el otro contador y el resto de la lógica, no es tan fácil verlo...
After packing:
IOs 7 / 96
GBs 0 / 8
GB_IOs 0 / 8
LCs 89 / 1280
DFF 36
CARRY 12
CARRY, DFF 9
DFF PASS 16
CARRY PASS 6
BRAMs 0 / 16
WARMBOOTs 0 / 1
PLLs 0 / 1Resolvable net names on path:
0.640 ns .. 1.769 ns z[0][0]
2.148 ns .. 2.737 ns $abc$1101$n86
3.186 ns .. 3.775 ns $abc$1101$n97
4.175 ns .. 5.136 ns $abc$1101$n115
5.514 ns .. 6.987 ns $abc$1101$n6
lcout -> z[3][1]
Total number of logic levels: 5
Total path delay: 6.99 ns (143.12 MHz)
Y creo que esto es todo :D. Igual este salto a un sólo fichero en verilog te descoloca un poco al principio. Pero creo que ya has "machacado" suficiente el circuito como para entenderlo. Las estructuras generate con el corazón del HDL, es lo que permite hacer circuitos parametrizados. Parametrizar los tamaños de palabra esta bien, pero generar multiples variables de un módulo es donde está la potencia. Por ejemplo, en este caso, sólo con cambiar el número en for, podrías poner dos contadores más, para contar las horas. También podrías poner la parte del registro de pause dentro de un "generate if", de forma que si alguien no quiere usar esa funcionalidad, cambiando un parámetro no se sintetice ese registro.
Evidentemene, para poder cambiar el número del for, todas las señales de top deberían adaptarse. Es decir, habría que añadir un parámetro a top, por ejemplo, ZENKOP, y cambiar todos los "3" por "ZENKOP-1". Si quieres, es un ejercicio interesante.
Además, me parece muy interesante que te acostumbres a utilizar el simulador, porque da muchísma información sobre lo que está pasando en realidad, y permite ir comprobando las cosas de izquierda a derecha, verificando cada módulo paso a paso. Por eso te lo he facilitado en un fichero y te he indicado los comandos más directos. Lo que no sé es si utilizas GNU/Linux o Windows. Si es el segundo, ¿tienes acceso a algún equipo con linux o a una raspberry pi?
Badakit latza dala, hamar urte baino gehiagotan ikasitakoa pare astetan erdipurdi azaltzen ari natzaizu XD. Edozein momentutan gelditu eta atzera bueltatzea beharbazu, arazo barik esan. Edonola ere, kontuan izan "nire diseinurik onena" idatzi dudala oraingoan, nik neure proiektutan erabiliko nebana (falta den parametrizazioa bukatuz). Hau da, zirkuituak, funtzionaltasunik gehitu ezean, ez dauka mami gehiagorik. Zentzu hortan, lasai egon zaitezke, implementaziorarte heldu gara ta!
Ta zorionak neska! Detaile teknikoetan sartu naz zuzen-zuzen, eta martxan jartzeagatik zoriontzea ahaztu zait!
Ondo izan, animo, ta nahi duzunerako
Kaixo Unai,esker mila por toda la información, voy a tener que tomarme un rato largo (muy largo) para estudiarla y entenderla...