文章目录HDLBit 个人记录 (Verilog练习平台)Verilog LanguagesMore verilog featuresVectorsCircuitsCombinational logicMultiplexersSequential logiclateches and Flip-FlopsCounterShift registersMore circuitsFinite state machineSimple FSM1: synchronous reset.Designing a Moore FSMLemming 2Lemming 3lemming 4one-hot FSMPS/2 packet parserps/2 parser and data pathserial receiverserial receiver and data pathSerial receiver with parity checkQ8: Design a Mealy FSMq5a: serial twos complement (moore FSM)q5a: serial twos complement (Mealy FSM)q3a: FSMQ6 FSM (Q2a FSM)Q2b Another FSMHDLBit 个人记录 (Verilog练习平台)HDLBit网站上有时候会用system verilog的语法和verlog2001的语法标准有区别。可以注册账号写的代码就可以保存在云端了。Verilog LanguagesMore verilog featuresGenerate for-loops: 100 BCD adders: 将第一个addder特殊处理module top_module( input [399:0] a, b, input cin, output cout, output [399:0] sum ); wire[99:0] c; bcd_fadd f(a[3:0], b[3:0], cin, c[0], sum[3:0]); genvar i; generate for(i1; i100; ii1) begin: adder bcd_fadd f1(a[(4*i3):(4*i)], b[(4*i3):(4*i)], c[i-1], c[i], sum[(4*i3):(4*i)]); end endgenerate assign cout c[99]; endmoduleVectorsMore Replication: 使用复制写法module top_module ( input a, b, c, d, e, output [24:0] out );// // The output is XNOR of two vectors created by // concatenating and replicating the five inputs. // assign out ~{ ... } ^ { ... }; assign out ~{5{a, b, c, d ,e}} ^ {{5{a}}, {5{b}}, {5{c}}, {5{d}}, {5{e}}}; endmoduleCircuitsCombinational logicMultiplexers256-to-1 multiplexer.verilog2001中有part select语法module top_module( input [1023:0] in, input [7:0] sel, output [3:0] out ); assign out in[sel*4 :4]; endmoduleSequential logiclateches and Flip-FlopsDual edge这个我没想出来看了解析利用了异或的特性xx^y^ymodule top_module ( input clk, input d, output q ); reg q1, q2; always (posedge clk) begin q1 d ^ q2; end always (negedge clk) begin q2 d ^ q1; end assign q q1 ^ q2; endmoduleCounter12-hour clock时分秒的判断逻辑此外reset和ena互斥。module top_module( input clk, input reset, input ena, output pm, output [7:0] hh, output [7:0] mm, output [7:0] ss); always (posedge clk) begin if(reset) begin pm 0; ss 0; mm 0; hh h12; end else if (ena) begin ss (ss[3:0]9)? {ss[7:4]1,4b0}: ss1; if(ssh59)begin ss 0; mm mm[3:0]9? {mm[7:4]1,4b0}: mm1; if(mmh59) begin mm 0; hh hh[3:0]9? {hh[7:4]1,4b0}: hh1; if(hhh11) pm ~pm; if(hhh12) hh h01; end end end end endmoduleShift registers5bit LFSR5比特线性反馈移位器我将组合逻辑直接放在了always时序逻辑块里网站提供了参考答案将这部分组合逻辑剥离到另一个always组合逻辑块里。module top_module( input clk, input reset, // Active-high synchronous reset to 5h1 output [4:0] q ); always (posedge clk) begin if (reset ) q5d1; else begin q {q[0], q[4], q[3] ^ q[0], q[2], q[1]}; end end endmoduleshift registers使用generate生成同一种器件。module top_module ( input [3:0] SW, input [3:0] KEY, output [3:0] LEDR ); // wire[3:0] ws; assign ws[3] KEY[3]; assign ws[2] LEDR[3]; assign ws[1] LEDR[2]; assign ws[0] LEDR[1]; genvar i; generate for(i0; i4; i) begin: m MUXDFF mu(KEY[0], ws[i], SW[i], KEY[1], KEY[2], LEDR[i] ); end endgenerate endmodule module MUXDFF ( input clk, input w, R, E, L, output Q); always (posedge clk) begin Q L? R : (E? w:Q); end endmodule3 input LUTZ赋值时需要在always块外部才能构造组合逻辑否则在块内部会综合出寄存器导致输出延迟一个周期。module top_module ( input clk, input enable, input S, input A, B, C, output Z ); reg[7:0] Q; always (posedge clk) begin if (enable) Q {Q[6:0], S}; end assign Z Q[{A, B, C}]; endmoduleMore circuitsRule90按照题目提供的规律构造异或组合逻辑。module top_module( input clk, input load, input [511:0] data, output [511:0] q ); always (posedge clk) begin if(load) q data; else q {1b0, q[511:1]} ^ {q[510:0], 1b0}; end endmoduleRule110观察规律发现0值的情况仅有3种用0值写出组合逻辑。module top_module( input clk, input load, input [511:0] data, output [511:0] q ); wire[511:0] q1, q2; assign q1 {1b0, q[511:1]}; assign q2 {q[510:0], 1b0}; always (posedge clk) begin if(load) qdata; else begin q ~((q1 q q2) | ~(q | q2)); end end endmoduleConways Game of Life利用过程赋值中的阻塞赋值构建组合电路。module top_module( input clk, input load, input [255:0] data, output [255:0] q ); always (posedge clk) begin if(load) q data; else begin integer i, j; for(i0; i16; ii1) begin for(j0; j 16; jj1) begin integer i1, i2, j1, j2, n; i1 (i15)%16; i2 (i1)%16; j1 (j15)%16; j2 (j1)%16; n q[i1*16j1] q[i1*16j] q[i1*16j2] q[i2*16j1] q[i2*16j] q[i2*16j2] q[i*16j1] q[i*16j2]; case(n) 2: q[i*16j] q[i*16j]; 3: q[i*16j] 1b1; default: q[i*16j] 1b0; endcase end end end end endmoduleFinite state machineMoore状态机的输出只与当前状态有关与当前输入无关Mealy状态机的输出不仅与当前状态有关还取决于当前的输入信号。输入信号变化后输出会立即发生变化因此Mealy状态机的输出响应比Moore状态机快一个时钟周期。Simple FSM1: synchronous reset.给的示例程序将组合逻辑混入了时序逻辑块里极易出错。// Note the Verilog-1995 module declaration syntax here: module top_module(clk, reset, in, out); input clk; input reset; // Synchronous reset to state B input in; output out;// reg out; // Fill in state name declarations parameter A0, B1; reg present_state, next_state; always (posedge clk) begin if (reset) begin // Fill in reset logic present_state B; out B; end else begin case (present_state) // Fill in state transition logic A: next_state in? A : B; // 这里不可用赋值会使得赋值出现在present_state next_state; 之后 B: next_state in? B : A; // gemini说这种写法极易出现错误建议使用3段式 endcase // State flip-flops present_state next_state; case (present_state) // Fill in output logic A: out A; B: out B; endcase end end endmoduleDesigning a Moore FSM水位状态可以直接从s由组合逻辑给出只有dfr需要记录前序状态但是debugdfr花了很久时间参考了网上的解答才发现要初始化其实题目最后一句提到了dfr在reset要被赋值但是被我忽略了。此外网站给的解答是将中间两个水位结合dfr组成新的状态上下两个水位dfr固定。module top_module ( input clk, input reset, input [3:1] s, output fr3, output fr2, output fr1, output dfr ); parameter OFF0, ON1; reg state, next_state; reg[3:1] s_pre; /* 这种组合赋值没有延迟不符合测例要求 assign fr3 ~s[1]; assign fr2 ~s[2]; assign fr1 ~s[3]; */ always (*) begin next_state s s_pre? OFF: (ss_pre? ON: state); end always (posedge clk) begin if(reset) begin stateON; s_pre 0; //非常重要这个设定的初值用于判断后续对的dfr初值。 {fr1, fr2, fr3} {3{1b1}}; end else begin s_pre s; statenext_state; {fr1, fr2, fr3} ~s; end end assign dfr state; endmoduleLemming 2精巧设计状态值为下落划分两个状态因为题目需要下落后保持原有的方向所以如果下落简并为1个状态时那么就会无法记忆原有的方向信息。module top_module( input clk, input areset, // Freshly brainwashed Lemmings walk left. input bump_left, input bump_right, input ground, output walk_left, output walk_right, output aaah ); //设置状态的值使得L_F和LR_F和R的末位一致在组合逻辑里可以应用而L_F和R_F的高位为1在后面aaah赋值用到 // parameter要指定位宽否则会出现隐藏的问题比如后续为next_state赋值R_F: next_state {1b0, state[0]}就会不正常 parameter L2d0, R2d1, L_F2d2, R_F2d3; reg[1:0] state, next_state; always (*) begin if (~ground) next_state {1b1, state[0]};//L-L_F,R-R_F else begin case(state) L_F: next_state L; R_F: next_state R; L: next_state bump_left? R: L; R: next_state bump_right? L: R; endcase end end always (posedge clk, posedge areset) begin if(areset) state L; else state next_state; end assign walk_left (stateL); assign walk_right (stateR); assign aaah (state[1]1b1); endmoduleLemming 3注意dig的状态转换module top_module( input clk, input areset, // Freshly brainwashed Lemmings walk left. input bump_left, input bump_right, input ground, input dig, output walk_left, output walk_right, output aaah, output digging ); //引入下落状态保证最后一位存L, R的信息 parameter L3d0, R3d1, L_F3d2, R_F3d3, L_D 3b100, R_D3b101; reg[2:0] state, next_state; always (*) begin if (~ground) next_state {2b01, state[0]};//L-L_F,R-R_FL_D-L_F,R_D-R_F else if(dig ~state[1]) next_state {2b10, state[0]}; //对比时序图可知下落过程会在ground出现时存在但是仍然无法开始dig else begin case(state) L_D: next_state L_D; // dig的优先级高保持该状态 R_D: next_state R_D; L_F: next_state L; R_F: next_state R; L: next_state bump_left? R: L; R: next_state bump_right? L: R; endcase end end always (posedge clk, posedge areset) begin if(areset) state L; else state next_state; end assign walk_left (stateL); assign walk_right (stateR); assign aaah (state[1]1b1); assign digging (state[2]1b1); endmodulelemming 4注意赋值时的位宽极易出错module top_module( input clk, input areset, // Freshly brainwashed Lemmings walk left. input bump_left, input bump_right, input ground, input dig, output walk_left, output walk_right, output aaah, output digging ); //引入下落状态保证最后一位存L, R的信息splat不需要保存LR信息且优先级最高 parameter L3d0, R3d1, L_F3d2, R_F3d3, L_D 3b100, R_D3b101, SPLAT3b110, die_height5d20; reg[2:0] state, next_state; reg[4:0] counter; wire wait_splat; // 下面是组合逻辑 连线 assign wait_splat (counterdie_height)? 1b1: 1b0; always (*) begin if (stateSPLAT) next_state SPLAT; else if (~ground) next_state {2b01, state[0]};//L-L_F,R-R_FL_D-L_F,R_D-R_F else if (wait_splat) next_state SPLAT; //接触地面时转换 else if(dig ~state[1]) next_state {2b10, state[0]}; //对比时序图可知下落过程会在ground出现时存在但是仍然无法开始dig else begin case(state) SPLAT: next_state SPLAT; L_D: next_state L_D; // dig的优先级高保持该状态 R_D: next_state R_D; L_F: next_state L; R_F: next_state R; L: next_state bump_left? R: L; R: next_state bump_right? L: R; default: next_state x; //这里的case可以避免verilog综合出latch endcase end end // 下面是时序逻辑 连线 always (posedge clk, posedge areset) begin if(areset) begin state L; counter 0; end else begin state next_state; counter (state[2:1]2b01)? ((counter!die_height)? counter 1b1 :counter): 4d0; end end assign walk_left (stateL); assign walk_right (stateR); assign aaah (state[2:1]2b01); assign digging (state[2:1]2b10); endmoduleone-hot FSM题目要求观察位之间的运算关系所以按照之前FSM设计自定义组合逻辑块是无法通过测例的必须使用位运算逻辑。module top_module( input in, input [9:0] state, output [9:0] next_state, output out1, output out2); /* parameter S010d1, S110d2, S210d4, S310d8, S410d16, S510d32, S610d64, S710d128, S810d256, S910d512; always (*) begin case(state) S0: next_state in? S1: S0; S1: next_state in? S2: S0; S2: next_state in? S3: S0; S3: next_state in? S4: S0; S4: next_state in? S5: S0; S5: next_state in? S6: S8; S6: next_state in? S7: S9; S7: next_state in? S7: S0; S8: next_state in? S1: S0; S9: next_state in? S1: S0; default: next_state 0; endcase end */ assign next_state[0] ~in (state[0] | state[1] | state[2] | state[3] | state[4] | state[7] | state[8] | state[9]); assign next_state[1] in (state[0] | state[8] | state[9]); assign next_state[2] in state[1]; assign next_state[3] in state[2]; assign next_state[4] in state[3]; assign next_state[5] in state[4]; assign next_state[6] in state[5]; assign next_state[7] in (state[6] | state[7]); assign next_state[8] ~in state[5]; assign next_state[9] ~in state[6]; assign out1 state[8] | state[9]; assign out2 state[7] | state[9]; endmodulePS/2 packet parser在done信号后可以立即进入下一个字节这个我没注意到可以结合网站上的FSM图揣摩。我没有用网站提供的状态符号。module top_module( input clk, input [7:0] in, input reset, // Synchronous reset output done); // parameter B12d0, B232d1, W2d2, D2d3; // State transition logic (combinational) reg[1:0] state, next_state; always (*) begin case(state) B1: next_state B23; B23: next_state D; D: next_state in[3]? B1: W; W: next_state in[3]? B1: W; endcase end // State flip-flops (sequential) always (posedge clk) begin if(reset) state W; else state next_state; end // Output logic assign done (stateD); endmodule module top_module( input clk, input [7:0] in, input reset, // Synchronous reset output done); // parameter B12d0, B232d1, W2d2, D2d3; // State transition logic (combinational) reg[1:0] state, next_state; always (*) begin case(state) B1: next_state B23; B23: next_state D; D: next_state in[3]? B1: W; W: next_state in[3]? B1: W; endcase end // State flip-flops (sequential) always (posedge clk) begin if(reset) state W; else state next_state; end // Output logic assign done (stateD); endmoduleps/2 parser and data pathmodule top_module( input clk, input [7:0] in, input reset, // Synchronous reset output [23:0] out_bytes, output done); // parameter B12d0, B22d1, B32d2, D2d3; // State transition logic (combinational) reg[1:0] state, next_state; always (*) begin case(state) B1: next_state in[3]? B2:B1; B2: next_state B3; B3: next_state D; D: next_state in[3]? B2:B1; endcase end // State flip-flops (sequential) always (posedge clk) begin if(reset) state B1; else begin state next_state; case(state) B1: out_bytes[23:16] in; B2: out_bytes[15:8] in; B3: out_bytes[7:0] in; D: out_bytes[23:16] in; endcase end end // Output logic assign done (stateD); // New: Datapath to store incoming bytes. endmoduleserial receiver花了比较久时间在如何判断donemodule top_module( input clk, input in, input reset, // Synchronous reset output done ); parameter WAIT2d0, BYTE2d1, STOP2d3, W4d8; reg[1:0] state, next_state; reg[3:0] counter; wire b8; assign b8 (counterW)? 1b1: 1b0; always (*) begin case(state) WAIT: next_state ~in? BYTE: WAIT; BYTE: next_state b8? STOP: BYTE; STOP: next_state in? WAIT:STOP; default: next_state x; endcase end always (posedge clk) begin if(reset) begin counter 0; state WAIT; end else begin state next_state; counter (next_stateBYTE | next_stateSTOP)? counter1b1: 0; //next_stateBYTE其实代表这个周期就是BYTE状态因为上一句赋值了 end done (next_stateWAIT)(stateSTOP) (counter5d9); end // done的时序比stop慢一拍所以直接assign不符合时序要求 // assign done (next_stateWAIT)(stateSTOP); endmodule看到了网上引入ERROR状态这样可以简化done的判别条件图片中最后一行显示state[0]的状态在第二个周期从WAIT状态变为BYTE状态。module top_module( input clk, input in, input reset, // Synchronous reset output done ); parameter WAIT2d0, BYTE2d1, ERROR2d2, STOP2d3, W4d8; reg[1:0] state, next_state; reg[3:0] counter; wire b8; assign b8 (counterW)? 1b1: 1b0; always (*) begin case(state) WAIT: next_state ~in? BYTE: WAIT; BYTE: next_state b8? (in? STOP: ERROR): BYTE; STOP: next_state ~in? BYTE: WAIT; ERROR: next_state in? WAIT: ERROR; endcase end always (posedge clk) begin if(reset) begin counter 0; state WAIT; end else begin state next_state; counter (stateBYTE)? counter1b1: 0; //使用stateBYTEcounter8时的时间延迟了 end // 如果不引入ERROR状态直接通过下面式子也可判断done // done (next_stateWAIT)(stateSTOP) (counter5d9); end assign done stateSTOP; // done的时序比stop慢一拍所以直接assign不符合时序要求 // assign done (next_stateWAIT)(stateSTOP); endmoduleserial receiver and data path在上一题带有ERROR状态的always时序逻辑块里赋值网上有解答用移位赋值下一道题我用了移位赋值if (next_stateBYTE) out_byte[counter] in;Serial receiver with parity checkmodule top_module( input clk, input in, input reset, // Synchronous reset output [7:0] out_byte, output done ); // // Modify FSM and datapath from Fsm_serialdata parameter WAIT3d0, BYTE3d1, ERROR3d2, STOP3d3, PARITY3d4, W4d8; reg[2:0] state, next_state; reg[3:0] counter; reg p_check; // 检查结果需要留到下一个周期 wire b8, odd, parity_reset; // 组合逻辑连线 parity p(clk, parity_reset, in, odd); assign b8 (counterW)? 1b1: 1b0; assign parity_reset (stateWAIT | stateSTOP); // 从start开始因为要触发resetstart是0不会影响。 always (*) begin case(state) WAIT: next_state ~in? BYTE: WAIT; BYTE: next_state b8? PARITY: BYTE; PARITY: next_state in? STOP: ERROR; // 不能用 (p_check in) 这样在in正常是stop位但是parity错会误入ERROR状态。 STOP: next_state ~in? BYTE: WAIT; ERROR: next_state in? WAIT: ERROR; endcase end always (posedge clk) begin if(reset) begin counter 0; state WAIT; p_check 0; end else begin state next_state; counter (stateBYTE)? counter1b1: 0; //使用stateBYTEcounter8时的时间延迟了 end // New: Datapath to latch input bits. case(next_state) BYTE: begin out_byte {in, out_byte[7:1]}; end endcase if(statePARITY) p_check odd; end assign done p_check (stateSTOP); // New: Add parity checking. endmoduleQ8: Design a Mealy FSM注意时序逻辑块的敏感列表上升沿和下降沿使用module top_module ( input clk, input aresetn, // Asynchronous active-low reset input x, output z ); parameter S02d0, S12d1, S102d2; reg[1:0] state, next_state; always (*) begin case(state) S0: next_state x? S1: S0; S1: next_state x? S1: S10; S10: next_state x? S1: S0; default: next_state x; endcase end always (posedge clk, negedge aresetn) begin if(~aresetn) state S0; else state next_state; end assign z x (stateS10); endmoduleq5a: serial two’s complement (moore FSM)状态里存储{进位当前位}module top_module ( input clk, input areset, input x, output z ); // 状态里存储{进位当前位} // S2代表有进位当前位0S0,S1代表无进位当前为0和1S3没用不可能到达的状态 parameter S0 2d0, S12d1, S22d2, S32d3; reg[1:0] state, next_state; always (*) begin case(state) S0: next_state ~x? S1:S0; S1: next_state ~x? S1:S0; S2: next_state ~x? S2: S1; default: next_state x; endcase end always (posedge clk, posedge areset) begin if(areset) stateS2; else statenext_state; end assign z state[0]; endmoduleq5a: serial two’s complement (Mealy FSM)只使用进位作为状态module top_module ( input clk, input areset, input x, output z ); // 相当于是加法器的cout即进位 parameter A1b1, B1b0; reg state, next_state; always (*) begin case(state) A: next_state x? B: A; B: next_state B; endcase end always (posedge clk, posedge areset) begin if(areset) state A; else state next_state; end assign z x? state: (~state); endmoduleq3a: FSM被折磨了2hmodule top_module ( input clk, input reset, // Synchronous reset input s, input w, output z ); // 计数不再合并到状态里单独计数 parameter A2d0, B2d1, B22d2, B32d3; reg[1:0] state, next_state, count; reg w_s; always (*) begin case(state) A: next_state s? B: A; B: next_state B2; B2: next_state B3; B3: next_state B; endcase end always (posedge clk) begin if(reset) begin stateA; count 0; end else begin state next_state; w_s w; if(next_stateA) count (stateB)? (w? 2d1:2d0): (w? count 2d1: count);// 尝试用next_stateB判断会提前一个相位。 // z (stateB) (count2d2); end end // assign z (stateB) w; assign z (stateB) (count2d2); endmoduleQ6 FSM (Q2a FSM)Q6 FSM 和1Q2a FSM只有w取反的区别下面列出Q6的代码module top_module ( input clk, input reset, // synchronous reset input w, output z); parameter A3d0, B3d1, C3d2, D3d3, E3d4, F3d5; reg[2:0] state, next_state; always (*) begin case(state) A: next_state w? A: B; B: next_state w? D: C; C: next_state w? D: E; D: next_state w? A: F; E: next_state w? D: E; F: next_state w? D: C; endcase end always (posedge clk) begin if(reset) state A; else state next_state; end assign z (stateE) | (stateF); endmoduleQ2b Another FSM测例给的周期表明101序列上升沿后立即要输出f1而不是等一个周期后输入。module top_module ( input clk, input resetn, // active-low synchronous reset input x, input y, output f, output g ); parameter A3d0, F_S3d1, X_MON3d2, Y_MON3d3, Y_MON_13d4, SUC3d5, FAIL3d6; reg[2:0] state, next_state, rec; wire enter_g; // 组合逻辑连线 assign enter_g (rec[0] ~rec[1] rec[2]); always (*) begin case(state) A: next_state F_S; F_S: next_state X_MON; X_MON: next_state enter_g? Y_MON: X_MON; Y_MON: next_state y? SUC:FAIL; // Y_MON: next_state y? SUC:Y_MON_1; // Y_MON_1: next_state y? SUC:FAIL; SUC: next_state SUC; FAIL: next_state FAIL; default: next_state x; endcase end always (posedge clk) begin if(~resetn) begin state A; rec 0; end else begin state next_state; if(stateX_MON) rec {rec[1:0], x}; end end assign f stateF_S; // (next_stateY_MON)为了提前f的输出周期实际上使用的测例是在101序列中1出现的上升沿后立即产生f1 assign g (next_stateY_MON) | (stateY_MON) | (stateSUC); endmodule