/******************************************************************* VeriLab 4 AUTOMATA: T & JK FLIP-FLOPS, COUNTERS AND OTHERS SIMPLE AUTOMATA ********************************************************************/ /* An automaton is a circuit that reaches the autonomy of the evolution in the own state space. We remaind that a memory (1-OS) has the autonomy of meintaining the internal state induced by a previous external event. An automaton 'swims' inside the space of its states. The automaton maintains its state between two active edges of the clock and at each active edge of the clock switces in a new sate, according with the received signals and/or according with its internal rule. The internal rule is given by a new loop, the second loop of 2-OS. The first loop allows to mentain the state from an edge of clock to another edge, and this new, second, loop offer the posibility to have the own internal evolving rule. The smaller automaton has two state and one input. This is the T flip-flop, the smaller and the simplest automaton. Follows another 2-state automaton: the JK flop-flop, the biger flip-flop. In this VeriLab we approach only simple automaton. Remember that simple means to have a small and independent by size definition. In this respect a counter is a simple automaton. Simple are also machines to compute some usual functions. An example could be a sequential multiplier (accumulator) performing the operation by repeated additions. This machine consists in a composition of two simple automaton: a counter and an accumulator automaton serialy connected. The last example will be a stack built using a reversible counter that generates addresses for accessing a random acces memory for write and read. */ /*************** PROBLEM NO.1: The simplest automaton: the T flip-flop */ /* module t_ff(q, nq, t, clock, reset); input t, // if t = 1 then the automaton swithes synchronised by the positive edge of // the clock in the other state, else the automaton maintains the current state clock, reset; output q, nq; wire xor_out; d_ff ff(q, nq, xor_out, clock, reset); xor #1 (xor_out, q, t); // the XOR which closes the loop endmodule // The D flip-flop (a behavioral description) module d_ff(q, nq, d, clock, reset); input d, clock, reset; output q, nq; reg q; always @(posedge clock) if (reset) #2 q = 0; else #2 q = d; assign nq = ~q; endmodule module t_test; reg t, clock, reset; wire q, nq; initial begin clock = 0; forever #10 clock = ~clock; end initial begin t = 0; reset = 1; // the flip-flop must be initialised because must have // a well defined state in order to maintain or to change it #30 reset = 0; #40 t = 1; // the flip-flop starts to toggle #100 t = 0; #30 $stop; end t_ff dut(q, nq, t, clock, reset); initial $vw_dumpvars; endmodule */ /*************** PROBLEM NO.2: The biggest flip-flop as the simplest 2-input automaton: the JK flip-flop */ /* module jk_ff(q, nq, j, k, clock, reset); input j, k, clock, reset; output q, nq; reg q; always @(posedge clock or reset) if (~reset) q = 0; // low-level active asynchronous reset else case ({j, k}) 2'b00: q = q; 2'b01: q = 0; 2'b10: q = 1; 2'b11: q = ~q; endcase assign nq = ~q; endmodule module jk_test; reg j, k, clock, reset; wire q, nq; initial begin clock = 0; forever #10 clock = ~clock; end initial begin j = 0; k = 0; reset = 0; #30 reset = 1; #40 j = 1; #100 k = 1; #100 j = 0; #30 $stop; end jk_ff dut(q, nq, j, k, clock, reset); initial $vw_dumpvars; endmodule */ /*************** PROBLEM NO.3: The asynchronous counter */ /* module async_counter(ext, q2, q1, q0, count, clock, reset); input count, clock, reset; output ext, q2, q1, q0; wire nq1, nq0; t_ff ff_2(q2, ext, count, nq1, reset), ff_1(q1, nq1, count, nq0, reset), ff_0(q0, nq0, count, clock, reset); endmodule module t_ff(q, nq, t, clock, reset); input t, clock, reset; output q, nq; wire xor_out; d_ff ff(q, nq, xor_out, clock, reset); xor #1 (xor_out, q, t); endmodule module d_ff(q, nq, d, clock, reset); input d, clock, reset; output q, nq; reg q; always @(posedge clock) if (reset) #2 q = 0; else #2 q = d; assign nq = ~q; endmodule module test_async_counter; reg count, clock, reset; wire ext, q2, q1, q0; initial begin clock = 0; forever #10 clock = ~clock; end initial begin count = 1; reset = 1; #35 reset = 0; #200 count = 0; #40 $stop; end async_counter our_counter(ext, q2, q1, q0, count, clock, reset); initial $vw_dumpvars; endmodule */ /*************** PROBLEM NO.4: The structure of an n-bit synchronous counter */ /* module sync_counter(out, carry, in, clock, reset, load, down, count); parameter dim = 8; input clock, reset, load, down, count; input[dim - 1:0] in; output carry; output[dim - 1:0] out; reg[7:0] out; wire[dim - 1:0] xor_0_out, xor_1_out, mux_out; wire[dim:0] prefix_out; and_prefixes pref(prefix_out, {xor_0_out, count}); mux8_4to1 select(mux_out, 8'b0, 8'b0, in, xor_1_out, {reset, load}); assign xor_1_out = out ^ prefix_out[dim - 1:0], xor_0_out = out ^ (8'b0 - down); always @(posedge clock) out = mux_out; assign carry = prefix_out[dim]; endmodule module and_prefixes(out, in); parameter dim = 8; input[dim:0] in; output[dim:0] out; reg[dim:0] out; integer k; always @(in) begin out[0] = in[0]; for(k = 1; k < dim + 1; k= k + 1) out[k] = out[k-1] & in[k]; end endmodule module mux8_4to1(out, in3, in2,in1, in0, sel); parameter dim = 8; input[1:0] sel; input[dim - 1:0] in3, in2,in1, in0; output[dim - 1:0] out; reg[dim - 1:0] out; always @(in3 or in2 or in1 or in0 or sel) case (sel) 2'b00: out = in0; 2'b01: out = in1; 2'b10: out = in2; 2'b11: out = in3; endcase endmodule module test_sync_counter; parameter dim = 8; reg clock, reset, load, down, count; reg[dim - 1:0] in; wire carry; wire[dim -1:0] out; initial begin clock = 0; forever #10 clock = ~clock; end initial begin {reset, load, down, count} = 4'b1000; #40 {reset, load, down, count} = 4'b1111; #40 {reset, load, down, count} = 4'b0001; #400 {reset, load, down, count} = 4'b0011; #440 {reset, load, down, count} = 4'b0000; in = 8'd200; #20 {reset, load, down, count} = 4'b0100; #20 {reset, load, down, count} = 4'b0011; #300 $stop; end sync_counter dut(out, carry, in, clock, reset, load, down, count); initial $monitor("time=%0d clock=%b com=%b in=%b out=%b carry=%b", $time, clock, {reset, load, down, count}, in, dut.out, dut.carry); endmodule */ /*************** PROBLEM NO.5: How to design all 2-input, 2-state and one output automata? How many are all these automata? The solution: a simple programable structure. How long is the 'program'? Two 8-bit words. Therefore, there are 65536 kinds of such automata */ /* module prog_aut(out, in1, in0, loop_program, out_program, clock, reset); input in1, in0, clock, reset; input[7:0] loop_program, // 8-bit word to define one function from 256 functions out_program; // 8-bit word to define one function from 256 functions output out; reg state; // one bit state register // A multimplexer with 3-bit selection performs the output function given by the // actual value of the 8-bit selected input assign out = out_program[{state, in1, in0}]; // Another multiplexer closes the loop over the 1-bit state register always @(posedge clock) if (reset) state = 0; else state = loop_program[{state, in1, in0}]; endmodule // An application: serial n-bit adder (another application can be the JK flip-flop) module adder_automaton(out, no1, no0, reset, clock); input no1, no0, reset, clock; output out; // The two 8-bit words that follows represents the truth table of the full adder prog_aut ser_add(out, no1, no0, 8'b11101000, 8'b10010110, clock, reset); endmodule // Three serial registers & an adder_automaton = serial_adder. module serial_adder; // module used to test adder_automaton reg clock, reset, enable; reg[15:0] number_1, number_0, result; wire out; initial begin clock = 0; forever #10 clock = ~clock; end initial begin reset = 1; enable = 0; number_1 = 16'd12345; number_0 = 16'd3245; //result = 0; #20 reset = 0; enable = 1; #320 enable = 0; #40 $stop; end always @(posedge clock) if (enable) begin number_1 <= number_1 >> 1; number_0 <= number_0 >> 1; result <= {out, result[15:1]}; end adder_automaton the_adder(out, number_1[0], number_0[0], reset, clock); initial $monitor("time=%0d clock=%b no1=%d no0=%d result=%d", $time, clock, number_1, number_0, result); endmodule */ /*************** PROBLEM NO.6: Multiplier (accumulator) */ ///* module multiplier(out, end_mult, in, reset, load_1, load_0, clock); input reset, load_1, // command the load of 'in' as the first operand (multiplied) load_0, // command the load of 'in' as the second operand (multiplicand) clock; input[7:0] in; // data input that receive succesively the two operands together // with the two load command output end_mult; // shows the end of the multiplication previously started by // loading the second operand using 'load_0' output[15:0] out; // the output, validated by 'end_mult' reg[7:0] multiplied; // register to be loaded with the multiplied reg[15:0] out; // the accumulator register where the result is sequentialy formed always @(posedge clock) begin if (load_1) multiplied = in; // loads the multiplier if (reset) out = 0; // clears the previous result else if (~end_mult) out = multiplied + out; // accumulates end // Counter automaton used to decrement the multiplicand until zero when the accumulation // of multiplicand ends down_counter command_automaton(end_mult, in, load_0, clock); endmodule module down_counter(zero, in, load, clock); input load, // command that initializes the counter to the value 'in' clock; input[7:0] in; output zero; // indicates the value zero in counter reg[7:0] counter; always @(posedge clock) if (load) counter = in; else if (~zero) counter = counter - 1; // counter counts down // while it is not zero assign zero = ~| counter; // detects the value zero that stops the counting endmodule module test_mult; reg reset, load_1, load_0, clock; reg[7:0] in; wire end_mult; wire[15:0] out; initial begin clock = 0; forever #10 clock = ~clock; end initial begin reset = 1; in = 8'd7; #20 load_1 = 1; reset = 0; #20 load_1 = 0; load_0 = 1; in = 8'd27; #20 load_0 = 0; #1000 $stop; end multiplier dut(out, end_mult, in, reset, load_1, load_0, clock); initial $monitor("time=%0d in=%d com=%b end=%b out=%d", $time, in, {reset, load_1, load_0}, dut.end_mult, dut.out); endmodule //*/ /*************** PROBLEM NO.7: Multiplier using an adder and a shifter in order to save time (as home work) */ /* */ /*************** PROBLEM NO.8: Stack memory */ /* module lifo(out, full, in, push, pop, clock, reset); input push, // writes in the top of stack (tos) the 'in' value; the new tos // will be available in the next clock cycle pop, // removes the tos; the new tos will be accessible in the // next clock cycle clock, reset; // reset the addres counter and initializes the tos with zero input[15:0] in; output full; // shows that the far end of the stack is reached output[15:0] out; reg[3:0] add_reg; // a counter used as pointer to address the memory in which // the stack is organized reg[15:0] memory[0:15]; // the memory in which the stack is organized; has 16 words // of 16 bits each wire[3:0] inc_dec_out; // the connection between counter and memory assign out = memory[add_reg], // the current value of counter points the tos full = & add_reg; // when the tos is located in the address 1111 the stack is full // The increment/decrement module used to change the address in 'add_reg' and to generate // write address inc_dec add_reg_loop(inc_dec_out, add_reg, pop); // Writing in memory in the address that immediately follows of the address of tos always @(in or inc_dec_out or clock) if (push && ~clock) memory[inc_dec_out] = in; always @(posedge clock) if (reset) begin add_reg = 0; // initial value of the pointer memory[0] = 0; // initial top of stack end else if (push || pop) add_reg = inc_dec_out; // moving the pointer endmodule module inc_dec(out, in, com); // a combinational circuit that closes the loop of the pointer input com; // commands the increment or the decrement input[3:0] in; output[3:0] out; reg[3:0] out; always @(in or com) if (com) out = in - 1; else out = in + 1; endmodule module lifo_test; reg push, pop, clock, reset; reg[15:0] in; wire full; wire[15:0] out; initial begin clock = 0; forever #10 clock = ~clock; end initial begin reset = 1; #20 reset = 0; in = 16'd28; #20 push = 1; #20 push = 0; in = 16'd82; #20 push = 1; #20 push = 0; in = 16'd222; #20 push = 1; #260 push = 0; #20 pop = 1; #300 pop = 0; #40 $stop; end lifo lifo_ut(out, full, in, push, pop, clock, reset); initial $monitor("time=%d clock=%b in=%d com=%b out=%d full=%b add_reg=%d", $time, clock, in, {reset, push, pop}, lifo_ut.out, lifo_ut.full, lifo_ut.add_reg); endmodule */